diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 72f9bd20..078d6f72 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Dependencies diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index befd40c8..8b75233a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Configure Flutter @@ -48,7 +48,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Java @@ -82,7 +82,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Java @@ -117,7 +117,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools @@ -146,7 +146,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 5c545163..82d5696c 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -22,7 +22,7 @@ jobs: - name: Setup Flutter ╰(✿˙ᗜ˙)੭━☆゚.*・。゚ uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools ᕙ|” ◉ ◡ ◉ ”|ᕗ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4f27cec..64d5844e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Clone Olm @@ -81,7 +81,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Java @@ -131,7 +131,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Java @@ -182,7 +182,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools @@ -232,7 +232,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools @@ -286,7 +286,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools @@ -331,7 +331,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f1eb4b11..45d08923 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Flutter ╰(✿˙ᗜ˙)੭━☆゚.*・。゚ uses: subosito/flutter-action@v2.8.0 with: - flutter-version: '3.19.5' + flutter-version: '3.22.1' channel: 'stable' - name: Setup Tools ᕙ|” ◉ ◡ ◉ ”|ᕗ diff --git a/README.md b/README.md index f2a70b2e..c6a15258 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Help translate Commet to your language on [Weblate](https://hosted.weblate.org/p # Development -Commet is built using [Flutter](https://flutter.dev), currently v3.19.5 +Commet is built using [Flutter](https://flutter.dev), currently v3.22.1 This repo currently has a monorepo structure, containing two flutter projects: Commet and Tiamat. Commet is the main client, and Tiamat is a sort of wrapper around Material with some extra goodies, which is used to maintain a consistent style across the app. Tiamat may eventually be moved to its own repo, but for now it is maintained here for ease of development. ## Building diff --git a/commet/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java b/commet/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java deleted file mode 100644 index 752fc185..00000000 --- a/commet/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java +++ /dev/null @@ -1,25 +0,0 @@ -// Generated file. -// -// If you wish to remove Flutter's multidex support, delete this entire file. -// -// Modifications to this file should be done in a copy under a different name -// as this file may be regenerated. - -package io.flutter.app; - -import android.app.Application; -import android.content.Context; -import androidx.annotation.CallSuper; -import androidx.multidex.MultiDex; - -/** - * Extension of {@link android.app.Application}, adding multidex support. - */ -public class FlutterMultiDexApplication extends Application { - @Override - @CallSuper - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - MultiDex.install(this); - } -} diff --git a/commet/android/app/src/main/kotlin/chat/commet/commet/MainActivity.kt b/commet/android/app/src/main/kotlin/chat/commet/commet/MainActivity.kt index 7d806e7f..1eef7878 100644 --- a/commet/android/app/src/main/kotlin/chat/commet/commet/MainActivity.kt +++ b/commet/android/app/src/main/kotlin/chat/commet/commet/MainActivity.kt @@ -6,12 +6,10 @@ import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugins.GeneratedPluginRegistrant import android.content.Context -import androidx.multidex.MultiDex class MainActivity: FlutterActivity() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) - MultiDex.install(this) } override fun provideFlutterEngine(context: Context): FlutterEngine? { diff --git a/commet/integration_test/extensions/common_flows.dart b/commet/integration_test/extensions/common_flows.dart index 5f4c5a5e..3da311bf 100644 --- a/commet/integration_test/extensions/common_flows.dart +++ b/commet/integration_test/extensions/common_flows.dart @@ -1,13 +1,11 @@ import 'dart:io'; -import 'package:commet/client/matrix/matrix_client.dart'; import 'package:commet/config/app_config.dart'; import 'package:commet/ui/organisms/side_navigation_bar.dart'; import 'package:commet/ui/pages/login/login_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:commet/main.dart'; -import 'package:matrix/encryption/utils/key_verification.dart'; import 'package:matrix/matrix.dart'; import 'package:path_provider/path_provider.dart'; @@ -112,29 +110,30 @@ extension CommonFlows on WidgetTester { } Future createTestClient() async { - var otherClient = Client( - "Commet Integration Tester", - verificationMethods: { - KeyVerificationMethod.emoji, - KeyVerificationMethod.numbers - }, - nativeImplementations: MatrixClient.nativeImplementations, - logLevel: Level.verbose, - databaseBuilder: (client) async { - final db = HiveCollectionsDatabase( - client.clientName, await AppConfig.getDatabasePath()); - await db.open(); - return db; - }, - ); - - await otherClient.checkHomeserver(Uri.http(homeserver)); - - await otherClient.login(LoginType.mLoginPassword, - identifier: AuthenticationUserIdentifier(user: username), - password: password); - - return otherClient; + throw UnimplementedError(); + // var otherClient = Client( + // "Commet Integration Tester", + // verificationMethods: { + // KeyVerificationMethod.emoji, + // KeyVerificationMethod.numbers + // }, + // nativeImplementations: MatrixClient.nativeImplementations, + // logLevel: Level.verbose, + // databaseBuilder: (client) async { + // final db = HiveCollectionsDatabase( + // client.clientName, await AppConfig.getDatabasePath()); + // await db.open(); + // return db; + // }, + // ); + + // await otherClient.checkHomeserver(Uri.http(homeserver)); + + // await otherClient.login(LoginType.mLoginPassword, + // identifier: AuthenticationUserIdentifier(user: username), + // password: password); + + // return otherClient; } Future openSettings(App app) async { diff --git a/commet/lib/cache/cached_file.dart b/commet/lib/cache/cached_file.dart deleted file mode 100644 index 4600248c..00000000 --- a/commet/lib/cache/cached_file.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:isar/isar.dart'; - -part 'cached_file.g.dart'; - -@collection -class CachedFile { - CachedFile(this.filePath, this.fileId, this.lastAccessedTimestamp); - - Id id = Isar.autoIncrement; - - String fileId; - - String filePath; - - int lastAccessedTimestamp; -} diff --git a/commet/lib/cache/drift_file_cache.dart b/commet/lib/cache/drift_file_cache.dart new file mode 100644 index 00000000..12715bd0 --- /dev/null +++ b/commet/lib/cache/drift_file_cache.dart @@ -0,0 +1,226 @@ +import 'dart:io'; +import 'dart:isolate'; +import 'dart:ui'; + +import 'package:commet/cache/file_cache.dart'; +import 'package:commet/config/app_config.dart'; +import 'package:commet/config/build_config.dart'; +import 'package:commet/debug/log.dart'; +import 'package:commet/utils/rng.dart'; +import 'package:drift/drift.dart'; +import 'package:drift/isolate.dart'; +import 'package:drift/native.dart'; +import 'package:flutter/services.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; + +part 'drift_file_cache.g.dart'; + +FileCache? getFileCacheImplementation() { + return DriftFileCache(); +} + +class FileCacheEntry extends Table { + TextColumn get id => text()(); + TextColumn get path => text()(); + + IntColumn get lastAccessedTimestamp => integer()(); + + @override + Set get primaryKey => {id}; +} + +@DriftDatabase(tables: [FileCacheEntry]) +class DriftFileCacheDatabase extends _$DriftFileCacheDatabase { + DriftFileCacheDatabase(super.e); + + @override + int get schemaVersion => 1; +} + +class DriftFileCache implements FileCache { + bool isInit = false; + late DriftFileCacheDatabase db; + + static final String isolateName = "chat.commet.commetapp.isolate.file_cache"; + + @override + Future clean() async { + Log.i("Cleaning files"); + + var now = DateTime.now(); + var cutoffTime = now.subtract(const Duration(days: 5)); + var timeMs = cutoffTime.millisecondsSinceEpoch; + + var removeFiles = await (db.select(db.fileCacheEntry) + ..where( + (tbl) => tbl.lastAccessedTimestamp.isSmallerThanValue(timeMs))) + .get(); + + var allFiles = await (db.select(db.fileCacheEntry).get()); + + Log.i("Found: ${removeFiles.length}/${allFiles.length} files for cleaning"); + + for (var file in removeFiles) { + _cleanFile(file); + } + + var removedIds = removeFiles.map((e) => e.id).toList(); + await (db.delete(db.fileCacheEntry) + ..where((tbl) => tbl.id.isIn(removedIds))) + .go(); + } + + Future _cleanFile(FileCacheEntryData entry) async { + var file = File(entry.path); + if (!await file.exists()) { + return; + } + + file.delete(); + } + + @override + Future close() { + return db.close(); + } + + @override + Future fetchFile( + String identifier, Future Function() getter) async { + var existing = await getFile(identifier); + if (existing != null) return existing; + + var bytes = await getter(); + var path = await generateTempFilePath(); + if (BuildConfig.DEBUG) path += "_${Uri.encodeComponent(identifier)}"; + + var file = File(path); + await file.create(recursive: true); + await file.writeAsBytes(bytes); + + var entry = FileCacheEntryCompanion.insert( + id: identifier, + path: path, + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch); + + await db.into(db.fileCacheEntry).insertOnConflictUpdate(entry); + + return file.uri; + } + + @override + Future getFile(String identifier) async { + if (!await hasFile(identifier)) return null; + + var entry = await _getByFileId(identifier); + if (entry == null) return null; + //var lastAccess = DateTime.fromMillisecondsSinceEpoch(entry!.lastAccessedTimestamp).toLocal().toString(); + + db.into(db.fileCacheEntry).insertOnConflictUpdate(entry.copyWith( + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch)); + + var file = File(entry.path); + + return file.uri; + } + + @override + Future hasFile(String identifier) async { + var file = await _getByFileId(identifier); + if (file == null) return false; + + // if the file exists in the database but not on disk, we should remove it from db + var exists = await File(file.path).exists(); + if (!exists) + (db.delete(db.fileCacheEntry)..where((tbl) => tbl.id.equals(file.id))) + .go(); + + return exists; + } + + @override + Future init() async { + if (isInit) { + return; + } + + isInit = true; + + var port = IsolateNameServer.lookupPortByName(DriftFileCache.isolateName); + + var isolate = DriftIsolate.fromConnectPort( + port ?? (await createIsolate()).connectPort); + + db = DriftFileCacheDatabase(await isolate.connect()); + clean(); + } + + Future createIsolate() async { + final token = RootIsolateToken.instance!; + var isolate = await DriftIsolate.spawn(() { + BackgroundIsolateBinaryMessenger.ensureInitialized(token); + + return LazyDatabase(() async { + final dir = p.join(await AppConfig.getDatabasePath(), "app"); + var directory = Directory(dir); + if (!await directory.exists()) { + await directory.create(recursive: true); + } + + final file = File(p.join(dir, "app_data.db")); + return NativeDatabase(file); + }); + }, isolateSpawn: DriftFileCache._spawn); + + IsolateNameServer.registerPortWithName( + isolate.connectPort, DriftFileCache.isolateName); + + return isolate; + } + + static Future _spawn( + void Function(T message) entryPoint, T message) { + return Isolate.spawn(entryPoint, message, debugName: "File Cache Isolate"); + } + + @override + Future putFile(String identifier, Uint8List bytes) async { + var path = await generateTempFilePath(); + if (BuildConfig.DEBUG) path += "_${Uri.encodeComponent(identifier)}"; + var file = File(path); + await file.create(recursive: true); + await file.writeAsBytes(bytes); + + var entry = FileCacheEntryCompanion.insert( + id: identifier, + path: path, + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch); + + await db.into(db.fileCacheEntry).insertOnConflictUpdate(entry); + + return file.uri; + } + + Future newPath() async { + final dir = await getTemporaryDirectory(); + String fileName = RandomUtils.getRandomString(30); + return p.join(dir.path, "chat.commet.app", "file_cache", fileName); + } + + Future generateTempFilePath() async { + var path = ""; + for (path = await newPath(); + await File(path).exists(); + path = await newPath()) {} + + return path; + } + + Future _getByFileId(String fileId) async { + return (db.select(db.fileCacheEntry) + ..where((tbl) => tbl.id.equals(fileId)) + ..limit(1)) + .getSingleOrNull(); + } +} diff --git a/commet/lib/cache/file_cache.dart b/commet/lib/cache/file_cache.dart index d25b11d7..980fbdc4 100644 --- a/commet/lib/cache/file_cache.dart +++ b/commet/lib/cache/file_cache.dart @@ -1,5 +1,5 @@ import 'file_cache_stub.dart' - if (dart.library.io) "package:commet/cache/isar_file_cache.dart"; + if (dart.library.io) "package:commet/cache/drift_file_cache.dart"; import 'package:flutter/foundation.dart'; diff --git a/commet/lib/cache/isar_file_cache.dart b/commet/lib/cache/isar_file_cache.dart deleted file mode 100644 index e75b3994..00000000 --- a/commet/lib/cache/isar_file_cache.dart +++ /dev/null @@ -1,189 +0,0 @@ -import 'dart:io'; - -import 'package:commet/cache/cached_file.dart'; -import 'package:commet/cache/file_cache.dart'; -import 'package:commet/config/app_config.dart'; -import 'package:commet/config/build_config.dart'; -import 'package:commet/debug/log.dart'; -import 'package:commet/utils/rng.dart'; -import 'package:flutter/foundation.dart'; -import 'package:isar/isar.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as p; - -FileCache? getFileCacheImplementation() { - return IsarFileCache(); -} - -class IsarFileCache implements FileCache { - Isar? db; - IsarCollection? files; - - bool isInit = false; - - Future newPath() async { - final dir = await getTemporaryDirectory(); - String fileName = RandomUtils.getRandomString(30); - return p.join(dir.path, "chat.commet.app", "file_cache", fileName); - } - - Future generateTempFilePath() async { - var path = ""; - for (path = await newPath(); - await File(path).exists(); - path = await newPath()) {} - - return path; - } - - @override - Future init() async { - if (isInit) { - return; - } - - isInit = true; - - final dir = p.join(await AppConfig.getDatabasePath(), "cache"); - var directory = Directory(dir); - if (!await directory.exists()) { - await directory.create(recursive: true); - } - - db = - await Isar.open([CachedFileSchema], directory: dir, name: "file_cache"); - - files = db!.collection(); - clean(); - } - - @override - Future close() async { - await db!.close(); - } - - Future _getByFileId(String fileId) async { - return await files!.filter().fileIdEqualTo(fileId).findFirst(); - } - - @override - Future hasFile(String identifier) async { - var file = await _getByFileId(identifier); - if (file == null) return false; - - // if the file exists in the database but not on disk, we should remove it from db - var exists = await File(file.filePath).exists(); - if (!exists) - await db!.writeTxn(() async { - files!.delete(file.id); - }); - - return exists; - } - - @override - Future getFile(String identifier) async { - if (!await hasFile(identifier)) return null; - - var entry = await _getByFileId(identifier); - if (entry == null) return null; - //var lastAccess = DateTime.fromMillisecondsSinceEpoch(entry!.lastAccessedTimestamp).toLocal().toString(); - - entry.lastAccessedTimestamp = DateTime.now().millisecondsSinceEpoch; - - db!.writeTxn(() async { - await files!.put(entry); - }); - - var file = File(entry.filePath); - - return file.uri; - } - - @override - Future putFile(String identifier, Uint8List bytes) async { - var path = await generateTempFilePath(); - if (BuildConfig.DEBUG) path += "_${Uri.encodeComponent(identifier)}"; - var file = File(path); - await file.create(recursive: true); - await file.writeAsBytes(bytes); - - CachedFile entry = CachedFile( - file.path, identifier, DateTime.now().millisecondsSinceEpoch); - - db!.writeTxn(() async { - await files!.put(entry); - }); - - return file.uri; - } - - @override - Future fetchFile( - String identifier, Future Function() getter) async { - var existing = await getFile(identifier); - if (existing != null) return existing; - - var bytes = await getter(); - var path = await generateTempFilePath(); - if (BuildConfig.DEBUG) path += "_${Uri.encodeComponent(identifier)}"; - - var file = File(path); - await file.create(recursive: true); - await file.writeAsBytes(bytes); - - CachedFile entry = CachedFile( - file.path, identifier, DateTime.now().millisecondsSinceEpoch); - - db!.writeTxn(() async { - await files!.put(entry); - }); - - return file.uri; - } - - @override - Future clean() async { - Log.i("Cleaning files"); - - var now = DateTime.now(); - var cutoffTime = now.subtract(const Duration(days: 2)); - var timeMs = cutoffTime.millisecondsSinceEpoch; - - var removeFiles = - await files!.filter().lastAccessedTimestampLessThan(timeMs).findAll(); - - var allFiles = await files!.where().findAll(); - - Log.i("Found: ${removeFiles.length}/${allFiles.length} files for cleaning"); - - for (var file in removeFiles) { - _cleanFile(file); - } - - db!.writeTxn(() async { - files!.deleteAll(removeFiles.map((e) => e.id).toList()); - }); - } - - Future _cleanFile(CachedFile entry) async { - var file = File(entry.filePath); - if (!await file.exists()) { - return; - } - - file.delete(); - } - - // static bool _shouldRemoveFile( - // {required DateTime lastAccessedTime, required int fileSize}) { - // const largeFileSize = 10 * 1048576; //Ten Megabytes - // var diff = DateTime.now().difference(lastAccessedTime); - - // if (fileSize > largeFileSize) { - // return diff.inDays > 1; - // } - - // return true; - // } -} diff --git a/commet/lib/client/matrix/database/matrix_database.dart b/commet/lib/client/matrix/database/matrix_database.dart index 6020511d..14f1516d 100644 --- a/commet/lib/client/matrix/database/matrix_database.dart +++ b/commet/lib/client/matrix/database/matrix_database.dart @@ -8,6 +8,6 @@ Future getMatrixDatabase(String clientName) { return getMatrixDatabaseImplementation(clientName); } -Future getLegacyMatrixDatabase(String clientName) { +Future getLegacyMatrixDatabase(String clientName) { return getLegacyMatrixDatabaseImplementation(clientName); } diff --git a/commet/lib/client/matrix/database/matrix_database_html.dart b/commet/lib/client/matrix/database/matrix_database_html.dart index 3d89092b..b5a6ce4a 100644 --- a/commet/lib/client/matrix/database/matrix_database_html.dart +++ b/commet/lib/client/matrix/database/matrix_database_html.dart @@ -1,4 +1,3 @@ -import 'package:commet/config/app_config.dart'; import 'package:matrix/matrix.dart'; import 'package:universal_html/html.dart' as html; @@ -10,11 +9,7 @@ Future getMatrixDatabaseImplementation(String clientName) async { return db; } -Future getLegacyMatrixDatabaseImplementation( +Future getLegacyMatrixDatabaseImplementation( String clientName) async { - // ignore: deprecated_member_use - final db = HiveCollectionsDatabase( - clientName, await AppConfig.getHiveDatabasePath()); - await db.open(); - return db; + return null; } diff --git a/commet/lib/client/matrix/database/matrix_database_io.dart b/commet/lib/client/matrix/database/matrix_database_io.dart index 9dad25fe..0112f770 100644 --- a/commet/lib/client/matrix/database/matrix_database_io.dart +++ b/commet/lib/client/matrix/database/matrix_database_io.dart @@ -1,28 +1,63 @@ import 'dart:io'; +import 'dart:isolate'; +import 'dart:ui'; import 'package:commet/config/app_config.dart'; +import 'package:drift/drift.dart'; +import 'package:drift/isolate.dart'; +import 'package:flutter/services.dart'; import 'package:matrix/matrix.dart'; -import 'package:matrix_dart_sdk_isar_db/matrix_dart_sdk_isar_db.dart'; +import 'package:matrix_dart_sdk_drift_db/matrix_dart_sdk_drift_db.dart'; import 'package:path/path.dart' as p; +// ignore: depend_on_referenced_packages +import 'package:drift/native.dart'; Future getMatrixDatabaseImplementation(String clientName) async { - var path = await AppConfig.getIsarDatabasePath(); - path = p.join(path, clientName, "data.db"); - var dir = p.dirname(path); + var port = + IsolateNameServer.lookupPortByName(_getIsolateNameForClient(clientName)); - if (!await Directory(dir).exists()) { - await Directory(dir).create(recursive: true); - } + var isolate = DriftIsolate.fromConnectPort( + port ?? (await _createIsolate(clientName)).connectPort); - var db = await MatrixSdkIsarDatabase.init(dir, clientName); - return db; + return MatrixSdkDriftDatabase.init(await isolate.connect()); } -Future getLegacyMatrixDatabaseImplementation( +Future _createIsolate(String clientName) async { + final token = RootIsolateToken.instance!; + var isolate = await DriftIsolate.spawn( + () { + BackgroundIsolateBinaryMessenger.ensureInitialized(token); + + return LazyDatabase(() async { + var path = await AppConfig.getDriftDatabasePath(); + path = p.join(path, clientName, "data.db"); + var dir = p.dirname(path); + + if (!await Directory(dir).exists()) { + await Directory(dir).create(recursive: true); + } + + final file = File(path); + return NativeDatabase(file); + }); + }, + isolateSpawn: (Function(T message) entryPoint, T message) { + return Isolate.spawn(entryPoint, message, + debugName: "Client $clientName DB Isolate"); + }, + ); + + IsolateNameServer.registerPortWithName( + isolate.connectPort, _getIsolateNameForClient(clientName)); + + return isolate; +} + +String _getIsolateNameForClient(String clientName) { + return "chat.commet.commetapp.isolate.client_$clientName"; +} + +Future getLegacyMatrixDatabaseImplementation( String clientName) async { - // ignore: deprecated_member_use - final db = HiveCollectionsDatabase( - clientName, await AppConfig.getHiveDatabasePath()); - await db.open(); - return db; + return null; } diff --git a/commet/lib/client/matrix/database/matrix_database_stub.dart b/commet/lib/client/matrix/database/matrix_database_stub.dart index ebd207dc..5221cda7 100644 --- a/commet/lib/client/matrix/database/matrix_database_stub.dart +++ b/commet/lib/client/matrix/database/matrix_database_stub.dart @@ -4,7 +4,7 @@ Future getMatrixDatabaseImplementation(String clientName) async { throw UnimplementedError(); } -Future getLegacyMatrixDatabaseImplementation( +Future getLegacyMatrixDatabaseImplementation( String clientName) async { throw UnimplementedError(); } diff --git a/commet/lib/client/matrix/matrix_client.dart b/commet/lib/client/matrix/matrix_client.dart index b00230fb..cddb553a 100644 --- a/commet/lib/client/matrix/matrix_client.dart +++ b/commet/lib/client/matrix/matrix_client.dart @@ -249,8 +249,6 @@ class MatrixClient extends Client { }, supportedLoginTypes: {matrix.AuthenticationTypes.password}, nativeImplementations: nativeImplementations, - legacyDatabaseBuilder: (client) => - getLegacyMatrixDatabase(client.clientName), databaseBuilder: (client) => getMatrixDatabase(client.clientName), ); diff --git a/commet/lib/config/app_config.dart b/commet/lib/config/app_config.dart index 867f51b2..c10221da 100644 --- a/commet/lib/config/app_config.dart +++ b/commet/lib/config/app_config.dart @@ -13,19 +13,11 @@ class AppConfig { return join(dir.path, "db"); } - static Future getIsarDatabasePath() async { + static Future getDriftDatabasePath() async { if (BuildConfig.WEB) { return "commet"; } - final dir = await getApplicationSupportDirectory(); - return join(dir.path, "isar"); - } - - static Future getHiveDatabasePath() async { - if (BuildConfig.WEB) { - return "commet"; - } - final dir = await getApplicationSupportDirectory(); - return join(dir.path, "hive"); + final dir = await getDatabasePath(); + return join(dir, "account", "drift"); } } diff --git a/commet/lib/ui/atoms/icon_button.dart b/commet/lib/ui/atoms/icon_button.dart index 9a7c0508..ad728f57 100644 --- a/commet/lib/ui/atoms/icon_button.dart +++ b/commet/lib/ui/atoms/icon_button.dart @@ -31,7 +31,7 @@ class _IconButtonState extends State { hovered = false; }); }, - cursor: MaterialStateMouseCursor.clickable, + cursor: WidgetStateMouseCursor.clickable, child: Padding( padding: const EdgeInsets.all(4.0), child: SizedBox( diff --git a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart index 2cec4b1c..9de58299 100644 --- a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart @@ -153,7 +153,7 @@ class _MatrixRoomPermissionsViewState extends State { child: Tile.low1( child: MouseRegion( cursor: widget.canEdit - ? MaterialStateMouseCursor.clickable + ? WidgetStateMouseCursor.clickable : MouseCursor.defer, child: Padding( padding: const EdgeInsets.fromLTRB(8, 8, 30, 8), diff --git a/commet/lib/utils/scaled_app.dart b/commet/lib/utils/scaled_app.dart index 88bb2601..cf9fd490 100644 --- a/commet/lib/utils/scaled_app.dart +++ b/commet/lib/utils/scaled_app.dart @@ -68,6 +68,10 @@ class ScaledWidgetsFlutterBinding extends WidgetsFlutterBinding { ViewConfiguration createViewConfigurationFor(RenderView renderView) { final FlutterView view = platformDispatcher.implicitView!; final devicePixelRatio = view.devicePixelRatio; + + final BoxConstraints physicalConstraints = + BoxConstraints.fromViewConstraints(view.physicalConstraints); + final physicalSize = view.physicalSize; if (physicalSize.isEmpty) { @@ -75,7 +79,8 @@ class ScaledWidgetsFlutterBinding extends WidgetsFlutterBinding { } else { devicePixelRatioScaled = devicePixelRatio * scale; return ViewConfiguration( - size: physicalSize / devicePixelRatioScaled, + physicalConstraints: physicalConstraints, + logicalConstraints: physicalConstraints / devicePixelRatioScaled, devicePixelRatio: devicePixelRatioScaled, ); } diff --git a/commet/linux/flutter/generated_plugin_registrant.cc b/commet/linux/flutter/generated_plugin_registrant.cc index 1f787071..d89dc448 100644 --- a/commet/linux/flutter/generated_plugin_registrant.cc +++ b/commet/linux/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -21,9 +20,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) desktop_drop_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin"); desktop_drop_plugin_register_with_registrar(desktop_drop_registrar); - g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); - isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); diff --git a/commet/linux/flutter/generated_plugins.cmake b/commet/linux/flutter/generated_plugins.cmake index cc291f1f..8c942fc1 100644 --- a/commet/linux/flutter/generated_plugins.cmake +++ b/commet/linux/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_drop - isar_flutter_libs media_kit_libs_linux media_kit_video pasteboard diff --git a/commet/macos/Flutter/GeneratedPluginRegistrant.swift b/commet/macos/Flutter/GeneratedPluginRegistrant.swift index 8f4ed398..d1703718 100644 --- a/commet/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/commet/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,6 @@ import desktop_drop import device_info_plus import flutter_local_notifications import flutter_web_auth_2 -import isar_flutter_libs import media_kit_libs_macos_video import media_kit_video import package_info_plus @@ -30,7 +29,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) - IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) diff --git a/commet/pubspec.lock b/commet/pubspec.lock index 7fc72042..60f14fbe 100644 --- a/commet/pubspec.lock +++ b/commet/pubspec.lock @@ -5,18 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "61.0.0" + version: "67.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "6.4.1" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + url: "https://pub.dev" + source: hosted + version: "0.11.3" archive: dependency: transitive description: @@ -117,10 +125,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.4.11" build_runner_core: dependency: transitive description: @@ -281,14 +289,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" - dartx: - dependency: transitive - description: - name: dartx - sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" - url: "https://pub.dev" - source: hosted - version: "1.2.0" dbus: dependency: transitive description: @@ -337,6 +337,22 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + drift: + dependency: "direct main" + description: + name: drift + sha256: "6acedc562ffeed308049f78fb1906abad3d65714580b6745441ee6d50ec564cd" + url: "https://pub.dev" + source: hosted + version: "2.18.0" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + sha256: d9b020736ea85fff1568699ce18b89fabb3f0f042e8a7a05e84a3ec20d39acde + url: "https://pub.dev" + source: hosted + version: "2.18.0" dropdown_button2: dependency: transitive description: @@ -733,26 +749,26 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" intl_translation: dependency: "direct main" description: name: intl_translation - sha256: c8dce69cd7ce7ffea26126c32d284c829a94f08c13e4322ec0d98753dde6baff + sha256: b858d88b569f3c529e992ba7186aa495f3e862897df60edb932563c619943610 url: "https://pub.dev" source: hosted - version: "0.18.2" + version: "0.20.0" intl_utils: dependency: "direct main" description: name: intl_utils - sha256: "5cad11e11ff7662c3cd0ef04729248591d71ed023d4ef0903a137528b4568adf" + sha256: c2b1f5c72c25512cbeef5ab015c008fc50fe7e04813ba5541c25272300484bf4 url: "https://pub.dev" source: hosted - version: "2.8.5" + version: "2.8.7" io: dependency: transitive description: @@ -761,30 +777,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - isar: - dependency: "direct main" - description: - name: isar - sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea" - url: "https://pub.dev" - source: hosted - version: "3.1.0+1" - isar_flutter_libs: - dependency: "direct main" - description: - name: isar_flutter_libs - sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8 - url: "https://pub.dev" - source: hosted - version: "3.1.0+1" - isar_generator: - dependency: "direct main" - description: - name: isar_generator - sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133" - url: "https://pub.dev" - source: hosted - version: "3.1.0+1" js: dependency: transitive description: @@ -813,26 +805,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: @@ -906,13 +898,13 @@ packages: url: "https://github.com/Airyzz/matrix-dart-sdk.git" source: git version: "0.26.1" - matrix_dart_sdk_isar_db: + matrix_dart_sdk_drift_db: dependency: "direct main" description: path: "." ref: HEAD - resolved-ref: "73d9bc83de38586c9e4efec08787e96382d424d4" - url: "https://github.com/commetchat/matrix-dart-sdk-isar-db.git" + resolved-ref: "03592725f0f4446787b2dc370a5d326e4c41d3a8" + url: "https://github.com/commetchat/matrix-dart-sdk-drift-db.git" source: git version: "0.0.1" media_kit: @@ -991,10 +983,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: "direct main" description: @@ -1291,6 +1283,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" receive_intent: dependency: "direct main" description: @@ -1565,10 +1565,18 @@ packages: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060 + sha256: "9f89a7e7dc36eac2035808427eba1c3fbd79e59c3a22093d8dace6d36b1fe89e" url: "https://pub.dev" source: hosted - version: "0.5.20" + version: "0.5.23" + sqlparser: + dependency: transitive + description: + name: sqlparser + sha256: ade9a67fd70d0369329ed3373208de7ebd8662470e8c396fc8d0d60f9acdfc9f + url: "https://pub.dev" + source: hosted + version: "0.36.0" stack_trace: dependency: transitive description: @@ -1637,26 +1645,26 @@ packages: dependency: "direct main" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.0" tiamat: dependency: "direct main" description: @@ -1664,14 +1672,6 @@ packages: relative: true source: path version: "1.0.0+1" - time: - dependency: transitive - description: - name: time - sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 - url: "https://pub.dev" - source: hosted - version: "2.1.4" timezone: dependency: transitive description: @@ -1876,10 +1876,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" volume_controller: dependency: transitive description: @@ -2016,14 +2016,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" - xxh3: - dependency: transitive - description: - name: xxh3 - sha256: a92b30944a9aeb4e3d4f3c3d4ddb3c7816ca73475cd603682c4f8149690f56d7 - url: "https://pub.dev" - source: hosted - version: "1.0.1" yaml: dependency: transitive description: @@ -2033,5 +2025,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.3 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.19.0" diff --git a/commet/pubspec.yaml b/commet/pubspec.yaml index b006a383..9d5bfdf5 100644 --- a/commet/pubspec.yaml +++ b/commet/pubspec.yaml @@ -25,11 +25,8 @@ dependencies: http: ^1.1.0 implicitly_animated_list: ^2.2.0 intl: any - intl_translation: ^0.18.2 + intl_translation: ^0.20.0 intl_utils: any - isar: ^3.1.0+1 - isar_flutter_libs: ^3.1.0+1 - isar_generator: ^3.1.0+1 just_the_tooltip: ^0.0.12 matrix: git: @@ -76,17 +73,18 @@ dependencies: ref: fix tiamat: path: ../tiamat/ - matrix_dart_sdk_isar_db: - git: https://github.com/commetchat/matrix-dart-sdk-isar-db.git + matrix_dart_sdk_drift_db: + git: https://github.com/commetchat/matrix-dart-sdk-drift-db.git encrypted_url_preview: git: https://github.com/commetchat/encrypted_url_preview.git signal_sticker_api: git: https://github.com/commetchat/signal-sticker-api.git - sqlite3_flutter_libs: ^0.5.18 + sqlite3_flutter_libs: ^0.5.23 fuzzy: ^0.5.1 encrypt: ^5.0.3 pointycastle: ^3.7.4 flutter_web_auth_2: ^3.1.1 + drift: ^2.18.0 ## ---- Putting some extra lines in here to help git with the diff ## ---- Probably good to keep this stuff at the bottom of the list @@ -99,7 +97,7 @@ dependencies: dev_dependencies: - build_runner: any + build_runner: ^2.4.11 flutter_launcher_icons: ^0.13.1 flutter_lints: ^2.0.0 msix: ^3.7.0 @@ -108,6 +106,7 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter + drift_dev: ^2.18.0 flutter_intl: class_name: T diff --git a/commet/windows/flutter/generated_plugin_registrant.cc b/commet/windows/flutter/generated_plugin_registrant.cc index cb536252..8d62a578 100644 --- a/commet/windows/flutter/generated_plugin_registrant.cc +++ b/commet/windows/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -23,8 +22,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { DesktopDropPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopDropPlugin")); - IsarFlutterLibsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( diff --git a/commet/windows/flutter/generated_plugins.cmake b/commet/windows/flutter/generated_plugins.cmake index 9f655f72..b1b6bd4e 100644 --- a/commet/windows/flutter/generated_plugins.cmake +++ b/commet/windows/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_drop - isar_flutter_libs media_kit_libs_windows_video media_kit_video pasteboard