Skip to content

Commit 69e17a6

Browse files
committed
fix: simplify seen by indicator
1 parent 17903aa commit 69e17a6

File tree

7 files changed

+91
-88
lines changed

7 files changed

+91
-88
lines changed

lib/chat/chat_model.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class ChatModel extends SafeChangeNotifier {
5454
/// The unfiltered onSync stream of the [Client]
5555
Stream<SyncUpdate> get syncStream => _client.onSync.stream;
5656

57+
Stream<List<Receipt>> getRoomsReceipts(Event event) =>
58+
getJoinedRoomUpdate(event.room.id).map((_) => event.receipts);
59+
60+
Future<List<User>> requestParticipants(Room room) async =>
61+
room.requestParticipants();
62+
5763
Stream<List<User>> getUsersStreamOfJoinedRoom(
5864
Room room, {
5965
List<Membership> membershipFilter = const [

lib/chat/room_x.dart

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,6 @@
11
import 'package:matrix/matrix.dart';
22

33
extension RoomX on Room {
4-
List<User> getSeenByUsers(List<Event> events, {String? eventId}) {
5-
if (events.isEmpty) return [];
6-
eventId ??= events.first.eventId;
7-
8-
final lastReceipts = <User>{};
9-
for (final e in events) {
10-
lastReceipts.addAll(
11-
e.receipts.map((r) => r.user).where(
12-
(u) => u.id != client.userID && u.id != events.first.senderId,
13-
),
14-
);
15-
if (e.eventId == eventId) {
16-
break;
17-
}
18-
}
19-
20-
return lastReceipts.toList();
21-
}
22-
234
bool get canEditAtleastSomething =>
245
ownPowerLevel == 100 ||
256
canKick ||

lib/chat/timeline_model.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class TimelineModel extends SafeChangeNotifier {
1414

1515
Future<void> requestHistory(
1616
Timeline timeline, {
17-
int historyCount = 350,
17+
int historyCount = 50,
1818
StateFilter? filter,
1919
bool notify = true,
2020
}) async {

lib/chat/view/chat_room/chat_room_page.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class _ChatRoomPageState extends State<ChatRoomPage> {
3636
void initState() {
3737
super.initState();
3838
_timelineFuture = widget.room.getTimeline(
39-
onUpdate: () => _roomListKey.currentState?.setState(() {}),
4039
onNewEvent: () => _roomListKey.currentState?.setState(() {}),
4140
onChange: (i) => _roomListKey.currentState?.setState(() {}),
4241
onInsert: (i) => _roomListKey.currentState?.insertItem(i),

lib/chat/view/chat_room/chat_room_timeline_list.dart

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import '../../../common/view/theme.dart';
99
import '../../../common/view/ui_constants.dart';
1010
import '../../timeline_model.dart';
1111
import '../events/chat_event_column.dart';
12+
import 'chat_seen_by_indicator.dart';
1213
import 'chat_typing_indicator.dart';
1314
import 'titlebar/chat_room_title_bar.dart';
1415

@@ -83,14 +84,26 @@ class _ChatRoomTimelineListState extends State<ChatRoomTimelineList> {
8384
key: ValueKey('${event.eventId}tag'),
8485
child: FadeTransition(
8586
opacity: animation,
86-
child: ChatEventColumn(
87-
key: ValueKey('${event.eventId}column'),
88-
event: event,
89-
maybePreviousEvent: maybePreviousEvent,
90-
jump: _jump,
91-
showSeenByIndicator: i == 0,
92-
timeline: widget.timeline,
93-
room: widget.room,
87+
child: Column(
88+
mainAxisSize: MainAxisSize.min,
89+
children: [
90+
ChatEventColumn(
91+
key: ValueKey('${event.eventId}column'),
92+
event: event,
93+
maybePreviousEvent: maybePreviousEvent,
94+
jump: _jump,
95+
showSeenByIndicator: i == 0,
96+
timeline: widget.timeline,
97+
room: widget.room,
98+
),
99+
if (i == 0)
100+
ChatEventSeenByIndicator(
101+
key: ValueKey(
102+
'${event.eventId}${widget.timeline.events.length}',
103+
),
104+
event: event,
105+
),
106+
],
94107
),
95108
),
96109
);

lib/chat/view/chat_room/chat_seen_by_indicator.dart

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,42 @@ import 'package:watch_it/watch_it.dart';
55
import '../../../common/view/build_context_x.dart';
66
import '../../../common/view/ui_constants.dart';
77
import '../../chat_model.dart';
8-
import '../../room_x.dart';
98
import '../../search_model.dart';
109
import '../chat_avatar.dart';
1110
import '../chat_profile_dialog.dart';
1211

13-
class ChatSeenByIndicator extends StatefulWidget
14-
with WatchItStatefulWidgetMixin {
15-
const ChatSeenByIndicator({
12+
class ChatEventSeenByIndicator extends StatelessWidget with WatchItMixin {
13+
const ChatEventSeenByIndicator({
1614
super.key,
17-
required this.room,
18-
required this.timeline,
15+
required this.event,
1916
});
2017

21-
final Room room;
22-
final Timeline timeline;
18+
final Event event;
2319

2420
static const maxAvatars = 7;
2521

26-
@override
27-
State<ChatSeenByIndicator> createState() => _ChatSeenByIndicatorState();
28-
}
29-
30-
class _ChatSeenByIndicatorState extends State<ChatSeenByIndicator> {
31-
@override
32-
void initState() {
33-
super.initState();
34-
widget.room.requestParticipants();
35-
}
36-
3722
@override
3823
Widget build(BuildContext context) {
39-
final events = watchStream(
40-
(ChatModel m) => m.getReadEventsFromSync(widget.room),
41-
initialValue: widget.timeline.events,
42-
).data;
43-
final list = <Event>{...widget.timeline.events, ...?events}.toList();
44-
final seenByUsers = widget.room.getSeenByUsers(list);
24+
watchFuture(
25+
(ChatModel m) => m.requestParticipants(event.room),
26+
initialValue: event.room.getParticipants(),
27+
);
28+
29+
final seenByUsers = watchStream(
30+
(ChatModel m) => m.getRoomsReceipts(event),
31+
initialValue: event.receipts,
32+
)
33+
.data
34+
?.map((e) => e.user)
35+
.where((e) => e.id != di<ChatModel>().myUserId)
36+
.toList() ??
37+
[];
4538

4639
return Container(
4740
width: double.infinity,
48-
alignment: widget.room.isDirectChat ||
49-
di<ChatModel>().isUserEvent(list.first) &&
50-
list.first.type != EventTypes.Reaction
41+
alignment: event.room.isDirectChat ||
42+
di<ChatModel>().isUserEvent(event) &&
43+
event.type != EventTypes.Reaction
5144
? Alignment.centerRight
5245
: Alignment.centerLeft,
5346
child: AnimatedContainer(
@@ -60,35 +53,19 @@ class _ChatSeenByIndicatorState extends State<ChatSeenByIndicator> {
6053
child: Wrap(
6154
spacing: kSmallPadding,
6255
children: [
63-
...(seenByUsers.length > ChatSeenByIndicator.maxAvatars
64-
? seenByUsers.sublist(0, ChatSeenByIndicator.maxAvatars)
56+
...(seenByUsers.length > maxAvatars
57+
? seenByUsers.sublist(
58+
0,
59+
maxAvatars,
60+
)
6561
: seenByUsers)
6662
.map(
67-
(user) => Tooltip(
63+
(user) => ChatEventSeenByAvatar(
6864
key: ValueKey(user.id + user.avatarUrl.toString()),
69-
message: user.displayName ?? user.id,
70-
child: InkWell(
71-
borderRadius: BorderRadius.circular(15),
72-
onTap: () async {
73-
final profile =
74-
await di<SearchModel>().lookupProfile(user.id);
75-
if (context.mounted) {
76-
showDialog(
77-
context: context,
78-
builder: (context) =>
79-
ChatProfileDialog(userId: profile.userId),
80-
);
81-
}
82-
},
83-
child: ChatAvatar(
84-
avatarUri: user.avatarUrl,
85-
fallBackIconSize: 10,
86-
dimension: 15,
87-
),
88-
),
65+
user: user,
8966
),
9067
),
91-
if (seenByUsers.length > ChatSeenByIndicator.maxAvatars)
68+
if (seenByUsers.length > maxAvatars)
9269
SizedBox(
9370
width: 15,
9471
height: 15,
@@ -97,7 +74,7 @@ class _ChatSeenByIndicatorState extends State<ChatSeenByIndicator> {
9774
borderRadius: BorderRadius.circular(30),
9875
child: Center(
9976
child: Text(
100-
'+${seenByUsers.length - ChatSeenByIndicator.maxAvatars}',
77+
'+${seenByUsers.length - maxAvatars}',
10178
style: const TextStyle(fontSize: 9),
10279
),
10380
),
@@ -109,3 +86,36 @@ class _ChatSeenByIndicatorState extends State<ChatSeenByIndicator> {
10986
);
11087
}
11188
}
89+
90+
class ChatEventSeenByAvatar extends StatelessWidget {
91+
const ChatEventSeenByAvatar({
92+
super.key,
93+
required this.user,
94+
});
95+
96+
final User user;
97+
98+
@override
99+
Widget build(BuildContext context) {
100+
return Tooltip(
101+
message: user.displayName ?? user.id,
102+
child: InkWell(
103+
borderRadius: BorderRadius.circular(15),
104+
onTap: () async {
105+
final profile = await di<SearchModel>().lookupProfile(user.id);
106+
if (context.mounted) {
107+
showDialog(
108+
context: context,
109+
builder: (context) => ChatProfileDialog(userId: profile.userId),
110+
);
111+
}
112+
},
113+
child: ChatAvatar(
114+
avatarUri: user.avatarUrl,
115+
fallBackIconSize: 10,
116+
dimension: 15,
117+
),
118+
),
119+
);
120+
}
121+
}

lib/chat/view/events/chat_event_column.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import '../../../common/date_time_x.dart';
55
import '../../../common/view/build_context_x.dart';
66
import '../../../l10n/l10n.dart';
77
import '../../event_x.dart';
8-
import '../chat_room/chat_seen_by_indicator.dart';
98
import 'chat_event_tile.dart';
109

1110
class ChatEventColumn extends StatelessWidget {
@@ -52,11 +51,6 @@ class ChatEventColumn extends StatelessWidget {
5251
maybePreviousEvent,
5352
),
5453
),
55-
if (showSeenByIndicator)
56-
ChatSeenByIndicator(
57-
room: room,
58-
timeline: timeline,
59-
),
6054
],
6155
);
6256
}

0 commit comments

Comments
 (0)