Skip to content

Commit

Permalink
TW-1774: update the chat list item avatar when have new syncUpdate event
Browse files Browse the repository at this point in the history
  • Loading branch information
sherlockvn committed Jul 22, 2024
1 parent 523fa89 commit b54ea4e
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 10 deletions.
9 changes: 7 additions & 2 deletions lib/pages/chat_list/chat_list_body_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ class ChatListBodyView extends StatelessWidget {
),
stream: controller.activeClient.onSync.stream
.where((s) => s.hasRoomUpdate)
.rateLimit(const Duration(seconds: 1)),
builder: (context, _) {
.rateLimitWithSyncUpdate(const Duration(seconds: 1)),
builder: (context, syncUpdateSnapshot) {
Logs().v(
'ChatListBodyView: StreamBuilder: snapshot: ${syncUpdateSnapshot.data?.rooms}',
);
if (controller.activeFilter == ActiveFilter.spaces) {
return SpaceView(
controller,
Expand Down Expand Up @@ -163,6 +166,7 @@ class ChatListBodyView extends StatelessWidget {
child: ChatListViewBuilder(
controller: controller,
rooms: controller.filteredRoomsForPin,
syncUpdate: syncUpdateSnapshot.data,
),
),
if (!controller.filteredRoomsForAllIsEmpty)
Expand Down Expand Up @@ -192,6 +196,7 @@ class ChatListBodyView extends StatelessWidget {
child: ChatListViewBuilder(
controller: controller,
rooms: controller.filteredRoomsForAll,
syncUpdate: syncUpdateSnapshot.data,
),
),
],
Expand Down
14 changes: 6 additions & 8 deletions lib/pages/chat_list/chat_list_item.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item_avatar.dart';
import 'package:fluffychat/presentation/mixins/chat_list_item_mixin.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item_style.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item_subtitle.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item_title.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/twake_snackbar.dart';
import 'package:fluffychat/widgets/avatar/avatar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

Expand All @@ -27,6 +26,7 @@ class ChatListItem extends StatelessWidget with ChatListItemMixin {
final void Function()? onTapAvatar;
final void Function(TapDownDetails)? onSecondaryTapDown;
final void Function()? onLongPress;
final JoinedRoomUpdate? joinedRoomUpdate;

const ChatListItem(
this.room, {
Expand All @@ -39,6 +39,7 @@ class ChatListItem extends StatelessWidget with ChatListItemMixin {
this.onSecondaryTapDown,
this.onLongPress,
super.key,
this.joinedRoomUpdate,
});

void clickAction(BuildContext context) async {
Expand Down Expand Up @@ -87,9 +88,6 @@ class ChatListItem extends StatelessWidget with ChatListItemMixin {

@override
Widget build(BuildContext context) {
final displayName = room.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)!),
);
return Padding(
padding: ChatListItemStyle.paddingConversation,
child: Material(
Expand All @@ -114,10 +112,10 @@ class ChatListItem extends StatelessWidget with ChatListItemMixin {
padding: ChatListItemStyle.paddingAvatar,
child: Stack(
children: [
Avatar(
mxContent: room.avatar,
name: displayName,
ChatListItemAvatar(
room: room,
onTap: onTapAvatar,
joinedRoomUpdate: joinedRoomUpdate,
),
if (_isGroupChat)
Positioned(
Expand Down
104 changes: 104 additions & 0 deletions lib/pages/chat_list/chat_list_item_avatar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar/avatar.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

class ChatListItemAvatar extends StatefulWidget {
final Room room;
final void Function()? onTap;
final JoinedRoomUpdate? joinedRoomUpdate;

const ChatListItemAvatar({
required this.room,
this.onTap,
this.joinedRoomUpdate,
super.key,
});

@override
State<ChatListItemAvatar> createState() => _ChatListItemAvatarState();
}

class _ChatListItemAvatarState extends State<ChatListItemAvatar> {
final ValueNotifier<Uri?> avatarUrlNotifier = ValueNotifier<Uri>(Uri());

@override
void initState() {
avatarUrlNotifier.value = widget.room.avatar ?? Uri();
super.initState();
}

@override
void dispose() {
avatarUrlNotifier.dispose();
super.dispose();
}

@override
void didUpdateWidget(ChatListItemAvatar oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.joinedRoomUpdate != widget.joinedRoomUpdate) {
updateAvatarUrlFromJoinedRoomUpdate();
}
}

@override
Widget build(BuildContext context) {
final displayName = widget.room.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)!),
);
return ValueListenableBuilder(
valueListenable: avatarUrlNotifier,
builder: (context, avatarUrl, child) {
return Avatar(
mxContent: avatarUrl,
name: displayName,
onTap: widget.onTap,
);
},
);
}

void updateAvatarUrlFromJoinedRoomUpdate() {
if (isChatHaveAvatarUpdated) {
if (isGroupChatAvatarUpdated) {
updateGroupAvatar();
} else if (isDirectChatAvatarUpdated) {
updateDirectChatAvatar();
}
}
}

bool get isChatHaveAvatarUpdated =>
widget.joinedRoomUpdate?.timeline?.events?.isNotEmpty == true;

bool get isDirectChatAvatarUpdated {
return widget.room.isDirectChat &&
widget.joinedRoomUpdate?.timeline?.events?.last.type ==
EventTypes.RoomMember;
}

bool get isGroupChatAvatarUpdated =>
widget.joinedRoomUpdate?.timeline?.events?.last.type ==
EventTypes.RoomAvatar;

void updateDirectChatAvatar() {
final event = widget.joinedRoomUpdate?.timeline?.events?.last;
final avatarMxc = event?.content['avatar_url'];
if (avatarMxc is String &&
avatarMxc.isNotEmpty &&
event?.senderId == widget.room.directChatMatrixID) {
avatarUrlNotifier.value = Uri.tryParse(avatarMxc);
}
}

void updateGroupAvatar() {
final avatarMxc =
widget.joinedRoomUpdate?.timeline?.events?.last.content['url'];

if (avatarMxc is String && avatarMxc.isNotEmpty) {
avatarUrlNotifier.value = Uri.tryParse(avatarMxc);
}
}
}
7 changes: 7 additions & 0 deletions lib/pages/chat_list/chat_list_view_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
class ChatListViewBuilder extends StatelessWidget {
final ChatListController controller;
final List<Room> rooms;
final SyncUpdate? syncUpdate;

const ChatListViewBuilder({
super.key,
required this.controller,
required this.rooms,
this.syncUpdate,
});

@override
Expand All @@ -41,12 +43,14 @@ class ChatListViewBuilder extends StatelessWidget {
chatListItem: _CommonChatListItem(
controller: controller,
room: rooms[index],
joinedRoomUpdate: syncUpdate?.rooms?.join?[rooms[index].id],
),
);
}
return _CommonChatListItem(
controller: controller,
room: rooms[index],
joinedRoomUpdate: syncUpdate?.rooms?.join?[rooms[index].id],
);
},
);
Expand Down Expand Up @@ -155,10 +159,12 @@ class _CommonChatListItem extends StatelessWidget {
const _CommonChatListItem({
required this.controller,
required this.room,
this.joinedRoomUpdate,
});

final ChatListController controller;
final Room room;
final JoinedRoomUpdate? joinedRoomUpdate;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -195,6 +201,7 @@ class _CommonChatListItem extends StatelessWidget {
},
),
activeChat: activeRoomId == room.id,
joinedRoomUpdate: joinedRoomUpdate,
);
},
);
Expand Down

0 comments on commit b54ea4e

Please sign in to comment.