mirror of
https://github.com/krille-chan/fluffychat
synced 2024-09-19 17:35:18 +00:00
chore: Follow up new spaces design
This commit is contained in:
parent
5c23453e66
commit
254f21ce00
5 changed files with 90 additions and 67 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue