fluffychat merge

This commit is contained in:
ggurdin 2025-06-25 12:50:17 -04:00
commit c67f779063
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
26 changed files with 1795 additions and 373 deletions

View file

@ -20,6 +20,8 @@ jobs:
- uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
- uses: moonrepo/setup-rust@v1
- run: rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
- run: flutter pub get
- name: Prepare web
run: ./scripts/prepare-web.sh

View file

@ -48,6 +48,7 @@ jobs:
cache: true
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install nodejs -y
- uses: moonrepo/setup-rust@v1
- run: flutter pub get
- name: Prepare web
run: ./scripts/prepare-web.sh

1546
.gitignore vendored

File diff suppressed because it is too large Load diff

View file

@ -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';
@ -98,7 +99,7 @@ abstract class AppRoutes {
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
const Login(),
Login(client: state.extra as Client),
),
redirect: loggedInRedirect,
),
@ -443,7 +444,7 @@ abstract class AppRoutes {
// pageBuilder: (context, state) => defaultPageBuilder(
// context,
// state,
// const Login(),
// Login(client: state.extra as Client),
// ),
// redirect: loggedOutRedirect,
// ),
@ -461,17 +462,6 @@ abstract class AppRoutes {
},
redirect: loggedOutRedirect,
),
GoRoute(
path: 'homeserver',
pageBuilder: (context, state) {
return defaultPageBuilder(
context,
state,
const SettingsHomeserver(),
);
},
redirect: loggedOutRedirect,
),
GoRoute(
path: 'security',
redirect: loggedOutRedirect,

View file

@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
import 'package:collection/collection.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod;
import 'package:get_storage/get_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -50,6 +51,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);

View file

@ -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) {

View file

@ -16,7 +16,8 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
class Login extends StatefulWidget {
const Login({super.key});
final Client client;
const Login({required this.client, super.key});
@override
LoginController createState() => LoginController();
@ -51,17 +52,17 @@ class LoginController extends State<Login> {
// TODO: implement initState
super.initState();
loadingSignIn = true;
pangeaController.checkHomeServerAction().then((value) {
setState(() {
loadingSignIn = false;
});
}).catchError((e) {
final String err = e.toString();
setState(() {
loadingSignIn = false;
passwordError = err.toLocalizedString(context);
});
});
// pangeaController.checkHomeServerAction().then((value) {
// setState(() {
// loadingSignIn = false;
// });
// }).catchError((e) {
// final String err = e.toString();
// setState(() {
// loadingSignIn = false;
// passwordError = err.toLocalizedString(context);
// });
// });
usernameController.addListener(() => setState(() {}));
passwordController.addListener(() => setState(() {}));
@ -132,17 +133,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);
@ -168,14 +170,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;
}
@ -183,10 +184,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',
@ -209,13 +210,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(() {});
}
@ -238,12 +239,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(
@ -283,11 +283,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(

View file

@ -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);

View file

@ -24,7 +24,6 @@ import 'package:fluffychat/pangea/toolbar/controllers/text_to_speech_controller.
import 'package:fluffychat/pangea/user/controllers/permissions_controller.dart';
import 'package:fluffychat/pangea/user/controllers/user_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../config/app_config.dart';
import '../../choreographer/controllers/it_feedback_controller.dart';
import '../utils/firebase_analytics.dart';
@ -131,29 +130,29 @@ class PangeaController {
await Future.wait(futures);
}
Future<void> checkHomeServerAction() async {
if (matrixState.getLoginClient().homeserver != null) {
await Future.delayed(Duration.zero);
return;
}
// Future<void> checkHomeServerAction() async {
// if (matrixState.getLoginClient().homeserver != null) {
// await Future.delayed(Duration.zero);
// return;
// }
final String homeServer =
AppConfig.defaultHomeserver.trim().toLowerCase().replaceAll(' ', '-');
var homeserver = Uri.parse(homeServer);
if (homeserver.scheme.isEmpty) {
homeserver = Uri.https(homeServer, '');
}
// final String homeServer =
// AppConfig.defaultHomeserver.trim().toLowerCase().replaceAll(' ', '-');
// var homeserver = Uri.parse(homeServer);
// if (homeserver.scheme.isEmpty) {
// homeserver = Uri.https(homeServer, '');
// }
try {
await matrixState.getLoginClient().register();
matrixState.loginRegistrationSupported = true;
} on MatrixException catch (e) {
matrixState.loginRegistrationSupported =
e.requireAdditionalAuthentication;
}
// try {
// await matrixState.getLoginClient().register();
// matrixState.loginRegistrationSupported = true;
// } on MatrixException catch (e) {
// matrixState.loginRegistrationSupported =
// e.requireAdditionalAuthentication;
// }
// setState(() => error = (e).toLocalizedString(context));
}
// // setState(() => error = (e).toLocalizedString(context));
// }
/// check user information if not found then redirect to Date of birth page
_handleLoginStateChange(LoginState state) {

View file

@ -171,7 +171,7 @@ class SignupPageController extends State<SignupPage> {
}
Future<void> _signupFuture() async {
final client = Matrix.of(context).getLoginClient();
final client = await Matrix.of(context).getLoginClient();
final email = emailController.text;
if (email.isNotEmpty) {
Matrix.of(context).currentClientSecret =

View file

@ -16,12 +16,10 @@ import 'package:fluffychat/widgets/matrix.dart';
Future<void> pangeaSSOLoginAction(
IdentityProvider provider,
Client client,
BuildContext context,
) async {
final bool isDefaultPlatform =
(PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS);
final redirectUrl = kIsWeb
? Uri.parse(html.window.location.href)
.resolveUri(
@ -31,16 +29,15 @@ Future<void> pangeaSSOLoginAction(
: isDefaultPlatform
? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
: 'http://localhost:3001//login';
final url = Matrix.of(context).getLoginClient().homeserver!.replace(
path: '/_matrix/client/v3/login/sso/redirect/${provider.id ?? ''}',
final client = await Matrix.of(context).getLoginClient();
final url = client.homeserver!.replace(
path: '/_matrix/client/v3/login/sso/redirect',
queryParameters: {'redirectUrl': redirectUrl},
);
final urlScheme = isDefaultPlatform
? Uri.parse(redirectUrl).scheme
: "http://localhost:3001";
String result;
try {
result = await FlutterWebAuth2.authenticate(
@ -54,7 +51,6 @@ Future<void> pangeaSSOLoginAction(
}
rethrow;
}
final token = Uri.parse(result).queryParameters['loginToken'];
if (token?.isEmpty ?? false) return;

View file

@ -8,7 +8,6 @@ import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pangea/login/utils/sso_login_action.dart';
import 'package:fluffychat/pangea/login/widgets/full_width_button.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
enum SSOProvider { google, apple }
@ -67,7 +66,6 @@ class PangeaSsoButton extends StatelessWidget {
id: provider.id,
name: provider.name,
),
Matrix.of(context).getLoginClient(),
context,
),
onError: (e, s) {

View file

@ -63,7 +63,7 @@ Future<void> _loginFuture({
identifier = AuthenticationUserIdentifier(user: username);
}
final client = matrix.getLoginClient();
final client = await matrix.getLoginClient();
final redirect = client.onLoginStateChanged.stream
.where((state) => state == LoginState.loggedIn)

View file

@ -1,153 +0,0 @@
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/login/login.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import '../../../widgets/matrix.dart';
extension PangeaPasswordForgotten on LoginController {
void pangeaPasswordForgotten() async {
final TextEditingController emailController = TextEditingController();
final TextEditingController newPasswordController = TextEditingController();
showDialog(
context: context,
useRootNavigator: false,
builder: (BuildContext context) => Scaffold(
backgroundColor: Colors.transparent,
body: AlertDialog(
title: Text(L10n.of(context).passwordForgotten),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.of(context).enterAnEmailAddress),
const SizedBox(height: 12),
TextField(
controller: emailController,
decoration: InputDecoration(
hintText: L10n.of(context).enterAnEmailAddress,
),
),
],
),
actions: [
TextButton(
child: Text(L10n.of(context).cancel),
onPressed: () {
Navigator.of(context).pop();
return;
},
),
TextButton(
child: Text(L10n.of(context).ok),
onPressed: () async {
if (emailController.text == "") return;
final clientSecret =
DateTime.now().millisecondsSinceEpoch.toString();
final response = await showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context)
.getLoginClient()
.requestTokenToResetPasswordEmail(
clientSecret,
emailController.text,
LoginController.sendAttempt++,
),
);
if (response.error != null) {
return;
}
Navigator.of(context).pop();
showDialog(
context: context,
useRootNavigator: false,
builder: (BuildContext context) => Scaffold(
backgroundColor: Colors.transparent,
body: AlertDialog(
title: Text(L10n.of(context).passwordForgotten),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.of(context).chooseAStrongPassword),
const SizedBox(height: 12),
TextField(
obscureText: true,
controller: newPasswordController,
decoration: const InputDecoration(
hintText: "******",
),
),
],
),
actions: [
TextButton(
child: Text(L10n.of(context).cancel),
onPressed: () {
Navigator.of(context).pop();
return;
},
),
TextButton(
child: Text(L10n.of(context).ok),
onPressed: () async {
if (newPasswordController.text == "") return;
final ok = await showOkAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context).weSentYouAnEmail,
// #Pangea
// message: L10n.of(context).pleaseClickOnLink,
message: L10n.of(context).clickOnEmailLink,
// Pangea#
okLabel: L10n.of(context).iHaveClickedOnLink,
);
if (ok != OkCancelResult.ok) return;
final data = <String, dynamic>{
'new_password': newPasswordController.text,
'logout_devices': false,
"auth": AuthenticationThreePidCreds(
type: AuthenticationTypes.emailIdentity,
threepidCreds: ThreepidCreds(
sid: response.result!.sid,
clientSecret: clientSecret,
),
).toJson(),
};
final success = await showFutureLoadingDialog(
context: context,
future: () =>
Matrix.of(context).getLoginClient().request(
RequestType.POST,
'/client/r0/account/password',
data: data,
),
);
if (success.error == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
L10n.of(context).passwordHasBeenChanged,
),
),
);
usernameController.text = emailController.text;
passwordController.text =
newPasswordController.text;
login();
}
},
),
],
),
),
);
},
),
],
),
),
);
}
}

View file

@ -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;
}

View file

@ -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';
@ -47,7 +48,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(
@ -101,9 +102,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);
@ -132,7 +139,7 @@ abstract class ClientManager {
// Pangea#
},
logLevel: kReleaseMode ? Level.warning : Level.verbose,
databaseBuilder: flutterMatrixSdkDatabaseBuilder,
database: await flutterMatrixSdkDatabaseBuilder(clientName),
supportedLoginTypes: {
AuthenticationTypes.password,
AuthenticationTypes.sso,

View file

@ -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]

View file

@ -16,10 +16,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) {
@ -27,7 +27,7 @@ Future<DatabaseApi> flutterMatrixSdkDatabaseBuilder(Client client) async {
ErrorHandler.logError(
e: e,
s: s,
data: {"clientID": client.id},
data: {"clientID": clientName},
m: "Failed to open matrix sdk database. Openning fallback database.",
);
// Pangea#
@ -53,7 +53,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();
}
@ -77,10 +77,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();
@ -97,7 +97,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();
@ -109,7 +109,7 @@ Future<MatrixSdkDatabase> _constructDatabase(Client client) async {
// Pangea#
// migrate from potential previous SQLite database path to current one
await _migrateLegacyLocation(path, client.clientName);
await _migrateLegacyLocation(path, clientName);
// required for [getDatabasesPath]
databaseFactory = factory;
@ -139,8 +139,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,

View file

@ -80,9 +80,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) {
// #Pangea
currentBundle!.first!.homeserver =
@ -167,29 +164,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');
});
// #Pangea
candidate.homeserver = Uri.parse("https://${AppConfig.defaultHomeserver}");
// Pangea#

View file

@ -21,6 +21,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_vodozemac
)
set(PLUGIN_BUNDLED_LIBRARIES)

View file

@ -11,13 +11,17 @@ PODS:
- FlutterMacOS
- emoji_picker_flutter (0.0.1):
- FlutterMacOS
- file_picker (0.0.1):
- FlutterMacOS
- file_selector_macos (0.0.1):
- FlutterMacOS
- flutter_local_notifications (0.0.1):
- FlutterMacOS
- flutter_new_badger (0.0.1):
- FlutterMacOS
- flutter_secure_storage_macos (6.1.1):
- flutter_secure_storage_macos (6.1.3):
- FlutterMacOS
- flutter_vodozemac (0.0.1):
- FlutterMacOS
- flutter_web_auth_2 (3.0.0):
- FlutterMacOS
@ -26,8 +30,10 @@ PODS:
- WebRTC-SDK (= 125.6422.06)
- FlutterMacOS (1.0.0)
- geolocator_apple (1.2.0):
- Flutter
- FlutterMacOS
- just_audio (0.0.1):
- Flutter
- FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
@ -36,25 +42,24 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- record_darwin (1.0.0):
- Flutter
- record_macos (1.0.0):
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite (0.0.3):
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- SQLCipher (4.5.7):
- SQLCipher/standard (= 4.5.7)
- SQLCipher/common (4.5.7)
- SQLCipher/standard (4.5.7):
- SQLCipher (4.8.0):
- SQLCipher/standard (= 4.8.0)
- SQLCipher/common (4.8.0)
- SQLCipher/standard (4.8.0):
- SQLCipher/common
- sqlcipher_flutter_libs (0.0.1):
- FlutterMacOS
- SQLCipher (~> 4.5.7)
- SQLCipher (~> 4.8.0)
- url_launcher_macos (0.0.1):
- FlutterMacOS
- video_compress (0.3.0):
@ -75,22 +80,24 @@ DEPENDENCIES:
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
- dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`)
- emoji_picker_flutter (from `Flutter/ephemeral/.symlinks/plugins/emoji_picker_flutter/macos`)
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
- flutter_new_badger (from `Flutter/ephemeral/.symlinks/plugins/flutter_new_badger/macos`)
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
- flutter_vodozemac (from `Flutter/ephemeral/.symlinks/plugins/flutter_vodozemac/macos`)
- flutter_web_auth_2 (from `Flutter/ephemeral/.symlinks/plugins/flutter_web_auth_2/macos`)
- flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/macos`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
- geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/darwin`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- record_darwin (from `Flutter/ephemeral/.symlinks/plugins/record_darwin/macos`)
- record_macos (from `Flutter/ephemeral/.symlinks/plugins/record_macos/macos`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- sqlcipher_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlcipher_flutter_libs/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- video_compress (from `Flutter/ephemeral/.symlinks/plugins/video_compress/macos`)
@ -116,6 +123,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos
emoji_picker_flutter:
:path: Flutter/ephemeral/.symlinks/plugins/emoji_picker_flutter/macos
file_picker:
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
file_selector_macos:
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
flutter_local_notifications:
@ -124,6 +133,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_new_badger/macos
flutter_secure_storage_macos:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
flutter_vodozemac:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_vodozemac/macos
flutter_web_auth_2:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_web_auth_2/macos
flutter_webrtc:
@ -131,23 +142,23 @@ EXTERNAL SOURCES:
FlutterMacOS:
:path: Flutter/ephemeral
geolocator_apple:
:path: Flutter/ephemeral/.symlinks/plugins/geolocator_apple/macos
:path: Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin
just_audio:
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/darwin
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
pasteboard:
:path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
record_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/record_darwin/macos
record_macos:
:path: Flutter/ephemeral/.symlinks/plugins/record_macos/macos
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sqflite:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin
sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
sqlcipher_flutter_libs:
:path: Flutter/ephemeral/.symlinks/plugins/sqlcipher_flutter_libs/macos
url_launcher_macos:
@ -162,36 +173,38 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos
SPEC CHECKSUMS:
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f
emoji_picker_flutter: 533634326b1c5de9a181ba14b9758e6dfe967a20
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4
flutter_new_badger: 5e34f40142e994b2aaff32e94062189695ee025d
flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9
flutter_web_auth_2: 2e1dc2d2139973e4723c5286ce247dd590390d70
flutter_webrtc: d55fd3f5c75b42940b6b4b2cf376a5797398d1f8
app_links: afe860c55c7ef176cea7fb630a2b7d7736de591d
audio_session: eaca2512cf2b39212d724f35d11f46180ad3a33e
desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
dynamic_color: b820c000cc68df65e7ba7ff177cb98404ce56651
emoji_picker_flutter: b9d4f4d08bdf3168fa3827f1290d435083745a14
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
flutter_local_notifications: 7e5a17a1dbc00d83dc10d43c2c4c05f2ceed233c
flutter_new_badger: 6fe9bf7e42793a164032c21f164c0ad9985cd0f2
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
flutter_vodozemac: fd2ea9cb3e2a37beaac883a369811fbfe042fc53
flutter_web_auth_2: 62b08da29f15a20fa63f144234622a1488d45b65
flutter_webrtc: 377dbcebdde6fed0fc40de87bcaaa2bffcec9a88
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
geolocator_apple: 72a78ae3f3e4ec0db62117bd93e34523f5011d58
just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
record_darwin: df0a677188e5fed18472550298e675f19ddaffbe
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
SQLCipher: 5e6bfb47323635c8b657b1b27d25c5f1baf63bf5
sqlcipher_flutter_libs: db7047866b877c027b050bb808b5480c68955c5e
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
video_compress: c896234f100791b5fef7f049afa38f6d2ef7b42f
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
record_macos: 295d70bd5fb47145df78df7b80e6697cd18403c0
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
SQLCipher: 908f846ca79d74be4e1776b3b86c6ad9e6c0b04f
sqlcipher_flutter_libs: 72569ed27a3f8d3502571be15fdc3e28f8f8570c
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
video_compress: 752b161da855df2492dd1a8fa899743cc8fe9534
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497
WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db
window_to_front: 4cdc24ddd8461ad1a55fa06286d6a79d8b29e8d8
window_to_front: 9e76fd432e36700a197dac86a0011e49c89abe0a
PODFILE CHECKSUM: d0975b16fbdecb73b109d8fbc88aa77ffe4c7a8d

View file

@ -222,6 +222,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
build_cli_annotations:
dependency: transitive
description:
name: build_cli_annotations
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
url: "https://pub.dev"
source: hosted
version: "2.1.0"
cached_network_image:
dependency: "direct main"
description:
@ -852,14 +860,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter_olm:
dependency: "direct main"
description:
name: flutter_olm
sha256: "5e6211af8cba1abf7d1f92e543f6d573dfe6017fe4742e0d04ba84beab47f940"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_openssl_crypto:
dependency: "direct main"
description:
@ -876,6 +876,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.28"
flutter_rust_bridge:
dependency: transitive
description:
name: flutter_rust_bridge
sha256: b416ff56002789e636244fb4cc449f587656eff995e5a7169457eb0593fcaddb
url: "https://pub.dev"
source: hosted
version: "2.10.0"
flutter_secure_storage:
dependency: "direct main"
description:
@ -963,6 +971,14 @@ packages:
url: "https://github.com/famedly/flutter_typeahead.git"
source: git
version: "5.2.0"
flutter_vodozemac:
dependency: "direct main"
description:
name: flutter_vodozemac
sha256: e9a6257ccdefacd2bf0128fcf41086d809f05fb34e9a4ebe0f50e7e3ff4c0970
url: "https://pub.dev"
source: hosted
version: "0.2.0"
flutter_web_auth_2:
dependency: "direct main"
description:
@ -1511,11 +1527,11 @@ packages:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: "9e47d07f6c78c72b7ee7269497622ba1fce5c94a"
ref: merge-upstream
resolved-ref: "6c6cc5cec17a47e1da26b5cdef14a99301661b61"
url: "https://github.com/pangeachat/matrix-dart-sdk.git"
source: git
version: "0.40.2"
version: "1.0.1"
meta:
dependency: transitive
description:
@ -1580,14 +1596,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
olm:
dependency: transitive
description:
name: olm
sha256: "6a3fe1e5170b954dd9e4ba3b27513e6aa9b7591eb7bb0d7f6f32140b7f140c6f"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
open_file:
dependency: "direct main"
description:
@ -2770,6 +2778,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "15.0.0"
vodozemac:
dependency: transitive
description:
name: vodozemac
sha256: dba14017e042748fb22d270e8ab1d3e46965b89788dd3857dba938ec07571968
url: "https://pub.dev"
source: hosted
version: "0.2.0"
wakelock_plus:
dependency: "direct main"
description:

View file

@ -45,7 +45,6 @@ dependencies:
sdk: flutter
flutter_map: ^6.1.0
flutter_new_badger: ^1.1.1
flutter_olm: 2.0.0
flutter_openssl_crypto: ^0.5.0
flutter_secure_storage: ^9.2.4
flutter_shortcuts_new: ^2.0.0
@ -53,6 +52,7 @@ dependencies:
git:
url: https://github.com/famedly/flutter_typeahead.git
ref: main
flutter_vodozemac: ^0.2.0
flutter_web_auth_2: ^3.1.1 # Version 4 blocked by https://github.com/MixinNetwork/flutter-plugins/issues/379
flutter_webrtc: ^0.12.9
geolocator: ^13.0.1
@ -72,7 +72,7 @@ dependencies:
matrix:
git:
url: https://github.com/pangeachat/matrix-dart-sdk.git # repo
ref: main
ref: merge-upstream
# matrix: ^0.40.2
# Pangea#
mime: ^1.0.6
@ -218,4 +218,4 @@ dependency_overrides:
url: https://github.com/ThexXTURBOXx/flutter_web_auth_2.git
ref: 3.x-without-v1
path: flutter_web_auth_2
win32: 5.5.3
win32: 5.5.3

View file

@ -1,10 +1,9 @@
#!/bin/sh -ve
rm -rf assets/js/package
OLM_VERSION=$(cat pubspec.yaml | yq .dependencies.flutter_olm)
DOWNLOAD_PATH="https://github.com/famedly/olm/releases/download/v$OLM_VERSION/olm.zip"
cd assets/js/ && curl -L $DOWNLOAD_PATH > olm.zip && cd ../../
cd assets/js/ && unzip olm.zip && cd ../../
cd assets/js/ && rm olm.zip && cd ../../
cd assets/js/ && mv javascript package && cd ../../
git clone https://github.com/famedly/dart-vodozemac.git .vodozemac
cd .vodozemac
cargo install flutter_rust_bridge_codegen
flutter_rust_bridge_codegen build-web --dart-root dart --rust-root $(readlink -f rust) --release
cd ..
mv .vodozemac/dart/web/pkg ./web/
rm -rf .vodozemac

View file

@ -2,8 +2,7 @@
import 'package:matrix/encryption/utils/key_verification.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
Future<Client> prepareTestClient({
bool loggedIn = false,
@ -22,7 +21,11 @@ Future<Client> prepareTestClient({
importantStateEvents: <String>{
'im.ponies.room_emotes', // we want emotes to work properly
},
databaseBuilder: flutterMatrixSdkDatabaseBuilder,
database: await MatrixSdkDatabase.init(
'test',
database: await databaseFactoryFfi.openDatabase(':memory:'),
sqfliteFactory: databaseFactoryFfi,
),
supportedLoginTypes: {
AuthenticationTypes.password,
AuthenticationTypes.sso,

View file

@ -25,6 +25,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_vodozemac
)
set(PLUGIN_BUNDLED_LIBRARIES)