2019-06-21 11:30:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019 Zender & Kurtz GbR.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Christian Pauly <krille@famedly.com>
|
|
|
|
* Marcel Radzio <mtrnord@famedly.com>
|
|
|
|
*
|
|
|
|
* This file is part of famedlysdk.
|
|
|
|
*
|
|
|
|
* famedlysdk is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* famedlysdk is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import 'dart:async';
|
|
|
|
import 'dart:core';
|
2019-07-12 09:26:07 +00:00
|
|
|
|
2019-08-08 10:51:07 +00:00
|
|
|
import 'package:famedlysdk/src/RoomState.dart';
|
2019-08-07 09:38:51 +00:00
|
|
|
|
2019-06-21 11:30:39 +00:00
|
|
|
import 'Client.dart';
|
|
|
|
import 'Room.dart';
|
|
|
|
import 'User.dart';
|
|
|
|
import 'sync/EventUpdate.dart';
|
|
|
|
import 'sync/RoomUpdate.dart';
|
|
|
|
|
2019-09-02 08:33:32 +00:00
|
|
|
typedef onRoomListUpdateCallback = void Function();
|
|
|
|
typedef onRoomListInsertCallback = void Function(int insertID);
|
|
|
|
typedef onRoomListRemoveCallback = void Function(int insertID);
|
|
|
|
|
2019-06-21 11:30:39 +00:00
|
|
|
/// Represents a list of rooms for this client, which will automatically update
|
|
|
|
/// itself and call the [onUpdate], [onInsert] and [onDelete] callbacks. To get
|
|
|
|
/// the initial room list, use the store or create a RoomList instance by using
|
|
|
|
/// [client.getRoomList].
|
|
|
|
class RoomList {
|
|
|
|
final Client client;
|
|
|
|
List<Room> rooms = [];
|
|
|
|
|
|
|
|
final bool onlyLeft;
|
|
|
|
|
|
|
|
/// Will be called, when the room list has changed. Can be used e.g. to update
|
|
|
|
/// the state of a StatefulWidget.
|
2019-06-25 10:06:26 +00:00
|
|
|
final onRoomListUpdateCallback onUpdate;
|
2019-06-21 11:30:39 +00:00
|
|
|
|
|
|
|
/// Will be called, when a new room is added to the list.
|
2019-06-25 10:06:26 +00:00
|
|
|
final onRoomListInsertCallback onInsert;
|
2019-06-21 11:30:39 +00:00
|
|
|
|
|
|
|
/// Will be called, when a room has been removed from the list.
|
2019-06-25 10:06:26 +00:00
|
|
|
final onRoomListRemoveCallback onRemove;
|
2019-06-21 11:30:39 +00:00
|
|
|
|
|
|
|
StreamSubscription<EventUpdate> eventSub;
|
|
|
|
StreamSubscription<RoomUpdate> roomSub;
|
|
|
|
|
|
|
|
RoomList(
|
|
|
|
{this.client,
|
|
|
|
this.rooms,
|
|
|
|
this.onUpdate,
|
|
|
|
this.onInsert,
|
|
|
|
this.onRemove,
|
2019-09-19 14:00:17 +00:00
|
|
|
this.onlyLeft = false}) {
|
2019-06-21 11:30:39 +00:00
|
|
|
eventSub ??= client.connection.onEvent.stream.listen(_handleEventUpdate);
|
|
|
|
roomSub ??= client.connection.onRoomUpdate.stream.listen(_handleRoomUpdate);
|
2019-08-29 07:16:07 +00:00
|
|
|
sort();
|
2019-06-21 11:30:39 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 10:06:28 +00:00
|
|
|
Room getRoomByAlias(String alias) {
|
|
|
|
for (int i = 0; i < rooms.length; i++) {
|
|
|
|
if (rooms[i].canonicalAlias == alias) return rooms[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-08-29 09:03:43 +00:00
|
|
|
Room getRoomById(String id) {
|
|
|
|
for (int j = 0; j < rooms.length; j++) {
|
|
|
|
if (rooms[j].id == id) return rooms[j];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-07-30 07:35:52 +00:00
|
|
|
void _handleRoomUpdate(RoomUpdate chatUpdate) {
|
2019-06-21 11:30:39 +00:00
|
|
|
// Update the chat list item.
|
|
|
|
// Search the room in the rooms
|
|
|
|
num j = 0;
|
|
|
|
for (j = 0; j < rooms.length; j++) {
|
|
|
|
if (rooms[j].id == chatUpdate.id) break;
|
|
|
|
}
|
2019-09-12 10:35:57 +00:00
|
|
|
final bool found = (j < rooms.length && rooms[j].id == chatUpdate.id);
|
2019-07-12 09:26:07 +00:00
|
|
|
final bool isLeftRoom = chatUpdate.membership == Membership.leave;
|
2019-06-21 11:30:39 +00:00
|
|
|
|
|
|
|
// Does the chat already exist in the list rooms?
|
2019-06-27 17:34:15 +00:00
|
|
|
if (!found && ((!onlyLeft && !isLeftRoom) || (onlyLeft && isLeftRoom))) {
|
2019-07-12 09:26:07 +00:00
|
|
|
num position = chatUpdate.membership == Membership.invite ? 0 : j;
|
2019-06-21 11:30:39 +00:00
|
|
|
// Add the new chat to the list
|
|
|
|
Room newRoom = Room(
|
2019-07-23 13:10:38 +00:00
|
|
|
id: chatUpdate.id,
|
|
|
|
membership: chatUpdate.membership,
|
|
|
|
prev_batch: chatUpdate.prev_batch,
|
|
|
|
highlightCount: chatUpdate.highlight_count,
|
|
|
|
notificationCount: chatUpdate.notification_count,
|
2019-08-06 09:47:09 +00:00
|
|
|
mHeroes: chatUpdate.summary?.mHeroes,
|
|
|
|
mJoinedMemberCount: chatUpdate.summary?.mJoinedMemberCount,
|
|
|
|
mInvitedMemberCount: chatUpdate.summary?.mInvitedMemberCount,
|
2019-08-07 10:27:02 +00:00
|
|
|
states: {},
|
|
|
|
roomAccountData: {},
|
2019-08-08 07:58:37 +00:00
|
|
|
client: client,
|
2019-07-23 13:10:38 +00:00
|
|
|
);
|
2019-06-21 11:30:39 +00:00
|
|
|
rooms.insert(position, newRoom);
|
2019-06-25 10:34:03 +00:00
|
|
|
if (onInsert != null) onInsert(position);
|
2019-06-21 11:30:39 +00:00
|
|
|
}
|
2019-06-27 17:34:15 +00:00
|
|
|
// If the membership is "leave" or not "leave" but onlyLeft=true then remove the item and stop here
|
|
|
|
else if (found &&
|
|
|
|
((!onlyLeft && isLeftRoom) || (onlyLeft && !isLeftRoom))) {
|
2019-06-27 10:33:02 +00:00
|
|
|
rooms.removeAt(j);
|
2019-06-25 10:34:03 +00:00
|
|
|
if (onRemove != null) onRemove(j);
|
2019-06-21 11:30:39 +00:00
|
|
|
}
|
2019-09-19 14:00:17 +00:00
|
|
|
// Update notification, highlight count and/or additional informations
|
2019-06-21 11:30:39 +00:00
|
|
|
else if (found &&
|
2019-07-12 09:26:07 +00:00
|
|
|
chatUpdate.membership != Membership.leave &&
|
2019-06-21 11:30:39 +00:00
|
|
|
(rooms[j].notificationCount != chatUpdate.notification_count ||
|
2019-09-19 14:00:17 +00:00
|
|
|
rooms[j].highlightCount != chatUpdate.highlight_count ||
|
|
|
|
chatUpdate.summary != null)) {
|
2019-06-21 11:30:39 +00:00
|
|
|
rooms[j].notificationCount = chatUpdate.notification_count;
|
|
|
|
rooms[j].highlightCount = chatUpdate.highlight_count;
|
2019-09-19 14:00:17 +00:00
|
|
|
if (chatUpdate.prev_batch != null)
|
|
|
|
rooms[j].prev_batch = chatUpdate.prev_batch;
|
2019-08-06 09:47:09 +00:00
|
|
|
if (chatUpdate.summary != null) {
|
|
|
|
if (chatUpdate.summary.mHeroes != null)
|
|
|
|
rooms[j].mHeroes = chatUpdate.summary.mHeroes;
|
|
|
|
if (chatUpdate.summary.mJoinedMemberCount != null)
|
|
|
|
rooms[j].mJoinedMemberCount = chatUpdate.summary.mJoinedMemberCount;
|
|
|
|
if (chatUpdate.summary.mInvitedMemberCount != null)
|
|
|
|
rooms[j].mInvitedMemberCount = chatUpdate.summary.mInvitedMemberCount;
|
|
|
|
}
|
2019-09-03 11:24:44 +00:00
|
|
|
if (rooms[j].onUpdate != null) rooms[j].onUpdate();
|
2019-06-21 11:30:39 +00:00
|
|
|
}
|
|
|
|
sortAndUpdate();
|
|
|
|
}
|
|
|
|
|
2019-07-30 07:35:52 +00:00
|
|
|
void _handleEventUpdate(EventUpdate eventUpdate) {
|
2019-08-29 08:26:21 +00:00
|
|
|
if (eventUpdate.type != "timeline" && eventUpdate.type != "state") return;
|
2019-06-21 11:30:39 +00:00
|
|
|
// Search the room in the rooms
|
|
|
|
num j = 0;
|
|
|
|
for (j = 0; j < rooms.length; j++) {
|
|
|
|
if (rooms[j].id == eventUpdate.roomID) break;
|
|
|
|
}
|
|
|
|
final bool found = (j < rooms.length && rooms[j].id == eventUpdate.roomID);
|
2019-07-23 13:03:16 +00:00
|
|
|
if (!found) return;
|
2019-06-21 11:30:39 +00:00
|
|
|
|
2019-08-08 10:51:07 +00:00
|
|
|
RoomState stateEvent = RoomState.fromJson(eventUpdate.content, rooms[j]);
|
2019-08-07 09:38:51 +00:00
|
|
|
if (rooms[j].states[stateEvent.key] != null &&
|
|
|
|
rooms[j].states[stateEvent.key].time > stateEvent.time) return;
|
|
|
|
rooms[j].states[stateEvent.key] = stateEvent;
|
2019-09-03 11:24:44 +00:00
|
|
|
if (rooms[j].onUpdate != null) rooms[j].onUpdate();
|
2019-06-21 11:30:39 +00:00
|
|
|
sortAndUpdate();
|
|
|
|
}
|
|
|
|
|
2019-08-29 07:16:07 +00:00
|
|
|
sort() {
|
2019-06-21 11:30:39 +00:00
|
|
|
rooms?.sort((a, b) =>
|
|
|
|
b.timeCreated.toTimeStamp().compareTo(a.timeCreated.toTimeStamp()));
|
2019-08-29 07:16:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sortAndUpdate() {
|
|
|
|
sort();
|
2019-06-25 10:34:03 +00:00
|
|
|
if (onUpdate != null) onUpdate();
|
2019-06-21 11:30:39 +00:00
|
|
|
}
|
|
|
|
}
|