⚡ Improve chat loading speed
This commit is contained in:
		| @@ -1,7 +1,6 @@ | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:solian/models/channel.dart'; | ||||
| import 'package:solian/models/event.dart'; | ||||
| import 'package:solian/platform.dart'; | ||||
| import 'package:solian/providers/database/database.dart'; | ||||
| import 'package:solian/providers/database/services/messages.dart'; | ||||
|  | ||||
| @@ -31,79 +30,32 @@ class ChatEventController { | ||||
|     this.channel = channel; | ||||
|     this.scope = scope; | ||||
|  | ||||
|     syncLocal(channel); | ||||
|  | ||||
|     isLoading.value = true; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       final result = await src.fetchRemoteEvents( | ||||
|         channel, | ||||
|         scope, | ||||
|         depth: 1, | ||||
|         offset: 0, | ||||
|       ); | ||||
|     await syncLocal(channel, take: 10); | ||||
|  | ||||
|     src.pullRemoteEvents(channel, scope: scope, take: 10).then((result) { | ||||
|       totalEvents.value = result?.$2 ?? 0; | ||||
|       if (result != null) { | ||||
|         for (final x in result.$1.reversed) { | ||||
|           final entry = LocalMessageEventTableData( | ||||
|             id: x.id, | ||||
|             channelId: x.channelId, | ||||
|             createdAt: x.createdAt, | ||||
|             data: x, | ||||
|           ); | ||||
|           insertEvent(entry); | ||||
|           applyEvent(entry); | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       final result = await src.pullRemoteEvents( | ||||
|         channel, | ||||
|         scope: scope, | ||||
|         depth: 1, | ||||
|       ); | ||||
|       totalEvents.value = result?.$2 ?? 0; | ||||
|       await syncLocal(channel); | ||||
|     } | ||||
|       syncLocal(channel, take: 10); | ||||
|     }); | ||||
|     isLoading.value = false; | ||||
|   } | ||||
|  | ||||
|   Future<void> loadEvents(Channel channel, String scope) async { | ||||
|     const take = 20; | ||||
|     final offset = currentEvents.length; | ||||
|  | ||||
|     isLoading.value = true; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       final result = await src.fetchRemoteEvents( | ||||
|         channel, | ||||
|         scope, | ||||
|         depth: 3, | ||||
|         offset: currentEvents.length, | ||||
|       ); | ||||
|       if (result != null) { | ||||
|         totalEvents.value = result.$2; | ||||
|         for (final x in result.$1.reversed) { | ||||
|           final entry = LocalMessageEventTableData( | ||||
|             id: x.id, | ||||
|             channelId: x.channelId, | ||||
|             createdAt: x.createdAt, | ||||
|             data: x, | ||||
|           ); | ||||
|           currentEvents.add(entry); | ||||
|           applyEvent(entry); | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       final result = await src.pullRemoteEvents( | ||||
|         channel, | ||||
|         depth: 3, | ||||
|         scope: scope, | ||||
|         offset: currentEvents.length, | ||||
|       ); | ||||
|     await syncLocal(channel, take: take, offset: offset); | ||||
|     src.pullRemoteEvents(channel, scope: scope, offset: offset).then((result) { | ||||
|       totalEvents.value = result?.$2 ?? 0; | ||||
|       await syncLocal(channel); | ||||
|     } | ||||
|       syncLocal(channel, take: take, offset: offset); | ||||
|     }); | ||||
|     isLoading.value = false; | ||||
|   } | ||||
|  | ||||
|   Future<bool> syncLocal(Channel channel) async { | ||||
|     if (PlatformInfo.isWeb) return false; | ||||
|     final data = await src.listEvents(channel); | ||||
|   Future<bool> syncLocal(Channel channel, | ||||
|       {required int take, int offset = 0}) async { | ||||
|     final data = await src.listEvents(channel, take: take, offset: offset); | ||||
|     currentEvents.replaceRange(0, currentEvents.length, data); | ||||
|     for (final x in data.reversed) { | ||||
|       applyEvent(x); | ||||
| @@ -113,16 +65,7 @@ class ChatEventController { | ||||
|  | ||||
|   receiveEvent(Event remote) async { | ||||
|     LocalMessageEventTableData entry; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       entry = LocalMessageEventTableData( | ||||
|         id: remote.id, | ||||
|         channelId: remote.channelId, | ||||
|         createdAt: remote.createdAt, | ||||
|         data: remote, | ||||
|       ); | ||||
|     } else { | ||||
|     entry = await src.receiveEvent(remote); | ||||
|     } | ||||
|  | ||||
|     totalEvents.value++; | ||||
|     insertEvent(entry); | ||||
|   | ||||
| @@ -51,15 +51,9 @@ class MessagesFetchingProvider extends GetxController { | ||||
|   Future<(List<Event>, int)?> fetchRemoteEvents( | ||||
|     Channel channel, | ||||
|     String scope, { | ||||
|     required int depth, | ||||
|     bool Function(List<Event> items)? onBrake, | ||||
|     take = 10, | ||||
|     offset = 0, | ||||
|   }) async { | ||||
|     if (depth <= 0) { | ||||
|       return null; | ||||
|     } | ||||
|  | ||||
|     final AuthProvider auth = Get.find(); | ||||
|     if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
| @@ -77,23 +71,9 @@ class MessagesFetchingProvider extends GetxController { | ||||
|     final result = | ||||
|         response.data?.map((e) => Event.fromJson(e)).toList() ?? List.empty(); | ||||
|  | ||||
|     if (onBrake != null && onBrake(result)) { | ||||
|     return (result, response.count); | ||||
|   } | ||||
|  | ||||
|     final expandResult = (await fetchRemoteEvents( | ||||
|           channel, | ||||
|           scope, | ||||
|           depth: depth - 1, | ||||
|           take: take, | ||||
|           offset: offset + result.length, | ||||
|         )) | ||||
|             ?.$1 ?? | ||||
|         List.empty(); | ||||
|  | ||||
|     return ([...result, ...expandResult], response.count); | ||||
|   } | ||||
|  | ||||
|   Future<LocalMessageEventTableData> receiveEvent(Event remote) async { | ||||
|     // Insert record | ||||
|     final database = Get.find<DatabaseProvider>().database; | ||||
| @@ -151,22 +131,14 @@ class MessagesFetchingProvider extends GetxController { | ||||
|  | ||||
|   /// Pull the remote events to local database | ||||
|   Future<(List<Event>, int)?> pullRemoteEvents(Channel channel, | ||||
|       {String scope = 'global', depth = 10, offset = 0}) async { | ||||
|       {String scope = 'global', take = 10, offset = 0}) async { | ||||
|     final database = Get.find<DatabaseProvider>().database; | ||||
|     final lastOne = await (database.select(database.localMessageEventTable) | ||||
|           ..where((x) => x.channelId.equals(channel.id)) | ||||
|           ..orderBy([(t) => OrderingTerm.desc(t.id)]) | ||||
|           ..limit(1)) | ||||
|         .getSingleOrNull(); | ||||
|  | ||||
|     final data = await fetchRemoteEvents( | ||||
|       channel, | ||||
|       scope, | ||||
|       depth: depth, | ||||
|       offset: offset, | ||||
|       onBrake: (items) { | ||||
|         return items.any((x) => x.id == lastOne?.id); | ||||
|       }, | ||||
|       take: take, | ||||
|     ); | ||||
|     if (data != null) { | ||||
|       await database.batch((batch) { | ||||
| @@ -185,11 +157,13 @@ class MessagesFetchingProvider extends GetxController { | ||||
|     return data; | ||||
|   } | ||||
|  | ||||
|   Future<List<LocalMessageEventTableData>> listEvents(Channel channel) async { | ||||
|   Future<List<LocalMessageEventTableData>> listEvents(Channel channel, | ||||
|       {required int take, int offset = 0}) async { | ||||
|     final database = Get.find<DatabaseProvider>().database; | ||||
|     return await (database.select(database.localMessageEventTable) | ||||
|           ..where((x) => x.channelId.equals(channel.id)) | ||||
|           ..orderBy([(t) => OrderingTerm.desc(t.id)])) | ||||
|           ..orderBy([(t) => OrderingTerm.desc(t.id)]) | ||||
|           ..limit(take, offset: offset)) | ||||
|         .get(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -274,6 +274,9 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> | ||||
|                 color: Theme.of(context).colorScheme.surface, | ||||
|                 child: AppNavigationRegion( | ||||
|                   isCollapsed: _isCollapsed, | ||||
|                   onSelected: () { | ||||
|                     _closeDrawer(); | ||||
|                   }, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|   | ||||
| @@ -10,10 +10,12 @@ import 'package:solian/widgets/channel/channel_list.dart'; | ||||
|  | ||||
| class AppNavigationRegion extends StatefulWidget { | ||||
|   final bool isCollapsed; | ||||
|   final Function onSelected; | ||||
|  | ||||
|   const AppNavigationRegion({ | ||||
|     super.key, | ||||
|     this.isCollapsed = false, | ||||
|     required this.onSelected, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
| @@ -204,6 +206,7 @@ class _AppNavigationRegionState extends State<AppNavigationRegion> { | ||||
|                         isCollapsed: widget.isCollapsed, | ||||
|                         selfId: auth.userProfile.value!['id'], | ||||
|                         noCategory: true, | ||||
|                         onSelected: (_) => widget.onSelected(), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user