diff --git a/lib/src/Event.dart b/lib/src/Event.dart index c129528..de3eaf9 100644 --- a/lib/src/Event.dart +++ b/lib/src/Event.dart @@ -27,7 +27,6 @@ import 'package:famedlysdk/src/utils/ChatTime.dart'; import 'package:famedlysdk/src/utils/Receipt.dart'; import './Room.dart'; -import 'User.dart'; /// Defines a timeline event for a room. class Event extends RoomState { @@ -106,8 +105,7 @@ class Event extends RoomState { for (var entry in room.roomAccountData["m.receipt"].content.entries) { if (entry.value["event_id"] == eventId) receiptsList.add(Receipt( - room.states[entry.key]?.asUser ?? User(entry.key), - ChatTime(entry.value["ts"]))); + room.getUserByMXIDSync(entry.key), ChatTime(entry.value["ts"]))); } return receiptsList; } diff --git a/lib/src/Room.dart b/lib/src/Room.dart index 6103220..40338b1 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -176,8 +176,7 @@ class Room { List typingMxid = ephemerals["m.typing"].content["user_ids"]; List typingUsers = []; for (int i = 0; i < typingMxid.length; i++) - typingUsers.add( - states[typingMxid[i]]?.asUser ?? User(typingMxid[i], room: this)); + typingUsers.add(getUserByMXIDSync(typingMxid[i])); return typingUsers; } @@ -707,16 +706,56 @@ class Room { return participants; } + /// Returns the [User] object for the given [mxID] or requests it from + /// the homeserver and waits for a response. Future getUserByMXID(String mxID) async { if (states[mxID] != null) return states[mxID].asUser; + return requestUser(mxID); + } + + /// Returns the [User] object for the given [mxID] or requests it from + /// the homeserver and returns a default [User] object while waiting. + User getUserByMXIDSync(String mxID) { + if (states[mxID] != null) + return states[mxID].asUser; + else { + requestUser(mxID); + return User(mxID, room: this); + } + } + + Set _requestingMatrixIds = Set(); + + /// Requests a missing [User] for this room. Important for clients using + /// lazy loading. + Future requestUser(String mxID) async { + if (mxID == null || !_requestingMatrixIds.add(mxID)) return null; final dynamic resp = await client.connection.jsonRequest( type: HTTPType.GET, action: "/client/r0/rooms/$id/state/m.room.member/$mxID"); - if (resp is ErrorResponse) return null; - return User(mxID, + if (resp is ErrorResponse) { + _requestingMatrixIds.remove(mxID); + return null; + } + final User user = User(mxID, displayName: resp["displayname"], avatarUrl: resp["avatar_url"], room: this); + states[mxID] = user; + if (client.store != null) + client.store.transaction(() { + client.store.storeEventUpdate( + EventUpdate( + content: resp, + roomID: id, + type: "state", + eventType: "m.room.member"), + ); + return; + }); + if (onUpdate != null) onUpdate(); + _requestingMatrixIds.remove(mxID); + return user; } /// Searches for the event in the store. If it isn't found, try to request it diff --git a/lib/src/RoomState.dart b/lib/src/RoomState.dart index 105a140..b6548ff 100644 --- a/lib/src/RoomState.dart +++ b/lib/src/RoomState.dart @@ -43,7 +43,7 @@ class RoomState { /// The user who has sent this event if it is not a global account data event. final String senderId; - User get sender => room.states[senderId]?.asUser ?? User(senderId); + User get sender => room.getUserByMXIDSync(senderId); /// The time this event has received at the server. May be null for events like /// account data. @@ -64,7 +64,7 @@ class RoomState { /// the overwriting semantics for this piece of room state. final String stateKey; - User get stateKeyUser => room.states[stateKey]?.asUser ?? User(stateKey); + User get stateKeyUser => room.getUserByMXIDSync(stateKey); RoomState( {this.content,