import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod; import 'package:matrix/encryption/utils/key_verification.dart'; import 'package:matrix/matrix.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart' as sqflite_native; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:pyramid/core/voip_manager.dart'; final matrixClientProvider = FutureProvider((ref) async { final DatabaseFactory factory; if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) { // Use the native sqflite plugin — Android/iOS have system SQLite built-in, // no .so loading required. factory = sqflite_native.databaseFactory; } else if (!kIsWeb) { sqfliteFfiInit(); factory = databaseFactoryFfi; } else { throw UnsupportedError('Web not supported'); } final appDir = await getApplicationSupportDirectory(); final dbPath = p.join(appDir.path, 'pyramid.sqlite'); final db = await factory.openDatabase(dbPath); // Optimization for Windows/FFI to prevent "database is locked" errors try { await db.execute('PRAGMA journal_mode=WAL'); await db.execute('PRAGMA busy_timeout = 5000'); } catch (e) { if (kDebugMode) print('Could not set PRAGMAs: $e'); } final sdkDb = await MatrixSdkDatabase.init('pyramid', database: db); final client = Client( 'Pyramid', database: sdkDb, // Custom State-Events, die beim App-Start mit aus der DB geladen werden // müssen — sonst sind Space-Banner & Voice-Presence nach Neustart leer, // bis der jeweilige Raum vollständig nachgeladen wird. importantStateEvents: { 'io.pyramid.space.banner', 'io.pyramid.voice.presence', }, verificationMethods: { KeyVerificationMethod.numbers, KeyVerificationMethod.emoji, KeyVerificationMethod.qrShow, }, logLevel: kReleaseMode ? Level.warning : Level.verbose, nativeImplementations: NativeImplementationsIsolate( compute, vodozemacInit: () => vod.init(), ), ); await client.init( waitForFirstSync: false, waitUntilLoadCompletedLoaded: false, ); // Re-use or create singleton instance try { PyramidVoipManager.instance.client; } catch (_) { PyramidVoipManager(client); } return client; }); final secureStorageProvider = Provider((ref) { return const FlutterSecureStorage(); });