From b14e55355f7cc4868dd2a668b7f600b7e1399680 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 14 Sep 2024 00:30:33 +0800 Subject: [PATCH] :recycle: Use drift instead for floor --- ios/Podfile.lock | 40 +- lib/controllers/chat_events_controller.dart | 99 ++-- lib/main.dart | 4 + lib/providers/auth.dart | 6 - lib/providers/database/database.dart | 24 + lib/providers/database/database.g.dart | 429 ++++++++++++++++++ lib/providers/database/services/messages.dart | 202 +++++++++ lib/providers/database/tables/json.dart | 13 + lib/providers/database/tables/messages.dart | 22 + lib/providers/message/adaptor.dart | 173 ------- lib/providers/message/events.dart | 83 ---- lib/providers/message/events.g.dart | 228 ---------- lib/screens/dashboard.dart | 5 +- lib/screens/settings.dart | 6 +- lib/widgets/channel/channel_list.dart | 5 +- lib/widgets/chat/chat_event.dart | 2 +- lib/widgets/chat/chat_event_list.dart | 2 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 214 ++++----- pubspec.yaml | 10 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 24 files changed, 886 insertions(+), 692 deletions(-) create mode 100644 lib/providers/database/database.dart create mode 100644 lib/providers/database/database.g.dart create mode 100644 lib/providers/database/services/messages.dart create mode 100644 lib/providers/database/tables/json.dart create mode 100644 lib/providers/database/tables/messages.dart delete mode 100644 lib/providers/message/adaptor.dart delete mode 100644 lib/providers/message/events.dart delete mode 100644 lib/providers/message/events.g.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index af7871b..ac02cac 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -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 diff --git a/lib/controllers/chat_events_controller.dart b/lib/controllers/chat_events_controller.dart index 60f52ef..6405183 100644 --- a/lib/controllers/chat_events_controller.dart +++ b/lib/controllers/chat_events_controller.dart @@ -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 currentEvents = RxList.empty(growable: true); + final RxList currentEvents = + RxList.empty(growable: true); final RxInt totalEvents = 0.obs; final RxBool isLoading = false.obs; @@ -17,27 +18,13 @@ class ChatEventController { String? scope; Future initialize() async { - if (!PlatformInfo.isWeb) { - database = await createHistoryDb(); - } + src = Get.find(); currentEvents.clear(); } - Future getEvent(int id) async { + Future 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 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 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 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 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, ), ); } diff --git a/lib/main.dart b/lib/main.dart index 9263d4c..5bbfb0b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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()); diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index e1541de..840ce67 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -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().notifications.clear(); Get.find().notificationUnread.value = 0; - final chatHistory = ChatEventController(); - chatHistory.initialize().then((_) async { - await chatHistory.database.localEvents.wipeLocalEvents(); - }); - storage.deleteAll(); } diff --git a/lib/providers/database/database.dart b/lib/providers/database/database.dart new file mode 100644 index 0000000..3ee3795 --- /dev/null +++ b/lib/providers/database/database.dart @@ -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(); +} diff --git a/lib/providers/database/database.g.dart b/lib/providers/database/database.g.dart new file mode 100644 index 0000000..9b4c0db --- /dev/null +++ b/lib/providers/database/database.g.dart @@ -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 id = GeneratedColumn( + '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 channelId = GeneratedColumn( + 'channel_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumnWithTypeConverter data = + GeneratedColumn('data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter($LocalMessageEventTableTable.$converterdata); + static const VerificationMeta _createdAtMeta = + const VerificationMeta('createdAt'); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: Constant(DateTime.now())); + @override + List 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 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 get $primaryKey => {id}; + @override + LocalMessageEventTableData map(Map 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 $converterdata = + const MessageEventConverter(); +} + +class LocalMessageEventTableData extends DataClass + implements Insertable { + 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 toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['channel_id'] = Variable(channelId); + if (!nullToAbsent || data != null) { + map['data'] = Variable( + $LocalMessageEventTableTable.$converterdata.toSql(data)); + } + map['created_at'] = Variable(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 json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalMessageEventTableData( + id: serializer.fromJson(json['id']), + channelId: serializer.fromJson(json['channelId']), + data: serializer.fromJson(json['data']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'channelId': serializer.toJson(channelId), + 'data': serializer.toJson(data), + 'createdAt': serializer.toJson(createdAt), + }; + } + + LocalMessageEventTableData copyWith( + {int? id, + int? channelId, + Value 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 { + final Value id; + final Value channelId; + final Value data; + final Value 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 custom({ + Expression? id, + Expression? channelId, + Expression? data, + Expression? 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? id, + Value? channelId, + Value? data, + Value? createdAt}) { + return LocalMessageEventTableCompanion( + id: id ?? this.id, + channelId: channelId ?? this.channelId, + data: data ?? this.data, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (channelId.present) { + map['channel_id'] = Variable(channelId.value); + } + if (data.present) { + map['data'] = Variable( + $LocalMessageEventTableTable.$converterdata.toSql(data.value)); + } + if (createdAt.present) { + map['created_at'] = Variable(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> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [localMessageEventTable]; +} + +typedef $$LocalMessageEventTableTableCreateCompanionBuilder + = LocalMessageEventTableCompanion Function({ + Value id, + required int channelId, + required Event? data, + Value createdAt, +}); +typedef $$LocalMessageEventTableTableUpdateCompanionBuilder + = LocalMessageEventTableCompanion Function({ + Value id, + Value channelId, + Value data, + Value createdAt, +}); + +class $$LocalMessageEventTableTableFilterComposer + extends FilterComposer<_$AppDatabase, $LocalMessageEventTableTable> { + $$LocalMessageEventTableTableFilterComposer(super.$state); + ColumnFilters get id => $state.composableBuilder( + column: $state.table.id, + builder: (column, joinBuilders) => + ColumnFilters(column, joinBuilders: joinBuilders)); + + ColumnFilters get channelId => $state.composableBuilder( + column: $state.table.channelId, + builder: (column, joinBuilders) => + ColumnFilters(column, joinBuilders: joinBuilders)); + + ColumnWithTypeConverterFilters get data => + $state.composableBuilder( + column: $state.table.data, + builder: (column, joinBuilders) => ColumnWithTypeConverterFilters( + column, + joinBuilders: joinBuilders)); + + ColumnFilters 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 get id => $state.composableBuilder( + column: $state.table.id, + builder: (column, joinBuilders) => + ColumnOrderings(column, joinBuilders: joinBuilders)); + + ColumnOrderings get channelId => $state.composableBuilder( + column: $state.table.channelId, + builder: (column, joinBuilders) => + ColumnOrderings(column, joinBuilders: joinBuilders)); + + ColumnOrderings get data => $state.composableBuilder( + column: $state.table.data, + builder: (column, joinBuilders) => + ColumnOrderings(column, joinBuilders: joinBuilders)); + + ColumnOrderings 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 id = const Value.absent(), + Value channelId = const Value.absent(), + Value data = const Value.absent(), + Value createdAt = const Value.absent(), + }) => + LocalMessageEventTableCompanion( + id: id, + channelId: channelId, + data: data, + createdAt: createdAt, + ), + createCompanionCallback: ({ + Value id = const Value.absent(), + required int channelId, + required Event? data, + Value 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); +} diff --git a/lib/providers/database/services/messages.dart b/lib/providers/database/services/messages.dart new file mode 100644 index 0000000..f814a49 --- /dev/null +++ b/lib/providers/database/services/messages.dart @@ -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, 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 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, int)?> fetchRemoteEvents( + Channel channel, + String scope, { + required int remainDepth, + bool Function(List 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 receiveEvent(Event remote) async { + // Insert record + final database = Get.find().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 getEvent(int id, Channel channel, + {String scope = 'global'}) async { + final database = Get.find().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, int)?> pullRemoteEvents(Channel channel, + {String scope = 'global', depth = 10, offset = 0}) async { + final database = Get.find().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> listEvents(Channel channel) async { + final database = Get.find().database; + return await (database.select(database.localMessageEventTable) + ..where((x) => x.channelId.equals(channel.id)) + ..orderBy([(t) => OrderingTerm.desc(t.id)])) + .get(); + } + + Future getLastInChannel(Channel channel) async { + final database = Get.find().database; + return await (database.select(database.localMessageEventTable) + ..where((x) => x.channelId.equals(channel.id)) + ..orderBy([(t) => OrderingTerm.desc(t.id)])) + .getSingleOrNull(); + } +} diff --git a/lib/providers/database/tables/json.dart b/lib/providers/database/tables/json.dart new file mode 100644 index 0000000..f7f4e24 --- /dev/null +++ b/lib/providers/database/tables/json.dart @@ -0,0 +1,13 @@ +import 'dart:convert'; + +import 'package:drift/drift.dart'; + +class JsonConverter extends TypeConverter { + const JsonConverter(); + + @override + Object? fromSql(String fromDb) => jsonDecode(fromDb); + + @override + String toSql(Object? value) => jsonEncode(value); +} diff --git a/lib/providers/database/tables/messages.dart b/lib/providers/database/tables/messages.dart new file mode 100644 index 0000000..bccb2a3 --- /dev/null +++ b/lib/providers/database/tables/messages.dart @@ -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 { + const MessageEventConverter(); + + @override + Event? fromSql(String fromDb) => Event.fromJson(jsonDecode(fromDb)); + + @override + String toSql(Event? value) => jsonEncode(value?.toJson()); +} diff --git a/lib/providers/message/adaptor.dart b/lib/providers/message/adaptor.dart deleted file mode 100644 index 9a0874d..0000000 --- a/lib/providers/message/adaptor.dart +++ /dev/null @@ -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 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, 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 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, int)?> getRemoteEvents( - Channel channel, - String scope, { - required int remainDepth, - bool Function(List 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 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 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, 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> listEvents(Channel channel) async { - return await localEvents.findAllByChannel(channel.id); - } -} diff --git a/lib/providers/message/events.dart b/lib/providers/message/events.dart deleted file mode 100644 index fb7928e..0000000 --- a/lib/providers/message/events.dart +++ /dev/null @@ -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 { - @override - DateTime decode(int databaseValue) { - return DateTime.fromMillisecondsSinceEpoch(databaseValue); - } - - @override - int encode(DateTime value) { - return value.millisecondsSinceEpoch; - } -} - -class RemoteEventConverter extends TypeConverter { - @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 countByChannel(int channelId); - - @Query('SELECT * FROM LocalEvent WHERE id = :id') - Future findById(int id); - - @Query('SELECT * FROM LocalEvent WHERE channelId = :channelId ORDER BY createdAt DESC') - Future> findAllByChannel(int channelId); - - @Query('SELECT * FROM LocalEvent WHERE channelId = :channelId ORDER BY createdAt DESC LIMIT 1') - Future findLastByChannel(int channelId); - - @Insert(onConflict: OnConflictStrategy.replace) - Future insert(LocalEvent m); - - @Insert(onConflict: OnConflictStrategy.replace) - Future insertBulk(List m); - - @Update(onConflict: OnConflictStrategy.replace) - Future update(LocalEvent m); - - @Query('DELETE FROM LocalEvent WHERE id = :id') - Future delete(int id); - - @Query('DELETE FROM LocalEvent WHERE channelId = :channelId') - Future> deleteByChannel(int channelId); - - @Query('DELETE FROM LocalEvent') - Future wipeLocalEvents(); -} - -@TypeConverters([DateTimeConverter, RemoteEventConverter]) -@Database(version: 2, entities: [LocalEvent]) -abstract class MessageHistoryDb extends FloorDatabase { - LocalEventDao get localEvents; -} diff --git a/lib/providers/message/events.g.dart b/lib/providers/message/events.g.dart deleted file mode 100644 index 09b2b9d..0000000 --- a/lib/providers/message/events.g.dart +++ /dev/null @@ -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 migrations); - - /// Adds a database [Callback] to the builder. - $MessageHistoryDbBuilderContract addCallback(Callback callback); - - /// Creates the database and initializes it. - Future 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 _migrations = []; - - Callback? _callback; - - @override - $MessageHistoryDbBuilderContract addMigrations(List migrations) { - _migrations.addAll(migrations); - return this; - } - - @override - $MessageHistoryDbBuilderContract addCallback(Callback callback) { - _callback = callback; - return this; - } - - @override - Future 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? listener]) { - changeListener = listener ?? StreamController.broadcast(); - } - - LocalEventDao? _localEventsInstance; - - Future open( - String path, - List 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) => { - 'id': item.id, - 'data': _remoteEventConverter.encode(item.data), - 'channelId': item.channelId, - 'createdAt': _dateTimeConverter.encode(item.createdAt) - }), - _localEventUpdateAdapter = UpdateAdapter( - database, - 'LocalEvent', - ['id'], - (LocalEvent item) => { - 'id': item.id, - 'data': _remoteEventConverter.encode(item.data), - 'channelId': item.channelId, - 'createdAt': _dateTimeConverter.encode(item.createdAt) - }); - - final sqflite.DatabaseExecutor database; - - final StreamController changeListener; - - final QueryAdapter _queryAdapter; - - final InsertionAdapter _localEventInsertionAdapter; - - final UpdateAdapter _localEventUpdateAdapter; - - @override - Future countByChannel(int channelId) async { - return _queryAdapter.query( - 'SELECT COUNT(id) FROM LocalEvent WHERE channelId = ?1', - mapper: (Map row) => row.values.first as int, - arguments: [channelId]); - } - - @override - Future findById(int id) async { - return _queryAdapter.query('SELECT * FROM LocalEvent WHERE id = ?1', - mapper: (Map 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> findAllByChannel(int channelId) async { - return _queryAdapter.queryList( - 'SELECT * FROM LocalEvent WHERE channelId = ?1 ORDER BY createdAt DESC', - mapper: (Map 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 findLastByChannel(int channelId) async { - return _queryAdapter.query( - 'SELECT * FROM LocalEvent WHERE channelId = ?1 ORDER BY createdAt DESC LIMIT 1', - mapper: (Map 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 delete(int id) async { - await _queryAdapter - .queryNoReturn('DELETE FROM LocalEvent WHERE id = ?1', arguments: [id]); - } - - @override - Future> deleteByChannel(int channelId) async { - return _queryAdapter.queryList( - 'DELETE FROM LocalEvent WHERE channelId = ?1', - mapper: (Map 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 wipeLocalEvents() async { - await _queryAdapter.queryNoReturn('DELETE FROM LocalEvent'); - } - - @override - Future insert(LocalEvent m) async { - await _localEventInsertionAdapter.insert(m, OnConflictStrategy.replace); - } - - @override - Future insertBulk(List m) async { - await _localEventInsertionAdapter.insertList(m, OnConflictStrategy.replace); - } - - @override - Future update(LocalEvent m) async { - await _localEventUpdateAdapter.update(m, OnConflictStrategy.replace); - } -} - -// ignore_for_file: unused_element -final _dateTimeConverter = DateTimeConverter(); -final _remoteEventConverter = RemoteEventConverter(); diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index 6be76c5..8c755e8 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -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 { Future _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(); + final out = await src.getWhatsNewEvents(_lastRead.messagesLastReadAt!); if (out == null) return; setState(() { _currentMessages = out.$1; diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index d60707c..4621c21 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -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 { 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 }, ), ], diff --git a/lib/widgets/channel/channel_list.dart b/lib/widgets/channel/channel_list.dart index 785da91..de2f405 100644 --- a/lib/widgets/channel/channel_list.dart +++ b/lib/widgets/channel/channel_list.dart @@ -105,7 +105,7 @@ class _ChannelListWidgetState extends State { 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 { )); } + 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, ); diff --git a/lib/widgets/chat/chat_event.dart b/lib/widgets/chat/chat_event.dart index ba7d575..00f4945 100644 --- a/lib/widgets/chat/chat_event.dart +++ b/lib/widgets/chat/chat_event.dart @@ -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, ), diff --git a/lib/widgets/chat/chat_event_list.dart b/lib/widgets/chat/chat_event_list.dart index 9fe8d99..4905275 100644 --- a/lib/widgets/chat/chat_event_list.dart +++ b/lib/widgets/chat/chat_event_list.dart @@ -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, diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 63960ac..fca9c2f 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include 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); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 5705c88..885d4ce 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST media_kit_libs_linux media_kit_video pasteboard + sqlite3_flutter_libs url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 34686c2..573eb29 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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")) } diff --git a/pubspec.lock b/pubspec.lock index 9e03ac5..8ee01ff 100644 --- a/pubspec.lock +++ b/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: diff --git a/pubspec.yaml b/pubspec.yaml index 536d44a..6202d52 100644 --- a/pubspec.yaml +++ b/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 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index a0fca33..f3f9893 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include 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")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b666aba..f09bc38 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -19,6 +19,7 @@ list(APPEND FLUTTER_PLUGIN_LIST protocol_handler_windows screen_brightness_windows share_plus + sqlite3_flutter_libs url_launcher_windows )