chore: Follow up new spaces design

This commit is contained in:
Krille 2024-07-15 13:18:15 +02:00
parent 5c23453e66
commit 254f21ce00
No known key found for this signature in database
GPG key ID: E067ECD60F1A0652
5 changed files with 90 additions and 67 deletions

View file

@ -200,7 +200,7 @@ class ChatListController extends State<ChatList>
if (result.error != null) return; if (result.error != null) return;
} }
void onChatTap(Room room, BuildContext context) async { void onChatTap(Room room) async {
if (room.isSpace) { if (room.isSpace) {
setActiveSpace(room.id); setActiveSpace(room.id);
return; return;

View file

@ -32,7 +32,7 @@ class ChatListViewBody extends StatelessWidget {
return SpaceView( return SpaceView(
spaceId: activeSpace, spaceId: activeSpace,
onBack: controller.clearActiveSpace, onBack: controller.clearActiveSpace,
onChatTab: (room) => controller.onChatTap(room, context), onChatTab: (room) => controller.onChatTap(room),
onChatContext: (room) => controller.chatContextAction(room), onChatContext: (room) => controller.chatContextAction(room),
activeChat: controller.activeChat, activeChat: controller.activeChat,
toParentSpace: controller.setActiveSpace, toParentSpace: controller.setActiveSpace,
@ -62,17 +62,15 @@ class ChatListViewBody extends StatelessWidget {
builder: (context, _) { builder: (context, _) {
final rooms = controller.filteredRooms; final rooms = controller.filteredRooms;
final spaces = rooms.where((r) => r.isSpace); final spaces = client.rooms.where((r) => r.isSpace);
final spaceDelegateCandidates = <String, Room>{}; final spaceDelegateCandidates = <String, Room>{};
for (final space in spaces) { for (final space in spaces) {
spaceDelegateCandidates[space.id] = space;
for (final spaceChild in space.spaceChildren) { for (final spaceChild in space.spaceChildren) {
final roomId = spaceChild.roomId; final roomId = spaceChild.roomId;
if (roomId == null) continue; if (roomId == null) continue;
spaceDelegateCandidates[roomId] = space; spaceDelegateCandidates[roomId] = space;
} }
} }
final spaceDelegates = <String>{};
return SafeArea( return SafeArea(
child: CustomScrollView( child: CustomScrollView(
@ -298,26 +296,14 @@ class ChatListViewBody extends StatelessWidget {
SliverList.builder( SliverList.builder(
itemCount: rooms.length, itemCount: rooms.length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
var room = rooms[i]; final room = rooms[i];
if (controller.activeFilter != ActiveFilter.groups) { final space = spaceDelegateCandidates[room.id];
final parent = room.isSpace
? room
: spaceDelegateCandidates[room.id];
if (parent != null) {
if (spaceDelegates.contains(parent.id)) {
return const SizedBox.shrink();
}
spaceDelegates.add(parent.id);
room = parent;
}
}
return ChatListItem( return ChatListItem(
room, room,
lastEventRoom: rooms[i], space: space,
key: Key('chat_list_item_${room.id}'), key: Key('chat_list_item_${room.id}'),
filter: filter, filter: filter,
onTap: () => controller.onChatTap(room, context), onTap: () => controller.onChatTap(room),
onLongPress: () => controller.chatContextAction(room), onLongPress: () => controller.chatContextAction(room),
activeChat: controller.activeChat == room.id, activeChat: controller.activeChat == room.id,
); );

View file

@ -17,7 +17,7 @@ enum ArchivedRoomAction { delete, rejoin }
class ChatListItem extends StatelessWidget { class ChatListItem extends StatelessWidget {
final Room room; final Room room;
final Room? lastEventRoom; final Room? space;
final bool activeChat; final bool activeChat;
final void Function()? onLongPress; final void Function()? onLongPress;
final void Function()? onForget; final void Function()? onForget;
@ -31,7 +31,7 @@ class ChatListItem extends StatelessWidget {
this.onLongPress, this.onLongPress,
this.onForget, this.onForget,
this.filter, this.filter,
this.lastEventRoom, this.space,
super.key, super.key,
}); });
@ -64,21 +64,19 @@ class ChatListItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isMuted = room.pushRuleState != PushRuleState.notify; final isMuted = room.pushRuleState != PushRuleState.notify;
final lastEventRoom = this.lastEventRoom ?? room; final typingText = room.getLocalizedTypingText(context);
final typingText = lastEventRoom.getLocalizedTypingText(context); final lastEvent = room.lastEvent;
final lastEvent = lastEventRoom.lastEvent;
final ownMessage = lastEvent?.senderId == room.client.userID; final ownMessage = lastEvent?.senderId == room.client.userID;
final unread = final unread = room.isUnread || room.membership == Membership.invite;
lastEventRoom.isUnread || lastEventRoom.membership == Membership.invite;
final theme = Theme.of(context); final theme = Theme.of(context);
final directChatMatrixId = room.directChatMatrixID; final directChatMatrixId = room.directChatMatrixID;
final isDirectChat = directChatMatrixId != null; final isDirectChat = directChatMatrixId != null;
final unreadBubbleSize = unread || lastEventRoom.hasNewMessages final unreadBubbleSize = unread || room.hasNewMessages
? lastEventRoom.notificationCount > 0 ? room.notificationCount > 0
? 20.0 ? 20.0
: 14.0 : 14.0
: 0.0; : 0.0;
final hasNotifications = lastEventRoom.notificationCount > 0; final hasNotifications = room.notificationCount > 0;
final backgroundColor = final backgroundColor =
activeChat ? theme.colorScheme.secondaryContainer : null; activeChat ? theme.colorScheme.secondaryContainer : null;
final displayname = room.getLocalizedDisplayname( final displayname = room.getLocalizedDisplayname(
@ -92,6 +90,7 @@ class ChatListItem extends StatelessWidget {
final needLastEventSender = lastEvent == null final needLastEventSender = lastEvent == null
? false ? false
: room.getState(EventTypes.RoomMember, lastEvent.senderId) == null; : room.getState(EventTypes.RoomMember, lastEvent.senderId) == null;
final space = this.space;
return Padding( return Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -117,17 +116,69 @@ class ChatListItem extends StatelessWidget {
duration: FluffyThemes.animationDuration, duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve, curve: FluffyThemes.animationCurve,
scale: hovered ? 1.1 : 1.0, scale: hovered ? 1.1 : 1.0,
child: SizedBox(
width: Avatar.defaultSize,
height: Avatar.defaultSize,
child: Stack(
children: [
if (space != null)
Positioned(
top: 0,
left: 0,
child: Avatar( child: Avatar(
border: BorderSide(
width: 2,
color: backgroundColor ??
Theme.of(context).colorScheme.surface,
),
borderRadius: BorderRadius.circular(
AppConfig.borderRadius / 4,
),
mxContent: space.avatar,
size: Avatar.defaultSize * 0.75,
name: space.getLocalizedDisplayname(),
onTap: onLongPress,
),
),
Positioned(
bottom: 0,
right: 0,
child: Avatar(
border: space == null
? room.isSpace
? BorderSide(
width: 0,
color: Theme.of(context)
.colorScheme
.outline,
)
: null
: BorderSide(
width: 2,
color: backgroundColor ??
Theme.of(context)
.colorScheme
.surface,
),
borderRadius: room.isSpace borderRadius: room.isSpace
? BorderRadius.circular(AppConfig.borderRadius / 3) ? BorderRadius.circular(
AppConfig.borderRadius / 4,
)
: null, : null,
mxContent: room.avatar, mxContent: room.avatar,
size: space != null
? Avatar.defaultSize * 0.75
: Avatar.defaultSize,
name: displayname, name: displayname,
presenceUserId: directChatMatrixId, presenceUserId: directChatMatrixId,
presenceBackgroundColor: backgroundColor, presenceBackgroundColor: backgroundColor,
onTap: onLongPress, onTap: onLongPress,
), ),
), ),
],
),
),
),
), ),
Positioned( Positioned(
bottom: -2, bottom: -2,
@ -205,20 +256,6 @@ class ChatListItem extends StatelessWidget {
subtitle: Row( subtitle: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
if (room.isSpace) ...[
room.id != lastEventRoom.id &&
lastEventRoom.isUnreadOrInvited
? Avatar(
mxContent: lastEventRoom.avatar,
name: lastEventRoom.name,
size: 18,
)
: const Icon(
Icons.workspaces_outlined,
size: 18,
),
const SizedBox(width: 4),
],
if (typingText.isEmpty && if (typingText.isEmpty &&
ownMessage && ownMessage &&
room.lastEvent!.status.isSending) ...[ room.lastEvent!.status.isSending) ...[
@ -243,7 +280,7 @@ class ChatListItem extends StatelessWidget {
), ),
), ),
Expanded( Expanded(
child: room.isSpace && !lastEventRoom.isUnreadOrInvited child: room.isSpace && room.membership == Membership.join
? Text( ? Text(
L10n.of(context)!.countChatsAndCountParticipants( L10n.of(context)!.countChatsAndCountParticipants(
room.spaceChildren.length.toString(), room.spaceChildren.length.toString(),
@ -297,8 +334,7 @@ class ChatListItem extends StatelessWidget {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
fontWeight: fontWeight: unread || room.hasNewMessages
unread || lastEventRoom.hasNewMessages
? FontWeight.bold ? FontWeight.bold
: null, : null,
color: theme.colorScheme.onSurfaceVariant, color: theme.colorScheme.onSurfaceVariant,
@ -318,9 +354,7 @@ class ChatListItem extends StatelessWidget {
width: !hasNotifications && !unread && !room.hasNewMessages width: !hasNotifications && !unread && !room.hasNewMessages
? 0 ? 0
: (unreadBubbleSize - 9) * : (unreadBubbleSize - 9) *
lastEventRoom.notificationCount room.notificationCount.toString().length +
.toString()
.length +
9, 9,
decoration: BoxDecoration( decoration: BoxDecoration(
color: room.highlightCount > 0 || color: room.highlightCount > 0 ||
@ -335,7 +369,7 @@ class ChatListItem extends StatelessWidget {
child: Center( child: Center(
child: hasNotifications child: hasNotifications
? Text( ? Text(
lastEventRoom.notificationCount.toString(), room.notificationCount.toString(),
style: TextStyle( style: TextStyle(
color: room.highlightCount > 0 color: room.highlightCount > 0
? Colors.white ? Colors.white

View file

@ -26,6 +26,10 @@ class ChatListView extends StatelessWidget {
controller.activeFilter == ActiveFilter.allChats, controller.activeFilter == ActiveFilter.allChats,
onPopInvoked: (pop) async { onPopInvoked: (pop) async {
if (pop) return; if (pop) return;
if (controller.activeSpaceId != null) {
controller.clearActiveSpace();
return;
}
final selMode = controller.selectMode; final selMode = controller.selectMode;
if (controller.isSearchMode) { if (controller.isSearchMode) {
controller.cancelSearch(); controller.cancelSearch();

View file

@ -17,6 +17,7 @@ class Avatar extends StatelessWidget {
final Color? presenceBackgroundColor; final Color? presenceBackgroundColor;
final BorderRadius? borderRadius; final BorderRadius? borderRadius;
final IconData? icon; final IconData? icon;
final BorderSide? border;
const Avatar({ const Avatar({
this.mxContent, this.mxContent,
@ -27,6 +28,7 @@ class Avatar extends StatelessWidget {
this.presenceUserId, this.presenceUserId,
this.presenceBackgroundColor, this.presenceBackgroundColor,
this.borderRadius, this.borderRadius,
this.border,
this.icon, this.icon,
super.key, super.key,
}); });
@ -67,10 +69,7 @@ class Avatar extends StatelessWidget {
color: color, color: color,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius, borderRadius: borderRadius,
side: BorderSide( side: border ?? BorderSide.none,
width: 0,
color: Theme.of(context).dividerColor,
),
), ),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: noPic child: noPic