Merge branch 'room-fix-states-with-statekeys' into 'master'

[Room] fix states with statekeys

See merge request famedly/famedlysdk!118
This commit is contained in:
Christian Pauly 2019-11-20 13:02:23 +00:00
commit a408764c86
6 changed files with 132 additions and 25 deletions

View File

@ -32,6 +32,7 @@ export 'package:famedlysdk/src/sync/UserUpdate.dart';
export 'package:famedlysdk/src/utils/ChatTime.dart';
export 'package:famedlysdk/src/utils/MatrixFile.dart';
export 'package:famedlysdk/src/utils/MxContent.dart';
export 'package:famedlysdk/src/utils/StatesMap.dart';
export 'package:famedlysdk/src/AccountData.dart';
export 'package:famedlysdk/src/Client.dart';
export 'package:famedlysdk/src/Connection.dart';

View File

@ -37,6 +37,7 @@ import 'package:mime_type/mime_type.dart';
import './User.dart';
import 'Connection.dart';
import 'Timeline.dart';
import 'utils/StatesMap.dart';
typedef onRoomUpdate = void Function();
@ -67,8 +68,7 @@ class Room {
/// The number of users with membership of invite.
int mInvitedMemberCount;
/// Key-Value store for room states.
Map<String, RoomState> states = {};
StatesMap states = StatesMap();
/// Key-Value store for ephemerals.
Map<String, RoomAccountData> ephemerals = {};
@ -155,18 +155,16 @@ class Room {
Event get lastEvent {
ChatTime lastTime = ChatTime(0);
Event lastEvent = null;
for (final entry in states.entries) {
final RoomState state = entry.value;
if ((state.time != null && state.time > lastTime) ||
state.typeKey == "m.room.message") {
lastTime = state.time;
lastEvent = state.timelineEvent;
if (state.typeKey == "m.room.message") {
break;
Event lastEvent = states["m.room.message"]?.timelineEvent;
if (lastEvent == null)
states.forEach((final String key, final entry) {
if (!entry.containsKey("")) return;
final RoomState state = entry[""];
if (state.time != null && state.time > lastTime) {
lastTime = state.time;
lastEvent = state.timelineEvent;
}
}
}
});
return lastEvent;
}
@ -194,7 +192,6 @@ class Room {
this.mHeroes = const [],
this.mInvitedMemberCount = 0,
this.mJoinedMemberCount = 0,
this.states = const {},
this.roomAccountData = const {},
});
@ -624,7 +621,6 @@ class Room {
mJoinedMemberCount: row["joined_member_count"],
mHeroes: row["heroes"]?.split(",") ?? [],
client: matrix,
states: {},
roomAccountData: {},
);
@ -635,7 +631,8 @@ class Room {
RoomState newState = RoomState.fromJson(rawStates[i], newRoom);
newStates[newState.key] = newState;
}
newRoom.states = newStates;
for (var entry in newStates.entries)
newRoom.states[entry.key] = entry.value;
}
Map<String, RoomAccountData> newRoomAccountData = {};
@ -682,9 +679,13 @@ class Room {
/// case.
List<User> getParticipants() {
List<User> userList = [];
for (var entry in states.entries)
if (entry.value.type == EventTypes.RoomMember)
userList.add(entry.value.asUser);
if (states["m.room.member"] is Map<String, dynamic>) {
print('Check members: ${states["m.room.member"].length}');
for (var entry in states["m.room.member"].entries) {
RoomState state = entry.value;
if (state.type == EventTypes.RoomMember) userList.add(state.asUser);
}
}
return userList;
}

View File

@ -130,7 +130,6 @@ class RoomList {
mHeroes: chatUpdate.summary?.mHeroes,
mJoinedMemberCount: chatUpdate.summary?.mJoinedMemberCount,
mInvitedMemberCount: chatUpdate.summary?.mInvitedMemberCount,
states: {},
roomAccountData: {},
client: client,
);

View File

@ -0,0 +1,36 @@
import 'package:famedlysdk/famedlysdk.dart';
/// Matrix room states are addressed by a tuple of the [type] and an
/// optional [stateKey].
class StatesMap {
Map<String, Map<String, RoomState>> states = {};
/// Returns either the [RoomState] or a map of state_keys to [RoomState] objects.
/// If you just enter a MatrixID, it will try to return the corresponding m.room.member event.
dynamic operator [](String key) {
if (key.startsWith("@") && key.contains(":")) {
if (!states.containsKey("m.room.member")) states["m.room.member"] = {};
return states["m.room.member"][key];
}
if (!states.containsKey(key)) states[key] = {};
if (states[key][""] is RoomState)
return states[key][""];
else if (states[key].length == 0)
return null;
else
return states[key];
}
void operator []=(String key, RoomState val) {
if (key.startsWith("@") && key.contains(":")) {
if (!states.containsKey("m.room.member")) states["m.room.member"] = {};
states["m.room.member"][key] = val;
}
if (!states.containsKey(key)) states[key] = {};
states[key][val.stateKey ?? ""] = val;
}
bool containsKey(String key) => states.containsKey(key);
void forEach(f) => states.forEach(f);
}

74
test/StatesMap_test.dart Normal file
View File

@ -0,0 +1,74 @@
/*
* 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 'package:famedlysdk/famedlysdk.dart';
import 'package:test/test.dart';
import 'package:famedlysdk/src/utils/StatesMap.dart';
void main() {
/// All Tests related to the ChatTime
group("StateKeys", () {
test("Operator overload", () async {
StatesMap states = StatesMap();
states["m.room.name"] = RoomState(
eventId: "1",
content: {"name": "test"},
typeKey: "m.room.name",
stateKey: "",
roomId: "!test:test.test",
senderId: "@alice:test.test");
states["@alice:test.test"] = RoomState(
eventId: "2",
content: {"membership": "join"},
typeKey: "m.room.name",
stateKey: "@alice:test.test",
roomId: "!test:test.test",
senderId: "@alice:test.test");
states["m.room.member"]["@bob:test.test"] = RoomState(
eventId: "3",
content: {"membership": "join"},
typeKey: "m.room.name",
stateKey: "@bob:test.test",
roomId: "!test:test.test",
senderId: "@bob:test.test");
states["com.test.custom"] = RoomState(
eventId: "4",
content: {"custom": "stuff"},
typeKey: "com.test.custom",
stateKey: "customStateKey",
roomId: "!test:test.test",
senderId: "@bob:test.test");
expect(states["m.room.name"].eventId, "1");
expect(states["@alice:test.test"].eventId, "2");
expect(states["m.room.member"]["@alice:test.test"].eventId, "2");
expect(states["@bob:test.test"].eventId, "3");
expect(states["m.room.member"]["@bob:test.test"].eventId, "3");
expect(states["m.room.member"].length, 2);
expect(states["com.test.custom"]["customStateKey"].eventId, "4");
});
});
}

View File

@ -43,11 +43,7 @@ void main() {
client.homeserver = "https://fakeServer.notExisting";
Room room = Room(
id: roomID,
client: client,
prev_batch: "1234",
states: {},
roomAccountData: {});
id: roomID, client: client, prev_batch: "1234", roomAccountData: {});
Timeline timeline = Timeline(
room: room,
events: [],