From 88fa22ba4e1c1dbbf587d2536f93be99da0f6e2f Mon Sep 17 00:00:00 2001 From: sherlock Date: Tue, 6 Feb 2024 15:11:33 +0700 Subject: [PATCH] TW-217: update new UX for share and forward screen --- lib/pages/forward/forward.dart | 17 ++-- lib/pages/forward/forward_view.dart | 18 ++--- lib/pages/forward/recent_chat_list.dart | 77 +++++++++++-------- lib/pages/forward/recent_chat_list_style.dart | 15 ++++ lib/pages/share/share.dart | 18 ++--- lib/pages/share/share_view.dart | 10 +-- 6 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 lib/pages/forward/recent_chat_list_style.dart diff --git a/lib/pages/forward/forward.dart b/lib/pages/forward/forward.dart index 3f65adf589..cb6a5fe257 100644 --- a/lib/pages/forward/forward.dart +++ b/lib/pages/forward/forward.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:collection/collection.dart'; import 'package:dartz/dartz.dart' hide State; import 'package:fluffychat/app_state/failure.dart'; import 'package:fluffychat/app_state/success.dart'; @@ -46,7 +45,7 @@ class ForwardController extends State with SearchRecentChat { final AutoScrollController recentChatScrollController = AutoScrollController(); - final selectedEventsNotifier = ValueNotifier([]); + final ValueNotifier selectedRoomIdNotifier = ValueNotifier(''); @override void initState() { @@ -68,18 +67,12 @@ class ForwardController extends State with SearchRecentChat { recentChatScrollController.dispose(); forwardMessageInteractorStreamSubscription?.cancel(); disposeSearchRecentChat(); + selectedRoomIdNotifier.dispose(); super.dispose(); } - void onSelectChat(String id) { - if (selectedEventsNotifier.value.contains(id)) { - selectedEventsNotifier.value.remove(id); - } else { - selectedEventsNotifier.value.add(id); - } - selectedEventsNotifier.value = selectedEventsNotifier.value.sorted( - (current, next) => current.compareTo(next), - ); + void onToggleSelectChat(String id) { + selectedRoomIdNotifier.value = id; } final ActiveFilter _activeFilterAllChats = ActiveFilter.allChats; @@ -91,7 +84,7 @@ class ForwardController extends State with SearchRecentChat { forwardMessageInteractorStreamSubscription = _forwardMessageInteractor .execute( rooms: filteredRoomsForAll, - selectedEvents: selectedEventsNotifier.value, + selectedEvents: [selectedRoomIdNotifier.value], matrixState: Matrix.of(context), ) .listen( diff --git a/lib/pages/forward/forward_view.dart b/lib/pages/forward/forward_view.dart index 2e535f2e4d..6c594339b1 100644 --- a/lib/pages/forward/forward_view.dart +++ b/lib/pages/forward/forward_view.dart @@ -51,9 +51,9 @@ class ForwardView extends StatelessWidget { if (rooms.isNotEmpty) { return RecentChatList( rooms: rooms, - selectedEventsNotifier: controller.selectedEventsNotifier, + selectedChatNotifier: controller.selectedRoomIdNotifier, onSelectedChat: (roomId) => - controller.onSelectChat(roomId), + controller.onToggleSelectChat(roomId), recentChatScrollController: controller.recentChatScrollController, ); @@ -68,7 +68,7 @@ class ForwardView extends StatelessWidget { ), floatingActionButton: ForwardButton( forwardAction: controller.forwardAction, - selectedEventsNotifier: controller.selectedEventsNotifier, + selectedChatNotifier: controller.selectedRoomIdNotifier, forwardMessageNotifier: controller.forwardMessageNotifier, ), ); @@ -78,12 +78,12 @@ class ForwardView extends StatelessWidget { class ForwardButton extends StatelessWidget { const ForwardButton({ super.key, - required this.selectedEventsNotifier, + required this.selectedChatNotifier, required this.forwardMessageNotifier, required this.forwardAction, }); - final ValueNotifier> selectedEventsNotifier; + final ValueNotifier selectedChatNotifier; final void Function() forwardAction; @@ -91,10 +91,10 @@ class ForwardButton extends StatelessWidget { @override Widget build(BuildContext context) { - return ValueListenableBuilder>( - valueListenable: selectedEventsNotifier, - builder: ((context, selectedEvents, child) { - if (selectedEvents.length != 1) { + return ValueListenableBuilder( + valueListenable: selectedChatNotifier, + builder: ((context, selectedChat, child) { + if (selectedChat.isEmpty) { return const SizedBox(); } diff --git a/lib/pages/forward/recent_chat_list.dart b/lib/pages/forward/recent_chat_list.dart index 126be76005..bbf7207445 100644 --- a/lib/pages/forward/recent_chat_list.dart +++ b/lib/pages/forward/recent_chat_list.dart @@ -1,5 +1,6 @@ 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/pages/forward/recent_chat_list_style.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/widgets/avatar/avatar.dart'; import 'package:flutter/material.dart'; @@ -11,23 +12,25 @@ class RecentChatList extends StatelessWidget { super.key, required this.rooms, required this.recentChatScrollController, - required this.selectedEventsNotifier, required this.onSelectedChat, + required this.selectedChatNotifier, }); final List rooms; final ScrollController recentChatScrollController; - final ValueNotifier> selectedEventsNotifier; + final ValueNotifier selectedChatNotifier; final void Function(String roomId) onSelectedChat; + static const durationToggleItem = Duration(milliseconds: 200); + @override Widget build(BuildContext context) { - return ValueListenableBuilder>( - valueListenable: selectedEventsNotifier, - builder: (context, selectedEvents, child) { + return ValueListenableBuilder( + valueListenable: selectedChatNotifier, + builder: (context, selectedChat, child) { return ListView.builder( padding: EdgeInsets.zero, shrinkWrap: true, @@ -35,42 +38,48 @@ class RecentChatList extends StatelessWidget { itemCount: rooms.length, itemBuilder: (BuildContext context, int index) { final room = rooms[index]; - final selected = selectedEvents.contains(room.id); + final selected = selectedChat == room.id; return Material( - borderRadius: BorderRadius.circular(16.0), + borderRadius: RecentChatListStyle.borderRadiusItem, child: InkWell( - borderRadius: BorderRadius.circular(16.0), + borderRadius: RecentChatListStyle.borderRadiusItem, onTap: () => onSelectedChat(room.id), - child: Row( - children: [ - Checkbox( - value: selected, - onChanged: (value) => onSelectedChat(room.id), - ), - Avatar( - mxContent: room.avatar, - name: room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context)!), + child: Padding( + padding: RecentChatListStyle.paddingVerticalBetweenItem, + child: Row( + children: [ + AnimatedCrossFade( + duration: durationToggleItem, + firstChild: Checkbox( + value: selected, + onChanged: (value) => onSelectedChat(room.id), + ), + secondChild: const SizedBox.shrink(), + crossFadeState: selected + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, ), - onTap: null, - ), - Expanded( - child: Padding( - padding: const EdgeInsetsDirectional.only( - top: 8.0, - bottom: 8.0, - start: 8.0, - end: 6.0, + Avatar( + mxContent: room.avatar, + name: room.getLocalizedDisplayname( + MatrixLocals(L10n.of(context)!), ), - child: Column( - children: [ - ChatListItemTitle(room: room), - ChatListItemSubtitle(room: room), - ], + onTap: null, + ), + Expanded( + child: Padding( + padding: + RecentChatListStyle.paddingHorizontalBetweenItem, + child: Column( + children: [ + ChatListItemTitle(room: room), + ChatListItemSubtitle(room: room), + ], + ), ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/pages/forward/recent_chat_list_style.dart b/lib/pages/forward/recent_chat_list_style.dart new file mode 100644 index 0000000000..3607d69055 --- /dev/null +++ b/lib/pages/forward/recent_chat_list_style.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class RecentChatListStyle { + static BorderRadius borderRadiusItem = BorderRadius.circular(16); + + static const paddingVerticalBetweenItem = EdgeInsetsDirectional.only( + top: 8.0, + bottom: 8.0, + ); + + static const paddingHorizontalBetweenItem = EdgeInsetsDirectional.only( + start: 8.0, + end: 6.0, + ); +} diff --git a/lib/pages/share/share.dart b/lib/pages/share/share.dart index 79cae2f26c..8a102b0038 100644 --- a/lib/pages/share/share.dart +++ b/lib/pages/share/share.dart @@ -1,4 +1,3 @@ -import 'package:collection/collection.dart'; import 'package:fluffychat/di/global/get_it_initializer.dart'; import 'package:fluffychat/domain/usecase/send_file_interactor.dart'; import 'package:fluffychat/event/twake_event_types.dart'; @@ -34,7 +33,7 @@ class ShareController extends State final searchFocusNode = FocusNode(); - final selectedRoomsNotifier = ValueNotifier([]); + final selectedChatNotifier = ValueNotifier(''); @override void initState() { @@ -53,20 +52,13 @@ class ShareController extends State isSearchModeNotifier.dispose(); recentChatScrollController.dispose(); searchFocusNode.dispose(); - selectedRoomsNotifier.dispose(); + selectedChatNotifier.dispose(); disposeSearchRecentChat(); super.dispose(); } - void onSelectChat(String id) { - if (selectedRoomsNotifier.value.contains(id)) { - selectedRoomsNotifier.value.remove(id); - } else { - selectedRoomsNotifier.value.add(id); - } - selectedRoomsNotifier.value = selectedRoomsNotifier.value.sorted( - (current, next) => current.compareTo(next), - ); + void onToggleSelectChat(String id) { + selectedChatNotifier.value = id; } void toggleSearchMode() { @@ -81,7 +73,7 @@ class ShareController extends State void shareTo(String roomId) async { final room = Room( - id: selectedRoomsNotifier.value.first, + id: selectedChatNotifier.value, client: Matrix.of(context).client, ); final shareContentList = Matrix.of(context).shareContentList; diff --git a/lib/pages/share/share_view.dart b/lib/pages/share/share_view.dart index 4f946a5121..3ebceb3ef8 100644 --- a/lib/pages/share/share_view.dart +++ b/lib/pages/share/share_view.dart @@ -41,9 +41,9 @@ class ShareView extends StatelessWidget { if (rooms.isNotEmpty) { return RecentChatList( rooms: rooms, - selectedEventsNotifier: controller.selectedRoomsNotifier, + selectedChatNotifier: controller.selectedChatNotifier, onSelectedChat: (roomId) => - controller.onSelectChat(roomId), + controller.onToggleSelectChat(roomId), recentChatScrollController: controller.recentChatScrollController, ); @@ -57,8 +57,8 @@ class ShareView extends StatelessWidget { ), ), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, - floatingActionButton: ValueListenableBuilder>( - valueListenable: controller.selectedRoomsNotifier, + floatingActionButton: ValueListenableBuilder( + valueListenable: controller.selectedChatNotifier, builder: ((context, selectedEvents, child) { if (selectedEvents.length != 1) { return const SizedBox(); @@ -73,7 +73,7 @@ class ShareView extends StatelessWidget { child: TwakeIconButton( paddingAll: 0, onTap: () => controller.shareTo( - controller.selectedRoomsNotifier.value.first, + controller.selectedChatNotifier.value, ), tooltip: L10n.of(context)!.send, imagePath: ImagePaths.icSend,