Compare commits
	
		
			2 Commits
		
	
	
		
			214d5c4a53
			...
			6ed6f60fbc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6ed6f60fbc | |||
| e65a414065 | 
| @@ -40,6 +40,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|   bool _hasMore = true; |   bool _hasMore = true; | ||||||
|   bool _isSyncing = false; |   bool _isSyncing = false; | ||||||
|   bool _isJumping = false; |   bool _isJumping = false; | ||||||
|  |   DateTime? _lastPauseTime; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   FutureOr<List<LocalChatMessage>> build(String roomId) async { |   FutureOr<List<LocalChatMessage>> build(String roomId) async { | ||||||
| @@ -68,12 +69,28 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     if (identity != null) { |     if (identity != null) { | ||||||
|       ref.listen(appLifecycleStateProvider, (_, next) { |       ref.listen(appLifecycleStateProvider, (_, next) { | ||||||
|         next.whenData((state) { |         next.whenData((state) { | ||||||
|           if (state == AppLifecycleState.resumed) { |           if (state == AppLifecycleState.paused) { | ||||||
|  |             _lastPauseTime = DateTime.now(); | ||||||
|             developer.log( |             developer.log( | ||||||
|               'App resumed, syncing messages', |               'App paused, recording time', | ||||||
|               name: 'MessagesNotifier', |               name: 'MessagesNotifier', | ||||||
|             ); |             ); | ||||||
|             syncMessages(); |           } else if (state == AppLifecycleState.resumed) { | ||||||
|  |             if (_lastPauseTime != null) { | ||||||
|  |               final diff = DateTime.now().difference(_lastPauseTime!); | ||||||
|  |               if (diff > const Duration(minutes: 1)) { | ||||||
|  |                 developer.log( | ||||||
|  |                   'App resumed after >1 min, syncing messages', | ||||||
|  |                   name: 'MessagesNotifier', | ||||||
|  |                 ); | ||||||
|  |                 syncMessages(); | ||||||
|  |               } else { | ||||||
|  |                 developer.log( | ||||||
|  |                   'App resumed within 1 min, skipping sync', | ||||||
|  |                   name: 'MessagesNotifier', | ||||||
|  |                 ); | ||||||
|  |               } | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|       }); |       }); | ||||||
|   | |||||||
| @@ -178,6 +178,102 @@ Future<List<SnChatRoom>> chatroomsJoined(Ref ref) async { | |||||||
|       .toList(); |       .toList(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class ChatListBodyWidget extends HookConsumerWidget { | ||||||
|  |   final bool isFloating; | ||||||
|  |   final TabController tabController; | ||||||
|  |   final ValueNotifier<int> selectedTab; | ||||||
|  |  | ||||||
|  |   const ChatListBodyWidget({ | ||||||
|  |     super.key, | ||||||
|  |     this.isFloating = false, | ||||||
|  |     required this.tabController, | ||||||
|  |     required this.selectedTab, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final chats = ref.watch(chatroomsJoinedProvider); | ||||||
|  |     final callState = ref.watch(callNotifierProvider); | ||||||
|  |  | ||||||
|  |     Widget bodyWidget = Column( | ||||||
|  |       children: [ | ||||||
|  |         Consumer( | ||||||
|  |           builder: (context, ref, _) { | ||||||
|  |             final summaryState = ref.watch(chatSummaryProvider); | ||||||
|  |             return summaryState.maybeWhen( | ||||||
|  |               loading: | ||||||
|  |                   () => const LinearProgressIndicator( | ||||||
|  |                     minHeight: 2, | ||||||
|  |                     borderRadius: BorderRadius.zero, | ||||||
|  |                   ), | ||||||
|  |               orElse: () => const SizedBox.shrink(), | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |         Expanded( | ||||||
|  |           child: chats.when( | ||||||
|  |             data: | ||||||
|  |                 (items) => RefreshIndicator( | ||||||
|  |                   onRefresh: | ||||||
|  |                       () => Future.sync(() { | ||||||
|  |                         ref.invalidate(chatroomsJoinedProvider); | ||||||
|  |                       }), | ||||||
|  |                   child: ListView.builder( | ||||||
|  |                     padding: getTabbedPadding( | ||||||
|  |                       context, | ||||||
|  |                       bottom: callState.isConnected ? 96 : null, | ||||||
|  |                     ), | ||||||
|  |                     itemCount: | ||||||
|  |                         items | ||||||
|  |                             .where( | ||||||
|  |                               (item) => | ||||||
|  |                                   selectedTab.value == 0 || | ||||||
|  |                                   (selectedTab.value == 1 && item.type == 1) || | ||||||
|  |                                   (selectedTab.value == 2 && item.type != 1), | ||||||
|  |                             ) | ||||||
|  |                             .length, | ||||||
|  |                     itemBuilder: (context, index) { | ||||||
|  |                       final filteredItems = | ||||||
|  |                           items | ||||||
|  |                               .where( | ||||||
|  |                                 (item) => | ||||||
|  |                                     selectedTab.value == 0 || | ||||||
|  |                                     (selectedTab.value == 1 && | ||||||
|  |                                         item.type == 1) || | ||||||
|  |                                     (selectedTab.value == 2 && item.type != 1), | ||||||
|  |                               ) | ||||||
|  |                               .toList(); | ||||||
|  |                       final item = filteredItems[index]; | ||||||
|  |                       return ChatRoomListTile( | ||||||
|  |                         room: item, | ||||||
|  |                         isDirect: item.type == 1, | ||||||
|  |                         onTap: () { | ||||||
|  |                           context.pushNamed( | ||||||
|  |                             'chatRoom', | ||||||
|  |                             pathParameters: {'id': item.id}, | ||||||
|  |                           ); | ||||||
|  |                         }, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |             loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |             error: | ||||||
|  |                 (error, stack) => ResponseErrorWidget( | ||||||
|  |                   error: error, | ||||||
|  |                   onRetry: () { | ||||||
|  |                     ref.invalidate(chatroomsJoinedProvider); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return isFloating ? Card(child: bodyWidget) : bodyWidget; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| class ChatShellScreen extends HookConsumerWidget { | class ChatShellScreen extends HookConsumerWidget { | ||||||
|   final Widget child; |   final Widget child; | ||||||
|   const ChatShellScreen({super.key, required this.child}); |   const ChatShellScreen({super.key, required this.child}); | ||||||
| @@ -191,9 +287,23 @@ class ChatShellScreen extends HookConsumerWidget { | |||||||
|         isRoot: true, |         isRoot: true, | ||||||
|         child: Row( |         child: Row( | ||||||
|           children: [ |           children: [ | ||||||
|             Flexible(flex: 2, child: ChatListScreen(isAside: true)), |             Flexible( | ||||||
|             const VerticalDivider(width: 1), |               flex: 2, | ||||||
|             Flexible(flex: 4, child: child), |               child: ChatListScreen( | ||||||
|  |                 isAside: true, | ||||||
|  |                 isFloating: true, | ||||||
|  |               ).padding(left: 16, vertical: 16), | ||||||
|  |             ), | ||||||
|  |             const Gap(8), | ||||||
|  |             Flexible( | ||||||
|  |               flex: 4, | ||||||
|  |               child: ClipRRect( | ||||||
|  |                 borderRadius: const BorderRadius.only( | ||||||
|  |                   topLeft: Radius.circular(8), | ||||||
|  |                 ), | ||||||
|  |                 child: child, | ||||||
|  |               ).padding(top: 16), | ||||||
|  |             ), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|       ); |       ); | ||||||
| @@ -205,24 +315,23 @@ class ChatShellScreen extends HookConsumerWidget { | |||||||
|  |  | ||||||
| class ChatListScreen extends HookConsumerWidget { | class ChatListScreen extends HookConsumerWidget { | ||||||
|   final bool isAside; |   final bool isAside; | ||||||
|   const ChatListScreen({super.key, this.isAside = false}); |   final bool isFloating; | ||||||
|  |   const ChatListScreen({ | ||||||
|  |     super.key, | ||||||
|  |     this.isAside = false, | ||||||
|  |     this.isFloating = false, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final isWide = isWideScreen(context); |     final isWide = isWideScreen(context); | ||||||
|     if (isWide && !isAside) { |  | ||||||
|       return const EmptyPageHolder(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     final chats = ref.watch(chatroomsJoinedProvider); |  | ||||||
|     final chatInvites = ref.watch(chatroomInvitesProvider); |     final chatInvites = ref.watch(chatroomInvitesProvider); | ||||||
|     final tabController = useTabController(initialLength: 3); |     final tabController = useTabController(initialLength: 3); | ||||||
|     final selectedTab = useState( |     final selectedTab = useState( | ||||||
|       0, |       0, | ||||||
|     ); // 0 for All, 1 for Direct Messages, 2 for Group Chats |     ); // 0 for All, 1 for Direct Messages, 2 for Group Chats | ||||||
|  |  | ||||||
|     final callState = ref.watch(callNotifierProvider); |  | ||||||
|  |  | ||||||
|     useEffect(() { |     useEffect(() { | ||||||
|       tabController.addListener(() { |       tabController.addListener(() { | ||||||
|         selectedTab.value = tabController.index; |         selectedTab.value = tabController.index; | ||||||
| @@ -250,6 +359,76 @@ class ChatListScreen extends HookConsumerWidget { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (isAside) { | ||||||
|  |       return Card( | ||||||
|  |         margin: EdgeInsets.zero, | ||||||
|  |         child: ClipRRect( | ||||||
|  |           borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||||
|  |           child: Column( | ||||||
|  |             children: [ | ||||||
|  |               Row( | ||||||
|  |                 children: [ | ||||||
|  |                   Expanded( | ||||||
|  |                     child: TabBar( | ||||||
|  |                       dividerColor: Colors.transparent, | ||||||
|  |                       controller: tabController, | ||||||
|  |                       tabAlignment: TabAlignment.start, | ||||||
|  |                       isScrollable: true, | ||||||
|  |                       tabs: [ | ||||||
|  |                         const Tab(icon: Icon(Symbols.chat)), | ||||||
|  |                         const Tab(icon: Icon(Symbols.person)), | ||||||
|  |                         const Tab(icon: Icon(Symbols.group)), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   Padding( | ||||||
|  |                     padding: const EdgeInsets.only(right: 8), | ||||||
|  |                     child: IconButton( | ||||||
|  |                       icon: Badge( | ||||||
|  |                         label: Text( | ||||||
|  |                           chatInvites.when( | ||||||
|  |                             data: (invites) => invites.length.toString(), | ||||||
|  |                             error: (_, _) => '0', | ||||||
|  |                             loading: () => '0', | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                         isLabelVisible: chatInvites.when( | ||||||
|  |                           data: (invites) => invites.isNotEmpty, | ||||||
|  |                           error: (_, _) => false, | ||||||
|  |                           loading: () => false, | ||||||
|  |                         ), | ||||||
|  |                         child: const Icon(Symbols.email), | ||||||
|  |                       ), | ||||||
|  |                       onPressed: () { | ||||||
|  |                         showModalBottomSheet( | ||||||
|  |                           useRootNavigator: true, | ||||||
|  |                           isScrollControlled: true, | ||||||
|  |                           context: context, | ||||||
|  |                           builder: (context) => const _ChatInvitesSheet(), | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ).padding(horizontal: 8), | ||||||
|  |               const Divider(height: 1), | ||||||
|  |               Expanded( | ||||||
|  |                 child: ChatListBodyWidget( | ||||||
|  |                   isFloating: false, | ||||||
|  |                   tabController: tabController, | ||||||
|  |                   selectedTab: selectedTab, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (isWide && !isAside) { | ||||||
|  |       return const EmptyPageHolder(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return AppScaffold( |     return AppScaffold( | ||||||
|       extendBody: false, // Prevent conflicts with tabs navigation |       extendBody: false, // Prevent conflicts with tabs navigation | ||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
| @@ -353,81 +532,10 @@ class ChatListScreen extends HookConsumerWidget { | |||||||
|         child: const Icon(Symbols.add), |         child: const Icon(Symbols.add), | ||||||
|       ), |       ), | ||||||
|       floatingActionButtonLocation: TabbedFabLocation(context), |       floatingActionButtonLocation: TabbedFabLocation(context), | ||||||
|       body: Column( |       body: ChatListBodyWidget( | ||||||
|         children: [ |         isFloating: false, | ||||||
|           Consumer( |         tabController: tabController, | ||||||
|             builder: (context, ref, _) { |         selectedTab: selectedTab, | ||||||
|               final summaryState = ref.watch(chatSummaryProvider); |  | ||||||
|               return summaryState.maybeWhen( |  | ||||||
|                 loading: |  | ||||||
|                     () => const LinearProgressIndicator( |  | ||||||
|                       minHeight: 2, |  | ||||||
|                       borderRadius: BorderRadius.zero, |  | ||||||
|                     ), |  | ||||||
|                 orElse: () => const SizedBox.shrink(), |  | ||||||
|               ); |  | ||||||
|             }, |  | ||||||
|           ), |  | ||||||
|           Expanded( |  | ||||||
|             child: chats.when( |  | ||||||
|               data: |  | ||||||
|                   (items) => RefreshIndicator( |  | ||||||
|                     onRefresh: |  | ||||||
|                         () => Future.sync(() { |  | ||||||
|                           ref.invalidate(chatroomsJoinedProvider); |  | ||||||
|                         }), |  | ||||||
|                     child: ListView.builder( |  | ||||||
|                       padding: getTabbedPadding( |  | ||||||
|                         context, |  | ||||||
|                         bottom: callState.isConnected ? 96 : null, |  | ||||||
|                       ), |  | ||||||
|                       itemCount: |  | ||||||
|                           items |  | ||||||
|                               .where( |  | ||||||
|                                 (item) => |  | ||||||
|                                     selectedTab.value == 0 || |  | ||||||
|                                     (selectedTab.value == 1 && |  | ||||||
|                                         item.type == 1) || |  | ||||||
|                                     (selectedTab.value == 2 && item.type != 1), |  | ||||||
|                               ) |  | ||||||
|                               .length, |  | ||||||
|                       itemBuilder: (context, index) { |  | ||||||
|                         final filteredItems = |  | ||||||
|                             items |  | ||||||
|                                 .where( |  | ||||||
|                                   (item) => |  | ||||||
|                                       selectedTab.value == 0 || |  | ||||||
|                                       (selectedTab.value == 1 && |  | ||||||
|                                           item.type == 1) || |  | ||||||
|                                       (selectedTab.value == 2 && |  | ||||||
|                                           item.type != 1), |  | ||||||
|                                 ) |  | ||||||
|                                 .toList(); |  | ||||||
|                         final item = filteredItems[index]; |  | ||||||
|                         return ChatRoomListTile( |  | ||||||
|                           room: item, |  | ||||||
|                           isDirect: item.type == 1, |  | ||||||
|                           onTap: () { |  | ||||||
|                             context.pushNamed( |  | ||||||
|                               'chatRoom', |  | ||||||
|                               pathParameters: {'id': item.id}, |  | ||||||
|                             ); |  | ||||||
|                           }, |  | ||||||
|                         ); |  | ||||||
|                       }, |  | ||||||
|                     ), |  | ||||||
|                   ), |  | ||||||
|               loading: () => const Center(child: CircularProgressIndicator()), |  | ||||||
|               error: |  | ||||||
|                   (error, stack) => ResponseErrorWidget( |  | ||||||
|                     error: error, |  | ||||||
|                     onRetry: () { |  | ||||||
|                       ref.invalidate(chatroomsJoinedProvider); |  | ||||||
|                     }, |  | ||||||
|                   ), |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|         ], |  | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -34,8 +34,6 @@ import "package:island/widgets/chat/call_button.dart"; | |||||||
| import "package:island/widgets/chat/chat_input.dart"; | import "package:island/widgets/chat/chat_input.dart"; | ||||||
| import "package:island/widgets/chat/public_room_preview.dart"; | import "package:island/widgets/chat/public_room_preview.dart"; | ||||||
|  |  | ||||||
| final flashingMessagesProvider = StateProvider<Set<String>>((ref) => {}); |  | ||||||
|  |  | ||||||
| class ChatRoomScreen extends HookConsumerWidget { | class ChatRoomScreen extends HookConsumerWidget { | ||||||
|   final String id; |   final String id; | ||||||
|   const ChatRoomScreen({super.key, required this.id}); |   const ChatRoomScreen({super.key, required this.id}); | ||||||
| @@ -404,7 +402,7 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|           listController: listController, |           listController: listController, | ||||||
|           padding: EdgeInsets.only( |           padding: EdgeInsets.only( | ||||||
|             top: 16, |             top: 16, | ||||||
|             bottom: 96 + MediaQuery.of(context).padding.bottom, |             bottom: 80 + MediaQuery.of(context).padding.bottom, | ||||||
|           ), |           ), | ||||||
|           controller: scrollController, |           controller: scrollController, | ||||||
|           reverse: true, // Show newest messages at the bottom |           reverse: true, // Show newest messages at the bottom | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import "package:image_picker/image_picker.dart"; | |||||||
| import "package:island/models/chat.dart"; | import "package:island/models/chat.dart"; | ||||||
| import "package:island/models/file.dart"; | import "package:island/models/file.dart"; | ||||||
| import "package:island/pods/config.dart"; | import "package:island/pods/config.dart"; | ||||||
|  | import "package:island/services/responsive.dart"; | ||||||
| import "package:island/widgets/content/attachment_preview.dart"; | import "package:island/widgets/content/attachment_preview.dart"; | ||||||
| import "package:material_symbols_icons/material_symbols_icons.dart"; | import "package:material_symbols_icons/material_symbols_icons.dart"; | ||||||
| import "package:pasteboard/pasteboard.dart"; | import "package:pasteboard/pasteboard.dart"; | ||||||
| @@ -117,8 +118,16 @@ class ChatInput extends HookConsumerWidget { | |||||||
|       return KeyEventResult.ignored; |       return KeyEventResult.ignored; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     final double leftMargin = isWideScreen(context) ? 8 : 16; | ||||||
|  |     final double rightMargin = isWideScreen(context) ? leftMargin + 8 : 16; | ||||||
|  |     const double bottomMargin = 16; | ||||||
|  |  | ||||||
|     return Container( |     return Container( | ||||||
|       margin: const EdgeInsets.all(16), |       margin: EdgeInsets.only( | ||||||
|  |         left: leftMargin, | ||||||
|  |         right: rightMargin, | ||||||
|  |         bottom: bottomMargin, | ||||||
|  |       ), | ||||||
|       child: Material( |       child: Material( | ||||||
|         elevation: 2, |         elevation: 2, | ||||||
|         color: Theme.of(context).colorScheme.surfaceContainerHighest, |         color: Theme.of(context).colorScheme.surfaceContainerHighest, | ||||||
| @@ -131,10 +140,7 @@ class ChatInput extends HookConsumerWidget { | |||||||
|                 duration: const Duration(milliseconds: 150), |                 duration: const Duration(milliseconds: 150), | ||||||
|                 switchInCurve: Curves.fastEaseInToSlowEaseOut, |                 switchInCurve: Curves.fastEaseInToSlowEaseOut, | ||||||
|                 switchOutCurve: Curves.fastEaseInToSlowEaseOut, |                 switchOutCurve: Curves.fastEaseInToSlowEaseOut, | ||||||
|                 transitionBuilder: ( |                 transitionBuilder: (Widget child, Animation<double> animation) { | ||||||
|                   Widget child, |  | ||||||
|                   Animation<double> animation, |  | ||||||
|                 ) { |  | ||||||
|                   return SlideTransition( |                   return SlideTransition( | ||||||
|                     position: Tween<Offset>( |                     position: Tween<Offset>( | ||||||
|                       begin: const Offset(0, -0.3), |                       begin: const Offset(0, -0.3), | ||||||
| @@ -148,10 +154,7 @@ class ChatInput extends HookConsumerWidget { | |||||||
|                     child: SizeTransition( |                     child: SizeTransition( | ||||||
|                       sizeFactor: animation, |                       sizeFactor: animation, | ||||||
|                       axisAlignment: -1.0, |                       axisAlignment: -1.0, | ||||||
|                       child: FadeTransition( |                       child: FadeTransition(opacity: animation, child: child), | ||||||
|                         opacity: animation, |  | ||||||
|                         child: child, |  | ||||||
|                       ), |  | ||||||
|                     ), |                     ), | ||||||
|                   ); |                   ); | ||||||
|                 }, |                 }, | ||||||
| @@ -177,18 +180,11 @@ class ChatInput extends HookConsumerWidget { | |||||||
|                                     chatSubscribe.length, |                                     chatSubscribe.length, | ||||||
|                                     args: [ |                                     args: [ | ||||||
|                                       chatSubscribe |                                       chatSubscribe | ||||||
|                                           .map( |                                           .map((x) => x.nick ?? x.account.nick) | ||||||
|                                             (x) => |  | ||||||
|                                                 x.nick ?? |  | ||||||
|                                                 x.account.nick, |  | ||||||
|                                           ) |  | ||||||
|                                           .join(', '), |                                           .join(', '), | ||||||
|                                     ], |                                     ], | ||||||
|                                   ), |                                   ), | ||||||
|                                   style: |                                   style: Theme.of(context).textTheme.bodySmall, | ||||||
|                                       Theme.of( |  | ||||||
|                                         context, |  | ||||||
|                                       ).textTheme.bodySmall, |  | ||||||
|                                 ), |                                 ), | ||||||
|                               ), |                               ), | ||||||
|                             ], |                             ], | ||||||
| @@ -224,7 +220,7 @@ class ChatInput extends HookConsumerWidget { | |||||||
|                     }, |                     }, | ||||||
|                     separatorBuilder: (_, _) => const Gap(8), |                     separatorBuilder: (_, _) => const Gap(8), | ||||||
|                   ), |                   ), | ||||||
|                 ).padding(top: 12), |                 ).padding(vertical: 12), | ||||||
|               if (messageReplyingTo != null || |               if (messageReplyingTo != null || | ||||||
|                   messageForwardingTo != null || |                   messageForwardingTo != null || | ||||||
|                   messageEditingTo != null) |                   messageEditingTo != null) | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ import 'package:gap/gap.dart'; | |||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/database/message.dart'; | import 'package:island/database/message.dart'; | ||||||
| import 'package:island/models/embed.dart'; | import 'package:island/models/embed.dart'; | ||||||
|  | import 'package:island/pods/chat/chat_rooms.dart'; | ||||||
| import 'package:island/pods/chat/messages_notifier.dart'; | import 'package:island/pods/chat/messages_notifier.dart'; | ||||||
| import 'package:island/pods/translate.dart'; | import 'package:island/pods/translate.dart'; | ||||||
| import 'package:island/pods/config.dart'; | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/screens/chat/room.dart'; |  | ||||||
| import 'package:island/utils/mapping.dart'; | import 'package:island/utils/mapping.dart'; | ||||||
| import 'package:island/widgets/account/account_pfc.dart'; | import 'package:island/widgets/account/account_pfc.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user