refactor: sdk 1.0
This commit is contained in:
parent
ca4db07d83
commit
e548d8f895
23 changed files with 1775 additions and 175 deletions
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/archive/archive.dart';
|
||||
|
|
@ -73,7 +74,7 @@ abstract class AppRoutes {
|
|||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const Login(),
|
||||
Login(client: state.extra as Client),
|
||||
),
|
||||
redirect: loggedInRedirect,
|
||||
),
|
||||
|
|
@ -260,7 +261,7 @@ abstract class AppRoutes {
|
|||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const Login(),
|
||||
Login(client: state.extra as Client),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod;
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
|
@ -20,6 +21,8 @@ void main() async {
|
|||
// widget bindings are initialized already.
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await vod.init();
|
||||
|
||||
Logs().nativeColors = !PlatformInfos.isIOS;
|
||||
final store = await SharedPreferences.getInstance();
|
||||
final clients = await ClientManager.getClients(store: store);
|
||||
|
|
|
|||
|
|
@ -69,10 +69,11 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
homeserverController.text.trim().toLowerCase().replaceAll(' ', '-');
|
||||
|
||||
if (homeserverInput.isEmpty) {
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
setState(() {
|
||||
error = loginFlows = null;
|
||||
isLoading = false;
|
||||
Matrix.of(context).getLoginClient().homeserver = null;
|
||||
client.homeserver = null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -88,7 +89,7 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
if (homeserver.scheme.isEmpty) {
|
||||
homeserver = Uri.https(homeserverInput, '');
|
||||
}
|
||||
final client = Matrix.of(context).getLoginClient();
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
final (_, _, loginFlows) = await client.checkHomeserver(homeserver);
|
||||
this.loginFlows = loginFlows;
|
||||
if (supportsSso && !legacyPasswordLogin) {
|
||||
|
|
@ -105,6 +106,7 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
}
|
||||
context.push(
|
||||
'${GoRouter.of(context).routeInformationProvider.value.uri.path}/login',
|
||||
extra: client,
|
||||
);
|
||||
} catch (e) {
|
||||
setState(
|
||||
|
|
@ -142,8 +144,8 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
: isDefaultPlatform
|
||||
? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
|
||||
: 'http://localhost:3001//login';
|
||||
|
||||
final url = Matrix.of(context).getLoginClient().homeserver!.replace(
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
final url = client.homeserver!.replace(
|
||||
path: '/_matrix/client/v3/login/sso/redirect',
|
||||
queryParameters: {'redirectUrl': redirectUrl},
|
||||
);
|
||||
|
|
@ -164,11 +166,12 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
isLoading = true;
|
||||
});
|
||||
try {
|
||||
await Matrix.of(context).getLoginClient().login(
|
||||
LoginType.mLoginToken,
|
||||
token: token,
|
||||
initialDeviceDisplayName: PlatformInfos.clientName,
|
||||
);
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
client.login(
|
||||
LoginType.mLoginToken,
|
||||
token: token,
|
||||
initialDeviceDisplayName: PlatformInfos.clientName,
|
||||
);
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
error = e.toLocalizedString(context);
|
||||
|
|
@ -200,7 +203,7 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
|||
isLoading = true;
|
||||
});
|
||||
try {
|
||||
final client = Matrix.of(context).getLoginClient();
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
await client.importDump(String.fromCharCodes(await file.readAsBytes()));
|
||||
Matrix.of(context).initMatrix();
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import '../../utils/platform_infos.dart';
|
|||
import 'login_view.dart';
|
||||
|
||||
class Login extends StatefulWidget {
|
||||
const Login({super.key});
|
||||
final Client client;
|
||||
const Login({required this.client, super.key});
|
||||
|
||||
@override
|
||||
LoginController createState() => LoginController();
|
||||
|
|
@ -68,17 +69,18 @@ class LoginController extends State<Login> {
|
|||
} else {
|
||||
identifier = AuthenticationUserIdentifier(user: username);
|
||||
}
|
||||
await matrix.getLoginClient().login(
|
||||
LoginType.mLoginPassword,
|
||||
identifier: identifier,
|
||||
// To stay compatible with older server versions
|
||||
// ignore: deprecated_member_use
|
||||
user: identifier.type == AuthenticationIdentifierTypes.userId
|
||||
? username
|
||||
: null,
|
||||
password: passwordController.text,
|
||||
initialDeviceDisplayName: PlatformInfos.clientName,
|
||||
);
|
||||
final client = await matrix.getLoginClient();
|
||||
client.login(
|
||||
LoginType.mLoginPassword,
|
||||
identifier: identifier,
|
||||
// To stay compatible with older server versions
|
||||
// ignore: deprecated_member_use
|
||||
user: identifier.type == AuthenticationIdentifierTypes.userId
|
||||
? username
|
||||
: null,
|
||||
password: passwordController.text,
|
||||
initialDeviceDisplayName: PlatformInfos.clientName,
|
||||
);
|
||||
} on MatrixException catch (exception) {
|
||||
setState(() => passwordError = exception.errorMessage);
|
||||
return setState(() => loading = false);
|
||||
|
|
@ -103,14 +105,13 @@ class LoginController extends State<Login> {
|
|||
void _checkWellKnown(String userId) async {
|
||||
if (mounted) setState(() => usernameError = null);
|
||||
if (!userId.isValidMatrixId) return;
|
||||
final oldHomeserver = Matrix.of(context).getLoginClient().homeserver;
|
||||
final oldHomeserver = widget.client.homeserver;
|
||||
try {
|
||||
var newDomain = Uri.https(userId.domain!, '');
|
||||
Matrix.of(context).getLoginClient().homeserver = newDomain;
|
||||
widget.client.homeserver = newDomain;
|
||||
DiscoveryInformation? wellKnownInformation;
|
||||
try {
|
||||
wellKnownInformation =
|
||||
await Matrix.of(context).getLoginClient().getWellknown();
|
||||
wellKnownInformation = await widget.client.getWellknown();
|
||||
if (wellKnownInformation.mHomeserver.baseUrl.toString().isNotEmpty) {
|
||||
newDomain = wellKnownInformation.mHomeserver.baseUrl;
|
||||
}
|
||||
|
|
@ -118,10 +119,10 @@ class LoginController extends State<Login> {
|
|||
// do nothing, newDomain is already set to a reasonable fallback
|
||||
}
|
||||
if (newDomain != oldHomeserver) {
|
||||
await Matrix.of(context).getLoginClient().checkHomeserver(newDomain);
|
||||
await widget.client.checkHomeserver(newDomain);
|
||||
|
||||
if (Matrix.of(context).getLoginClient().homeserver == null) {
|
||||
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
|
||||
if (widget.client.homeserver == null) {
|
||||
widget.client.homeserver = oldHomeserver;
|
||||
// okay, the server we checked does not appear to be a matrix server
|
||||
Logs().v(
|
||||
'$newDomain is not running a homeserver, asking to use $oldHomeserver',
|
||||
|
|
@ -144,13 +145,13 @@ class LoginController extends State<Login> {
|
|||
usernameError = null;
|
||||
if (mounted) setState(() {});
|
||||
} else {
|
||||
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
|
||||
widget.client.homeserver = oldHomeserver;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
|
||||
widget.client.homeserver = oldHomeserver;
|
||||
usernameError = e.toLocalizedString(context);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
|
@ -173,12 +174,11 @@ class LoginController extends State<Login> {
|
|||
final clientSecret = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final response = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () =>
|
||||
Matrix.of(context).getLoginClient().requestTokenToResetPasswordEmail(
|
||||
clientSecret,
|
||||
input,
|
||||
sendAttempt++,
|
||||
),
|
||||
future: () => widget.client.requestTokenToResetPasswordEmail(
|
||||
clientSecret,
|
||||
input,
|
||||
sendAttempt++,
|
||||
),
|
||||
);
|
||||
if (response.error != null) return;
|
||||
final password = await showTextInputDialog(
|
||||
|
|
@ -215,11 +215,11 @@ class LoginController extends State<Login> {
|
|||
};
|
||||
final success = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => Matrix.of(context).getLoginClient().request(
|
||||
RequestType.POST,
|
||||
'/client/v3/account/password',
|
||||
data: data,
|
||||
),
|
||||
future: () => widget.client.request(
|
||||
RequestType.POST,
|
||||
'/client/v3/account/password',
|
||||
data: data,
|
||||
),
|
||||
);
|
||||
if (success.error == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ class LoginView extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final homeserver = Matrix.of(context)
|
||||
.getLoginClient()
|
||||
.homeserver
|
||||
final homeserver = controller.widget.client.homeserver
|
||||
.toString()
|
||||
.replaceFirst('https://', '');
|
||||
final title = L10n.of(context).logInTo(homeserver);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ extension ClientDownloadContentExtension on Client {
|
|||
)
|
||||
: mxc;
|
||||
|
||||
final cachedData = await database?.getFile(cacheKey);
|
||||
final cachedData = await database.getFile(cacheKey);
|
||||
if (cachedData != null) return cachedData;
|
||||
|
||||
final httpUri = isThumbnail
|
||||
|
|
@ -55,7 +55,7 @@ extension ClientDownloadContentExtension on Client {
|
|||
}
|
||||
}
|
||||
|
||||
await database?.storeFile(cacheKey, imageData, 0);
|
||||
await database.storeFile(cacheKey, imageData, 0);
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:desktop_notifications/desktop_notifications.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod;
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:matrix/encryption/utils/key_verification.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
|
@ -46,7 +47,7 @@ abstract class ClientManager {
|
|||
await store.setStringList(clientNamespace, clientNames.toList());
|
||||
}
|
||||
final clients =
|
||||
clientNames.map((name) => createClient(name, store)).toList();
|
||||
await Future.wait(clientNames.map((name) => createClient(name, store)));
|
||||
if (initialize) {
|
||||
await Future.wait(
|
||||
clients.map(
|
||||
|
|
@ -98,9 +99,15 @@ abstract class ClientManager {
|
|||
|
||||
static NativeImplementations get nativeImplementations => kIsWeb
|
||||
? const NativeImplementationsDummy()
|
||||
: NativeImplementationsIsolate(compute);
|
||||
: NativeImplementationsIsolate(
|
||||
compute,
|
||||
vodozemacInit: vod.init,
|
||||
);
|
||||
|
||||
static Client createClient(String clientName, SharedPreferences store) {
|
||||
static Future<Client> createClient(
|
||||
String clientName,
|
||||
SharedPreferences store,
|
||||
) async {
|
||||
final shareKeysWith = AppSettings.shareKeysWith.getItem(store);
|
||||
final enableSoftLogout = AppSettings.enableSoftLogout.getItem(store);
|
||||
|
||||
|
|
@ -118,7 +125,7 @@ abstract class ClientManager {
|
|||
'im.ponies.room_emotes',
|
||||
},
|
||||
logLevel: kReleaseMode ? Level.warning : Level.verbose,
|
||||
databaseBuilder: flutterMatrixSdkDatabaseBuilder,
|
||||
database: await flutterMatrixSdkDatabaseBuilder(clientName),
|
||||
supportedLoginTypes: {
|
||||
AuthenticationTypes.password,
|
||||
AuthenticationTypes.sso,
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ extension LocalizedBody on Event {
|
|||
|
||||
bool get isAttachmentSmallEnough =>
|
||||
infoMap['size'] is int &&
|
||||
infoMap['size'] < room.client.database!.maxFileSize;
|
||||
infoMap['size'] < room.client.database.maxFileSize;
|
||||
|
||||
bool get isThumbnailSmallEnough =>
|
||||
thumbnailInfoMap['size'] is int &&
|
||||
thumbnailInfoMap['size'] < room.client.database!.maxFileSize;
|
||||
thumbnailInfoMap['size'] < room.client.database.maxFileSize;
|
||||
|
||||
bool get showThumbnail =>
|
||||
[MessageTypes.Image, MessageTypes.Sticker, MessageTypes.Video]
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ import 'cipher.dart';
|
|||
import 'sqlcipher_stub.dart'
|
||||
if (dart.library.io) 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart';
|
||||
|
||||
Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(Client client) async {
|
||||
Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(String clientName) async {
|
||||
MatrixSdkDatabase? database;
|
||||
try {
|
||||
database = await _constructDatabase(client);
|
||||
database = await _constructDatabase(clientName);
|
||||
await database.open();
|
||||
return database;
|
||||
} catch (e, s) {
|
||||
|
|
@ -36,7 +36,7 @@ Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(Client client) async {
|
|||
|
||||
// Delete database file:
|
||||
if (database == null && !kIsWeb) {
|
||||
final dbFile = File(await _getDatabasePath(client.clientName));
|
||||
final dbFile = File(await _getDatabasePath(clientName));
|
||||
if (await dbFile.exists()) await dbFile.delete();
|
||||
}
|
||||
|
||||
|
|
@ -58,10 +58,10 @@ Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(Client client) async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
||||
Future<MatrixSdkDatabase> _constructDatabase(String clientName) async {
|
||||
if (kIsWeb) {
|
||||
html.window.navigator.storage?.persist();
|
||||
return MatrixSdkDatabase(client.clientName);
|
||||
return await MatrixSdkDatabase.init(clientName);
|
||||
}
|
||||
|
||||
final cipher = await getDatabaseCipher();
|
||||
|
|
@ -75,7 +75,7 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
|||
);
|
||||
}
|
||||
|
||||
final path = await _getDatabasePath(client.clientName);
|
||||
final path = await _getDatabasePath(clientName);
|
||||
|
||||
// fix dlopen for old Android
|
||||
await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions();
|
||||
|
|
@ -84,7 +84,7 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
|||
createDatabaseFactoryFfi(ffiInit: SQfLiteEncryptionHelper.ffiInit);
|
||||
|
||||
// migrate from potential previous SQLite database path to current one
|
||||
await _migrateLegacyLocation(path, client.clientName);
|
||||
await _migrateLegacyLocation(path, clientName);
|
||||
|
||||
// required for [getDatabasesPath]
|
||||
databaseFactory = factory;
|
||||
|
|
@ -111,8 +111,8 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
|
|||
),
|
||||
);
|
||||
|
||||
return MatrixSdkDatabase(
|
||||
client.clientName,
|
||||
return await MatrixSdkDatabase.init(
|
||||
clientName,
|
||||
database: database,
|
||||
maxFileSize: 1000 * 1000 * 10,
|
||||
fileStorageLocation: fileStorageLocation?.uri,
|
||||
|
|
|
|||
|
|
@ -74,9 +74,6 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
BackgroundPush? backgroundPush;
|
||||
|
||||
Client get client {
|
||||
if (widget.clients.isEmpty) {
|
||||
widget.clients.add(getLoginClient());
|
||||
}
|
||||
if (_activeClient < 0 || _activeClient >= widget.clients.length) {
|
||||
return currentBundle!.first!;
|
||||
}
|
||||
|
|
@ -152,29 +149,31 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
AudioPlayer? audioPlayer;
|
||||
final ValueNotifier<String?> voiceMessageEventId = ValueNotifier(null);
|
||||
|
||||
Client getLoginClient() {
|
||||
Future<Client> getLoginClient() async {
|
||||
if (widget.clients.isNotEmpty && !client.isLogged()) {
|
||||
return client;
|
||||
}
|
||||
final candidate = _loginClientCandidate ??= ClientManager.createClient(
|
||||
final candidate =
|
||||
_loginClientCandidate ??= await ClientManager.createClient(
|
||||
'${AppConfig.applicationName}-${DateTime.now().millisecondsSinceEpoch}',
|
||||
store,
|
||||
)..onLoginStateChanged
|
||||
.stream
|
||||
.where((l) => l == LoginState.loggedIn)
|
||||
.first
|
||||
.then((_) {
|
||||
if (!widget.clients.contains(_loginClientCandidate)) {
|
||||
widget.clients.add(_loginClientCandidate!);
|
||||
}
|
||||
ClientManager.addClientNameToStore(
|
||||
_loginClientCandidate!.clientName,
|
||||
store,
|
||||
);
|
||||
_registerSubs(_loginClientCandidate!.clientName);
|
||||
_loginClientCandidate = null;
|
||||
FluffyChatApp.router.go('/rooms');
|
||||
});
|
||||
)
|
||||
..onLoginStateChanged
|
||||
.stream
|
||||
.where((l) => l == LoginState.loggedIn)
|
||||
.first
|
||||
.then((_) {
|
||||
if (!widget.clients.contains(_loginClientCandidate)) {
|
||||
widget.clients.add(_loginClientCandidate!);
|
||||
}
|
||||
ClientManager.addClientNameToStore(
|
||||
_loginClientCandidate!.clientName,
|
||||
store,
|
||||
);
|
||||
_registerSubs(_loginClientCandidate!.clientName);
|
||||
_loginClientCandidate = null;
|
||||
FluffyChatApp.router.go('/rooms');
|
||||
});
|
||||
return candidate;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue