♻️ Use drift instead for floor
This commit is contained in:
		| @@ -54,22 +54,22 @@ PODS: | ||||
|   - Firebase/Performance (11.0.0): | ||||
|     - Firebase/CoreOnly | ||||
|     - FirebasePerformance (~> 11.0.0) | ||||
|   - firebase_analytics (11.3.0): | ||||
|   - firebase_analytics (11.3.1): | ||||
|     - Firebase/Analytics (= 11.0.0) | ||||
|     - firebase_core | ||||
|     - Flutter | ||||
|   - firebase_core (3.4.1): | ||||
|     - Firebase/CoreOnly (= 11.0.0) | ||||
|     - Flutter | ||||
|   - firebase_crashlytics (4.1.0): | ||||
|   - firebase_crashlytics (4.1.1): | ||||
|     - Firebase/Crashlytics (= 11.0.0) | ||||
|     - firebase_core | ||||
|     - Flutter | ||||
|   - firebase_messaging (15.1.0): | ||||
|   - firebase_messaging (15.1.1): | ||||
|     - Firebase/Messaging (= 11.0.0) | ||||
|     - firebase_core | ||||
|     - Flutter | ||||
|   - firebase_performance (0.10.0-5): | ||||
|   - firebase_performance (0.10.0-6): | ||||
|     - Firebase/Performance (= 11.0.0) | ||||
|     - firebase_core | ||||
|     - Flutter | ||||
| @@ -264,6 +264,24 @@ PODS: | ||||
|   - sqflite (0.0.3): | ||||
|     - Flutter | ||||
|     - FlutterMacOS | ||||
|   - "sqlite3 (3.46.1+1)": | ||||
|     - "sqlite3/common (= 3.46.1+1)" | ||||
|   - "sqlite3/common (3.46.1+1)" | ||||
|   - "sqlite3/dbstatvtab (3.46.1+1)": | ||||
|     - sqlite3/common | ||||
|   - "sqlite3/fts5 (3.46.1+1)": | ||||
|     - sqlite3/common | ||||
|   - "sqlite3/perf-threadsafe (3.46.1+1)": | ||||
|     - sqlite3/common | ||||
|   - "sqlite3/rtree (3.46.1+1)": | ||||
|     - sqlite3/common | ||||
|   - sqlite3_flutter_libs (0.0.1): | ||||
|     - Flutter | ||||
|     - "sqlite3 (~> 3.46.0+1)" | ||||
|     - sqlite3/dbstatvtab | ||||
|     - sqlite3/fts5 | ||||
|     - sqlite3/perf-threadsafe | ||||
|     - sqlite3/rtree | ||||
|   - SwiftyGif (5.4.5) | ||||
|   - TOCropViewController (2.7.4) | ||||
|   - url_launcher_ios (0.0.1): | ||||
| @@ -305,6 +323,7 @@ DEPENDENCIES: | ||||
|   - share_plus (from `.symlinks/plugins/share_plus/ios`) | ||||
|   - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) | ||||
|   - sqflite (from `.symlinks/plugins/sqflite/darwin`) | ||||
|   - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) | ||||
|   - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) | ||||
|   - volume_controller (from `.symlinks/plugins/volume_controller/ios`) | ||||
|   - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) | ||||
| @@ -334,6 +353,7 @@ SPEC REPOS: | ||||
|     - PromisesObjC | ||||
|     - PromisesSwift | ||||
|     - SDWebImage | ||||
|     - sqlite3 | ||||
|     - SwiftyGif | ||||
|     - TOCropViewController | ||||
|     - WebRTC-SDK | ||||
| @@ -399,6 +419,8 @@ EXTERNAL SOURCES: | ||||
|     :path: ".symlinks/plugins/shared_preferences_foundation/darwin" | ||||
|   sqflite: | ||||
|     :path: ".symlinks/plugins/sqflite/darwin" | ||||
|   sqlite3_flutter_libs: | ||||
|     :path: ".symlinks/plugins/sqlite3_flutter_libs/ios" | ||||
|   url_launcher_ios: | ||||
|     :path: ".symlinks/plugins/url_launcher_ios/ios" | ||||
|   volume_controller: | ||||
| @@ -413,11 +435,11 @@ SPEC CHECKSUMS: | ||||
|   DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 | ||||
|   file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 | ||||
|   Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9 | ||||
|   firebase_analytics: 1a66fe8d4375eccff44671ea37897683a78b2675 | ||||
|   firebase_analytics: b8ce6c2c4b245d3c3bb3a147965d09da0f455959 | ||||
|   firebase_core: ba84e940cf5cbbc601095f86556560937419195c | ||||
|   firebase_crashlytics: e4f04180f443d5a8b56fbc0685bdbd7d90dd26f0 | ||||
|   firebase_messaging: 15d8b557010f3bb7b98d0302e1c7c8fbcd244425 | ||||
|   firebase_performance: d373c742649e2d85d92cc223b4511c3d132887ef | ||||
|   firebase_crashlytics: 4111f8198b78c99471c955af488cecd8224967e6 | ||||
|   firebase_messaging: c40f84e7a98da956d5262fada373b5c458edcf13 | ||||
|   firebase_performance: 8b7b9ca5adf3a9b3afa12b4eb96b9cabefc2c248 | ||||
|   FirebaseABTesting: c2e22c3aab99afa81d0561708b2c1c356c556976 | ||||
|   FirebaseAnalytics: 27eb78b97880ea4a004839b9bac0b58880f5a92a | ||||
|   FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383 | ||||
| @@ -460,6 +482,8 @@ SPEC CHECKSUMS: | ||||
|   share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad | ||||
|   shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 | ||||
|   sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec | ||||
|   sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb | ||||
|   sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b | ||||
|   SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 | ||||
|   TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654 | ||||
|   url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe | ||||
|   | ||||
| @@ -2,13 +2,14 @@ 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/message/adaptor.dart'; | ||||
| import 'package:solian/providers/message/events.dart'; | ||||
| import 'package:solian/providers/database/database.dart'; | ||||
| import 'package:solian/providers/database/services/messages.dart'; | ||||
|  | ||||
| class ChatEventController { | ||||
|   late final MessageHistoryDb database; | ||||
|   late final MessagesFetchingProvider src; | ||||
|  | ||||
|   final RxList<LocalEvent> currentEvents = RxList.empty(growable: true); | ||||
|   final RxList<LocalMessageEventTableData> currentEvents = | ||||
|       RxList.empty(growable: true); | ||||
|   final RxInt totalEvents = 0.obs; | ||||
|  | ||||
|   final RxBool isLoading = false.obs; | ||||
| @@ -17,27 +18,13 @@ class ChatEventController { | ||||
|   String? scope; | ||||
|  | ||||
|   Future<void> initialize() async { | ||||
|     if (!PlatformInfo.isWeb) { | ||||
|       database = await createHistoryDb(); | ||||
|     } | ||||
|     src = Get.find(); | ||||
|     currentEvents.clear(); | ||||
|   } | ||||
|  | ||||
|   Future<LocalEvent?> getEvent(int id) async { | ||||
|   Future<LocalMessageEventTableData?> getEvent(int id) async { | ||||
|     if (channel == null || scope == null) return null; | ||||
|  | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       final remoteRecord = await getRemoteEvent(id, channel!, scope!); | ||||
|       if (remoteRecord == null) return null; | ||||
|       return LocalEvent( | ||||
|         remoteRecord.id, | ||||
|         remoteRecord, | ||||
|         remoteRecord.channelId, | ||||
|         remoteRecord.createdAt, | ||||
|       ); | ||||
|     } else { | ||||
|       return await database.getEvent(id, channel!, scope: scope!); | ||||
|     } | ||||
|     return await src.getEvent(id, channel!, scope: scope!); | ||||
|   } | ||||
|  | ||||
|   Future<void> getEvents(Channel channel, String scope) async { | ||||
| @@ -48,7 +35,7 @@ class ChatEventController { | ||||
|  | ||||
|     isLoading.value = true; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       final result = await getRemoteEvents( | ||||
|       final result = await src.fetchRemoteEvents( | ||||
|         channel, | ||||
|         scope, | ||||
|         remainDepth: 3, | ||||
| @@ -57,13 +44,18 @@ class ChatEventController { | ||||
|       totalEvents.value = result?.$2 ?? 0; | ||||
|       if (result != null) { | ||||
|         for (final x in result.$1.reversed) { | ||||
|           final entry = LocalEvent(x.id, x, x.channelId, x.createdAt); | ||||
|           final entry = LocalMessageEventTableData( | ||||
|             id: x.id, | ||||
|             channelId: x.channelId, | ||||
|             createdAt: x.createdAt, | ||||
|             data: x, | ||||
|           ); | ||||
|           insertEvent(entry); | ||||
|           applyEvent(entry); | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       final result = await database.syncRemoteEvents( | ||||
|       final result = await src.pullRemoteEvents( | ||||
|         channel, | ||||
|         scope: scope, | ||||
|       ); | ||||
| @@ -76,7 +68,7 @@ class ChatEventController { | ||||
|   Future<void> loadEvents(Channel channel, String scope) async { | ||||
|     isLoading.value = true; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       final result = await getRemoteEvents( | ||||
|       final result = await src.fetchRemoteEvents( | ||||
|         channel, | ||||
|         scope, | ||||
|         remainDepth: 3, | ||||
| @@ -85,13 +77,18 @@ class ChatEventController { | ||||
|       if (result != null) { | ||||
|         totalEvents.value = result.$2; | ||||
|         for (final x in result.$1.reversed) { | ||||
|           final entry = LocalEvent(x.id, x, x.channelId, x.createdAt); | ||||
|           final entry = LocalMessageEventTableData( | ||||
|             id: x.id, | ||||
|             channelId: x.channelId, | ||||
|             createdAt: x.createdAt, | ||||
|             data: x, | ||||
|           ); | ||||
|           currentEvents.add(entry); | ||||
|           applyEvent(entry); | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       final result = await database.syncRemoteEvents( | ||||
|       final result = await src.pullRemoteEvents( | ||||
|         channel, | ||||
|         depth: 3, | ||||
|         scope: scope, | ||||
| @@ -105,7 +102,7 @@ class ChatEventController { | ||||
|  | ||||
|   Future<bool> syncLocal(Channel channel) async { | ||||
|     if (PlatformInfo.isWeb) return false; | ||||
|     final data = await database.localEvents.findAllByChannel(channel.id); | ||||
|     final data = await src.listEvents(channel); | ||||
|     currentEvents.replaceRange(0, currentEvents.length, data); | ||||
|     for (final x in data.reversed) { | ||||
|       applyEvent(x); | ||||
| @@ -114,26 +111,28 @@ class ChatEventController { | ||||
|   } | ||||
|  | ||||
|   receiveEvent(Event remote) async { | ||||
|     LocalEvent entry; | ||||
|     LocalMessageEventTableData entry; | ||||
|     if (PlatformInfo.isWeb) { | ||||
|       entry = LocalEvent( | ||||
|         remote.id, | ||||
|         remote, | ||||
|         remote.channelId, | ||||
|         remote.createdAt, | ||||
|       entry = LocalMessageEventTableData( | ||||
|         id: remote.id, | ||||
|         channelId: remote.channelId, | ||||
|         createdAt: remote.createdAt, | ||||
|         data: remote, | ||||
|       ); | ||||
|     } else { | ||||
|       entry = await database.receiveEvent(remote); | ||||
|       entry = await src.receiveEvent(remote); | ||||
|     } | ||||
|  | ||||
|     insertEvent(entry); | ||||
|     applyEvent(entry); | ||||
|   } | ||||
|  | ||||
|   insertEvent(LocalEvent entry) { | ||||
|   void insertEvent(LocalMessageEventTableData entry) { | ||||
|     if (entry.channelId != channel?.id) return; | ||||
|  | ||||
|     final idx = currentEvents.indexWhere((x) => x.data.uuid == entry.data.uuid); | ||||
|     final idx = currentEvents.indexWhere( | ||||
|       (x) => x.data!.uuid == entry.data!.uuid, | ||||
|     ); | ||||
|     if (idx != -1) { | ||||
|       currentEvents[idx] = entry; | ||||
|     } else { | ||||
| @@ -141,36 +140,36 @@ class ChatEventController { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   applyEvent(LocalEvent entry) { | ||||
|   void applyEvent(LocalMessageEventTableData entry) { | ||||
|     if (entry.channelId != channel?.id) return; | ||||
|  | ||||
|     switch (entry.data.type) { | ||||
|     switch (entry.data!.type) { | ||||
|       case 'messages.edit': | ||||
|         final body = EventMessageBody.fromJson(entry.data.body); | ||||
|         final body = EventMessageBody.fromJson(entry.data!.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           final idx = | ||||
|               currentEvents.indexWhere((x) => x.data.id == body.relatedEvent); | ||||
|               currentEvents.indexWhere((x) => x.data!.id == body.relatedEvent); | ||||
|           if (idx != -1) { | ||||
|             currentEvents[idx].data.body = entry.data.body; | ||||
|             currentEvents[idx].data.updatedAt = entry.data.updatedAt; | ||||
|             currentEvents[idx].data!.body = entry.data!.body; | ||||
|             currentEvents[idx].data!.updatedAt = entry.data!.updatedAt; | ||||
|           } | ||||
|         } | ||||
|       case 'messages.delete': | ||||
|         final body = EventMessageBody.fromJson(entry.data.body); | ||||
|         final body = EventMessageBody.fromJson(entry.data!.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           currentEvents.removeWhere((x) => x.id == body.relatedEvent); | ||||
|         } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   addPendingEvent(Event info) async { | ||||
|   Future<void> addPendingEvent(Event info) async { | ||||
|     currentEvents.insert( | ||||
|       0, | ||||
|       LocalEvent( | ||||
|         info.id, | ||||
|         info, | ||||
|         info.channelId, | ||||
|         DateTime.now(), | ||||
|       LocalMessageEventTableData( | ||||
|         id: info.id, | ||||
|         channelId: info.channelId, | ||||
|         createdAt: DateTime.now(), | ||||
|         data: info, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -13,6 +13,8 @@ import 'package:solian/firebase_options.dart'; | ||||
| import 'package:solian/platform.dart'; | ||||
| import 'package:solian/providers/attachment_uploader.dart'; | ||||
| import 'package:solian/providers/daily_sign.dart'; | ||||
| import 'package:solian/providers/database/database.dart'; | ||||
| import 'package:solian/providers/database/services/messages.dart'; | ||||
| import 'package:solian/providers/last_read.dart'; | ||||
| import 'package:solian/providers/link_expander.dart'; | ||||
| import 'package:solian/providers/navigation.dart'; | ||||
| @@ -43,6 +45,7 @@ void main() async { | ||||
|  | ||||
|   GoRouter.optionURLReflectsImperativeAPIs = true; | ||||
|  | ||||
|   Get.put(DatabaseProvider()); | ||||
|   Get.put(AppTranslations()); | ||||
|   await AppTranslations.init(); | ||||
|  | ||||
| @@ -135,6 +138,7 @@ class SolianApp extends StatelessWidget { | ||||
|     Get.lazyPut(() => StatusProvider()); | ||||
|     Get.lazyPut(() => ChannelProvider()); | ||||
|     Get.lazyPut(() => RealmProvider()); | ||||
|     Get.lazyPut(() => MessagesFetchingProvider()); | ||||
|     Get.lazyPut(() => ChatCallProvider()); | ||||
|     Get.lazyPut(() => AttachmentUploaderController()); | ||||
|     Get.lazyPut(() => LinkExpandProvider()); | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_secure_storage/flutter_secure_storage.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:get/get_connect/http/src/request/request.dart'; | ||||
| import 'package:solian/controllers/chat_events_controller.dart'; | ||||
| import 'package:solian/exceptions/request.dart'; | ||||
| import 'package:solian/exceptions/unauthorized.dart'; | ||||
| import 'package:solian/providers/websocket.dart'; | ||||
| @@ -199,11 +198,6 @@ class AuthProvider extends GetConnect { | ||||
|     Get.find<WebSocketProvider>().notifications.clear(); | ||||
|     Get.find<WebSocketProvider>().notificationUnread.value = 0; | ||||
|  | ||||
|     final chatHistory = ChatEventController(); | ||||
|     chatHistory.initialize().then((_) async { | ||||
|       await chatHistory.database.localEvents.wipeLocalEvents(); | ||||
|     }); | ||||
|  | ||||
|     storage.deleteAll(); | ||||
|   } | ||||
|  | ||||
|   | ||||
							
								
								
									
										24
									
								
								lib/providers/database/database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/providers/database/database.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| import 'package:drift/drift.dart'; | ||||
| import 'package:drift_flutter/drift_flutter.dart'; | ||||
| import 'package:get/get.dart' hide Value; | ||||
| import 'package:solian/providers/database/tables/messages.dart'; | ||||
|  | ||||
| import 'package:solian/models/event.dart'; | ||||
|  | ||||
| part 'database.g.dart'; | ||||
|  | ||||
| @DriftDatabase(tables: [LocalMessageEventTable]) | ||||
| class AppDatabase extends _$AppDatabase { | ||||
|   AppDatabase() : super(_openConnection()); | ||||
|  | ||||
|   @override | ||||
|   int get schemaVersion => 1; | ||||
|  | ||||
|   static QueryExecutor _openConnection() { | ||||
|     return driftDatabase(name: 'solar_network_local_db'); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class DatabaseProvider extends GetxController { | ||||
|   final database = AppDatabase(); | ||||
| } | ||||
							
								
								
									
										429
									
								
								lib/providers/database/database.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								lib/providers/database/database.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,429 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'database.dart'; | ||||
|  | ||||
| // ignore_for_file: type=lint | ||||
| class $LocalMessageEventTableTable extends LocalMessageEventTable | ||||
|     with TableInfo<$LocalMessageEventTableTable, LocalMessageEventTableData> { | ||||
|   @override | ||||
|   final GeneratedDatabase attachedDatabase; | ||||
|   final String? _alias; | ||||
|   $LocalMessageEventTableTable(this.attachedDatabase, [this._alias]); | ||||
|   static const VerificationMeta _idMeta = const VerificationMeta('id'); | ||||
|   @override | ||||
|   late final GeneratedColumn<int> id = GeneratedColumn<int>( | ||||
|       'id', aliasedName, false, | ||||
|       hasAutoIncrement: true, | ||||
|       type: DriftSqlType.int, | ||||
|       requiredDuringInsert: false, | ||||
|       defaultConstraints: | ||||
|           GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); | ||||
|   static const VerificationMeta _channelIdMeta = | ||||
|       const VerificationMeta('channelId'); | ||||
|   @override | ||||
|   late final GeneratedColumn<int> channelId = GeneratedColumn<int>( | ||||
|       'channel_id', aliasedName, false, | ||||
|       type: DriftSqlType.int, requiredDuringInsert: true); | ||||
|   static const VerificationMeta _dataMeta = const VerificationMeta('data'); | ||||
|   @override | ||||
|   late final GeneratedColumnWithTypeConverter<Event?, String> data = | ||||
|       GeneratedColumn<String>('data', aliasedName, false, | ||||
|               type: DriftSqlType.string, requiredDuringInsert: true) | ||||
|           .withConverter<Event?>($LocalMessageEventTableTable.$converterdata); | ||||
|   static const VerificationMeta _createdAtMeta = | ||||
|       const VerificationMeta('createdAt'); | ||||
|   @override | ||||
|   late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>( | ||||
|       'created_at', aliasedName, false, | ||||
|       type: DriftSqlType.dateTime, | ||||
|       requiredDuringInsert: false, | ||||
|       defaultValue: Constant(DateTime.now())); | ||||
|   @override | ||||
|   List<GeneratedColumn> get $columns => [id, channelId, data, createdAt]; | ||||
|   @override | ||||
|   String get aliasedName => _alias ?? actualTableName; | ||||
|   @override | ||||
|   String get actualTableName => $name; | ||||
|   static const String $name = 'local_message_event_table'; | ||||
|   @override | ||||
|   VerificationContext validateIntegrity( | ||||
|       Insertable<LocalMessageEventTableData> instance, | ||||
|       {bool isInserting = false}) { | ||||
|     final context = VerificationContext(); | ||||
|     final data = instance.toColumns(true); | ||||
|     if (data.containsKey('id')) { | ||||
|       context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); | ||||
|     } | ||||
|     if (data.containsKey('channel_id')) { | ||||
|       context.handle(_channelIdMeta, | ||||
|           channelId.isAcceptableOrUnknown(data['channel_id']!, _channelIdMeta)); | ||||
|     } else if (isInserting) { | ||||
|       context.missing(_channelIdMeta); | ||||
|     } | ||||
|     context.handle(_dataMeta, const VerificationResult.success()); | ||||
|     if (data.containsKey('created_at')) { | ||||
|       context.handle(_createdAtMeta, | ||||
|           createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta)); | ||||
|     } | ||||
|     return context; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Set<GeneratedColumn> get $primaryKey => {id}; | ||||
|   @override | ||||
|   LocalMessageEventTableData map(Map<String, dynamic> data, | ||||
|       {String? tablePrefix}) { | ||||
|     final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; | ||||
|     return LocalMessageEventTableData( | ||||
|       id: attachedDatabase.typeMapping | ||||
|           .read(DriftSqlType.int, data['${effectivePrefix}id'])!, | ||||
|       channelId: attachedDatabase.typeMapping | ||||
|           .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!, | ||||
|       data: $LocalMessageEventTableTable.$converterdata.fromSql(attachedDatabase | ||||
|           .typeMapping | ||||
|           .read(DriftSqlType.string, data['${effectivePrefix}data'])!), | ||||
|       createdAt: attachedDatabase.typeMapping | ||||
|           .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   $LocalMessageEventTableTable createAlias(String alias) { | ||||
|     return $LocalMessageEventTableTable(attachedDatabase, alias); | ||||
|   } | ||||
|  | ||||
|   static TypeConverter<Event?, String> $converterdata = | ||||
|       const MessageEventConverter(); | ||||
| } | ||||
|  | ||||
| class LocalMessageEventTableData extends DataClass | ||||
|     implements Insertable<LocalMessageEventTableData> { | ||||
|   final int id; | ||||
|   final int channelId; | ||||
|   final Event? data; | ||||
|   final DateTime createdAt; | ||||
|   const LocalMessageEventTableData( | ||||
|       {required this.id, | ||||
|       required this.channelId, | ||||
|       this.data, | ||||
|       required this.createdAt}); | ||||
|   @override | ||||
|   Map<String, Expression> toColumns(bool nullToAbsent) { | ||||
|     final map = <String, Expression>{}; | ||||
|     map['id'] = Variable<int>(id); | ||||
|     map['channel_id'] = Variable<int>(channelId); | ||||
|     if (!nullToAbsent || data != null) { | ||||
|       map['data'] = Variable<String>( | ||||
|           $LocalMessageEventTableTable.$converterdata.toSql(data)); | ||||
|     } | ||||
|     map['created_at'] = Variable<DateTime>(createdAt); | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   LocalMessageEventTableCompanion toCompanion(bool nullToAbsent) { | ||||
|     return LocalMessageEventTableCompanion( | ||||
|       id: Value(id), | ||||
|       channelId: Value(channelId), | ||||
|       data: data == null && nullToAbsent ? const Value.absent() : Value(data), | ||||
|       createdAt: Value(createdAt), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   factory LocalMessageEventTableData.fromJson(Map<String, dynamic> json, | ||||
|       {ValueSerializer? serializer}) { | ||||
|     serializer ??= driftRuntimeOptions.defaultSerializer; | ||||
|     return LocalMessageEventTableData( | ||||
|       id: serializer.fromJson<int>(json['id']), | ||||
|       channelId: serializer.fromJson<int>(json['channelId']), | ||||
|       data: serializer.fromJson<Event?>(json['data']), | ||||
|       createdAt: serializer.fromJson<DateTime>(json['createdAt']), | ||||
|     ); | ||||
|   } | ||||
|   @override | ||||
|   Map<String, dynamic> toJson({ValueSerializer? serializer}) { | ||||
|     serializer ??= driftRuntimeOptions.defaultSerializer; | ||||
|     return <String, dynamic>{ | ||||
|       'id': serializer.toJson<int>(id), | ||||
|       'channelId': serializer.toJson<int>(channelId), | ||||
|       'data': serializer.toJson<Event?>(data), | ||||
|       'createdAt': serializer.toJson<DateTime>(createdAt), | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   LocalMessageEventTableData copyWith( | ||||
|           {int? id, | ||||
|           int? channelId, | ||||
|           Value<Event?> data = const Value.absent(), | ||||
|           DateTime? createdAt}) => | ||||
|       LocalMessageEventTableData( | ||||
|         id: id ?? this.id, | ||||
|         channelId: channelId ?? this.channelId, | ||||
|         data: data.present ? data.value : this.data, | ||||
|         createdAt: createdAt ?? this.createdAt, | ||||
|       ); | ||||
|   LocalMessageEventTableData copyWithCompanion( | ||||
|       LocalMessageEventTableCompanion data) { | ||||
|     return LocalMessageEventTableData( | ||||
|       id: data.id.present ? data.id.value : this.id, | ||||
|       channelId: data.channelId.present ? data.channelId.value : this.channelId, | ||||
|       data: data.data.present ? data.data.value : this.data, | ||||
|       createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return (StringBuffer('LocalMessageEventTableData(') | ||||
|           ..write('id: $id, ') | ||||
|           ..write('channelId: $channelId, ') | ||||
|           ..write('data: $data, ') | ||||
|           ..write('createdAt: $createdAt') | ||||
|           ..write(')')) | ||||
|         .toString(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode => Object.hash(id, channelId, data, createdAt); | ||||
|   @override | ||||
|   bool operator ==(Object other) => | ||||
|       identical(this, other) || | ||||
|       (other is LocalMessageEventTableData && | ||||
|           other.id == this.id && | ||||
|           other.channelId == this.channelId && | ||||
|           other.data == this.data && | ||||
|           other.createdAt == this.createdAt); | ||||
| } | ||||
|  | ||||
| class LocalMessageEventTableCompanion | ||||
|     extends UpdateCompanion<LocalMessageEventTableData> { | ||||
|   final Value<int> id; | ||||
|   final Value<int> channelId; | ||||
|   final Value<Event?> data; | ||||
|   final Value<DateTime> createdAt; | ||||
|   const LocalMessageEventTableCompanion({ | ||||
|     this.id = const Value.absent(), | ||||
|     this.channelId = const Value.absent(), | ||||
|     this.data = const Value.absent(), | ||||
|     this.createdAt = const Value.absent(), | ||||
|   }); | ||||
|   LocalMessageEventTableCompanion.insert({ | ||||
|     this.id = const Value.absent(), | ||||
|     required int channelId, | ||||
|     required Event? data, | ||||
|     this.createdAt = const Value.absent(), | ||||
|   })  : channelId = Value(channelId), | ||||
|         data = Value(data); | ||||
|   static Insertable<LocalMessageEventTableData> custom({ | ||||
|     Expression<int>? id, | ||||
|     Expression<int>? channelId, | ||||
|     Expression<String>? data, | ||||
|     Expression<DateTime>? createdAt, | ||||
|   }) { | ||||
|     return RawValuesInsertable({ | ||||
|       if (id != null) 'id': id, | ||||
|       if (channelId != null) 'channel_id': channelId, | ||||
|       if (data != null) 'data': data, | ||||
|       if (createdAt != null) 'created_at': createdAt, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   LocalMessageEventTableCompanion copyWith( | ||||
|       {Value<int>? id, | ||||
|       Value<int>? channelId, | ||||
|       Value<Event?>? data, | ||||
|       Value<DateTime>? createdAt}) { | ||||
|     return LocalMessageEventTableCompanion( | ||||
|       id: id ?? this.id, | ||||
|       channelId: channelId ?? this.channelId, | ||||
|       data: data ?? this.data, | ||||
|       createdAt: createdAt ?? this.createdAt, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Map<String, Expression> toColumns(bool nullToAbsent) { | ||||
|     final map = <String, Expression>{}; | ||||
|     if (id.present) { | ||||
|       map['id'] = Variable<int>(id.value); | ||||
|     } | ||||
|     if (channelId.present) { | ||||
|       map['channel_id'] = Variable<int>(channelId.value); | ||||
|     } | ||||
|     if (data.present) { | ||||
|       map['data'] = Variable<String>( | ||||
|           $LocalMessageEventTableTable.$converterdata.toSql(data.value)); | ||||
|     } | ||||
|     if (createdAt.present) { | ||||
|       map['created_at'] = Variable<DateTime>(createdAt.value); | ||||
|     } | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return (StringBuffer('LocalMessageEventTableCompanion(') | ||||
|           ..write('id: $id, ') | ||||
|           ..write('channelId: $channelId, ') | ||||
|           ..write('data: $data, ') | ||||
|           ..write('createdAt: $createdAt') | ||||
|           ..write(')')) | ||||
|         .toString(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| abstract class _$AppDatabase extends GeneratedDatabase { | ||||
|   _$AppDatabase(QueryExecutor e) : super(e); | ||||
|   $AppDatabaseManager get managers => $AppDatabaseManager(this); | ||||
|   late final $LocalMessageEventTableTable localMessageEventTable = | ||||
|       $LocalMessageEventTableTable(this); | ||||
|   @override | ||||
|   Iterable<TableInfo<Table, Object?>> get allTables => | ||||
|       allSchemaEntities.whereType<TableInfo<Table, Object?>>(); | ||||
|   @override | ||||
|   List<DatabaseSchemaEntity> get allSchemaEntities => [localMessageEventTable]; | ||||
| } | ||||
|  | ||||
| typedef $$LocalMessageEventTableTableCreateCompanionBuilder | ||||
|     = LocalMessageEventTableCompanion Function({ | ||||
|   Value<int> id, | ||||
|   required int channelId, | ||||
|   required Event? data, | ||||
|   Value<DateTime> createdAt, | ||||
| }); | ||||
| typedef $$LocalMessageEventTableTableUpdateCompanionBuilder | ||||
|     = LocalMessageEventTableCompanion Function({ | ||||
|   Value<int> id, | ||||
|   Value<int> channelId, | ||||
|   Value<Event?> data, | ||||
|   Value<DateTime> createdAt, | ||||
| }); | ||||
|  | ||||
| class $$LocalMessageEventTableTableFilterComposer | ||||
|     extends FilterComposer<_$AppDatabase, $LocalMessageEventTableTable> { | ||||
|   $$LocalMessageEventTableTableFilterComposer(super.$state); | ||||
|   ColumnFilters<int> get id => $state.composableBuilder( | ||||
|       column: $state.table.id, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnFilters(column, joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnFilters<int> get channelId => $state.composableBuilder( | ||||
|       column: $state.table.channelId, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnFilters(column, joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnWithTypeConverterFilters<Event?, Event, String> get data => | ||||
|       $state.composableBuilder( | ||||
|           column: $state.table.data, | ||||
|           builder: (column, joinBuilders) => ColumnWithTypeConverterFilters( | ||||
|               column, | ||||
|               joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnFilters<DateTime> get createdAt => $state.composableBuilder( | ||||
|       column: $state.table.createdAt, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnFilters(column, joinBuilders: joinBuilders)); | ||||
| } | ||||
|  | ||||
| class $$LocalMessageEventTableTableOrderingComposer | ||||
|     extends OrderingComposer<_$AppDatabase, $LocalMessageEventTableTable> { | ||||
|   $$LocalMessageEventTableTableOrderingComposer(super.$state); | ||||
|   ColumnOrderings<int> get id => $state.composableBuilder( | ||||
|       column: $state.table.id, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnOrderings(column, joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnOrderings<int> get channelId => $state.composableBuilder( | ||||
|       column: $state.table.channelId, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnOrderings(column, joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnOrderings<String> get data => $state.composableBuilder( | ||||
|       column: $state.table.data, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnOrderings(column, joinBuilders: joinBuilders)); | ||||
|  | ||||
|   ColumnOrderings<DateTime> get createdAt => $state.composableBuilder( | ||||
|       column: $state.table.createdAt, | ||||
|       builder: (column, joinBuilders) => | ||||
|           ColumnOrderings(column, joinBuilders: joinBuilders)); | ||||
| } | ||||
|  | ||||
| class $$LocalMessageEventTableTableTableManager extends RootTableManager< | ||||
|     _$AppDatabase, | ||||
|     $LocalMessageEventTableTable, | ||||
|     LocalMessageEventTableData, | ||||
|     $$LocalMessageEventTableTableFilterComposer, | ||||
|     $$LocalMessageEventTableTableOrderingComposer, | ||||
|     $$LocalMessageEventTableTableCreateCompanionBuilder, | ||||
|     $$LocalMessageEventTableTableUpdateCompanionBuilder, | ||||
|     ( | ||||
|       LocalMessageEventTableData, | ||||
|       BaseReferences<_$AppDatabase, $LocalMessageEventTableTable, | ||||
|           LocalMessageEventTableData> | ||||
|     ), | ||||
|     LocalMessageEventTableData, | ||||
|     PrefetchHooks Function()> { | ||||
|   $$LocalMessageEventTableTableTableManager( | ||||
|       _$AppDatabase db, $LocalMessageEventTableTable table) | ||||
|       : super(TableManagerState( | ||||
|           db: db, | ||||
|           table: table, | ||||
|           filteringComposer: $$LocalMessageEventTableTableFilterComposer( | ||||
|               ComposerState(db, table)), | ||||
|           orderingComposer: $$LocalMessageEventTableTableOrderingComposer( | ||||
|               ComposerState(db, table)), | ||||
|           updateCompanionCallback: ({ | ||||
|             Value<int> id = const Value.absent(), | ||||
|             Value<int> channelId = const Value.absent(), | ||||
|             Value<Event?> data = const Value.absent(), | ||||
|             Value<DateTime> createdAt = const Value.absent(), | ||||
|           }) => | ||||
|               LocalMessageEventTableCompanion( | ||||
|             id: id, | ||||
|             channelId: channelId, | ||||
|             data: data, | ||||
|             createdAt: createdAt, | ||||
|           ), | ||||
|           createCompanionCallback: ({ | ||||
|             Value<int> id = const Value.absent(), | ||||
|             required int channelId, | ||||
|             required Event? data, | ||||
|             Value<DateTime> createdAt = const Value.absent(), | ||||
|           }) => | ||||
|               LocalMessageEventTableCompanion.insert( | ||||
|             id: id, | ||||
|             channelId: channelId, | ||||
|             data: data, | ||||
|             createdAt: createdAt, | ||||
|           ), | ||||
|           withReferenceMapper: (p0) => p0 | ||||
|               .map((e) => (e.readTable(table), BaseReferences(db, table, e))) | ||||
|               .toList(), | ||||
|           prefetchHooksCallback: null, | ||||
|         )); | ||||
| } | ||||
|  | ||||
| typedef $$LocalMessageEventTableTableProcessedTableManager | ||||
|     = ProcessedTableManager< | ||||
|         _$AppDatabase, | ||||
|         $LocalMessageEventTableTable, | ||||
|         LocalMessageEventTableData, | ||||
|         $$LocalMessageEventTableTableFilterComposer, | ||||
|         $$LocalMessageEventTableTableOrderingComposer, | ||||
|         $$LocalMessageEventTableTableCreateCompanionBuilder, | ||||
|         $$LocalMessageEventTableTableUpdateCompanionBuilder, | ||||
|         ( | ||||
|           LocalMessageEventTableData, | ||||
|           BaseReferences<_$AppDatabase, $LocalMessageEventTableTable, | ||||
|               LocalMessageEventTableData> | ||||
|         ), | ||||
|         LocalMessageEventTableData, | ||||
|         PrefetchHooks Function()>; | ||||
|  | ||||
| class $AppDatabaseManager { | ||||
|   final _$AppDatabase _db; | ||||
|   $AppDatabaseManager(this._db); | ||||
|   $$LocalMessageEventTableTableTableManager get localMessageEventTable => | ||||
|       $$LocalMessageEventTableTableTableManager( | ||||
|           _db, _db.localMessageEventTable); | ||||
| } | ||||
							
								
								
									
										202
									
								
								lib/providers/database/services/messages.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								lib/providers/database/services/messages.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| import 'package:drift/drift.dart'; | ||||
| import 'package:get/get.dart' hide Value; | ||||
| import 'package:solian/exceptions/request.dart'; | ||||
| import 'package:solian/models/channel.dart'; | ||||
| import 'package:solian/models/event.dart'; | ||||
| import 'package:solian/models/pagination.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/providers/database/database.dart'; | ||||
|  | ||||
| class MessagesFetchingProvider extends GetxController { | ||||
|   Future<(List<Event>, int)?> getWhatsNewEvents(int pivot, {take = 10}) async { | ||||
|     final AuthProvider auth = Get.find(); | ||||
|     if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|     final client = auth.configureClient('messaging'); | ||||
|  | ||||
|     final resp = await client.get( | ||||
|       '/whats-new?pivot=$pivot&take=$take', | ||||
|     ); | ||||
|  | ||||
|     if (resp.statusCode != 200) { | ||||
|       throw RequestException(resp); | ||||
|     } | ||||
|  | ||||
|     final PaginationResult response = PaginationResult.fromJson(resp.body); | ||||
|     final result = | ||||
|         response.data?.map((e) => Event.fromJson(e)).toList() ?? List.empty(); | ||||
|  | ||||
|     return (result, response.count); | ||||
|   } | ||||
|  | ||||
|   Future<Event?> fetchRemoteEvent(int id, Channel channel, String scope) async { | ||||
|     final AuthProvider auth = Get.find(); | ||||
|     if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|     final client = auth.configureClient('messaging'); | ||||
|  | ||||
|     final resp = await client.get( | ||||
|       '/channels/$scope/${channel.alias}/events/$id', | ||||
|     ); | ||||
|  | ||||
|     if (resp.statusCode == 404) { | ||||
|       return null; | ||||
|     } else if (resp.statusCode != 200) { | ||||
|       throw RequestException(resp); | ||||
|     } | ||||
|  | ||||
|     return Event.fromJson(resp.body); | ||||
|   } | ||||
|  | ||||
|   Future<(List<Event>, int)?> fetchRemoteEvents( | ||||
|     Channel channel, | ||||
|     String scope, { | ||||
|     required int remainDepth, | ||||
|     bool Function(List<Event> items)? onBrake, | ||||
|     take = 10, | ||||
|     offset = 0, | ||||
|   }) async { | ||||
|     if (remainDepth <= 0) { | ||||
|       return null; | ||||
|     } | ||||
|  | ||||
|     final AuthProvider auth = Get.find(); | ||||
|     if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|     final client = auth.configureClient('messaging'); | ||||
|  | ||||
|     final resp = await client.get( | ||||
|       '/channels/$scope/${channel.alias}/events?take=$take&offset=$offset', | ||||
|     ); | ||||
|  | ||||
|     if (resp.statusCode != 200) { | ||||
|       throw RequestException(resp); | ||||
|     } | ||||
|  | ||||
|     final PaginationResult response = PaginationResult.fromJson(resp.body); | ||||
|     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, | ||||
|           remainDepth: remainDepth - 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; | ||||
|     final entry = await database | ||||
|         .into(database.localMessageEventTable) | ||||
|         .insertReturning(LocalMessageEventTableCompanion.insert( | ||||
|           id: Value(remote.id), | ||||
|           channelId: remote.channelId, | ||||
|           data: remote, | ||||
|           createdAt: Value(remote.createdAt), | ||||
|         )); | ||||
|  | ||||
|     // Handle side-effect like editing and deleting | ||||
|     switch (remote.type) { | ||||
|       case 'messages.edit': | ||||
|         final body = EventMessageBody.fromJson(remote.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           final target = await (database.select(database.localMessageEventTable) | ||||
|                 ..where((x) => x.id.equals(body.relatedEvent!))) | ||||
|               .getSingleOrNull(); | ||||
|           if (target != null) { | ||||
|             target.data!.body = remote.body; | ||||
|             target.data!.updatedAt = remote.updatedAt; | ||||
|             await (database.update(database.localMessageEventTable) | ||||
|                   ..where((x) => x.id.equals(target.id))) | ||||
|                 .write( | ||||
|               LocalMessageEventTableCompanion(data: Value(target.data)), | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|       case 'messages.delete': | ||||
|         final body = EventMessageBody.fromJson(remote.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           await (database.delete(database.localMessageEventTable) | ||||
|                 ..where((x) => x.id.equals(body.relatedEvent!))) | ||||
|               .go(); | ||||
|         } | ||||
|     } | ||||
|     return entry; | ||||
|   } | ||||
|  | ||||
|   Future<LocalMessageEventTableData?> getEvent(int id, Channel channel, | ||||
|       {String scope = 'global'}) async { | ||||
|     final database = Get.find<DatabaseProvider>().database; | ||||
|     final localRecord = await (database.select(database.localMessageEventTable) | ||||
|           ..where((x) => x.id.equals(id))) | ||||
|         .getSingleOrNull(); | ||||
|     if (localRecord != null) return localRecord; | ||||
|  | ||||
|     final remoteRecord = await fetchRemoteEvent(id, channel, scope); | ||||
|     if (remoteRecord == null) return null; | ||||
|  | ||||
|     return await receiveEvent(remoteRecord); | ||||
|   } | ||||
|  | ||||
|   /// Pull the remote events to local database | ||||
|   Future<(List<Event>, int)?> pullRemoteEvents(Channel channel, | ||||
|       {String scope = 'global', depth = 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)])) | ||||
|         .getSingleOrNull(); | ||||
|  | ||||
|     final data = await fetchRemoteEvents( | ||||
|       channel, | ||||
|       scope, | ||||
|       remainDepth: depth, | ||||
|       offset: offset, | ||||
|       onBrake: (items) { | ||||
|         return items.any((x) => x.id == lastOne?.id); | ||||
|       }, | ||||
|     ); | ||||
|     if (data != null) { | ||||
|       await database.batch((batch) { | ||||
|         batch.insertAll( | ||||
|           database.localMessageEventTable, | ||||
|           data.$1.map((x) => LocalMessageEventTableCompanion( | ||||
|                 id: Value(x.id), | ||||
|                 channelId: Value(x.channelId), | ||||
|                 data: Value(x), | ||||
|                 createdAt: Value(x.createdAt), | ||||
|               )), | ||||
|         ); | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     return data; | ||||
|   } | ||||
|  | ||||
|   Future<List<LocalMessageEventTableData>> listEvents(Channel channel) 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)])) | ||||
|         .get(); | ||||
|   } | ||||
|  | ||||
|   Future<LocalMessageEventTableData?> getLastInChannel(Channel channel) 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)])) | ||||
|         .getSingleOrNull(); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										13
									
								
								lib/providers/database/tables/json.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/providers/database/tables/json.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:drift/drift.dart'; | ||||
|  | ||||
| class JsonConverter extends TypeConverter<Object?, String> { | ||||
|   const JsonConverter(); | ||||
|  | ||||
|   @override | ||||
|   Object? fromSql(String fromDb) => jsonDecode(fromDb); | ||||
|  | ||||
|   @override | ||||
|   String toSql(Object? value) => jsonEncode(value); | ||||
| } | ||||
							
								
								
									
										22
									
								
								lib/providers/database/tables/messages.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/providers/database/tables/messages.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:drift/drift.dart'; | ||||
| import 'package:solian/models/event.dart'; | ||||
|  | ||||
| class LocalMessageEventTable extends Table { | ||||
|   IntColumn get id => integer().autoIncrement()(); | ||||
|   IntColumn get channelId => integer()(); | ||||
|   TextColumn get data => text().map(const MessageEventConverter())(); | ||||
|   DateTimeColumn get createdAt => | ||||
|       dateTime().withDefault(Constant(DateTime.now()))(); | ||||
| } | ||||
|  | ||||
| class MessageEventConverter extends TypeConverter<Event?, String> { | ||||
|   const MessageEventConverter(); | ||||
|  | ||||
|   @override | ||||
|   Event? fromSql(String fromDb) => Event.fromJson(jsonDecode(fromDb)); | ||||
|  | ||||
|   @override | ||||
|   String toSql(Event? value) => jsonEncode(value?.toJson()); | ||||
| } | ||||
| @@ -1,173 +0,0 @@ | ||||
| import 'package:floor/floor.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:solian/exceptions/request.dart'; | ||||
| import 'package:solian/models/channel.dart'; | ||||
| import 'package:solian/models/event.dart'; | ||||
| import 'package:solian/models/pagination.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/providers/message/events.dart'; | ||||
|  | ||||
| Future<MessageHistoryDb> createHistoryDb() async { | ||||
|   final migration1to2 = Migration(1, 2, (database) async { | ||||
|     await database.execute('DROP TABLE IF EXISTS LocalMessage'); | ||||
|   }); | ||||
|  | ||||
|   return await $FloorMessageHistoryDb | ||||
|       .databaseBuilder('messaging_data.dart') | ||||
|       .addMigrations([migration1to2]).build(); | ||||
| } | ||||
|  | ||||
| Future<(List<Event>, int)?> getWhatsNewEvents(int pivot, {take = 10}) async { | ||||
|   final AuthProvider auth = Get.find(); | ||||
|   if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|   final client = auth.configureClient('messaging'); | ||||
|  | ||||
|   final resp = await client.get( | ||||
|     '/whats-new?pivot=$pivot&take=$take', | ||||
|   ); | ||||
|  | ||||
|   if (resp.statusCode != 200) { | ||||
|     throw RequestException(resp); | ||||
|   } | ||||
|  | ||||
|   final PaginationResult response = PaginationResult.fromJson(resp.body); | ||||
|   final result = | ||||
|       response.data?.map((e) => Event.fromJson(e)).toList() ?? List.empty(); | ||||
|  | ||||
|   return (result, response.count); | ||||
| } | ||||
|  | ||||
| Future<Event?> getRemoteEvent(int id, Channel channel, String scope) async { | ||||
|   final AuthProvider auth = Get.find(); | ||||
|   if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|   final client = auth.configureClient('messaging'); | ||||
|  | ||||
|   final resp = await client.get( | ||||
|     '/channels/$scope/${channel.alias}/events/$id', | ||||
|   ); | ||||
|  | ||||
|   if (resp.statusCode == 404) { | ||||
|     return null; | ||||
|   } else if (resp.statusCode != 200) { | ||||
|     throw RequestException(resp); | ||||
|   } | ||||
|  | ||||
|   return Event.fromJson(resp.body); | ||||
| } | ||||
|  | ||||
| Future<(List<Event>, int)?> getRemoteEvents( | ||||
|   Channel channel, | ||||
|   String scope, { | ||||
|   required int remainDepth, | ||||
|   bool Function(List<Event> items)? onBrake, | ||||
|   take = 10, | ||||
|   offset = 0, | ||||
| }) async { | ||||
|   if (remainDepth <= 0) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   final AuthProvider auth = Get.find(); | ||||
|   if (auth.isAuthorized.isFalse) return null; | ||||
|  | ||||
|   final client = auth.configureClient('messaging'); | ||||
|  | ||||
|   final resp = await client.get( | ||||
|     '/channels/$scope/${channel.alias}/events?take=$take&offset=$offset', | ||||
|   ); | ||||
|  | ||||
|   if (resp.statusCode != 200) { | ||||
|     throw RequestException(resp); | ||||
|   } | ||||
|  | ||||
|   final PaginationResult response = PaginationResult.fromJson(resp.body); | ||||
|   final result = | ||||
|       response.data?.map((e) => Event.fromJson(e)).toList() ?? List.empty(); | ||||
|  | ||||
|   if (onBrake != null && onBrake(result)) { | ||||
|     return (result, response.count); | ||||
|   } | ||||
|  | ||||
|   final expandResult = (await getRemoteEvents( | ||||
|         channel, | ||||
|         scope, | ||||
|         remainDepth: remainDepth - 1, | ||||
|         take: take, | ||||
|         offset: offset + result.length, | ||||
|       )) | ||||
|           ?.$1 ?? | ||||
|       List.empty(); | ||||
|  | ||||
|   return ([...result, ...expandResult], response.count); | ||||
| } | ||||
|  | ||||
| extension MessageHistoryAdaptor on MessageHistoryDb { | ||||
|   Future<LocalEvent> receiveEvent(Event remote) async { | ||||
|     final entry = LocalEvent( | ||||
|       remote.id, | ||||
|       remote, | ||||
|       remote.channelId, | ||||
|       remote.createdAt, | ||||
|     ); | ||||
|     await localEvents.insert(entry); | ||||
|     switch (remote.type) { | ||||
|       case 'messages.edit': | ||||
|         final body = EventMessageBody.fromJson(remote.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           final target = await localEvents.findById(body.relatedEvent!); | ||||
|           if (target != null) { | ||||
|             target.data.body = remote.body; | ||||
|             target.data.updatedAt = remote.updatedAt; | ||||
|             await localEvents.update(target); | ||||
|           } | ||||
|         } | ||||
|       case 'messages.delete': | ||||
|         final body = EventMessageBody.fromJson(remote.body); | ||||
|         if (body.relatedEvent != null) { | ||||
|           await localEvents.delete(body.relatedEvent!); | ||||
|         } | ||||
|     } | ||||
|     return entry; | ||||
|   } | ||||
|  | ||||
|   Future<LocalEvent?> getEvent(int id, Channel channel, | ||||
|       {String scope = 'global'}) async { | ||||
|     final localRecord = await localEvents.findById(id); | ||||
|     if (localRecord != null) return localRecord; | ||||
|  | ||||
|     final remoteRecord = await getRemoteEvent(id, channel, scope); | ||||
|     if (remoteRecord == null) return null; | ||||
|  | ||||
|     return await receiveEvent(remoteRecord); | ||||
|   } | ||||
|  | ||||
|   Future<(List<Event>, int)?> syncRemoteEvents(Channel channel, | ||||
|       {String scope = 'global', depth = 10, offset = 0}) async { | ||||
|     final lastOne = await localEvents.findLastByChannel(channel.id); | ||||
|  | ||||
|     final data = await getRemoteEvents( | ||||
|       channel, | ||||
|       scope, | ||||
|       remainDepth: depth, | ||||
|       offset: offset, | ||||
|       onBrake: (items) { | ||||
|         return items.any((x) => x.id == lastOne?.id); | ||||
|       }, | ||||
|     ); | ||||
|     if (data != null) { | ||||
|       await localEvents.insertBulk( | ||||
|         data.$1 | ||||
|             .map((x) => LocalEvent(x.id, x, x.channelId, x.createdAt)) | ||||
|             .toList(), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return data; | ||||
|   } | ||||
|  | ||||
|   Future<List<LocalEvent>> listEvents(Channel channel) async { | ||||
|     return await localEvents.findAllByChannel(channel.id); | ||||
|   } | ||||
| } | ||||
| @@ -1,83 +0,0 @@ | ||||
| import 'dart:async'; | ||||
| import 'dart:convert'; | ||||
| import 'package:floor/floor.dart'; | ||||
| import 'package:solian/models/event.dart'; | ||||
| import 'package:sqflite/sqflite.dart' as sqflite; | ||||
|  | ||||
| part 'events.g.dart'; | ||||
|  | ||||
| @entity | ||||
| class LocalEvent { | ||||
|   @primaryKey | ||||
|   final int id; | ||||
|  | ||||
|   final Event data; | ||||
|   final int channelId; | ||||
|  | ||||
|   final DateTime createdAt; | ||||
|  | ||||
|   LocalEvent(this.id, this.data, this.channelId, this.createdAt); | ||||
| } | ||||
|  | ||||
| class DateTimeConverter extends TypeConverter<DateTime, int> { | ||||
|   @override | ||||
|   DateTime decode(int databaseValue) { | ||||
|     return DateTime.fromMillisecondsSinceEpoch(databaseValue); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int encode(DateTime value) { | ||||
|     return value.millisecondsSinceEpoch; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class RemoteEventConverter extends TypeConverter<Event, String> { | ||||
|   @override | ||||
|   Event decode(String databaseValue) { | ||||
|     return Event.fromJson(jsonDecode(databaseValue)); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String encode(Event value) { | ||||
|     return jsonEncode(value.toJson()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @dao | ||||
| abstract class LocalEventDao { | ||||
|   @Query('SELECT COUNT(id) FROM LocalEvent WHERE channelId = :channelId') | ||||
|   Future<int?> countByChannel(int channelId); | ||||
|  | ||||
|   @Query('SELECT * FROM LocalEvent WHERE id = :id') | ||||
|   Future<LocalEvent?> findById(int id); | ||||
|  | ||||
|   @Query('SELECT * FROM LocalEvent WHERE channelId = :channelId ORDER BY createdAt DESC') | ||||
|   Future<List<LocalEvent>> findAllByChannel(int channelId); | ||||
|  | ||||
|   @Query('SELECT * FROM LocalEvent WHERE channelId = :channelId ORDER BY createdAt DESC LIMIT 1') | ||||
|   Future<LocalEvent?> findLastByChannel(int channelId); | ||||
|  | ||||
|   @Insert(onConflict: OnConflictStrategy.replace) | ||||
|   Future<void> insert(LocalEvent m); | ||||
|  | ||||
|   @Insert(onConflict: OnConflictStrategy.replace) | ||||
|   Future<void> insertBulk(List<LocalEvent> m); | ||||
|  | ||||
|   @Update(onConflict: OnConflictStrategy.replace) | ||||
|   Future<void> update(LocalEvent m); | ||||
|  | ||||
|   @Query('DELETE FROM LocalEvent WHERE id = :id') | ||||
|   Future<void> delete(int id); | ||||
|  | ||||
|   @Query('DELETE FROM LocalEvent WHERE channelId = :channelId') | ||||
|   Future<List<LocalEvent>> deleteByChannel(int channelId); | ||||
|  | ||||
|   @Query('DELETE FROM LocalEvent') | ||||
|   Future<void> wipeLocalEvents(); | ||||
| } | ||||
|  | ||||
| @TypeConverters([DateTimeConverter, RemoteEventConverter]) | ||||
| @Database(version: 2, entities: [LocalEvent]) | ||||
| abstract class MessageHistoryDb extends FloorDatabase { | ||||
|   LocalEventDao get localEvents; | ||||
| } | ||||
| @@ -1,228 +0,0 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'events.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // FloorGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| abstract class $MessageHistoryDbBuilderContract { | ||||
|   /// Adds migrations to the builder. | ||||
|   $MessageHistoryDbBuilderContract addMigrations(List<Migration> migrations); | ||||
|  | ||||
|   /// Adds a database [Callback] to the builder. | ||||
|   $MessageHistoryDbBuilderContract addCallback(Callback callback); | ||||
|  | ||||
|   /// Creates the database and initializes it. | ||||
|   Future<MessageHistoryDb> build(); | ||||
| } | ||||
|  | ||||
| // ignore: avoid_classes_with_only_static_members | ||||
| class $FloorMessageHistoryDb { | ||||
|   /// Creates a database builder for a persistent database. | ||||
|   /// Once a database is built, you should keep a reference to it and re-use it. | ||||
|   static $MessageHistoryDbBuilderContract databaseBuilder(String name) => | ||||
|       _$MessageHistoryDbBuilder(name); | ||||
|  | ||||
|   /// Creates a database builder for an in memory database. | ||||
|   /// Information stored in an in memory database disappears when the process is killed. | ||||
|   /// Once a database is built, you should keep a reference to it and re-use it. | ||||
|   static $MessageHistoryDbBuilderContract inMemoryDatabaseBuilder() => | ||||
|       _$MessageHistoryDbBuilder(null); | ||||
| } | ||||
|  | ||||
| class _$MessageHistoryDbBuilder implements $MessageHistoryDbBuilderContract { | ||||
|   _$MessageHistoryDbBuilder(this.name); | ||||
|  | ||||
|   final String? name; | ||||
|  | ||||
|   final List<Migration> _migrations = []; | ||||
|  | ||||
|   Callback? _callback; | ||||
|  | ||||
|   @override | ||||
|   $MessageHistoryDbBuilderContract addMigrations(List<Migration> migrations) { | ||||
|     _migrations.addAll(migrations); | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   $MessageHistoryDbBuilderContract addCallback(Callback callback) { | ||||
|     _callback = callback; | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<MessageHistoryDb> build() async { | ||||
|     final path = name != null | ||||
|         ? await sqfliteDatabaseFactory.getDatabasePath(name!) | ||||
|         : ':memory:'; | ||||
|     final database = _$MessageHistoryDb(); | ||||
|     database.database = await database.open( | ||||
|       path, | ||||
|       _migrations, | ||||
|       _callback, | ||||
|     ); | ||||
|     return database; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _$MessageHistoryDb extends MessageHistoryDb { | ||||
|   _$MessageHistoryDb([StreamController<String>? listener]) { | ||||
|     changeListener = listener ?? StreamController<String>.broadcast(); | ||||
|   } | ||||
|  | ||||
|   LocalEventDao? _localEventsInstance; | ||||
|  | ||||
|   Future<sqflite.Database> open( | ||||
|     String path, | ||||
|     List<Migration> migrations, [ | ||||
|     Callback? callback, | ||||
|   ]) async { | ||||
|     final databaseOptions = sqflite.OpenDatabaseOptions( | ||||
|       version: 2, | ||||
|       onConfigure: (database) async { | ||||
|         await database.execute('PRAGMA foreign_keys = ON'); | ||||
|         await callback?.onConfigure?.call(database); | ||||
|       }, | ||||
|       onOpen: (database) async { | ||||
|         await callback?.onOpen?.call(database); | ||||
|       }, | ||||
|       onUpgrade: (database, startVersion, endVersion) async { | ||||
|         await MigrationAdapter.runMigrations( | ||||
|             database, startVersion, endVersion, migrations); | ||||
|  | ||||
|         await callback?.onUpgrade?.call(database, startVersion, endVersion); | ||||
|       }, | ||||
|       onCreate: (database, version) async { | ||||
|         await database.execute( | ||||
|             'CREATE TABLE IF NOT EXISTS `LocalEvent` (`id` INTEGER NOT NULL, `data` TEXT NOT NULL, `channelId` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY (`id`))'); | ||||
|  | ||||
|         await callback?.onCreate?.call(database, version); | ||||
|       }, | ||||
|     ); | ||||
|     return sqfliteDatabaseFactory.openDatabase(path, options: databaseOptions); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   LocalEventDao get localEvents { | ||||
|     return _localEventsInstance ??= _$LocalEventDao(database, changeListener); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _$LocalEventDao extends LocalEventDao { | ||||
|   _$LocalEventDao( | ||||
|     this.database, | ||||
|     this.changeListener, | ||||
|   )   : _queryAdapter = QueryAdapter(database), | ||||
|         _localEventInsertionAdapter = InsertionAdapter( | ||||
|             database, | ||||
|             'LocalEvent', | ||||
|             (LocalEvent item) => <String, Object?>{ | ||||
|                   'id': item.id, | ||||
|                   'data': _remoteEventConverter.encode(item.data), | ||||
|                   'channelId': item.channelId, | ||||
|                   'createdAt': _dateTimeConverter.encode(item.createdAt) | ||||
|                 }), | ||||
|         _localEventUpdateAdapter = UpdateAdapter( | ||||
|             database, | ||||
|             'LocalEvent', | ||||
|             ['id'], | ||||
|             (LocalEvent item) => <String, Object?>{ | ||||
|                   'id': item.id, | ||||
|                   'data': _remoteEventConverter.encode(item.data), | ||||
|                   'channelId': item.channelId, | ||||
|                   'createdAt': _dateTimeConverter.encode(item.createdAt) | ||||
|                 }); | ||||
|  | ||||
|   final sqflite.DatabaseExecutor database; | ||||
|  | ||||
|   final StreamController<String> changeListener; | ||||
|  | ||||
|   final QueryAdapter _queryAdapter; | ||||
|  | ||||
|   final InsertionAdapter<LocalEvent> _localEventInsertionAdapter; | ||||
|  | ||||
|   final UpdateAdapter<LocalEvent> _localEventUpdateAdapter; | ||||
|  | ||||
|   @override | ||||
|   Future<int?> countByChannel(int channelId) async { | ||||
|     return _queryAdapter.query( | ||||
|         'SELECT COUNT(id) FROM LocalEvent WHERE channelId = ?1', | ||||
|         mapper: (Map<String, Object?> row) => row.values.first as int, | ||||
|         arguments: [channelId]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<LocalEvent?> findById(int id) async { | ||||
|     return _queryAdapter.query('SELECT * FROM LocalEvent WHERE id = ?1', | ||||
|         mapper: (Map<String, Object?> row) => LocalEvent( | ||||
|             row['id'] as int, | ||||
|             _remoteEventConverter.decode(row['data'] as String), | ||||
|             row['channelId'] as int, | ||||
|             _dateTimeConverter.decode(row['createdAt'] as int)), | ||||
|         arguments: [id]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<List<LocalEvent>> findAllByChannel(int channelId) async { | ||||
|     return _queryAdapter.queryList( | ||||
|         'SELECT * FROM LocalEvent WHERE channelId = ?1 ORDER BY createdAt DESC', | ||||
|         mapper: (Map<String, Object?> row) => LocalEvent( | ||||
|             row['id'] as int, | ||||
|             _remoteEventConverter.decode(row['data'] as String), | ||||
|             row['channelId'] as int, | ||||
|             _dateTimeConverter.decode(row['createdAt'] as int)), | ||||
|         arguments: [channelId]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<LocalEvent?> findLastByChannel(int channelId) async { | ||||
|     return _queryAdapter.query( | ||||
|         'SELECT * FROM LocalEvent WHERE channelId = ?1 ORDER BY createdAt DESC LIMIT 1', | ||||
|         mapper: (Map<String, Object?> row) => LocalEvent(row['id'] as int, _remoteEventConverter.decode(row['data'] as String), row['channelId'] as int, _dateTimeConverter.decode(row['createdAt'] as int)), | ||||
|         arguments: [channelId]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<void> delete(int id) async { | ||||
|     await _queryAdapter | ||||
|         .queryNoReturn('DELETE FROM LocalEvent WHERE id = ?1', arguments: [id]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<List<LocalEvent>> deleteByChannel(int channelId) async { | ||||
|     return _queryAdapter.queryList( | ||||
|         'DELETE FROM LocalEvent WHERE channelId = ?1', | ||||
|         mapper: (Map<String, Object?> row) => LocalEvent( | ||||
|             row['id'] as int, | ||||
|             _remoteEventConverter.decode(row['data'] as String), | ||||
|             row['channelId'] as int, | ||||
|             _dateTimeConverter.decode(row['createdAt'] as int)), | ||||
|         arguments: [channelId]); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<void> wipeLocalEvents() async { | ||||
|     await _queryAdapter.queryNoReturn('DELETE FROM LocalEvent'); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<void> insert(LocalEvent m) async { | ||||
|     await _localEventInsertionAdapter.insert(m, OnConflictStrategy.replace); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<void> insertBulk(List<LocalEvent> m) async { | ||||
|     await _localEventInsertionAdapter.insertList(m, OnConflictStrategy.replace); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<void> update(LocalEvent m) async { | ||||
|     await _localEventUpdateAdapter.update(m, OnConflictStrategy.replace); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // ignore_for_file: unused_element | ||||
| final _dateTimeConverter = DateTimeConverter(); | ||||
| final _remoteEventConverter = RemoteEventConverter(); | ||||
| @@ -18,8 +18,8 @@ import 'package:solian/models/post.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/providers/content/posts.dart'; | ||||
| import 'package:solian/providers/daily_sign.dart'; | ||||
| import 'package:solian/providers/database/services/messages.dart'; | ||||
| import 'package:solian/providers/last_read.dart'; | ||||
| import 'package:solian/providers/message/adaptor.dart'; | ||||
| import 'package:solian/providers/websocket.dart'; | ||||
| import 'package:solian/router.dart'; | ||||
| import 'package:solian/screens/account/notification.dart'; | ||||
| @@ -72,7 +72,8 @@ class _DashboardScreenState extends State<DashboardScreen> { | ||||
|   Future<void> _pullMessages() async { | ||||
|     if (_lastRead.messagesLastReadAt == null) return; | ||||
|     log('[Dashboard] Pulling messages with pivot: ${_lastRead.messagesLastReadAt}'); | ||||
|     final out = await getWhatsNewEvents(_lastRead.messagesLastReadAt!); | ||||
|     final src = Get.find<MessagesFetchingProvider>(); | ||||
|     final out = await src.getWhatsNewEvents(_lastRead.messagesLastReadAt!); | ||||
|     if (out == null) return; | ||||
|     setState(() { | ||||
|       _currentMessages = out.$1; | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| import 'package:solian/controllers/chat_events_controller.dart'; | ||||
| import 'package:solian/exts.dart'; | ||||
| import 'package:solian/providers/theme_switcher.dart'; | ||||
| import 'package:solian/router.dart'; | ||||
| @@ -97,10 +96,7 @@ class _SettingScreenState extends State<SettingScreen> { | ||||
|             contentPadding: const EdgeInsets.symmetric(horizontal: 22), | ||||
|             title: Text('messageHistoryWipe'.tr), | ||||
|             onTap: () { | ||||
|               final chatHistory = ChatEventController(); | ||||
|               chatHistory.initialize().then((_) async { | ||||
|                 await chatHistory.database.localEvents.wipeLocalEvents(); | ||||
|               }); | ||||
|               // TODO Wipe message history | ||||
|             }, | ||||
|           ), | ||||
|         ], | ||||
|   | ||||
| @@ -105,7 +105,7 @@ class _ChannelListWidgetState extends State<ChannelListWidget> { | ||||
|     return FutureBuilder( | ||||
|       future: Future.delayed( | ||||
|         const Duration(milliseconds: 500), | ||||
|         () => _eventController.database.localEvents.findLastByChannel(item.id), | ||||
|         () => _eventController.src.getLastInChannel(item), | ||||
|       ), | ||||
|       builder: (context, snapshot) { | ||||
|         if (!snapshot.hasData && snapshot.data == null) { | ||||
| @@ -114,8 +114,9 @@ class _ChannelListWidgetState extends State<ChannelListWidget> { | ||||
|           )); | ||||
|         } | ||||
|  | ||||
|         final data = snapshot.data!.data!; | ||||
|         return Text( | ||||
|           '${snapshot.data!.data.sender.account.nick}: ${snapshot.data!.data.body['text'] ?? 'Unsupported message to preview'}', | ||||
|           '${data.sender.account.nick}: ${data.body['text'] ?? 'Unsupported message to preview'}', | ||||
|           maxLines: 1, | ||||
|           overflow: TextOverflow.ellipsis, | ||||
|         ); | ||||
|   | ||||
| @@ -97,7 +97,7 @@ class ChatEvent extends StatelessWidget { | ||||
|         return Container( | ||||
|           constraints: const BoxConstraints(maxWidth: 480), | ||||
|           child: ChatEvent( | ||||
|             item: snapshot.data!.data, | ||||
|             item: snapshot.data!.data!, | ||||
|             isMerged: false, | ||||
|             isQuote: true, | ||||
|           ), | ||||
|   | ||||
| @@ -62,7 +62,7 @@ class ChatEventList extends StatelessWidget { | ||||
|               return GestureDetector( | ||||
|                 behavior: HitTestBehavior.opaque, | ||||
|                 child: ChatEvent( | ||||
|                   key: Key('m${item.uuid}'), | ||||
|                   key: Key('m${item!.uuid}'), | ||||
|                   item: item, | ||||
|                   isMerged: isMerged, | ||||
|                   chatController: chatController, | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include <media_kit_libs_linux/media_kit_libs_linux_plugin.h> | ||||
| #include <media_kit_video/media_kit_video_plugin.h> | ||||
| #include <pasteboard/pasteboard_plugin.h> | ||||
| #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> | ||||
| #include <url_launcher_linux/url_launcher_plugin.h> | ||||
|  | ||||
| void fl_register_plugins(FlPluginRegistry* registry) { | ||||
| @@ -41,6 +42,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { | ||||
|   g_autoptr(FlPluginRegistrar) pasteboard_registrar = | ||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); | ||||
|   pasteboard_plugin_register_with_registrar(pasteboard_registrar); | ||||
|   g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = | ||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); | ||||
|   sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); | ||||
|   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = | ||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); | ||||
|   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); | ||||
|   | ||||
| @@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST | ||||
|   media_kit_libs_linux | ||||
|   media_kit_video | ||||
|   pasteboard | ||||
|   sqlite3_flutter_libs | ||||
|   url_launcher_linux | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,7 @@ import screen_brightness_macos | ||||
| import share_plus | ||||
| import shared_preferences_foundation | ||||
| import sqflite | ||||
| import sqlite3_flutter_libs | ||||
| import url_launcher_macos | ||||
| import wakelock_plus | ||||
|  | ||||
| @@ -55,6 +56,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | ||||
|   SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) | ||||
|   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) | ||||
|   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) | ||||
|   Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) | ||||
|   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) | ||||
|   WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) | ||||
| } | ||||
|   | ||||
							
								
								
									
										214
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -30,6 +30,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.7.0" | ||||
|   analyzer_plugin: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: analyzer_plugin | ||||
|       sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.11.3" | ||||
|   animations: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -162,10 +170,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: cached_network_image | ||||
|       sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" | ||||
|       sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.4.0" | ||||
|     version: "3.4.1" | ||||
|   cached_network_image_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -178,10 +186,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: cached_network_image_web | ||||
|       sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" | ||||
|       sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.0" | ||||
|     version: "1.3.1" | ||||
|   carousel_slider: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -298,10 +306,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: dart_style | ||||
|       sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" | ||||
|       sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.6" | ||||
|     version: "2.3.7" | ||||
|   dart_webrtc: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -326,14 +334,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.4.4" | ||||
|   dev_build: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: dev_build | ||||
|       sha256: f526d1fbe68875f6119ffc333f114dfe6aa93ad04439276d53968f7977cc410e | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.0+11" | ||||
|   device_info_plus: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -374,6 +374,30 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.2" | ||||
|   drift: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: drift | ||||
|       sha256: "5b561ec76fff260e1e0593a29ca0d058a140a4b4dfb11dcc0c3813820cd20200" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.20.2" | ||||
|   drift_dev: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: drift_dev | ||||
|       sha256: "3ee987578ca2281b5ff91eadd757cd6dd36001458d6e33784f990d67ff38f756" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.20.3" | ||||
|   drift_flutter: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: drift_flutter | ||||
|       sha256: c670c947fe17ad149678a43fdbbfdb69321f0c83d315043e34e8ad2729e11f49 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.2.0" | ||||
|   dropdown_button2: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -466,26 +490,26 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: firebase_analytics | ||||
|       sha256: "7e032ade38dec2a92f543ba02c5f72f54ffaa095c60d2132b867eab56de3bc73" | ||||
|       sha256: "7b5ae39d853ead76f9d030dc23389bfec4ea826d7cccb4eea4873dcb0cdd172b" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "11.3.0" | ||||
|     version: "11.3.1" | ||||
|   firebase_analytics_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: firebase_analytics_platform_interface | ||||
|       sha256: b62a2444767d95067a7e36b1d6e335e0b877968574bbbfb656168c46f2e95a13 | ||||
|       sha256: "0205e05bb37abd29d5dec5cd89aeb04f3f58bf849aad21dd938be0507d52a40c" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.2.2" | ||||
|     version: "4.2.3" | ||||
|   firebase_analytics_web: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: firebase_analytics_web | ||||
|       sha256: bad44f71f96cfca6c16c9dd4f70b85f123ddca7d5dd698977449fadf298b1782 | ||||
|       sha256: "434807f8b30526e21cc062410c28ee5c6680a13626c4443b5ffede29f84b0c74" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.5.9+2" | ||||
|     version: "0.5.10" | ||||
|   firebase_core: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -514,26 +538,26 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: firebase_crashlytics | ||||
|       sha256: "4c9872020c0d97a161362ee6af7000cfdb8666234ddc290a15252ad379bb235a" | ||||
|       sha256: c4fdbb14ba6f36794f89dc27fb5c759c9cc67ecbaeb079edc4dba515bbf9f555 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.1.0" | ||||
|     version: "4.1.1" | ||||
|   firebase_crashlytics_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: firebase_crashlytics_platform_interface | ||||
|       sha256: ede8a199ff03378857d3c8cbb7fa58d37c27bb5a6b75faf8415ff6925dcaae2a | ||||
|       sha256: "891d6f7ba4b93672d0e1265f27b6a9dccd56ba2cc30ce6496586b32d1d8770ac" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.6.41" | ||||
|     version: "3.6.42" | ||||
|   firebase_messaging: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: firebase_messaging | ||||
|       sha256: "29941ba5a3204d80656c0e52103369aa9a53edfd9ceae05a2bb3376f24fda453" | ||||
|       sha256: cc02c4afd6510cd84586020670140c4a23fbe52af16cd260ccf8ede101bb8d1b | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "15.1.0" | ||||
|     version: "15.1.1" | ||||
|   firebase_messaging_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -554,26 +578,26 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: firebase_performance | ||||
|       sha256: "66666f697ecdcca2616af99f8ccfa74d795e5819c598227f2784fc00b1c6e421" | ||||
|       sha256: "879ce4d83242cb7d1ec67a8b45daa351f230211778e34eeea979894839c4832a" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.10.0+5" | ||||
|     version: "0.10.0+6" | ||||
|   firebase_performance_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: firebase_performance_platform_interface | ||||
|       sha256: ceaa026d067347cc6ea11113ba926ae450f56e305c186d1edce78f05983b481a | ||||
|       sha256: ac68eba644f593903a931ba7f26f0677b725d5a60f8f7bc0fed01d88a11d1463 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.1.4+41" | ||||
|     version: "0.1.4+42" | ||||
|   firebase_performance_web: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: firebase_performance_web | ||||
|       sha256: "6d121cd7e27b63995998dc4039caf0cbf304c2eee6fc6ed9ac7f80860cc0e51c" | ||||
|       sha256: ff53b9c5d8601fc983d0173b88fdfd8abcc74948f0a3753f3c1ec276b680f23c | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.1.6+13" | ||||
|     version: "0.1.7" | ||||
|   fixnum: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -590,38 +614,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.69.0" | ||||
|   floor: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: floor | ||||
|       sha256: c1b06023912b5b8e49deb6a9d867863c535ae1a232d991c3582bba3ee8687867 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.5.0" | ||||
|   floor_annotation: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: floor_annotation | ||||
|       sha256: a40949580a7ab0eee572686e2d3b1638fd6bd6a753e661d792ab4236b365b23b | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.5.0" | ||||
|   floor_common: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: floor_common | ||||
|       sha256: "41c9914862f83a821815e1b1ffd47a1e1ae2130c35ff882ba2d000a67713ba64" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.5.0" | ||||
|   floor_generator: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: floor_generator | ||||
|       sha256: "1499b3ab878a807e6fbe6f140dc014124845cd1df3090a113aae5fa7577a1e77" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.5.0" | ||||
|   flutter: | ||||
|     dependency: "direct main" | ||||
|     description: flutter | ||||
| @@ -861,14 +853,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "10.7.0" | ||||
|   freezed: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: freezed | ||||
|       sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.5.7" | ||||
|   freezed_annotation: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -1157,14 +1141,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.0.0" | ||||
|   lists: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: lists | ||||
|       sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.1" | ||||
|   livekit_client: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -1473,10 +1449,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: permission_handler_platform_interface | ||||
|       sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea | ||||
|       sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.2.2" | ||||
|     version: "4.2.3" | ||||
|   permission_handler_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1557,14 +1533,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.5.1" | ||||
|   process_run: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: process_run | ||||
|       sha256: "112a77da35be50617ed9e2230df68d0817972f225e7f97ce8336f76b4e601606" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.2.0" | ||||
|   protobuf: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1645,6 +1613,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.0" | ||||
|   recase: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: recase | ||||
|       sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.1.0" | ||||
|   rxdart: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1851,7 +1827,7 @@ packages: | ||||
|     source: hosted | ||||
|     version: "7.0.0" | ||||
|   sqflite: | ||||
|     dependency: "direct main" | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: sqflite | ||||
|       sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d | ||||
| @@ -1866,22 +1842,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.5.4+2" | ||||
|   sqflite_common_ffi: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: sqflite_common_ffi | ||||
|       sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.3" | ||||
|   sqflite_common_ffi_web: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: sqflite_common_ffi_web | ||||
|       sha256: cfc9d1c61a3e06e5b2e96994a44b11125b4f451fee95b9fad8bd473b4613d592 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.4.3+1" | ||||
|   sqlite3: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1890,14 +1850,22 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.4.6" | ||||
|   sqlite3_flutter_libs: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: sqlite3_flutter_libs | ||||
|       sha256: "62bbb4073edbcdf53f40c80775f33eea01d301b7b81417e5b3fb7395416258c1" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.5.24" | ||||
|   sqlparser: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: sqlparser | ||||
|       sha256: "7b20045d1ccfb7bc1df7e8f9fee5ae58673fce6ff62cefbb0e0fd7214e90e5a0" | ||||
|       sha256: "852cf80f9e974ac8e1b613758a8aa640215f7701352b66a7f468e95711eb570b" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.34.1" | ||||
|     version: "0.38.1" | ||||
|   stack_trace: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1930,14 +1898,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.2.0" | ||||
|   strings: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: strings | ||||
|       sha256: "052836499f03897d3860a603b330c1ea3c8a14177b21f34b15a1295f36024aae" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.1.2" | ||||
|   synchronized: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1986,14 +1946,6 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.2" | ||||
|   unicode: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: unicode | ||||
|       sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.3.1" | ||||
|   universal_io: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -2122,6 +2074,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.1.4" | ||||
|   very_good_infinite_list: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: very_good_infinite_list | ||||
|       sha256: "03445e302f9e0878b6b429c096825463e0990dd38fa69a3c5c74c646afd0e485" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.8.0" | ||||
|   vm_service: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -2206,10 +2166,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: win32_registry | ||||
|       sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6" | ||||
|       sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.4" | ||||
|     version: "1.1.5" | ||||
|   xdg_directories: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
							
								
								
									
										10
									
								
								pubspec.yaml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								pubspec.yaml
									
									
									
									
									
								
							| @@ -40,8 +40,6 @@ dependencies: | ||||
|   package_info_plus: ^8.0.0 | ||||
|   device_info_plus: ^10.1.0 | ||||
|   flutter_acrylic: ^1.1.4 | ||||
|   floor: ^1.5.0 | ||||
|   sqflite: ^2.3.3+1 | ||||
|   protocol_handler: ^0.2.0 | ||||
|   markdown: ^7.2.2 | ||||
|   pasteboard: ^0.3.0 | ||||
| @@ -77,6 +75,9 @@ dependencies: | ||||
|   media_kit: ^1.1.11 | ||||
|   media_kit_video: ^1.2.5 | ||||
|   media_kit_libs_video: ^1.0.5 | ||||
|   drift: ^2.20.2 | ||||
|   drift_flutter: ^0.2.0 | ||||
|   very_good_infinite_list: ^0.8.0 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
| @@ -85,13 +86,10 @@ dev_dependencies: | ||||
|   flutter_lints: ^4.0.0 | ||||
|   flutter_launcher_icons: ^0.13.1 | ||||
|  | ||||
|   floor_generator: ^1.4.0 | ||||
|   build_runner: ^2.4.12 | ||||
|   sqflite_common_ffi: ^2.3.3 | ||||
|   sqflite_common_ffi_web: ^0.4.3+1 | ||||
|   flutter_native_splash: ^2.4.1 | ||||
|   freezed: ^2.5.7 | ||||
|   json_serializable: ^6.8.0 | ||||
|   drift_dev: ^2.20.3 | ||||
|  | ||||
| flutter: | ||||
|   uses-material-design: true | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
| #include <protocol_handler_windows/protocol_handler_windows_plugin_c_api.h> | ||||
| #include <screen_brightness_windows/screen_brightness_windows_plugin.h> | ||||
| #include <share_plus/share_plus_windows_plugin_c_api.h> | ||||
| #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> | ||||
| #include <url_launcher_windows/url_launcher_windows.h> | ||||
|  | ||||
| void RegisterPlugins(flutter::PluginRegistry* registry) { | ||||
| @@ -57,6 +58,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { | ||||
|       registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); | ||||
|   SharePlusWindowsPluginCApiRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); | ||||
|   Sqlite3FlutterLibsPluginRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); | ||||
|   UrlLauncherWindowsRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("UrlLauncherWindows")); | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,7 @@ list(APPEND FLUTTER_PLUGIN_LIST | ||||
|   protocol_handler_windows | ||||
|   screen_brightness_windows | ||||
|   share_plus | ||||
|   sqlite3_flutter_libs | ||||
|   url_launcher_windows | ||||
| ) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user