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;
}
void onChatTap(Room room, BuildContext context) async {
void onChatTap(Room room) async {
if (room.isSpace) {
setActiveSpace(room.id);
return;

View file

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

View file

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

View file

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

View file

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