1814 add future loading dialog to prevent user interaction during signup login loading (#1866)

* chore: updates for running on android for flutter 3.29.0

* feat: show future loading dialog on signup and login

* chore: enable build on iOS for flutter 3.29.0
This commit is contained in:
ggurdin 2025-02-20 13:23:21 -05:00 committed by GitHub
parent e591ce3a4d
commit 33208aa30c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 505 additions and 890 deletions

View file

@ -51,7 +51,7 @@ post_install do |installer|
config.build_settings['ENABLE_BITCODE'] = 'NO'
# see https://github.com/flutter-webrtc/flutter-webrtc/issues/1054
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = 'arm64 i386'
config.build_settings["CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES"] = 'YES'

View file

@ -48,6 +48,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View file

@ -4,14 +4,14 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:app_links/app_links.dart';
import 'package:cross_file/cross_file.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_shortcuts/flutter_shortcuts.dart';
import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:uni_links/uni_links.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
@ -38,13 +38,12 @@ import 'package:fluffychat/widgets/share_scaffold_dialog.dart';
import '../../../utils/account_bundles.dart';
import '../../config/setting_keys.dart';
import '../../utils/url_launcher.dart';
import '../../utils/voip/callkeep_manager.dart';
import '../../widgets/fluffy_chat_app.dart';
import '../../widgets/matrix.dart';
import 'package:fluffychat/utils/tor_stub.dart'
if (dart.library.html) 'package:tor_detector_web/tor_detector_web.dart';
enum PopupMenuAction {
settings,
invite,
@ -184,23 +183,20 @@ class ChatListController extends State<ChatList>
case ActiveFilter.messages:
return (room) =>
!room.isSpace &&
room.isDirectChat
// #Pangea
room.isDirectChat // #Pangea
&&
!room.isAnalyticsRoom;
// Pangea#
case ActiveFilter.groups:
return (room) =>
!room.isSpace &&
!room.isDirectChat
// #Pangea
!room.isDirectChat // #Pangea
&&
!room.isAnalyticsRoom;
// Pangea#
case ActiveFilter.unread:
return (room) =>
room.isUnreadOrInvited
// #Pangea
room.isUnreadOrInvited // #Pangea
&&
!room.isAnalyticsRoom;
// Pangea#
@ -405,11 +401,11 @@ class ChatListController extends State<ChatList>
);
}
void _processIncomingUris(String? text) async {
if (text == null) return;
void _processIncomingUris(Uri? uri) async {
if (uri == null) return;
context.go('/rooms');
WidgetsBinding.instance.addPostFrameCallback((_) {
UrlLauncher(context, text).openMatrixToUrl();
UrlLauncher(context, uri.toString()).openMatrixToUrl();
});
}
@ -427,11 +423,8 @@ class ChatListController extends State<ChatList>
.then(_processIncomingSharedMedia);
// For receiving shared Uris
_intentUriStreamSubscription = linkStream.listen(_processIncomingUris);
if (FluffyChatApp.gotInitialLink == false) {
FluffyChatApp.gotInitialLink = true;
getInitialLink().then(_processIncomingUris);
}
_intentUriStreamSubscription =
AppLinks().uriLinkStream.listen(_processIncomingUris);
if (PlatformInfos.isAndroid) {
final shortcuts = FlutterShortcuts();
@ -459,7 +452,6 @@ class ChatListController extends State<ChatList>
scrollController.addListener(_onScroll);
_waitForFirstSync();
_hackyWebRTCFixForWeb();
CallKeepManager().initialize();
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (mounted) {
searchServer =
@ -851,7 +843,6 @@ class ChatListController extends State<ChatList>
return;
case ChatContextAction.leave:
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context).areYouSure,
// #Pangea

View file

@ -6,7 +6,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
import 'package:fluffychat/pangea/spaces/utils/space_code.dart';
import 'package:fluffychat/pangea/user/utils/logout.dart';
import 'package:fluffychat/pangea/user/utils/p_logout.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';

View file

@ -3,20 +3,17 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/login/pages/pangea_login_view.dart';
import 'package:fluffychat/pangea/login/widgets/p_sso_button.dart';
import 'package:fluffychat/pangea/user/utils/p_login.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../utils/platform_infos.dart';
class Login extends StatefulWidget {
const Login({super.key});
@ -28,30 +25,26 @@ class Login extends StatefulWidget {
class LoginController extends State<Login> {
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
String? usernameText;
String? passwordText;
String? usernameError;
String? passwordError;
bool loading = false;
bool showPassword = false;
void toggleShowPassword() =>
setState(() => showPassword = !loading && !showPassword);
// #Pangea
bool loadingSignIn = false;
bool loadingAppleSSO = false;
bool loadingGoogleSSO = false;
String? appleSSOError;
String? googleSSOError;
bool showPassword = false;
// #Pangea
final PangeaController pangeaController = MatrixState.pangeaController;
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
bool get enabledSignIn =>
!loadingSignIn &&
usernameText != null &&
usernameText!.isNotEmpty &&
passwordText != null &&
passwordText!.isNotEmpty;
usernameController.text.isNotEmpty &&
passwordController.text.isNotEmpty;
@override
void initState() {
@ -70,15 +63,8 @@ class LoginController extends State<Login> {
});
});
usernameController.addListener(() {
_setStateOnTextChange(usernameText, usernameController.text);
usernameText = usernameController.text;
});
passwordController.addListener(() {
_setStateOnTextChange(passwordText, passwordController.text);
passwordText = passwordController.text;
});
usernameController.addListener(() => setState(() {}));
passwordController.addListener(() => setState(() {}));
}
@override
@ -91,15 +77,10 @@ class LoginController extends State<Login> {
super.dispose();
}
void setSSOError(String? error, SSOProvider provider) {
if (provider == SSOProvider.apple) {
appleSSOError = error;
googleSSOError = null;
} else if (provider == SSOProvider.google) {
googleSSOError = error;
appleSSOError = null;
void setLoadingSignIn(bool loading) {
if (mounted) {
setState(() => loadingSignIn = loading);
}
if (mounted) setState(() {});
}
void setLoadingSSO(bool loading, SSOProvider provider) {
@ -113,121 +94,67 @@ class LoginController extends State<Login> {
if (mounted) setState(() {});
}
void _setStateOnTextChange(String? oldText, String newText) {
if ((oldText == null || oldText.isEmpty) && (newText.isNotEmpty)) {
setState(() {});
}
if ((oldText != null && oldText.isNotEmpty) && (newText.isEmpty)) {
setState(() {});
}
}
void login() async => pLoginAction(controller: this, context: context);
// void login() async {
// final matrix = Matrix.of(context);
// if (usernameController.text.isEmpty) {
// setState(() => usernameError = L10n.of(context).pleaseEnterYourUsername);
// } else {
// setState(() => usernameError = null);
// }
// if (passwordController.text.isEmpty) {
// setState(() => passwordError = L10n.of(context).pleaseEnterYourPassword);
// } else {
// setState(() => passwordError = null);
// }
// if (usernameController.text.isEmpty || passwordController.text.isEmpty) {
// return;
// }
// setState(() => loading = true);
// _coolDown?.cancel();
// try {
// final username = usernameController.text;
// AuthenticationIdentifier identifier;
// if (username.isEmail) {
// identifier = AuthenticationThirdPartyIdentifier(
// medium: 'email',
// address: username,
// );
// } else if (username.isPhoneNumber) {
// identifier = AuthenticationThirdPartyIdentifier(
// medium: 'msisdn',
// address: username,
// );
// } 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,
// );
// } on MatrixException catch (exception) {
// setState(() => passwordError = exception.errorMessage);
// return setState(() => loading = false);
// } catch (exception) {
// setState(() => passwordError = exception.toString());
// return setState(() => loading = false);
// }
// if (mounted) setState(() => loading = false);
// }
// Pangea#
void toggleShowPassword() =>
setState(() => showPassword = !loadingSignIn && !showPassword);
void login() async {
// #Pangea
final valid = formKey.currentState!.validate();
if (!valid) return;
// Pangea#
final matrix = Matrix.of(context);
if (usernameController.text.isEmpty) {
setState(() => usernameError = L10n.of(context).pleaseEnterYourUsername);
} else {
setState(() => usernameError = null);
}
if (passwordController.text.isEmpty) {
setState(() => passwordError = L10n.of(context).pleaseEnterYourPassword);
} else {
setState(() => passwordError = null);
}
if (usernameController.text.isEmpty || passwordController.text.isEmpty) {
return;
}
setState(() => loadingSignIn = true);
_coolDown?.cancel();
try {
// #Pangea
String username = usernameController.text.trim();
if (RegExp(r'^@(\w+):').hasMatch(username)) {
username =
RegExp(r'^@(\w+):').allMatches(username).elementAt(0).group(1)!;
}
// Pangea#
AuthenticationIdentifier identifier;
if (username.isEmail) {
identifier = AuthenticationThirdPartyIdentifier(
medium: 'email',
address: username,
);
} else if (username.isPhoneNumber) {
identifier = AuthenticationThirdPartyIdentifier(
medium: 'msisdn',
address: username,
);
} else {
identifier = AuthenticationUserIdentifier(user: username);
}
// #Pangea
// await matrix.getLoginClient().login(
final loginRes = await matrix.getLoginClient().login(
// Pangea#
LoginType.mLoginPassword,
identifier: identifier,
// To stay compatible with older server versions
// ignore: deprecated_member_use
user: identifier.type == AuthenticationIdentifierTypes.userId
? username
: null,
// #Pangea
// password: passwordController.text,
password: passwordController.text.trim(),
// Pangea#
initialDeviceDisplayName: PlatformInfos.clientName,
// #Pangea
onInitStateChanged: (state) {
if (state == InitState.settingUpEncryption) {
context.go("/rooms");
}
},
// Pangea#
);
MatrixState.pangeaController.pStoreService
.save(PLocalKey.loginType, 'password');
// #Pangea
GoogleAnalytics.login("pangea", loginRes.userId);
// Pangea#
} on MatrixException catch (exception) {
// #Pangea
// setState(() => passwordError = exception.errorMessage);
setState(() {
passwordError = exception.errorMessage;
usernameError = exception.errorMessage;
});
// Pangea#
return setState(() => loadingSignIn = false);
} catch (exception) {
// #Pangea
// setState(() => passwordError = exception.toString());
setState(() {
passwordError = exception.toString();
usernameError = exception.toString();
});
// Pangea#
return setState(() => loadingSignIn = false);
}
// #Pangea
// if (mounted) setState(() => loading = false);
// Pangea#
}
Timer? _coolDown;
void checkWellKnownWithCoolDown(String userId) async {
@ -381,7 +308,10 @@ class LoginController extends State<Login> {
// Pangea#
}
extension on String {
// #Pangea
// extension on String {
extension LoginExtension on String {
// Pangea#
static final RegExp _phoneRegex =
RegExp(r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$');
static final RegExp _emailRegex = RegExp(r'(.+)@(.+)\.(.+)');

View file

@ -4,7 +4,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
class QrScannerModal extends StatefulWidget {
final void Function(String) onScan;
@ -72,10 +72,4 @@ class QrScannerModalState extends State<QrScannerModal> {
if (data != null) widget.onScan(data);
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}

View file

@ -5,7 +5,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/user/utils/logout.dart';
import 'package:fluffychat/pangea/user/utils/p_logout.dart';
import 'package:fluffychat/utils/file_selector.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';

View file

@ -29,9 +29,6 @@ class PangeaLoginView extends StatelessWidget {
return null;
},
controller: controller.usernameController,
errorText: controller.usernameError,
showErrorText: controller.usernameError != null &&
controller.passwordError == null,
),
FullWidthTextField(
hintText: L10n.of(context).password,
@ -47,7 +44,6 @@ class PangeaLoginView extends StatelessWidget {
return null;
},
controller: controller.passwordController,
errorText: controller.passwordError,
),
FullWidthButton(
title: L10n.of(context).signIn,
@ -93,17 +89,13 @@ class PangeaLoginView extends StatelessWidget {
provider: SSOProvider.google,
title: L10n.of(context).signInWithGoogle,
loading: controller.loadingGoogleSSO,
error: controller.googleSSOError,
setLoading: controller.setLoadingSSO,
setError: controller.setSSOError,
),
PangeaSsoButton(
provider: SSOProvider.apple,
title: L10n.of(context).signInWithApple,
loading: controller.loadingAppleSSO,
error: controller.appleSSOError,
setLoading: controller.setLoadingSSO,
setError: controller.setSSOError,
),
],
),

View file

@ -3,13 +3,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix_api_lite/model/matrix_exception.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/login/pages/signup_view.dart';
import 'package:fluffychat/pangea/login/pages/signup_with_email_view.dart';
import 'package:fluffychat/pangea/login/widgets/p_sso_button.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
class SignupPage extends StatefulWidget {
@ -32,12 +31,9 @@ class SignupPageController extends State<SignupPage> {
String? passwordText;
String? emailText;
String? error;
bool loadingSignup = false;
bool loadingAppleSSO = false;
bool loadingGoogleSSO = false;
String? appleSSOError;
String? googleSSOError;
bool showPassword = false;
bool noEmailWarningConfirmed = false;
@ -69,21 +65,9 @@ class SignupPageController extends State<SignupPage> {
passwordController.dispose();
emailController.dispose();
loadingSignup = false;
error = null;
super.dispose();
}
void setSSOError(String? error, SSOProvider provider) {
if (provider == SSOProvider.apple) {
appleSSOError = error;
googleSSOError = null;
} else if (provider == SSOProvider.google) {
googleSSOError = error;
appleSSOError = null;
}
if (mounted) setState(() {});
}
void setLoadingSSO(bool loading, SSOProvider provider) {
if (provider == SSOProvider.apple) {
loadingAppleSSO = loading;
@ -149,13 +133,8 @@ class SignupPageController extends State<SignupPage> {
}
String? emailTextFieldValidator(String? value) {
// #Pangea
if (value == null || value.isEmpty) {
// if (value!.isEmpty && !noEmailWarningConfirmed) {
// noEmailWarningConfirmed = true;
// return L10n.of(context).noEmailWarning;
return L10n.of(context).pleaseEnterEmail;
// Pangea#
}
if (value.isNotEmpty && !value.contains('@')) {
return L10n.of(context).pleaseEnterValidEmail;
@ -172,83 +151,63 @@ class SignupPageController extends State<SignupPage> {
}
void signup([_]) async {
setState(() {
error = null;
});
setState(() => signupError = null);
final valid = formKey.currentState!.validate();
if (!isTnCChecked) {
setState(() {
signupError = L10n.of(context).pleaseAgreeToTOS;
});
}
if (!valid || !isTnCChecked) {
return;
setState(() => signupError = L10n.of(context).pleaseAgreeToTOS);
}
if (!valid || !isTnCChecked) return;
setState(() => loadingSignup = true);
setState(() {
loadingSignup = true;
});
await showFutureLoadingDialog(
context: context,
future: _signupFuture,
onError: (e, s) {
setState(() {
loadingSignup = false;
loadingAppleSSO = false;
loadingGoogleSSO = false;
});
return e is MatrixException
? e.errorMessage
: L10n.of(context).oopsSomethingWentWrong;
},
);
}
try {
final client = Matrix.of(context).getLoginClient();
final email = emailController.text;
if (email.isNotEmpty) {
Matrix.of(context).currentClientSecret =
DateTime.now().millisecondsSinceEpoch.toString();
Matrix.of(context).currentThreepidCreds =
await client.requestTokenToRegisterEmail(
Matrix.of(context).currentClientSecret,
email,
0,
);
}
final displayname = usernameController.text;
final localPart = displayname.toLowerCase().replaceAll(' ', '_');
final registerRes = await client.uiaRequestBackground(
(auth) => client.register(
username: localPart,
password: passwordController.text,
initialDeviceDisplayName: PlatformInfos.clientName,
auth: auth,
),
Future<void> _signupFuture() async {
final client = Matrix.of(context).getLoginClient();
final email = emailController.text;
if (email.isNotEmpty) {
Matrix.of(context).currentClientSecret =
DateTime.now().millisecondsSinceEpoch.toString();
Matrix.of(context).currentThreepidCreds =
await client.requestTokenToRegisterEmail(
Matrix.of(context).currentClientSecret,
email,
0,
);
}
GoogleAnalytics.login("pangea", registerRes.userId);
final displayname = usernameController.text;
final localPart = displayname.toLowerCase().replaceAll(' ', '_');
if (displayname != localPart && client.userID != null) {
await client.setDisplayName(
client.userID!,
displayname,
);
}
} on MatrixException catch (e, s) {
if (e.error != MatrixError.M_THREEPID_IN_USE) {
ErrorHandler.logError(
e: e,
s: s,
data: {},
);
}
error = e.errorMessage;
} catch (e, s) {
const cancelledString = "Exception: Request has been canceled";
if (e.toString() != cancelledString) {
ErrorHandler.logError(
e: e,
s: s,
data: {},
);
}
final registerRes = await client.uiaRequestBackground(
(auth) => client.register(
username: localPart,
password: passwordController.text,
initialDeviceDisplayName: PlatformInfos.clientName,
auth: auth,
),
);
if (mounted) {
error = (e).toLocalizedString(context);
}
} finally {
if (mounted) {
setState(() => loadingSignup = false);
}
GoogleAnalytics.login("pangea", registerRes.userId);
if (displayname != localPart && client.userID != null) {
await client.setDisplayName(
client.userID!,
displayname,
);
}
}

View file

@ -30,18 +30,14 @@ class SignupPageView extends StatelessWidget {
PangeaSsoButton(
provider: SSOProvider.google,
title: L10n.of(context).signUpWithGoogle,
setError: controller.setSSOError,
setLoading: controller.setLoadingSSO,
loading: controller.loadingGoogleSSO,
error: controller.googleSSOError,
),
PangeaSsoButton(
provider: SSOProvider.apple,
title: L10n.of(context).signUpWithApple,
setError: controller.setSSOError,
setLoading: controller.setLoadingSSO,
loading: controller.loadingAppleSSO,
error: controller.appleSSOError,
),
],
);

View file

@ -58,7 +58,6 @@ class SignupWithEmailView extends StatelessWidget {
forceColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: controller.enableSignUp ? controller.signup : null,
error: controller.error,
loading: controller.loadingSignup,
enabled: controller.enableSignUp,
),

View file

@ -5,9 +5,9 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:matrix/matrix_api_lite/model/matrix_exception.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.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 }
@ -46,53 +46,43 @@ class PangeaSsoButton extends StatelessWidget {
final SSOProvider provider;
final Function(bool, SSOProvider) setLoading;
final Function(String?, SSOProvider) setError;
final bool loading;
final String? error;
const PangeaSsoButton({
required this.title,
required this.provider,
required this.setLoading,
required this.setError,
this.loading = false,
this.error,
super.key,
});
Future<void> _runSSOLogin(BuildContext context) async {
try {
setLoading(true, provider);
setError(null, provider);
await pangeaSSOLoginAction(
setLoading(true, provider);
await showFutureLoadingDialog(
context: context,
future: () async => pangeaSSOLoginAction(
IdentityProvider(
id: provider.id,
name: provider.name,
),
Matrix.of(context).getLoginClient(),
context,
);
} catch (err, s) {
ErrorHandler.logError(
e: err,
s: s,
data: {},
);
final error = err is MatrixException
? err.errorMessage
: L10n.of(context).oopsSomethingWentWrong;
setError(error, provider);
} finally {
setLoading(false, provider);
}
),
onError: (e, s) {
setLoading(false, provider);
return e is MatrixException
? e.errorMessage
: L10n.of(context).oopsSomethingWentWrong;
},
onDismiss: () => setLoading(false, provider),
);
setLoading(false, provider);
}
@override
Widget build(BuildContext context) {
return FullWidthButton(
depressed: loading,
error: error,
loading: loading,
title: title,
icon: SvgPicture.asset(

View file

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/login/login.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/login/widgets/p_sso_button.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
void pLoginAction({
required LoginController controller,
required BuildContext context,
}) async {
final valid = controller.formKey.currentState!.validate();
if (!valid) return;
await showFutureLoadingDialog(
context: context,
future: () => _loginFuture(
controller: controller,
context: context,
),
onError: (e, s) {
controller.setLoadingSignIn(false);
controller.setLoadingSSO(false, SSOProvider.apple);
controller.setLoadingSSO(false, SSOProvider.google);
return e is MatrixException
? e.errorMessage
: L10n.of(context).oopsSomethingWentWrong;
},
);
}
Future<void> _loginFuture({
required LoginController controller,
required BuildContext context,
}) async {
final matrix = Matrix.of(context);
controller.setLoadingSignIn(true);
String username = controller.usernameController.text.trim();
if (RegExp(r'^@(\w+):').hasMatch(username)) {
username = RegExp(r'^@(\w+):').allMatches(username).elementAt(0).group(1)!;
}
AuthenticationIdentifier identifier;
if (username.isEmail) {
identifier = AuthenticationThirdPartyIdentifier(
medium: 'email',
address: username,
);
} else if (username.isPhoneNumber) {
identifier = AuthenticationThirdPartyIdentifier(
medium: 'msisdn',
address: username,
);
} else {
identifier = AuthenticationUserIdentifier(user: username);
}
final loginRes = 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: controller.passwordController.text.trim(),
initialDeviceDisplayName: PlatformInfos.clientName,
onInitStateChanged: (state) {
if (state == InitState.settingUpEncryption) {
context.go("/rooms");
}
},
);
MatrixState.pangeaController.pStoreService
.save(PLocalKey.loginType, 'password');
GoogleAnalytics.login("pangea", loginRes.userId);
}

View file

@ -11,10 +11,7 @@ void pLogoutAction(BuildContext context, {bool? isDestructiveAction}) async {
useRootNavigator: false,
context: context,
title: L10n.of(context).areYouSureYouWantToLogout,
// #Pangea
// message: L10n.of(context).noBackupWarning,
message: L10n.of(context).dontForgetPassword,
// Pangea#
okLabel: L10n.of(context).logout,
cancelLabel: L10n.of(context).cancel,
) ==

View file

@ -27,9 +27,9 @@ import 'package:flutter/material.dart';
import 'package:fcm_shared_isolate/fcm_shared_isolate.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_app_badger/flutter_app_badger.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_new_badger/flutter_new_badger.dart';
import 'package:http/http.dart' as http;
import 'package:matrix/matrix.dart';
import 'package:unifiedpush/unifiedpush.dart';
@ -203,9 +203,9 @@ class BackgroundPush {
.where((room) => room.isUnreadOrInvited && room.id != roomId)
.length;
if (unreadCount == 0) {
FlutterAppBadger.removeBadge();
FlutterNewBadger.removeBadge();
} else {
FlutterAppBadger.updateBadgeCount(unreadCount);
FlutterNewBadger.setBadge(unreadCount);
}
return;
}
@ -222,7 +222,8 @@ class BackgroundPush {
// Pangea#
if (PlatformInfos.isIOS) {
await firebase?.requestPermission();
} else if (PlatformInfos.isAndroid) {
}
if (PlatformInfos.isAndroid) {
_flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
@ -237,7 +238,6 @@ class BackgroundPush {
);
}
// Pangea#
final clientName = PlatformInfos.clientName;
oldTokens ??= <String>{};
final pushers = await (client.getPushers().catchError((e) {

View file

@ -1,20 +0,0 @@
import 'package:flutter_app_badger/flutter_app_badger.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/platform_infos.dart';
extension IosBadgeClientExtension on Client {
void updateIosBadge() {
if (PlatformInfos.isIOS) {
// Workaround for iOS not clearing notifications with fcm_shared_isolate
if (!rooms.any(
(r) => r.membership == Membership.invite || (r.notificationCount > 0),
)) {
// ignore: unawaited_futures
FlutterLocalNotificationsPlugin().cancelAll();
FlutterAppBadger.removeBadge();
}
}
}
}

View file

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_shortcuts/flutter_shortcuts.dart';
import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart';
import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -16,7 +16,6 @@ import 'package:fluffychat/utils/client_download_content_extension.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/voip/callkeep_manager.dart';
Future<void> pushHelper(
PushNotification notification, {
@ -121,9 +120,7 @@ Future<void> _tryPushHelper(
client.backgroundSync = true;
}
if (event.type == EventTypes.CallInvite) {
CallKeepManager().initialize();
} else if (event.type == EventTypes.CallHangup) {
if (event.type == EventTypes.CallHangup) {
client.backgroundSync = false;
}

View file

@ -1,325 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:callkeep/callkeep.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:permission_handler/permission_handler.dart';
class CallKeeper {
CallKeeper(this.callKeepManager, this.call) {
call.onCallStateChanged.stream.listen(_handleCallState);
}
CallKeepManager callKeepManager;
bool? held = false;
bool? muted = false;
bool connected = false;
CallSession call;
// update native caller to show what remote user has done.
void _handleCallState(CallState state) {
Logs().i('CallKeepManager::handleCallState: ${state.toString()}');
switch (state) {
case CallState.kConnecting:
Logs().v('callkeep connecting');
break;
case CallState.kConnected:
Logs().v('callkeep connected');
if (!connected) {
callKeepManager.answer(call.callId);
} else {
callKeepManager.setMutedCall(call.callId, false);
callKeepManager.setOnHold(call.callId, false);
}
break;
case CallState.kEnded:
callKeepManager.hangup(call.callId);
break;
case CallState.kFledgling:
case CallState.kInviteSent:
case CallState.kWaitLocalMedia:
case CallState.kCreateOffer:
case CallState.kCreateAnswer:
case CallState.kRinging:
case CallState.kEnding:
break;
}
}
}
Map<String?, CallKeeper> calls = <String?, CallKeeper>{};
class CallKeepManager {
factory CallKeepManager() {
return _instance;
}
CallKeepManager._internal() {
_callKeep = FlutterCallkeep();
}
static final CallKeepManager _instance = CallKeepManager._internal();
late FlutterCallkeep _callKeep;
String get appName => 'FluffyChat';
Future<bool> get hasPhoneAccountEnabled async =>
await _callKeep.hasPhoneAccount();
Map<String, dynamic> get alertOptions => <String, dynamic>{
'alertTitle': 'Permissions required',
'alertDescription':
'Allow $appName to register as a calling account? This will allow calls to be handled by the native android dialer.',
'cancelButton': 'Cancel',
'okButton': 'ok',
// Required to get audio in background when using Android 11
'foregroundService': {
'channelId': 'com.fluffy.fluffychat',
'channelName': 'Foreground service for my app',
'notificationTitle': '$appName is running on background',
'notificationIcon': 'mipmap/ic_notification_launcher',
},
'additionalPermissions': [''],
};
bool setupDone = false;
Future<void> showCallkitIncoming(CallSession call) async {
if (!setupDone) {
await _callKeep.setup(
null,
<String, dynamic>{
'ios': <String, dynamic>{
'appName': appName,
},
'android': alertOptions,
},
backgroundMode: true,
);
}
setupDone = true;
await displayIncomingCall(call);
call.onCallStateChanged.stream.listen((state) {
if (state == CallState.kEnded) {
_callKeep.endAllCalls();
}
});
call.onCallEventChanged.stream.listen(
(event) {
if (event == CallStateChange.kLocalHoldUnhold) {
Logs().i(
'Call hold event: local ${call.localHold}, remote ${call.remoteOnHold}',
);
}
},
);
}
void removeCall(String? callUUID) {
calls.remove(callUUID);
}
void addCall(String? callUUID, CallKeeper callKeeper) {
if (calls.containsKey(callUUID)) return;
calls[callUUID] = callKeeper;
}
void setCallHeld(String? callUUID, bool? held) {
calls[callUUID]!.held = held;
}
void setCallMuted(String? callUUID, bool? muted) {
calls[callUUID]!.muted = muted;
}
void didDisplayIncomingCall(CallKeepDidDisplayIncomingCall event) {
final callUUID = event.callUUID;
final number = event.handle;
Logs().v('[displayIncomingCall] $callUUID number: $number');
// addCall(callUUID, CallKeeper(this null));
}
void onPushKitToken(CallKeepPushKitToken event) {
Logs().v('[onPushKitToken] token => ${event.token}');
}
Future<void> initialize() async {
_callKeep.on(CallKeepPerformAnswerCallAction(), answerCall);
_callKeep.on(CallKeepDidPerformDTMFAction(), didPerformDTMFAction);
_callKeep.on(CallKeepDidToggleHoldAction(), didToggleHoldCallAction);
_callKeep.on(
CallKeepDidPerformSetMutedCallAction(),
didPerformSetMutedCallAction,
);
_callKeep.on(CallKeepPerformEndCallAction(), endCall);
_callKeep.on(CallKeepPushKitToken(), onPushKitToken);
_callKeep.on(CallKeepDidDisplayIncomingCall(), didDisplayIncomingCall);
Logs().i('[VOIP] Initialized');
}
Future<void> hangup(String callUUID) async {
await _callKeep.endCall(callUUID);
removeCall(callUUID);
}
Future<void> reject(String callUUID) async {
await _callKeep.rejectCall(callUUID);
}
Future<void> answer(String? callUUID) async {
final keeper = calls[callUUID]!;
if (!keeper.connected) {
await _callKeep.answerIncomingCall(callUUID!);
keeper.connected = true;
}
}
Future<void> setOnHold(String callUUID, bool held) async {
await _callKeep.setOnHold(callUUID, held);
setCallHeld(callUUID, held);
}
Future<void> setMutedCall(String callUUID, bool muted) async {
await _callKeep.setMutedCall(callUUID, muted);
setCallMuted(callUUID, muted);
}
Future<void> updateDisplay(String callUUID) async {
// Workaround because Android doesn't display well displayName, se we have to switch ...
if (isIOS) {
await _callKeep.updateDisplay(
callUUID,
displayName: 'New Name',
handle: callUUID,
);
} else {
await _callKeep.updateDisplay(
callUUID,
displayName: callUUID,
handle: 'New Name',
);
}
}
Future<CallKeeper> displayIncomingCall(CallSession call) async {
final callKeeper = CallKeeper(this, call);
addCall(call.callId, callKeeper);
await _callKeep.displayIncomingCall(
call.callId,
'${call.room.getLocalizedDisplayname()} (FluffyChat)',
localizedCallerName:
'${call.room.getLocalizedDisplayname()} (FluffyChat)',
handleType: 'number',
hasVideo: call.type == CallType.kVideo,
);
return callKeeper;
}
Future<void> checkoutPhoneAccountSetting(BuildContext context) async {
showDialog(
context: context,
barrierDismissible: true,
useRootNavigator: false,
builder: (_) => AlertDialog(
title: Text(L10n.of(context).callingPermissions),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
onTap: () => openCallingAccountsPage(context),
title: Text(L10n.of(context).callingAccount),
subtitle: Text(L10n.of(context).callingAccountDetails),
trailing: const Icon(Icons.phone),
),
const Divider(),
ListTile(
onTap: () => FlutterForegroundTask.openSystemAlertWindowSettings(
forceOpen: true,
),
title: Text(L10n.of(context).appearOnTop),
subtitle: Text(L10n.of(context).appearOnTopDetails),
trailing: const Icon(Icons.file_upload_rounded),
),
const Divider(),
ListTile(
onTap: () => openAppSettings(),
title: Text(L10n.of(context).otherCallingPermissions),
trailing: const Icon(Icons.mic),
),
],
),
),
);
}
void openCallingAccountsPage(BuildContext context) async {
await _callKeep.setup(context, <String, dynamic>{
'ios': <String, dynamic>{
'appName': appName,
},
'android': alertOptions,
});
final hasPhoneAccount = await _callKeep.hasPhoneAccount();
Logs().e(hasPhoneAccount.toString());
if (!hasPhoneAccount) {
await _callKeep.hasDefaultPhoneAccount(context, alertOptions);
} else {
await _callKeep.openPhoneAccounts();
}
}
/// CallActions.
Future<void> answerCall(CallKeepPerformAnswerCallAction event) async {
final callUUID = event.callUUID;
final keeper = calls[event.callUUID]!;
if (!keeper.connected) {
Logs().e('answered');
// Answer Call
keeper.call.answer();
keeper.connected = true;
}
Timer(const Duration(seconds: 1), () {
_callKeep.setCurrentCallActive(callUUID!);
});
}
Future<void> endCall(CallKeepPerformEndCallAction event) async {
final keeper = calls[event.callUUID];
keeper?.call.hangup(reason: CallErrorCode.userHangup);
removeCall(event.callUUID);
}
Future<void> didPerformDTMFAction(CallKeepDidPerformDTMFAction event) async {
final keeper = calls[event.callUUID]!;
keeper.call.sendDTMF(event.digits!);
}
Future<void> didPerformSetMutedCallAction(
CallKeepDidPerformSetMutedCallAction event,
) async {
final keeper = calls[event.callUUID];
if (event.muted!) {
keeper!.call.setMicrophoneMuted(true);
} else {
keeper!.call.setMicrophoneMuted(false);
}
setCallMuted(event.callUUID, event.muted);
}
Future<void> didToggleHoldCallAction(
CallKeepDidToggleHoldAction event,
) async {
final keeper = calls[event.callUUID];
if (event.hold!) {
keeper!.call.setRemoteOnHold(true);
} else {
keeper!.call.setRemoteOnHold(false);
}
setCallHeld(event.callUUID, event.hold);
}
}

View file

@ -1,10 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:just_audio/just_audio.dart';
import 'package:fluffychat/utils/platform_infos.dart';
class UserMediaManager {
factory UserMediaManager() {
return _instance;
@ -16,25 +11,16 @@ class UserMediaManager {
AudioPlayer? _assetsAudioPlayer;
final FlutterRingtonePlayer _flutterRingtonePlayer = FlutterRingtonePlayer();
Future<void> startRingingTone() async {
if (PlatformInfos.isMobile) {
await _flutterRingtonePlayer.playRingtone(volume: 80);
} else if ((kIsWeb || PlatformInfos.isMacOS) &&
_assetsAudioPlayer != null) {
const path = 'assets/sounds/phone.ogg';
final player = _assetsAudioPlayer = AudioPlayer();
player.setAsset(path);
player.play();
}
const path = 'assets/sounds/phone.ogg';
final player = _assetsAudioPlayer = AudioPlayer();
player.setAsset(path);
player.play();
return;
}
Future<void> stopRingingTone() async {
if (PlatformInfos.isMobile) {
await _flutterRingtonePlayer.stop();
}
await _assetsAudioPlayer?.stop();
_assetsAudioPlayer = null;
return;

View file

@ -11,7 +11,6 @@ import 'package:webrtc_interface/webrtc_interface.dart' hide Navigator;
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/dialer/dialer.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import '../../utils/voip/callkeep_manager.dart';
import '../../utils/voip/user_media_manager.dart';
import '../widgets/matrix.dart';
@ -89,8 +88,7 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate {
]) =>
webrtc_impl.createPeerConnection(configuration, constraints);
Future<bool> get hasCallingAccount async =>
kIsWeb ? false : await CallKeepManager().hasPhoneAccountEnabled;
Future<bool> get hasCallingAccount async => false;
@override
Future<void> playRingtone() async {
@ -113,46 +111,21 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate {
@override
Future<void> handleNewCall(CallSession call) async {
if (PlatformInfos.isAndroid) {
// probably works on ios too
final hasCallingAccount = await CallKeepManager().hasPhoneAccountEnabled;
if (call.direction == CallDirection.kIncoming &&
hasCallingAccount &&
call.type == CallType.kVoice) {
///Popup native telecom manager call UI for incoming call.
final callKeeper = CallKeeper(CallKeepManager(), call);
CallKeepManager().addCall(call.callId, callKeeper);
await CallKeepManager().showCallkitIncoming(call);
return;
} else {
try {
final wasForeground = await FlutterForegroundTask.isAppOnForeground;
try {
final wasForeground = await FlutterForegroundTask.isAppOnForeground;
await matrix.store.setString(
'wasForeground',
wasForeground == true ? 'true' : 'false',
);
FlutterForegroundTask.setOnLockScreenVisibility(true);
FlutterForegroundTask.wakeUpScreen();
FlutterForegroundTask.launchApp();
} catch (e) {
Logs().e('VOIP foreground failed $e');
}
// use fallback flutter call pages for outgoing and video calls.
addCallingOverlay(call.callId, call);
try {
if (!hasCallingAccount) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'No calling accounts found (used for native calls UI)',
),
),
);
}
} catch (e) {
Logs().e('failed to show snackbar');
}
await matrix.store.setString(
'wasForeground',
wasForeground == true ? 'true' : 'false',
);
FlutterForegroundTask.setOnLockScreenVisibility(true);
FlutterForegroundTask.wakeUpScreen();
FlutterForegroundTask.launchApp();
} catch (e) {
Logs().e('VOIP foreground failed $e');
}
// use fallback flutter call pages for outgoing and video calls.
addCallingOverlay(call.callId, call);
} else {
addCallingOverlay(call.callId, call);
}

View file

@ -20,6 +20,10 @@ Future<Result<T>> showFutureLoadingDialog<T>({
bool barrierDismissible = false,
bool delay = true,
ExceptionContext? exceptionContext,
// #Pangea
String Function(Object, StackTrace?)? onError,
VoidCallback? onDismiss,
// Pangea#
}) async {
final futureExec = future();
final resultFuture = ResultFuture(futureExec);
@ -48,6 +52,10 @@ Future<Result<T>> showFutureLoadingDialog<T>({
title: title,
backLabel: backLabel,
exceptionContext: exceptionContext,
// #Pangea
onError: onError,
onDismiss: onDismiss,
// Pangea#
),
);
return result ??
@ -70,6 +78,10 @@ class LoadingDialog<T> extends StatefulWidget {
final String? backLabel;
final Future<T> future;
final ExceptionContext? exceptionContext;
// #Pangea
final String Function(Object, StackTrace?)? onError;
final VoidCallback? onDismiss;
// Pangea#
const LoadingDialog({
super.key,
@ -77,6 +89,10 @@ class LoadingDialog<T> extends StatefulWidget {
this.title,
this.backLabel,
this.exceptionContext,
// #Pangea
this.onError,
this.onDismiss,
// Pangea#
});
@override
LoadingDialogState<T> createState() => LoadingDialogState<T>();
@ -90,11 +106,26 @@ class LoadingDialogState<T> extends State<LoadingDialog> {
void initState() {
super.initState();
widget.future.then(
(result) => Navigator.of(context).pop<Result<T>>(Result.value(result)),
onError: (e, s) => setState(() {
exception = e;
stackTrace = s;
}),
// #Pangea
// (result) => Navigator.of(context).pop<Result<T>>(Result.value(result)),
// onError: (e, s) => setState(() {
// exception = e;
// stackTrace = s;
// }),
(result) {
if (mounted) {
Navigator.of(context).pop<Result<T>>(Result.value(result));
}
},
onError: (e, s) {
if (mounted) {
setState(() {
exception = widget.onError?.call(e, s) ?? e;
stackTrace = s;
});
}
},
// Pangea#
);
}
@ -134,7 +165,20 @@ class LoadingDialogState<T> extends State<LoadingDialog> {
),
),
actions: exception == null
? null
// #Pangea
// ? null
? widget.onDismiss != null
? [
AdaptiveDialogAction(
onPressed: () {
widget.onDismiss!();
Navigator.of(context).pop();
},
child: Text(L10n.of(context).cancel),
),
]
: null
// Pangea#
: [
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop<Result<T>>(

View file

@ -7,11 +7,13 @@
#include "generated_plugin_registrant.h"
#include <audioplayers_linux/audioplayers_linux_plugin.h>
#include <desktop_webview_window/desktop_webview_window_plugin.h>
#include <dynamic_color/dynamic_color_plugin.h>
#include <emoji_picker_flutter/emoji_picker_flutter_plugin.h>
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <gtk/gtk_plugin.h>
#include <handy_window/handy_window_plugin.h>
#include <pasteboard/pasteboard_plugin.h>
#include <record_linux/record_linux_plugin.h>
@ -24,6 +26,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin");
dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);
@ -39,6 +44,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin");
flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar);
g_autoptr(FlPluginRegistrar) gtk_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin");
gtk_plugin_register_with_registrar(gtk_registrar);
g_autoptr(FlPluginRegistrar) handy_window_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "HandyWindowPlugin");
handy_window_plugin_register_with_registrar(handy_window_registrar);

View file

@ -4,11 +4,13 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux
desktop_webview_window
dynamic_color
emoji_picker_flutter
file_selector_linux
flutter_secure_storage_linux
flutter_webrtc
gtk
handy_window
pasteboard
record_linux

View file

@ -5,8 +5,10 @@
import FlutterMacOS
import Foundation
import app_links
import audio_session
import audioplayers_darwin
import desktop_webview_window
import device_info_plus
import dynamic_color
import emoji_picker_flutter
@ -14,8 +16,8 @@ import file_selector_macos
import firebase_analytics
import firebase_core
import firebase_messaging
import flutter_app_badger
import flutter_local_notifications
import flutter_new_badger
import flutter_secure_storage_macos
import flutter_tts
import flutter_web_auth_2
@ -42,8 +44,10 @@ import wakelock_plus
import window_to_front
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
EmojiPickerFlutterPlugin.register(with: registry.registrar(forPlugin: "EmojiPickerFlutterPlugin"))
@ -51,8 +55,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterAppBadgerPlugin.register(with: registry.registrar(forPlugin: "FlutterAppBadgerPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterNewBadgerPlugin.register(with: registry.registrar(forPlugin: "FlutterNewBadgerPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))

View file

@ -49,6 +49,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.2"
app_links:
dependency: "direct main"
description:
name: app_links
sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba"
url: "https://pub.dev"
source: hosted
version: "6.4.0"
app_links_linux:
dependency: transitive
description:
name: app_links_linux
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
url: "https://pub.dev"
source: hosted
version: "1.0.3"
app_links_platform_interface:
dependency: transitive
description:
name: app_links_platform_interface
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
app_links_web:
dependency: transitive
description:
name: app_links_web
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
url: "https://pub.dev"
source: hosted
version: "1.0.4"
archive:
dependency: "direct main"
description:
@ -69,10 +101,10 @@ packages:
dependency: "direct main"
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.12.0"
audio_session:
dependency: transitive
description:
@ -173,10 +205,10 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
build_config:
dependency: transitive
description:
@ -185,14 +217,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
callkeep:
dependency: "direct main"
description:
name: callkeep
sha256: "9e86e9632a603a61f7045c179ea5ca0ee4da0a49fc5f80c2fe09fb422b96d3c6"
url: "https://pub.dev"
source: hosted
version: "0.3.3"
canonical_json:
dependency: transitive
description:
@ -205,10 +229,10 @@ packages:
dependency: "direct main"
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
charcode:
dependency: transitive
description:
@ -245,18 +269,18 @@ packages:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
collection:
dependency: "direct main"
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.19.1"
colorize:
dependency: transitive
description:
@ -349,10 +373,10 @@ packages:
dependency: transitive
description:
name: dart_webrtc
sha256: e65506edb452148220efab53d8d2f8bb9d827bd8bcd53cf3a3e6df70b27f3d86
sha256: "03df5b41b23bc185ebcf4b0ffc92d002e295bf56287fb5f9d2c321ddaf7760cc"
url: "https://pub.dev"
source: hosted
version: "1.4.10"
version: "1.5.1"
dbus:
dependency: transitive
description:
@ -377,6 +401,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.3"
desktop_webview_window:
dependency: transitive
description:
name: desktop_webview_window
sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
url: "https://pub.dev"
source: hosted
version: "0.2.3"
device_info_plus:
dependency: "direct main"
description:
@ -461,10 +493,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
fcm_shared_isolate:
dependency: "direct main"
description:
@ -484,10 +516,10 @@ packages:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.0"
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
@ -653,14 +685,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_app_badger:
dependency: "direct main"
description:
name: flutter_app_badger
sha256: "64d4a279bab862ed28850431b9b446b9820aaae0bf363322d51077419f930fa8"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
flutter_cache_manager:
dependency: "direct main"
description:
@ -807,14 +831,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.1"
flutter_new_badger:
dependency: "direct main"
description:
name: flutter_new_badger
sha256: d3742ace8009663db1ac6ba0377b092f479c35deb33e05514ba05cc0b0a5aaaa
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter_olm:
dependency: "direct main"
description:
name: flutter_olm
sha256: "69aaac45d854e74d17d04dac8a0ca3f548266d271a0f0fa7600e006e81432417"
sha256: "5e6211af8cba1abf7d1f92e543f6d573dfe6017fe4742e0d04ba84beab47f940"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "2.0.0"
flutter_openssl_crypto:
dependency: "direct main"
description:
@ -831,14 +863,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.20"
flutter_ringtone_player:
dependency: "direct main"
description:
name: flutter_ringtone_player
sha256: d0277a04e629a6582d776f5dcc2a879a733f7326ba073b872a9ccfbff9d9b51f
url: "https://pub.dev"
source: hosted
version: "4.0.0+3"
flutter_secure_storage:
dependency: "direct main"
description:
@ -887,15 +911,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_shortcuts:
flutter_shortcuts_new:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: "930c51d56c87a7f8cefdf8c1db52c194baddc37d"
url: "https://github.com/krille-chan/flutter_shortcuts.git"
source: git
version: "1.4.0"
name: flutter_shortcuts_new
sha256: "16ee1c8a9bc9586b5117ebb774a8ff6b396f856743e97251eb483c4dc5769d7f"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_svg:
dependency: "direct main"
description:
@ -929,18 +952,18 @@ packages:
dependency: "direct main"
description:
name: flutter_web_auth_2
sha256: "4d3d2fd3d26bf1a26b3beafd4b4b899c0ffe10dc99af25abc58ffe24e991133c"
sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "4.1.0"
flutter_web_auth_2_platform_interface:
dependency: transitive
description:
name: flutter_web_auth_2_platform_interface
sha256: e8669e262005a8354389ba2971f0fc1c36188481234ff50d013aaf993f30f739
sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "4.1.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@ -950,10 +973,10 @@ packages:
dependency: "direct main"
description:
name: flutter_webrtc
sha256: f6800cc2af79018c12e955ddf8ad007891fdfbb8199b0ce3dccd0977ed2add9c
sha256: "9c4ca34ced1d1b780baf3776557f9edd0af18ce030969346f752e8df455faaab"
url: "https://pub.dev"
source: hosted
version: "0.11.7"
version: "0.12.10"
freezed_annotation:
dependency: transitive
description:
@ -1079,6 +1102,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
gtk:
dependency: transitive
description:
name: gtk
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
url: "https://pub.dev"
source: hosted
version: "2.1.0"
handy_window:
dependency: "direct main"
description:
@ -1235,34 +1266,34 @@ packages:
dependency: "direct main"
description:
name: in_app_purchase
sha256: def70fbaa2a274f4d835677459f6f7afc5469de912438f86076e51cbd4cbd5b4
sha256: "11a40f148eeb4f681a0572003e2b33432e110c90c1bbb4f9ef83b81ec0c4f737"
url: "https://pub.dev"
source: hosted
version: "3.1.13"
version: "3.2.1"
in_app_purchase_android:
dependency: transitive
description:
name: in_app_purchase_android
sha256: "28164faac635a6cc357c96f47813e675eec7622a8f41e829b501573dbbce2cce"
sha256: "45ae4fe253f85b4fcc58b421fe137f6e48aca16bf8a618cd760cb0542e7f854e"
url: "https://pub.dev"
source: hosted
version: "0.3.0+17"
version: "0.4.0"
in_app_purchase_platform_interface:
dependency: transitive
description:
name: in_app_purchase_platform_interface
sha256: "412efce2b9238c5ace4f057acad43f793ed06880e366d26ae322e796cadb051a"
sha256: "1d353d38251da5b9fea6635c0ebfc6bb17a2d28d0e86ea5e083bf64244f1fb4c"
url: "https://pub.dev"
source: hosted
version: "1.3.7"
version: "1.4.0"
in_app_purchase_storekit:
dependency: transitive
description:
name: in_app_purchase_storekit
sha256: c4b17a7f2ca8ddc7fd7996a8c32a3af6beddf91d651997c8675a5f23c103c9bc
sha256: "276831961023055b55a2156c1fc043f50f6215ff49fb0f5f2273da6eeb510ecf"
url: "https://pub.dev"
source: hosted
version: "0.3.8+1"
version: "0.3.21"
injector:
dependency: transitive
description:
@ -1360,18 +1391,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
@ -1440,10 +1471,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
@ -1473,10 +1504,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
mgrs_dart:
dependency: transitive
description:
@ -1505,10 +1536,10 @@ packages:
dependency: "direct main"
description:
name: native_imaging
sha256: "182ccd8e0815a8a2158500ef66c828c030f6b9e05783e41e22f33bbcfd46a3d5"
sha256: "93573afdcab070011d78a40fc1f69b61967f1f8485d2b81a7a2ee585a85f4c04"
url: "https://pub.dev"
source: hosted
version: "0.1.1"
version: "0.2.0"
nested:
dependency: transitive
description:
@ -1593,10 +1624,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
path_parsing:
dependency: transitive
description:
@ -1665,26 +1696,26 @@ packages:
dependency: "direct main"
description:
name: permission_handler
sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6"
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
url: "https://pub.dev"
source: hosted
version: "11.2.0"
version: "11.4.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: a5ebaa420cee8fd880ef10dedd42c6b3f493e7dbe27d7e0a7e1798669373082a
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
url: "https://pub.dev"
source: hosted
version: "12.0.4"
version: "12.1.0"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: "6ca25ee52518a8a26e80aaefe3c71caf6e2dfd809c1b20900d0882df6faed36e"
sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98
url: "https://pub.dev"
source: hosted
version: "9.3.1"
version: "9.4.6"
permission_handler_html:
dependency: transitive
description:
@ -1697,10 +1728,10 @@ packages:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: "5c43148f2bfb6d14c5a8162c0a712afe891f2d847f35fcff29c406b37da43c3c"
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "4.3.0"
permission_handler_windows:
dependency: transitive
description:
@ -1721,10 +1752,10 @@ packages:
dependency: transitive
description:
name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
version: "3.1.6"
platform_detect:
dependency: transitive
description:
@ -1801,10 +1832,10 @@ packages:
dependency: transitive
description:
name: process
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
version: "5.0.3"
proj4dart:
dependency: transitive
description:
@ -1857,10 +1888,10 @@ packages:
dependency: "direct main"
description:
name: purchases_flutter
sha256: "4ff3a62a685cd964590d2c8126be62c3ede3657a5421adf558fd95f01699643a"
sha256: "88099e7b2a9f140d565d6ded919b9b3b2a0187b59542e46abee1b16b319c2025"
url: "https://pub.dev"
source: hosted
version: "6.29.0"
version: "8.5.1"
qr:
dependency: transitive
description:
@ -1869,14 +1900,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.1"
qr_code_scanner:
qr_code_scanner_plus:
dependency: "direct main"
description:
name: qr_code_scanner
sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd
name: qr_code_scanner_plus
sha256: "39696b50d277097ee4d90d4292de36f38c66213a4f5216a06b2bdd2b63117859"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "2.0.10+1"
qr_image:
dependency: "direct main"
description:
@ -2182,10 +2213,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.10.1"
sprintf:
dependency: transitive
description:
@ -2238,26 +2269,26 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.1"
string_validator:
dependency: transitive
description:
@ -2310,34 +2341,34 @@ packages:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
test:
dependency: transitive
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
version: "1.25.15"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.4"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
version: "0.6.8"
text_to_speech:
dependency: "direct main"
description:
@ -2410,30 +2441,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
uni_links:
dependency: "direct main"
description:
name: uni_links
sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
uni_links_platform_interface:
dependency: transitive
description:
name: uni_links_platform_interface
sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
uni_links_web:
dependency: transitive
description:
name: uni_links_web
sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df"
url: "https://pub.dev"
source: hosted
version: "0.1.0"
unicode:
dependency: transitive
description:
@ -2606,18 +2613,18 @@ packages:
dependency: "direct main"
description:
name: video_compress
sha256: "5b42d89f3970c956bad7a86c29682b0892c11a4ddf95ae6e29897ee28788e377"
sha256: "31bc5cdb9a02ba666456e5e1907393c28e6e0e972980d7d8d619a7beda0d4f20"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "3.1.4"
video_player:
dependency: "direct main"
description:
name: video_player
sha256: e30df0d226c4ef82e2c150ebf6834b3522cf3f654d8e2f9419d376cdc071425d
sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17"
url: "https://pub.dev"
source: hosted
version: "2.9.1"
version: "2.9.2"
video_player_android:
dependency: transitive
description:
@ -2654,10 +2661,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.3.1"
wakelock_plus:
dependency: "direct main"
description:
@ -2718,10 +2725,10 @@ packages:
dependency: "direct main"
description:
name: webrtc_interface
sha256: abec3ab7956bd5ac539cf34a42fa0c82ea26675847c0966bb85160400eea9388
sha256: "10fc6dc0ac16f909f5e434c18902415211d759313c87261f1e4ec5b4f6a04c26"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
win32:
dependency: "direct overridden"
description:
@ -2779,5 +2786,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -13,11 +13,11 @@ environment:
dependencies:
animations: ^2.0.11
archive: ^3.6.1
app_links: ^6.3.3
archive: ^3.4.10
async: ^2.11.0
badges: ^3.1.2
blurhash_dart: ^1.2.1
callkeep: ^0.3.2
characters: ^1.2.0
chewie: ^1.8.1
collection: ^1.18.0
@ -37,7 +37,6 @@ dependencies:
file_selector: ^1.0.3
flutter:
sdk: flutter
flutter_app_badger: ^1.5.0
flutter_cache_manager: ^3.4.1
flutter_foreground_task: ^6.1.3
flutter_highlighter: ^0.1.1
@ -46,15 +45,14 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_map: ^6.1.0
flutter_olm: 1.3.2 # Keep in sync with scripts/prepare-web.sh ! 1.4.0 does currently not build on Android
flutter_new_badger: ^1.1.1
flutter_olm: 2.0.0
flutter_openssl_crypto: ^0.3.0
flutter_ringtone_player: ^4.0.0+2
flutter_secure_storage: ^9.2.3
flutter_shortcuts:
git: https://github.com/krille-chan/flutter_shortcuts.git
flutter_shortcuts_new: ^2.0.0
flutter_typeahead: ^5.2.0
flutter_web_auth_2: ^3.1.1 # Version 4 blocked by https://github.com/MixinNetwork/flutter-plugins/issues/379
flutter_webrtc: ^0.11.7
flutter_web_auth_2: ^4.1.0
flutter_webrtc: ^0.12.9
geolocator: ^13.0.1
go_router: ^14.3.0
handy_window: ^0.4.0
@ -76,17 +74,17 @@ dependencies:
# matrix: ^0.37.0
# Pangea#
mime: ^1.0.6
native_imaging: ^0.1.1
native_imaging: ^0.2.0
opus_caf_converter_dart: ^1.0.1
package_info_plus: ^8.1.1
pasteboard: ^0.2.0
path: ^1.9.0
path_provider: ^2.1.2
permission_handler: ^11.0.1
permission_handler: ^11.4.0
pretty_qr_code: ^3.2.1
provider: ^6.0.2
punycode: ^1.0.0
qr_code_scanner: ^1.0.1
qr_code_scanner_plus: ^2.0.10+1
qr_image: ^1.0.0
receive_sharing_intent: ^1.8.1
record: ^5.1.2
@ -98,13 +96,12 @@ dependencies:
sqlcipher_flutter_libs: ^0.6.1
swipe_to_action: ^0.3.0
tor_detector_web: ^1.1.0
uni_links: ^0.5.1
unifiedpush: ^5.0.1
unifiedpush_ui: ^0.1.0
universal_html: ^2.2.4
url_launcher: ^6.2.5
video_compress: ^3.1.3
video_player: ^2.8.5
video_compress: ^3.1.4
video_player: ^2.9.2
wakelock_plus: ^1.2.2
webrtc_interface: ^1.0.13
# #Pangea
@ -123,12 +120,12 @@ dependencies:
path: pangea_packages/fcm_shared_isolate
flutter_svg: ^2.0.10+1
get_storage: ^2.1.1
in_app_purchase: ^3.1.13
in_app_purchase: ^3.2.1
jwt_decode: ^0.3.1
language_tool: ^2.2.0
material_symbols_icons: ^4.2741.0
open_file: ^3.3.2
purchases_flutter: ^6.26.0
purchases_flutter: ^8.5.1
sentry_flutter: ^8.2.0
shimmer: ^3.0.0
rive: 0.11.11

View file

@ -6,7 +6,9 @@
#include "generated_plugin_registrant.h"
#include <app_links/app_links_plugin_c_api.h>
#include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <desktop_webview_window/desktop_webview_window_plugin.h>
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <emoji_picker_flutter/emoji_picker_flutter_plugin_c_api.h>
#include <file_selector_windows/file_selector_windows.h>
@ -26,8 +28,12 @@
#include <window_to_front/window_to_front_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
AppLinksPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
DesktopWebviewWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
EmojiPickerFlutterPluginCApiRegisterWithRegistrar(

View file

@ -3,7 +3,9 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
app_links
audioplayers_windows
desktop_webview_window
dynamic_color
emoji_picker_flutter
file_selector_windows