From abd733934bd1b3128de9f256e694e6cdd4a7c16a Mon Sep 17 00:00:00 2001 From: AmanRajSinghMourya Date: Thu, 31 Jul 2025 19:44:40 +0530 Subject: [PATCH] Introduced lock screen package from packages/lockscreen --- mobile/apps/auth/lib/main.dart | 18 +- .../local_authentication_service.dart | 144 ------- .../lib/ui/account/delete_account_page.dart | 4 +- mobile/apps/auth/lib/ui/code_widget.dart | 2 +- mobile/apps/auth/lib/ui/home_page.dart | 4 +- .../ui/settings/account_section_widget.dart | 4 +- .../ui/settings/data/duplicate_code_page.dart | 4 +- .../lib/ui/settings/data/export_widget.dart | 4 +- .../lock_screen/custom_pin_keypad.dart | 235 ----------- .../lock_screen/lock_screen_auto_lock.dart | 143 ------- .../lock_screen_confirm_password.dart | 186 -------- .../lock_screen/lock_screen_confirm_pin.dart | 211 ---------- .../lock_screen/lock_screen_options.dart | 397 ------------------ .../lock_screen/lock_screen_password.dart | 250 ----------- .../settings/lock_screen/lock_screen_pin.dart | 284 ------------- .../ui/settings/security_section_widget.dart | 14 +- mobile/apps/auth/lib/ui/settings_page.dart | 4 +- mobile/apps/auth/lib/ui/tools/app_lock.dart | 209 --------- .../apps/auth/lib/ui/tools/lock_screen.dart | 367 ---------------- mobile/apps/auth/lib/utils/auth_util.dart | 66 --- .../auth/lib/utils/lock_screen_settings.dart | 253 ----------- mobile/apps/auth/pubspec.lock | 35 ++ mobile/apps/auth/pubspec.yaml | 2 + mobile/packages/ui/pubspec.lock | 77 ++-- mobile/packages/ui/pubspec.yaml | 6 +- 25 files changed, 117 insertions(+), 2806 deletions(-) delete mode 100644 mobile/apps/auth/lib/services/local_authentication_service.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/custom_pin_keypad.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_auto_lock.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_password.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_pin.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_options.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_password.dart delete mode 100644 mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_pin.dart delete mode 100644 mobile/apps/auth/lib/ui/tools/app_lock.dart delete mode 100644 mobile/apps/auth/lib/ui/tools/lock_screen.dart delete mode 100644 mobile/apps/auth/lib/utils/auth_util.dart delete mode 100644 mobile/apps/auth/lib/utils/lock_screen_settings.dart diff --git a/mobile/apps/auth/lib/main.dart b/mobile/apps/auth/lib/main.dart index 29c8279abe..94cdb778ca 100644 --- a/mobile/apps/auth/lib/main.dart +++ b/mobile/apps/auth/lib/main.dart @@ -6,6 +6,7 @@ import "package:ente_auth/app/view/app.dart"; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/core/constants.dart'; import 'package:ente_auth/ente_theme_data.dart'; +import 'package:ente_auth/l10n/arb/app_localizations.dart'; import 'package:ente_auth/locale.dart'; import 'package:ente_auth/services/authenticator_service.dart'; import 'package:ente_auth/services/billing_service.dart'; @@ -17,14 +18,14 @@ import 'package:ente_auth/services/window_listener_service.dart'; import 'package:ente_auth/store/authenticator_db.dart'; import 'package:ente_auth/store/code_display_store.dart'; import 'package:ente_auth/store/code_store.dart'; -import 'package:ente_auth/ui/tools/app_lock.dart'; -import 'package:ente_auth/ui/tools/lock_screen.dart'; import 'package:ente_auth/ui/utils/icon_utils.dart'; import 'package:ente_auth/utils/directory_utils.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/window_protocol_handler.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; +import 'package:ente_lock_screen/lock_screen_settings.dart'; +import 'package:ente_lock_screen/ui/app_lock.dart'; +import 'package:ente_lock_screen/ui/lock_screen.dart'; import 'package:ente_logging/logging.dart'; import 'package:ente_network/network.dart'; import 'package:flutter/foundation.dart'; @@ -88,6 +89,7 @@ void main() async { Future _runInForeground() async { final savedThemeMode = _themeMode(await AdaptiveTheme.getThemeMode()); + final configuration = Configuration.instance; return await _runWithLogs(() async { _logger.info("Starting app in foreground"); try { @@ -101,12 +103,18 @@ Future _runInForeground() async { runApp( AppLock( builder: (args) => App(locale: locale), - lockScreen: const LockScreen(), + lockScreen: LockScreen(configuration), enabled: await LockScreenSettings.instance.shouldShowLockScreen(), locale: locale, lightTheme: lightThemeData, darkTheme: darkThemeData, savedThemeMode: savedThemeMode, + localeListResolutionCallback: localResolutionCallBack, + localizationsDelegates: const [ + ...AppLocalizations.localizationsDelegates, + ], + supportedLocales: appSupportedLocales, + backgroundLockLatency: const Duration(seconds: 0), ), ); }); @@ -160,5 +168,5 @@ Future _init(bool bool, {String? via}) async { await NotificationService.instance.init(); await UpdateService.instance.init(); await IconUtils.instance.init(); - await LockScreenSettings.instance.init(); + await LockScreenSettings.instance.init(Configuration.instance); } diff --git a/mobile/apps/auth/lib/services/local_authentication_service.dart b/mobile/apps/auth/lib/services/local_authentication_service.dart deleted file mode 100644 index 1502b2a36e..0000000000 --- a/mobile/apps/auth/lib/services/local_authentication_service.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'dart:io'; - -import 'package:ente_auth/ui/settings/lock_screen/lock_screen_password.dart'; -import 'package:ente_auth/ui/settings/lock_screen/lock_screen_pin.dart'; -import 'package:ente_auth/ui/tools/app_lock.dart'; -import 'package:ente_auth/utils/auth_util.dart'; -import 'package:ente_auth/utils/dialog_util.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; -import 'package:ente_auth/utils/toast_util.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_local_authentication/flutter_local_authentication.dart'; -import 'package:local_auth/local_auth.dart'; -import 'package:logging/logging.dart'; - -class LocalAuthenticationService { - LocalAuthenticationService._privateConstructor(); - static final LocalAuthenticationService instance = - LocalAuthenticationService._privateConstructor(); - final logger = Logger((LocalAuthenticationService).toString()); - int lastAuthTime = 0; - - Future requestLocalAuthentication( - BuildContext context, - String infoMessage, - ) async { - if (kDebugMode) { - // if last auth time is less than 60 seconds, don't ask for auth again - if (lastAuthTime != 0 && - DateTime.now().millisecondsSinceEpoch - lastAuthTime < 60000) { - return true; - } - } - if (await isLocalAuthSupportedOnDevice() || - LockScreenSettings.instance.getIsAppLockSet()) { - AppLock.of(context)!.setEnabled(false); - final result = await requestAuthentication( - context, - infoMessage, - isAuthenticatingForInAppChange: true, - ); - AppLock.of(context)!.setEnabled( - await LockScreenSettings.instance.shouldShowLockScreen(), - ); - if (!result) { - showToast(context, infoMessage); - return false; - } else { - lastAuthTime = DateTime.now().millisecondsSinceEpoch; - return true; - } - } - return true; - } - - Future requestEnteAuthForLockScreen( - BuildContext context, - String? savedPin, - String? savedPassword, { - bool isAuthenticatingOnAppLaunch = false, - bool isAuthenticatingForInAppChange = false, - }) async { - if (savedPassword != null) { - final result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return LockScreenPassword( - isChangingLockScreenSettings: true, - isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, - isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch, - authPass: savedPassword, - ); - }, - ), - ); - if (result) { - return true; - } - } - if (savedPin != null) { - final result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return LockScreenPin( - isChangingLockScreenSettings: true, - isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, - isAuthenticatingOnAppLaunch: isAuthenticatingOnAppLaunch, - authPin: savedPin, - ); - }, - ), - ); - if (result) { - return true; - } - } - return false; - } - - Future requestLocalAuthForLockScreen( - BuildContext context, - bool shouldEnableLockScreen, - String infoMessage, - String errorDialogContent, [ - String errorDialogTitle = "", - ]) async { - if (await isLocalAuthSupportedOnDevice()) { - AppLock.of(context)!.disable(); - final result = await requestAuthentication( - context, - infoMessage, - ); - if (result) { - AppLock.of(context)!.setEnabled(shouldEnableLockScreen); - await LockScreenSettings.instance - .setSystemLockScreen(shouldEnableLockScreen); - return true; - } else { - AppLock.of(context)!.setEnabled( - await LockScreenSettings.instance.shouldShowLockScreen(), - ); - } - } else { - // ignore: unawaited_futures - showErrorDialog( - context, - errorDialogTitle, - errorDialogContent, - ); - } - return false; - } - - Future isLocalAuthSupportedOnDevice() async { - try { - return Platform.isLinux - ? await FlutterLocalAuthentication().canAuthenticate() - : await LocalAuthentication().isDeviceSupported(); - } on MissingPluginException { - return false; - } - } -} diff --git a/mobile/apps/auth/lib/ui/account/delete_account_page.dart b/mobile/apps/auth/lib/ui/account/delete_account_page.dart index b8779e8cbb..d11b0ccaad 100644 --- a/mobile/apps/auth/lib/ui/account/delete_account_page.dart +++ b/mobile/apps/auth/lib/ui/account/delete_account_page.dart @@ -3,13 +3,13 @@ import 'dart:convert'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/models/delete_account.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; -import 'package:ente_auth/services/user_service.dart'; + import 'package:ente_auth/services/user_service.dart'; import 'package:ente_auth/ui/common/dialogs.dart'; import 'package:ente_auth/ui/common/gradient_button.dart'; import 'package:ente_auth/utils/email_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:flutter/material.dart'; class DeleteAccountPage extends StatelessWidget { diff --git a/mobile/apps/auth/lib/ui/code_widget.dart b/mobile/apps/auth/lib/ui/code_widget.dart index be9c2b8a69..df57d9b8a6 100644 --- a/mobile/apps/auth/lib/ui/code_widget.dart +++ b/mobile/apps/auth/lib/ui/code_widget.dart @@ -9,7 +9,6 @@ import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/models/code.dart'; import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart'; import 'package:ente_auth/onboarding/view/view_qr_page.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; import 'package:ente_auth/services/preference_service.dart'; import 'package:ente_auth/store/code_store.dart'; import 'package:ente_auth/theme/ente_theme.dart'; @@ -22,6 +21,7 @@ import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/toast_util.dart'; import 'package:ente_auth/utils/totp_util.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_context_menu/flutter_context_menu.dart'; diff --git a/mobile/apps/auth/lib/ui/home_page.dart b/mobile/apps/auth/lib/ui/home_page.dart index e218e4fbda..af1deec96f 100644 --- a/mobile/apps/auth/lib/ui/home_page.dart +++ b/mobile/apps/auth/lib/ui/home_page.dart @@ -33,12 +33,12 @@ import 'package:ente_auth/ui/reorder_codes_page.dart'; import 'package:ente_auth/ui/scanner_page.dart'; import 'package:ente_auth/ui/settings_page.dart'; import 'package:ente_auth/ui/sort_option_menu.dart'; -import 'package:ente_auth/ui/tools/app_lock.dart'; import 'package:ente_auth/utils/dialog_util.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/totp_util.dart'; import 'package:ente_events/event_bus.dart'; +import 'package:ente_lock_screen/lock_screen_settings.dart'; +import 'package:ente_lock_screen/ui/app_lock.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/mobile/apps/auth/lib/ui/settings/account_section_widget.dart b/mobile/apps/auth/lib/ui/settings/account_section_widget.dart index 47e639c2e7..89719c1da7 100644 --- a/mobile/apps/auth/lib/ui/settings/account_section_widget.dart +++ b/mobile/apps/auth/lib/ui/settings/account_section_widget.dart @@ -1,6 +1,5 @@ import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; +import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/services/user_service.dart'; import 'package:ente_auth/theme/ente_theme.dart'; import 'package:ente_auth/ui/account/change_email_dialog.dart'; @@ -15,6 +14,7 @@ import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/navigation_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:flutter/material.dart'; class AccountSectionWidget extends StatelessWidget { diff --git a/mobile/apps/auth/lib/ui/settings/data/duplicate_code_page.dart b/mobile/apps/auth/lib/ui/settings/data/duplicate_code_page.dart index 9de8695a52..0aba15ed34 100644 --- a/mobile/apps/auth/lib/ui/settings/data/duplicate_code_page.dart +++ b/mobile/apps/auth/lib/ui/settings/data/duplicate_code_page.dart @@ -1,11 +1,11 @@ import 'package:ente_auth/l10n/l10n.dart'; import 'package:ente_auth/models/code.dart'; -import 'package:ente_auth/services/deduplication_service.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; +import 'package:ente_auth/services/deduplication_service.dart'; import 'package:ente_auth/store/code_store.dart'; import 'package:ente_auth/theme/ente_theme.dart'; import 'package:ente_auth/ui/code_widget.dart'; import 'package:ente_auth/utils/dialog_util.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:logging/logging.dart'; diff --git a/mobile/apps/auth/lib/ui/settings/data/export_widget.dart b/mobile/apps/auth/lib/ui/settings/data/export_widget.dart index 3ec41b2fc2..2ab7030874 100644 --- a/mobile/apps/auth/lib/ui/settings/data/export_widget.dart +++ b/mobile/apps/auth/lib/ui/settings/data/export_widget.dart @@ -2,8 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/models/export/ente.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; +import 'package:ente_auth/models/export/ente.dart'; import 'package:ente_auth/store/code_store.dart'; import 'package:ente_auth/ui/components/buttons/button_widget.dart'; import 'package:ente_auth/ui/components/dialog_widget.dart'; @@ -14,6 +13,7 @@ import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/share_utils.dart'; import 'package:ente_auth/utils/toast_util.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:file_saver/file_saver.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/custom_pin_keypad.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/custom_pin_keypad.dart deleted file mode 100644 index f8ad367fe0..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/custom_pin_keypad.dart +++ /dev/null @@ -1,235 +0,0 @@ -import "package:ente_auth/theme/ente_theme.dart"; -import "package:flutter/material.dart"; - -class CustomPinKeypad extends StatelessWidget { - final TextEditingController controller; - const CustomPinKeypad({required this.controller, super.key}); - - @override - Widget build(BuildContext context) { - return SafeArea( - child: Container( - padding: const EdgeInsets.all(2), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Container( - color: getEnteColorScheme(context).strokeFainter, - child: Column( - children: [ - Row( - children: [ - _Button( - text: '', - number: '1', - onTap: () { - _onKeyTap('1'); - }, - ), - _Button( - text: "ABC", - number: '2', - onTap: () { - _onKeyTap('2'); - }, - ), - _Button( - text: "DEF", - number: '3', - onTap: () { - _onKeyTap('3'); - }, - ), - ], - ), - Row( - children: [ - _Button( - number: '4', - text: "GHI", - onTap: () { - _onKeyTap('4'); - }, - ), - _Button( - number: '5', - text: 'JKL', - onTap: () { - _onKeyTap('5'); - }, - ), - _Button( - number: '6', - text: 'MNO', - onTap: () { - _onKeyTap('6'); - }, - ), - ], - ), - Row( - children: [ - _Button( - number: '7', - text: 'PQRS', - onTap: () { - _onKeyTap('7'); - }, - ), - _Button( - number: '8', - text: 'TUV', - onTap: () { - _onKeyTap('8'); - }, - ), - _Button( - number: '9', - text: 'WXYZ', - onTap: () { - _onKeyTap('9'); - }, - ), - ], - ), - Row( - children: [ - const _Button( - number: '', - text: '', - muteButton: true, - onTap: null, - ), - _Button( - number: '0', - text: '', - onTap: () { - _onKeyTap('0'); - }, - ), - _Button( - number: '', - text: '', - icon: const Icon(Icons.backspace_outlined), - onTap: () { - _onBackspace(); - }, - ), - ], - ), - ], - ), - ), - ], - ), - ), - ); - } - - void _onKeyTap(String number) { - controller.text += number; - return; - } - - void _onBackspace() { - if (controller.text.isNotEmpty) { - controller.text = - controller.text.substring(0, controller.text.length - 1); - } - return; - } -} - -class _Button extends StatefulWidget { - final String number; - final String text; - final VoidCallback? onTap; - final bool muteButton; - final Widget? icon; - - const _Button({ - required this.number, - required this.text, - this.muteButton = false, - required this.onTap, - this.icon, - }); - - @override - State<_Button> createState() => _ButtonState(); -} - -class _ButtonState extends State<_Button> { - bool isPressed = false; - - void _onTapDown(TapDownDetails details) { - setState(() { - isPressed = true; - }); - } - - void _onTapUp(TapUpDetails details) async { - setState(() { - isPressed = false; - }); - } - - @override - Widget build(BuildContext context) { - final colorScheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - return Expanded( - child: GestureDetector( - onTap: widget.onTap, - onTapDown: _onTapDown, - onTapUp: _onTapUp, - child: AnimatedContainer( - duration: const Duration(milliseconds: 100), - curve: Curves.easeOut, - child: Container( - margin: const EdgeInsets.all(4), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(6), - color: isPressed - ? colorScheme.backgroundElevated - : widget.muteButton - ? colorScheme.fillFaintPressed - : widget.icon == null - ? colorScheme.backgroundElevated2 - : null, - ), - child: Center( - child: widget.muteButton - ? const SizedBox.shrink() - : widget.icon != null - ? Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 10, - ), - child: widget.icon, - ) - : Container( - padding: const EdgeInsets.all(4), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - widget.number, - style: textTheme.h3, - ), - Text( - widget.text, - style: textTheme.tinyBold, - ), - ], - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_auto_lock.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_auto_lock.dart deleted file mode 100644 index 869bb1e40a..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_auto_lock.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/theme/ente_theme.dart'; -import 'package:ente_auth/ui/components/captioned_text_widget.dart'; -import 'package:ente_auth/ui/components/divider_widget.dart'; -import 'package:ente_auth/ui/components/menu_item_widget.dart'; -import 'package:ente_auth/ui/components/separators.dart'; -import 'package:ente_auth/ui/components/title_bar_title_widget.dart'; -import 'package:ente_auth/ui/components/title_bar_widget.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; -import 'package:flutter/material.dart'; - -class LockScreenAutoLock extends StatefulWidget { - const LockScreenAutoLock({super.key}); - - @override - State createState() => _LockScreenAutoLockState(); -} - -class _LockScreenAutoLockState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - body: CustomScrollView( - primary: false, - slivers: [ - TitleBarWidget( - flexibleSpaceTitle: TitleBarTitleWidget( - title: context.l10n.autoLock, - ), - ), - SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - return const Padding( - padding: EdgeInsets.symmetric( - horizontal: 16, - vertical: 20, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(8)), - child: AutoLockItems(), - ), - ], - ), - ], - ), - ); - }, - childCount: 1, - ), - ), - ], - ), - ); - } -} - -class AutoLockItems extends StatefulWidget { - const AutoLockItems({super.key}); - - @override - State createState() => _AutoLockItemsState(); -} - -class _AutoLockItemsState extends State { - final autoLockDurations = LockScreenSettings.instance.autoLockDurations; - List items = []; - Duration currentAutoLockTime = const Duration(seconds: 5); - - @override - void initState() { - for (Duration autoLockDuration in autoLockDurations) { - if (autoLockDuration.inMilliseconds == - LockScreenSettings.instance.getAutoLockTime()) { - currentAutoLockTime = autoLockDuration; - break; - } - } - super.initState(); - } - - @override - Widget build(BuildContext context) { - items.clear(); - for (Duration autoLockDuration in autoLockDurations) { - items.add( - _menuItemForPicker(autoLockDuration), - ); - } - items = addSeparators( - items, - DividerWidget( - dividerType: DividerType.menuNoIcon, - bgColor: getEnteColorScheme(context).fillFaint, - ), - ); - return Column( - mainAxisSize: MainAxisSize.min, - children: items, - ); - } - - Widget _menuItemForPicker(Duration autoLockTime) { - return MenuItemWidget( - key: ValueKey(autoLockTime), - menuItemColor: getEnteColorScheme(context).fillFaint, - captionedTextWidget: CaptionedTextWidget( - title: _formatTime(autoLockTime), - ), - trailingIcon: currentAutoLockTime == autoLockTime ? Icons.check : null, - alignCaptionedTextToLeft: true, - isTopBorderRadiusRemoved: true, - isBottomBorderRadiusRemoved: true, - showOnlyLoadingState: true, - onTap: () async { - await LockScreenSettings.instance.setAutoLockTime(autoLockTime).then( - (value) => { - setState(() { - currentAutoLockTime = autoLockTime; - }), - }, - ); - }, - ); - } - - String _formatTime(Duration duration) { - if (duration.inHours != 0) { - return "${duration.inHours}hr"; - } else if (duration.inMinutes != 0) { - return "${duration.inMinutes}m"; - } else if (duration.inSeconds != 0) { - return "${duration.inSeconds}s"; - } else { - return context.l10n.immediately; - } - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_password.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_password.dart deleted file mode 100644 index dee6fd2db9..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_password.dart +++ /dev/null @@ -1,186 +0,0 @@ -import "package:ente_auth/l10n/l10n.dart"; -import "package:ente_auth/theme/ente_theme.dart"; -import "package:ente_auth/ui/common/dynamic_fab.dart"; -import "package:ente_auth/ui/components/buttons/icon_button_widget.dart"; -import "package:ente_auth/ui/components/text_input_widget.dart"; -import "package:ente_auth/utils/lock_screen_settings.dart"; -import "package:flutter/material.dart"; -import "package:flutter/services.dart"; - -class LockScreenConfirmPassword extends StatefulWidget { - const LockScreenConfirmPassword({ - super.key, - required this.password, - }); - final String password; - - @override - State createState() => - _LockScreenConfirmPasswordState(); -} - -class _LockScreenConfirmPasswordState extends State { - final _confirmPasswordController = TextEditingController(text: null); - final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance; - final _focusNode = FocusNode(); - final _isFormValid = ValueNotifier(false); - final _submitNotifier = ValueNotifier(false); - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - _focusNode.requestFocus(); - }); - } - - @override - void dispose() { - _submitNotifier.dispose(); - _focusNode.dispose(); - _isFormValid.dispose(); - _confirmPasswordController.dispose(); - super.dispose(); - } - - Future _confirmPasswordMatch() async { - if (widget.password == _confirmPasswordController.text) { - await _lockscreenSetting.setPassword(_confirmPasswordController.text); - - Navigator.of(context).pop(true); - Navigator.of(context).pop(true); - return; - } - await HapticFeedback.vibrate(); - throw Exception("Incorrect password"); - } - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - final isKeypadOpen = MediaQuery.viewInsetsOf(context).bottom > 100; - - FloatingActionButtonLocation? fabLocation() { - if (isKeypadOpen) { - return null; - } else { - return FloatingActionButtonLocation.centerFloat; - } - } - - return Scaffold( - resizeToAvoidBottomInset: isKeypadOpen, - appBar: AppBar( - elevation: 0, - leading: IconButton( - onPressed: () { - FocusScope.of(context).unfocus(); - Navigator.of(context).pop(); - }, - icon: Icon( - Icons.arrow_back, - color: colorTheme.textBase, - ), - ), - ), - floatingActionButton: ValueListenableBuilder( - valueListenable: _isFormValid, - builder: (context, isFormValid, child) { - return DynamicFAB( - isKeypadOpen: isKeypadOpen, - buttonText: context.l10n.confirm, - isFormValid: isFormValid, - onPressedFunction: () async { - _submitNotifier.value = !_submitNotifier.value; - }, - ); - }, - ), - floatingActionButtonLocation: fabLocation(), - floatingActionButtonAnimator: NoScalingAnimation(), - body: SingleChildScrollView( - child: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 120, - width: 120, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 82, - height: 82, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - colors: [ - Colors.grey.shade500.withOpacity(0.2), - Colors.grey.shade50.withOpacity(0.1), - Colors.grey.shade400.withOpacity(0.2), - Colors.grey.shade300.withOpacity(0.4), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorTheme.backgroundBase, - ), - ), - ), - ), - SizedBox( - height: 75, - width: 75, - child: CircularProgressIndicator( - color: colorTheme.fillFaintPressed, - value: 1, - strokeWidth: 1.5, - ), - ), - IconButtonWidget( - icon: Icons.lock, - iconButtonType: IconButtonType.primary, - iconColor: colorTheme.textBase, - ), - ], - ), - ), - Text( - context.l10n.reEnterPassword, - style: textTheme.bodyBold, - ), - const Padding(padding: EdgeInsets.all(12)), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: TextInputWidget( - hintText: context.l10n.confirmPassword, - autoFocus: true, - textCapitalization: TextCapitalization.none, - isPasswordInput: true, - shouldSurfaceExecutionStates: false, - onChange: (p0) { - _confirmPasswordController.text = p0; - _isFormValid.value = - _confirmPasswordController.text.isNotEmpty; - }, - onSubmit: (p0) { - return _confirmPasswordMatch(); - }, - submitNotifier: _submitNotifier, - ), - ), - const Padding(padding: EdgeInsets.all(12)), - ], - ), - ), - ), - ); - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_pin.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_pin.dart deleted file mode 100644 index 5ed7c48796..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_confirm_pin.dart +++ /dev/null @@ -1,211 +0,0 @@ -import "dart:io"; - -import "package:ente_auth/l10n/l10n.dart"; -import "package:ente_auth/theme/ente_theme.dart"; -import "package:ente_auth/ui/settings/lock_screen/custom_pin_keypad.dart"; -import "package:ente_auth/utils/lock_screen_settings.dart"; -import "package:flutter/material.dart"; -import "package:flutter/services.dart"; -import "package:pinput/pinput.dart"; - -class LockScreenConfirmPin extends StatefulWidget { - const LockScreenConfirmPin({super.key, required this.pin}); - final String pin; - @override - State createState() => _LockScreenConfirmPinState(); -} - -class _LockScreenConfirmPinState extends State { - final _confirmPinController = TextEditingController(text: null); - bool isConfirmPinValid = false; - bool isPlatformDesktop = false; - final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance; - final _pinPutDecoration = PinTheme( - height: 48, - width: 48, - padding: const EdgeInsets.only(top: 6.0), - decoration: BoxDecoration( - border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)), - borderRadius: BorderRadius.circular(15.0), - ), - ); - - @override - void initState() { - super.initState(); - isPlatformDesktop = - Platform.isLinux || Platform.isMacOS || Platform.isWindows; - } - - @override - void dispose() { - super.dispose(); - _confirmPinController.dispose(); - } - - Future _confirmPinMatch() async { - if (widget.pin == _confirmPinController.text) { - await _lockscreenSetting.setPin(_confirmPinController.text); - - Navigator.of(context).pop(true); - Navigator.of(context).pop(true); - return; - } - setState(() { - isConfirmPinValid = true; - }); - await HapticFeedback.vibrate(); - await Future.delayed(const Duration(milliseconds: 75)); - _confirmPinController.clear(); - setState(() { - isConfirmPinValid = false; - }); - } - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - return Scaffold( - appBar: AppBar( - elevation: 0, - leading: IconButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - icon: Icon( - Icons.arrow_back, - color: colorTheme.textBase, - ), - ), - ), - floatingActionButton: isPlatformDesktop - ? null - : CustomPinKeypad(controller: _confirmPinController), - floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, - body: SingleChildScrollView( - child: _getBody(colorTheme, textTheme), - ), - ); - } - - Widget _getBody(colorTheme, textTheme) { - return Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 120, - width: 120, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 82, - height: 82, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - colors: [ - Colors.grey.shade500.withOpacity(0.2), - Colors.grey.shade50.withOpacity(0.1), - Colors.grey.shade400.withOpacity(0.2), - Colors.grey.shade300.withOpacity(0.4), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorTheme.backgroundBase, - ), - ), - ), - ), - SizedBox( - height: 75, - width: 75, - child: ValueListenableBuilder( - valueListenable: _confirmPinController, - builder: (context, value, child) { - return TweenAnimationBuilder( - tween: Tween( - begin: 0, - end: _confirmPinController.text.length / 4, - ), - curve: Curves.ease, - duration: const Duration(milliseconds: 250), - builder: (context, value, _) => - CircularProgressIndicator( - backgroundColor: colorTheme.fillFaintPressed, - value: value, - color: colorTheme.primary400, - strokeWidth: 1.5, - ), - ); - }, - ), - ), - Icon( - Icons.lock, - color: colorTheme.textBase, - size: 30, - ), - ], - ), - ), - Text( - context.l10n.reEnterPin, - style: textTheme.bodyBold, - ), - const Padding(padding: EdgeInsets.all(12)), - Pinput( - length: 4, - showCursor: false, - useNativeKeyboard: isPlatformDesktop, - autofocus: true, - controller: _confirmPinController, - defaultPinTheme: _pinPutDecoration, - submittedPinTheme: _pinPutDecoration.copyWith( - textStyle: textTheme.h3Bold, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.fillBase, - ), - ), - ), - followingPinTheme: _pinPutDecoration.copyWith( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.fillMuted, - ), - ), - ), - focusedPinTheme: _pinPutDecoration, - errorPinTheme: _pinPutDecoration.copyWith( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.warning400, - ), - ), - ), - errorText: '', - obscureText: true, - obscuringCharacter: '*', - forceErrorState: isConfirmPinValid, - onCompleted: (value) async { - await _confirmPinMatch(); - }, - ), - ], - ), - ); - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_options.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_options.dart deleted file mode 100644 index 7f48bca84d..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_options.dart +++ /dev/null @@ -1,397 +0,0 @@ -import "dart:async"; -import "dart:io"; - -import "package:ente_auth/l10n/l10n.dart"; -import "package:ente_auth/services/local_authentication_service.dart"; -import "package:ente_auth/theme/ente_theme.dart"; -import "package:ente_auth/ui/components/buttons/button_widget.dart"; -import "package:ente_auth/ui/components/captioned_text_widget.dart"; -import "package:ente_auth/ui/components/dialog_widget.dart"; -import "package:ente_auth/ui/components/divider_widget.dart"; -import "package:ente_auth/ui/components/menu_item_widget.dart"; -import "package:ente_auth/ui/components/models/button_type.dart"; -import "package:ente_auth/ui/components/title_bar_title_widget.dart"; -import "package:ente_auth/ui/components/title_bar_widget.dart"; -import "package:ente_auth/ui/components/toggle_switch_widget.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_auto_lock.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_password.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_pin.dart"; -import "package:ente_auth/ui/tools/app_lock.dart"; -import "package:ente_auth/utils/lock_screen_settings.dart"; -import "package:ente_auth/utils/navigation_util.dart"; -import "package:ente_auth/utils/platform_util.dart"; -import "package:flutter/material.dart"; - -class LockScreenOptions extends StatefulWidget { - const LockScreenOptions({super.key}); - - @override - State createState() => _LockScreenOptionsState(); -} - -class _LockScreenOptionsState extends State { - final LockScreenSettings _lockScreenSettings = LockScreenSettings.instance; - late bool appLock = false; - bool isPinEnabled = false; - bool isPasswordEnabled = false; - late int autoLockTimeInMilliseconds; - late bool hideAppContent; - late bool isSystemLockEnabled = false; - - @override - void initState() { - super.initState(); - hideAppContent = _lockScreenSettings.getShouldHideAppContent(); - autoLockTimeInMilliseconds = _lockScreenSettings.getAutoLockTime(); - _initializeSettings(); - appLock = _lockScreenSettings.getIsAppLockSet(); - } - - Future _initializeSettings() async { - final bool passwordEnabled = await _lockScreenSettings.isPasswordSet(); - final bool pinEnabled = await _lockScreenSettings.isPinSet(); - final bool shouldHideAppContent = - _lockScreenSettings.getShouldHideAppContent(); - final bool systemLockEnabled = _lockScreenSettings.shouldShowSystemLockScreen(); - setState(() { - isPasswordEnabled = passwordEnabled; - isPinEnabled = pinEnabled; - hideAppContent = shouldHideAppContent; - isSystemLockEnabled = systemLockEnabled; - }); - } - - Future _deviceLock() async { - if (await LocalAuthenticationService.instance - .isLocalAuthSupportedOnDevice()) { - await _lockScreenSettings.removePinAndPassword(); - await _lockScreenSettings.setSystemLockScreen(!isSystemLockEnabled); - } else { - await showDialogWidget( - context: context, - title: context.l10n.noSystemLockFound, - body: context.l10n.deviceLockEnablePreSteps, - isDismissible: true, - buttons: const [ - ButtonWidget( - buttonType: ButtonType.secondary, - labelText: "OK", - isInAlert: true, - ), - ], - ); - } - await _initializeSettings(); - } - - Future _pinLock() async { - final bool result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return const LockScreenPin(); - }, - ), - ); - - if (result) { - await _lockScreenSettings.setSystemLockScreen(false); - await _lockScreenSettings.setAppLockEnabled(true); - setState(() { - appLock = _lockScreenSettings.getIsAppLockSet(); - }); - } - await _initializeSettings(); - } - - Future _passwordLock() async { - final bool result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return const LockScreenPassword(); - }, - ), - ); - if (result) { - await _lockScreenSettings.setSystemLockScreen(false); - setState(() { - appLock = _lockScreenSettings.getIsAppLockSet(); - }); - } - await _initializeSettings(); - } - - Future _onToggleSwitch() async { - AppLock.of(context)!.setEnabled(!appLock); - if (await LocalAuthenticationService.instance - .isLocalAuthSupportedOnDevice()) { - await _lockScreenSettings.setSystemLockScreen(!appLock); - await _lockScreenSettings.setAppLockEnabled(!appLock); - } else { - await _lockScreenSettings.setSystemLockScreen(false); - await _lockScreenSettings.setAppLockEnabled(false); - } - await _lockScreenSettings.removePinAndPassword(); - if (PlatformUtil.isMobile()) { - await _lockScreenSettings.setHideAppContent(!appLock); - setState(() { - hideAppContent = _lockScreenSettings.getShouldHideAppContent(); - }); - } - await _initializeSettings(); - setState(() { - appLock = !appLock; - }); - } - - Future _onAutoLock() async { - await routeToPage( - context, - const LockScreenAutoLock(), - ).then( - (value) { - setState(() { - autoLockTimeInMilliseconds = _lockScreenSettings.getAutoLockTime(); - }); - }, - ); - } - - Future _onHideContent() async { - setState(() { - hideAppContent = !hideAppContent; - }); - await _lockScreenSettings.setHideAppContent(hideAppContent); - } - - String _formatTime(Duration duration) { - if (duration.inHours != 0) { - return "in ${duration.inHours} hour${duration.inHours > 1 ? 's' : ''}"; - } else if (duration.inMinutes != 0) { - return "in ${duration.inMinutes} minute${duration.inMinutes > 1 ? 's' : ''}"; - } else if (duration.inSeconds != 0) { - return "in ${duration.inSeconds} second${duration.inSeconds > 1 ? 's' : ''}"; - } else { - return context.l10n.immediately; - } - } - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - return Scaffold( - body: CustomScrollView( - primary: false, - slivers: [ - TitleBarWidget( - flexibleSpaceTitle: TitleBarTitleWidget( - title: context.l10n.appLock, - ), - ), - SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: context.l10n.appLock, - ), - alignCaptionedTextToLeft: true, - singleBorderRadius: 8, - menuItemColor: colorTheme.fillFaint, - trailingWidget: ToggleSwitchWidget( - value: () => appLock, - onChanged: () => _onToggleSwitch(), - ), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 210), - switchInCurve: Curves.easeOut, - switchOutCurve: Curves.easeIn, - child: !appLock - ? Padding( - padding: const EdgeInsets.only( - top: 14, - left: 14, - right: 12, - ), - child: Text( - context.l10n.appLockDescription, - style: textTheme.miniFaint, - textAlign: TextAlign.left, - ), - ) - : const SizedBox(), - ), - const Padding( - padding: EdgeInsets.only(top: 24), - ), - ], - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 210), - switchInCurve: Curves.easeOut, - switchOutCurve: Curves.easeIn, - child: appLock - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: context.l10n.deviceLock, - ), - surfaceExecutionStates: false, - alignCaptionedTextToLeft: true, - isTopBorderRadiusRemoved: false, - isBottomBorderRadiusRemoved: true, - menuItemColor: colorTheme.fillFaint, - trailingIcon: isSystemLockEnabled - ? Icons.check - : null, - trailingIconColor: colorTheme.textBase, - onTap: () => _deviceLock(), - ), - DividerWidget( - dividerType: DividerType.menuNoIcon, - bgColor: colorTheme.fillFaint, - ), - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: context.l10n.pinLock, - ), - surfaceExecutionStates: false, - alignCaptionedTextToLeft: true, - isTopBorderRadiusRemoved: true, - isBottomBorderRadiusRemoved: true, - menuItemColor: colorTheme.fillFaint, - trailingIcon: - isPinEnabled ? Icons.check : null, - trailingIconColor: colorTheme.textBase, - onTap: () => _pinLock(), - ), - DividerWidget( - dividerType: DividerType.menuNoIcon, - bgColor: colorTheme.fillFaint, - ), - MenuItemWidget( - captionedTextWidget: CaptionedTextWidget( - title: context.l10n.password, - ), - surfaceExecutionStates: false, - alignCaptionedTextToLeft: true, - isTopBorderRadiusRemoved: true, - isBottomBorderRadiusRemoved: false, - menuItemColor: colorTheme.fillFaint, - trailingIcon: isPasswordEnabled - ? Icons.check - : null, - trailingIconColor: colorTheme.textBase, - onTap: () => _passwordLock(), - ), - const SizedBox( - height: 24, - ), - PlatformUtil.isMobile() - ? MenuItemWidget( - captionedTextWidget: - CaptionedTextWidget( - title: context.l10n.autoLock, - subTitle: _formatTime( - Duration( - milliseconds: - autoLockTimeInMilliseconds, - ), - ), - ), - surfaceExecutionStates: false, - alignCaptionedTextToLeft: true, - singleBorderRadius: 8, - menuItemColor: colorTheme.fillFaint, - trailingIconColor: - colorTheme.textBase, - onTap: () => _onAutoLock(), - ) - : const SizedBox.shrink(), - PlatformUtil.isMobile() - ? Padding( - padding: const EdgeInsets.only( - top: 14, - left: 14, - right: 12, - ), - child: Text( - context.l10n - .autoLockFeatureDescription, - style: textTheme.miniFaint, - textAlign: TextAlign.left, - ), - ) - : const SizedBox.shrink(), - PlatformUtil.isMobile() - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - const SizedBox(height: 24), - MenuItemWidget( - captionedTextWidget: - CaptionedTextWidget( - title: - context.l10n.hideContent, - ), - alignCaptionedTextToLeft: true, - singleBorderRadius: 8, - menuItemColor: - colorTheme.fillFaint, - trailingWidget: - ToggleSwitchWidget( - value: () => hideAppContent, - onChanged: () => - _onHideContent(), - ), - ), - Padding( - padding: const EdgeInsets.only( - top: 14, - left: 14, - right: 12, - ), - child: Text( - Platform.isAndroid - ? context.l10n - .hideContentDescriptionAndroid - : context.l10n - .hideContentDescriptioniOS, - style: textTheme.miniFaint, - textAlign: TextAlign.left, - ), - ), - ], - ) - : const SizedBox.shrink(), - ], - ) - : const SizedBox.shrink(), - ), - ], - ), - ), - ); - }, - childCount: 1, - ), - ), - ], - ), - ); - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_password.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_password.dart deleted file mode 100644 index 43a103523a..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_password.dart +++ /dev/null @@ -1,250 +0,0 @@ -import "dart:convert"; - -import "package:ente_auth/l10n/l10n.dart"; -import "package:ente_auth/theme/ente_theme.dart"; -import "package:ente_auth/ui/common/dynamic_fab.dart"; -import "package:ente_auth/ui/components/buttons/icon_button_widget.dart"; -import "package:ente_auth/ui/components/text_input_widget.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_confirm_password.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart"; -import "package:ente_auth/utils/lock_screen_settings.dart"; -import "package:ente_crypto_dart/ente_crypto_dart.dart"; -import "package:flutter/material.dart"; -import "package:flutter/services.dart"; - -/// [isChangingLockScreenSettings] Authentication required for changing lock screen settings. -/// Set to true when the app requires the user to authenticate before allowing -/// changes to the lock screen settings. - -/// [isAuthenticatingOnAppLaunch] Authentication required on app launch. -/// Set to true when the app requires the user to authenticate immediately upon opening. - -/// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password). -/// Set to true when the app requires the to authenticate for sensitive actions like email, password changes. - -class LockScreenPassword extends StatefulWidget { - const LockScreenPassword({ - super.key, - this.isChangingLockScreenSettings = false, - this.isAuthenticatingOnAppLaunch = false, - this.isAuthenticatingForInAppChange = false, - this.authPass, - }); - - final bool isChangingLockScreenSettings; - final bool isAuthenticatingOnAppLaunch; - final bool isAuthenticatingForInAppChange; - final String? authPass; - @override - State createState() => _LockScreenPasswordState(); -} - -class _LockScreenPasswordState extends State { - final _passwordController = TextEditingController(text: null); - final _focusNode = FocusNode(); - final _isFormValid = ValueNotifier(false); - final _submitNotifier = ValueNotifier(false); - int invalidAttemptsCount = 0; - - final _lockscreenSetting = LockScreenSettings.instance; - @override - void initState() { - super.initState(); - invalidAttemptsCount = _lockscreenSetting.getInvalidAttemptCount(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - _focusNode.requestFocus(); - }); - } - - @override - void dispose() { - super.dispose(); - _submitNotifier.dispose(); - _focusNode.dispose(); - _isFormValid.dispose(); - _passwordController.dispose(); - } - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - final isKeypadOpen = MediaQuery.viewInsetsOf(context).bottom > 100; - - FloatingActionButtonLocation? fabLocation() { - if (isKeypadOpen) { - return null; - } else { - return FloatingActionButtonLocation.centerFloat; - } - } - - return Scaffold( - resizeToAvoidBottomInset: isKeypadOpen, - appBar: AppBar( - elevation: 0, - leading: IconButton( - onPressed: () { - FocusScope.of(context).unfocus(); - Navigator.of(context).pop(false); - }, - icon: Icon( - Icons.arrow_back, - color: colorTheme.textBase, - ), - ), - ), - floatingActionButton: ValueListenableBuilder( - valueListenable: _isFormValid, - builder: (context, isFormValid, child) { - return DynamicFAB( - isKeypadOpen: isKeypadOpen, - buttonText: context.l10n.next, - isFormValid: isFormValid, - onPressedFunction: () async { - _submitNotifier.value = !_submitNotifier.value; - }, - ); - }, - ), - floatingActionButtonLocation: fabLocation(), - floatingActionButtonAnimator: NoScalingAnimation(), - body: SingleChildScrollView( - child: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 120, - width: 120, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 82, - height: 82, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - colors: [ - Colors.grey.shade500.withOpacity(0.2), - Colors.grey.shade50.withOpacity(0.1), - Colors.grey.shade400.withOpacity(0.2), - Colors.grey.shade300.withOpacity(0.4), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorTheme.backgroundBase, - ), - ), - ), - ), - SizedBox( - height: 75, - width: 75, - child: CircularProgressIndicator( - color: colorTheme.fillFaintPressed, - value: 1, - strokeWidth: 1.5, - ), - ), - IconButtonWidget( - icon: Icons.lock, - iconButtonType: IconButtonType.primary, - iconColor: colorTheme.textBase, - ), - ], - ), - ), - Text( - widget.isChangingLockScreenSettings - ? context.l10n.enterPassword - : context.l10n.setNewPassword, - textAlign: TextAlign.center, - style: textTheme.bodyBold, - ), - const Padding(padding: EdgeInsets.all(12)), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: TextInputWidget( - hintText: context.l10n.password, - autoFocus: true, - textCapitalization: TextCapitalization.none, - isPasswordInput: true, - shouldSurfaceExecutionStates: false, - onChange: (p0) { - _passwordController.text = p0; - _isFormValid.value = _passwordController.text.isNotEmpty; - }, - onSubmit: (p0) { - return _confirmPassword(); - }, - submitNotifier: _submitNotifier, - ), - ), - const Padding(padding: EdgeInsets.all(12)), - ], - ), - ), - ), - ); - } - - Future _confirmPasswordAuth(String inputtedPassword) async { - final Uint8List? salt = await _lockscreenSetting.getSalt(); - final hash = cryptoPwHash( - utf8.encode(inputtedPassword), - salt!, - sodium.crypto.pwhash.memLimitInteractive, - sodium.crypto.pwhash.opsLimitSensitive, - sodium, - ); - if (widget.authPass == base64Encode(hash)) { - await _lockscreenSetting.setInvalidAttemptCount(0); - - widget.isAuthenticatingOnAppLaunch || - widget.isAuthenticatingForInAppChange - ? Navigator.of(context).pop(true) - : Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => const LockScreenOptions(), - ), - ); - return true; - } else { - if (widget.isAuthenticatingOnAppLaunch) { - invalidAttemptsCount++; - await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount); - if (invalidAttemptsCount > 4) { - Navigator.of(context).pop(false); - } - } - - await HapticFeedback.vibrate(); - throw Exception("Incorrect password"); - } - } - - Future _confirmPassword() async { - if (widget.isChangingLockScreenSettings) { - await _confirmPasswordAuth(_passwordController.text); - return; - } else { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) => LockScreenConfirmPassword( - password: _passwordController.text, - ), - ), - ); - _passwordController.clear(); - } - } -} diff --git a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_pin.dart b/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_pin.dart deleted file mode 100644 index 8cd4509f51..0000000000 --- a/mobile/apps/auth/lib/ui/settings/lock_screen/lock_screen_pin.dart +++ /dev/null @@ -1,284 +0,0 @@ -import "dart:convert"; -import "dart:io"; - -import "package:ente_auth/l10n/l10n.dart"; -import "package:ente_auth/theme/colors.dart"; -import "package:ente_auth/theme/ente_theme.dart"; -import "package:ente_auth/theme/text_style.dart"; -import "package:ente_auth/ui/settings/lock_screen/custom_pin_keypad.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_confirm_pin.dart"; -import "package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart"; -import "package:ente_auth/utils/lock_screen_settings.dart"; -import "package:ente_crypto_dart/ente_crypto_dart.dart"; -import "package:flutter/material.dart"; -import "package:flutter/services.dart"; -import 'package:pinput/pinput.dart'; - -/// [isChangingLockScreenSettings] Authentication required for changing lock screen settings. -/// Set to true when the app requires the user to authenticate before allowing -/// changes to the lock screen settings. - -/// [isAuthenticatingOnAppLaunch] Authentication required on app launch. -/// Set to true when the app requires the user to authenticate immediately upon opening. - -/// [isAuthenticatingForInAppChange] Authentication required for in-app changes (e.g., email, password). -/// Set to true when the app requires the to authenticate for sensitive actions like email, password changes. - -class LockScreenPin extends StatefulWidget { - const LockScreenPin({ - super.key, - this.isChangingLockScreenSettings = false, - this.isAuthenticatingOnAppLaunch = false, - this.isAuthenticatingForInAppChange = false, - this.authPin, - }); - - final bool isAuthenticatingOnAppLaunch; - final bool isChangingLockScreenSettings; - final bool isAuthenticatingForInAppChange; - final String? authPin; - @override - State createState() => _LockScreenPinState(); -} - -class _LockScreenPinState extends State { - final _pinController = TextEditingController(text: null); - - final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance; - bool isPinValid = false; - int invalidAttemptsCount = 0; - bool isPlatformDesktop = false; - @override - void initState() { - super.initState(); - isPlatformDesktop = - Platform.isLinux || Platform.isMacOS || Platform.isWindows; - invalidAttemptsCount = _lockscreenSetting.getInvalidAttemptCount(); - } - - @override - void dispose() { - super.dispose(); - _pinController.dispose(); - } - - Future confirmPinAuth(String inputtedPin) async { - final Uint8List? salt = await _lockscreenSetting.getSalt(); - final hash = cryptoPwHash( - utf8.encode(inputtedPin), - salt!, - sodium.crypto.pwhash.memLimitInteractive, - sodium.crypto.pwhash.opsLimitSensitive, - sodium, - ); - if (widget.authPin == base64Encode(hash)) { - invalidAttemptsCount = 0; - await _lockscreenSetting.setInvalidAttemptCount(0); - widget.isAuthenticatingOnAppLaunch || - widget.isAuthenticatingForInAppChange - ? Navigator.of(context).pop(true) - : Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => const LockScreenOptions(), - ), - ); - return true; - } else { - setState(() { - isPinValid = true; - }); - await HapticFeedback.vibrate(); - await Future.delayed(const Duration(milliseconds: 75)); - _pinController.clear(); - setState(() { - isPinValid = false; - }); - - if (widget.isAuthenticatingOnAppLaunch) { - invalidAttemptsCount++; - await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount); - if (invalidAttemptsCount > 4) { - Navigator.of(context).pop(false); - } - } - return false; - } - } - - Future _confirmPin(String inputtedPin) async { - if (widget.isChangingLockScreenSettings) { - await confirmPinAuth(inputtedPin); - return; - } else { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) => - LockScreenConfirmPin(pin: inputtedPin), - ), - ); - _pinController.clear(); - } - } - - final _pinPutDecoration = PinTheme( - height: 48, - width: 48, - padding: const EdgeInsets.only(top: 6.0), - decoration: BoxDecoration( - border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)), - borderRadius: BorderRadius.circular(15.0), - ), - ); - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - return Scaffold( - appBar: AppBar( - elevation: 0, - leading: IconButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - icon: Icon( - Icons.arrow_back, - color: colorTheme.textBase, - ), - ), - ), - floatingActionButton: isPlatformDesktop - ? null - : CustomPinKeypad(controller: _pinController), - floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, - body: SingleChildScrollView( - child: _getBody(colorTheme, textTheme), - ), - ); - } - - Widget _getBody( - EnteColorScheme colorTheme, - EnteTextTheme textTheme, - ) { - return Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 120, - width: 120, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 82, - height: 82, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - colors: [ - Colors.grey.shade500.withOpacity(0.2), - Colors.grey.shade50.withOpacity(0.1), - Colors.grey.shade400.withOpacity(0.2), - Colors.grey.shade300.withOpacity(0.4), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorTheme.backgroundBase, - ), - ), - ), - ), - SizedBox( - height: 75, - width: 75, - child: ValueListenableBuilder( - valueListenable: _pinController, - builder: (context, value, child) { - return TweenAnimationBuilder( - tween: Tween( - begin: 0, - end: _pinController.text.length / 4, - ), - curve: Curves.ease, - duration: const Duration(milliseconds: 250), - builder: (context, value, _) => - CircularProgressIndicator( - backgroundColor: colorTheme.fillFaintPressed, - value: value, - color: colorTheme.primary400, - strokeWidth: 1.5, - ), - ); - }, - ), - ), - Icon( - Icons.lock, - color: colorTheme.textBase, - size: 30, - ), - ], - ), - ), - Text( - widget.isChangingLockScreenSettings - ? context.l10n.enterPin - : context.l10n.setNewPin, - style: textTheme.bodyBold, - ), - const Padding(padding: EdgeInsets.all(12)), - Pinput( - length: 4, - showCursor: false, - useNativeKeyboard: isPlatformDesktop, - controller: _pinController, - autofocus: true, - defaultPinTheme: _pinPutDecoration, - submittedPinTheme: _pinPutDecoration.copyWith( - textStyle: textTheme.h3Bold, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.fillBase, - ), - ), - ), - followingPinTheme: _pinPutDecoration.copyWith( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.fillMuted, - ), - ), - ), - focusedPinTheme: _pinPutDecoration, - errorPinTheme: _pinPutDecoration.copyWith( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: colorTheme.warning400, - ), - ), - ), - forceErrorState: isPinValid, - obscureText: true, - obscuringCharacter: '*', - errorText: '', - onCompleted: (value) async { - await _confirmPin(_pinController.text); - }, - ), - ], - ), - ); - } -} diff --git a/mobile/apps/auth/lib/ui/settings/security_section_widget.dart b/mobile/apps/auth/lib/ui/settings/security_section_widget.dart index dab16cb56f..1053e68b41 100644 --- a/mobile/apps/auth/lib/ui/settings/security_section_widget.dart +++ b/mobile/apps/auth/lib/ui/settings/security_section_widget.dart @@ -3,8 +3,7 @@ import 'dart:typed_data'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/models/user_details.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; +import 'package:ente_auth/models/user_details.dart'; import 'package:ente_auth/services/passkey_service.dart'; import 'package:ente_auth/services/user_service.dart'; import 'package:ente_auth/theme/ente_theme.dart'; @@ -16,15 +15,16 @@ import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart'; import 'package:ente_auth/ui/components/menu_item_widget.dart'; import 'package:ente_auth/ui/components/models/button_result.dart'; import 'package:ente_auth/ui/components/toggle_switch_widget.dart'; -import 'package:ente_auth/ui/settings/common_settings.dart'; -import 'package:ente_auth/ui/settings/lock_screen/lock_screen_options.dart'; -import 'package:ente_auth/utils/auth_util.dart'; -import 'package:ente_auth/utils/dialog_util.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; +import 'package:ente_auth/ui/settings/common_settings.dart'; +import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/navigation_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/toast_util.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; +import 'package:ente_lock_screen/auth_util.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; +import 'package:ente_lock_screen/lock_screen_settings.dart'; +import 'package:ente_lock_screen/ui/lock_screen_options.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; diff --git a/mobile/apps/auth/lib/ui/settings_page.dart b/mobile/apps/auth/lib/ui/settings_page.dart index eb6ffca0fe..d543985b57 100644 --- a/mobile/apps/auth/lib/ui/settings_page.dart +++ b/mobile/apps/auth/lib/ui/settings_page.dart @@ -2,8 +2,7 @@ import 'dart:io'; import 'package:ente_auth/core/configuration.dart'; import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/onboarding/view/onboarding_page.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; +import 'package:ente_auth/onboarding/view/onboarding_page.dart'; import 'package:ente_auth/services/user_service.dart'; import 'package:ente_auth/store/code_store.dart'; import 'package:ente_auth/theme/colors.dart'; @@ -27,6 +26,7 @@ import 'package:ente_auth/ui/settings/title_bar_widget.dart'; import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/navigation_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; +import 'package:ente_lock_screen/local_authentication_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/mobile/apps/auth/lib/ui/tools/app_lock.dart b/mobile/apps/auth/lib/ui/tools/app_lock.dart deleted file mode 100644 index 1428c553c6..0000000000 --- a/mobile/apps/auth/lib/ui/tools/app_lock.dart +++ /dev/null @@ -1,209 +0,0 @@ -import 'dart:async'; - -import 'package:ente_auth/locale.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -/// A widget which handles app lifecycle events for showing and hiding a lock screen. -/// This should wrap around a `MyApp` widget (or equivalent). -/// -/// [lockScreen] is a [Widget] which should be a screen for handling login logic and -/// calling `AppLock.of(context).didUnlock();` upon a successful login. -/// -/// [builder] is a [Function] taking an [Object] as its argument and should return a -/// [Widget]. The [Object] argument is provided by the [lockScreen] calling -/// `AppLock.of(context).didUnlock();` with an argument. [Object] can then be injected -/// in to your `MyApp` widget (or equivalent). -/// -/// [enabled] determines wether or not the [lockScreen] should be shown on app launch -/// and subsequent app pauses. This can be changed later on using `AppLock.of(context).enable();`, -/// `AppLock.of(context).disable();` or the convenience method `AppLock.of(context).setEnabled(enabled);` -/// using a bool argument. -/// -/// [backgroundLockLatency] determines how much time is allowed to pass when -/// the app is in the background state before the [lockScreen] widget should be -/// shown upon returning. It defaults to instantly. -/// - -// ignore_for_file: unnecessary_this, library_private_types_in_public_api -class AppLock extends StatefulWidget { - final Widget Function(Object?) builder; - final Widget lockScreen; - final bool enabled; - final Duration backgroundLockLatency; - final ThemeData? darkTheme; - final ThemeData? lightTheme; - final ThemeMode savedThemeMode; - final Locale? locale; - - const AppLock({ - super.key, - required this.builder, - required this.lockScreen, - required this.savedThemeMode, - this.enabled = true, - this.locale, - this.backgroundLockLatency = const Duration(seconds: 0), - this.darkTheme, - this.lightTheme, - }); - - static _AppLockState? of(BuildContext context) => - context.findAncestorStateOfType<_AppLockState>(); - - @override - State createState() => _AppLockState(); -} - -class _AppLockState extends State with WidgetsBindingObserver { - static final GlobalKey _navigatorKey = GlobalKey(); - - late bool _didUnlockForAppLaunch; - late bool _isLocked; - late bool _enabled; - - Timer? _backgroundLockLatencyTimer; - - @override - void initState() { - super.initState(); - - WidgetsBinding.instance.addObserver(this); - - this._didUnlockForAppLaunch = !this.widget.enabled; - this._isLocked = false; - this._enabled = this.widget.enabled; - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - if (!this._enabled) { - return; - } - - if (state == AppLifecycleState.paused && - (!this._isLocked && this._didUnlockForAppLaunch)) { - this._backgroundLockLatencyTimer = Timer( - Duration( - milliseconds: LockScreenSettings.instance.getAutoLockTime(), - ), - () => this.showLockScreen(), - ); - } - - if (state == AppLifecycleState.resumed) { - this._backgroundLockLatencyTimer?.cancel(); - } - - super.didChangeAppLifecycleState(state); - } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - - this._backgroundLockLatencyTimer?.cancel(); - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: this.widget.enabled ? this._lockScreen : this.widget.builder(null), - navigatorKey: _navigatorKey, - themeMode: widget.savedThemeMode, - theme: widget.lightTheme, - darkTheme: widget.darkTheme, - locale: widget.locale, - supportedLocales: appSupportedLocales, - localeListResolutionCallback: localResolutionCallBack, - localizationsDelegates: const [ - ...AppLocalizations.localizationsDelegates, - ], - onGenerateRoute: (settings) { - switch (settings.name) { - case '/lock-screen': - return PageRouteBuilder( - pageBuilder: (_, __, ___) => this._lockScreen, - ); - case '/unlocked': - return PageRouteBuilder( - pageBuilder: (_, __, ___) => - this.widget.builder(settings.arguments), - ); - } - return PageRouteBuilder(pageBuilder: (_, __, ___) => this._lockScreen); - }, - ); - } - - Widget get _lockScreen { - return PopScope( - child: this.widget.lockScreen, - canPop: false, - ); - } - - /// Causes `AppLock` to either pop the [lockScreen] if the app is already running - /// or instantiates widget returned from the [builder] method if the app is cold - /// launched. - /// - /// [args] is an optional argument which will get passed to the [builder] method - /// when built. Use this when you want to inject objects created from the - /// [lockScreen] in to the rest of your app so you can better guarantee that some - /// objects, services or databases are already instantiated before using them. - void didUnlock([Object? args]) { - if (this._didUnlockForAppLaunch) { - this._didUnlockOnAppPaused(); - } else { - this._didUnlockOnAppLaunch(args); - } - } - - /// Makes sure that [AppLock] shows the [lockScreen] on subsequent app pauses if - /// [enabled] is true of makes sure it isn't shown on subsequent app pauses if - /// [enabled] is false. - /// - /// This is a convenience method for calling the [enable] or [disable] method based - /// on [enabled]. - void setEnabled(bool enabled) { - if (enabled) { - this.enable(); - } else { - this.disable(); - } - } - - /// Makes sure that [AppLock] shows the [lockScreen] on subsequent app pauses. - void enable() { - setState(() { - this._enabled = true; - }); - } - - /// Makes sure that [AppLock] doesn't show the [lockScreen] on subsequent app pauses. - void disable() { - setState(() { - this._enabled = false; - }); - } - - /// Manually show the [lockScreen]. - Future showLockScreen() { - this._isLocked = true; - return _navigatorKey.currentState!.pushNamed('/lock-screen'); - } - - void _didUnlockOnAppLaunch(Object? args) { - this._didUnlockForAppLaunch = true; - _navigatorKey.currentState! - .pushReplacementNamed('/unlocked', arguments: args); - } - - void _didUnlockOnAppPaused() { - this._isLocked = false; - _navigatorKey.currentState!.pop(); - } -} diff --git a/mobile/apps/auth/lib/ui/tools/lock_screen.dart b/mobile/apps/auth/lib/ui/tools/lock_screen.dart deleted file mode 100644 index 71adcd3f28..0000000000 --- a/mobile/apps/auth/lib/ui/tools/lock_screen.dart +++ /dev/null @@ -1,367 +0,0 @@ -import 'dart:io'; -import 'dart:math'; - -import 'package:ente_auth/core/configuration.dart'; -import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/services/user_service.dart'; -import 'package:ente_auth/theme/ente_theme.dart'; -import 'package:ente_auth/ui/tools/app_lock.dart'; -import 'package:ente_auth/utils/auth_util.dart'; -import 'package:ente_auth/utils/dialog_util.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter_animate/flutter_animate.dart'; -import 'package:logging/logging.dart'; - -class LockScreen extends StatefulWidget { - const LockScreen({super.key}); - - @override - State createState() => _LockScreenState(); -} - -class _LockScreenState extends State with WidgetsBindingObserver { - final _logger = Logger("LockScreen"); - bool _isShowingLockScreen = false; - bool _hasPlacedAppInBackground = false; - bool _hasAuthenticationFailed = false; - int? lastAuthenticatingTime; - bool isTimerRunning = false; - int lockedTimeInSeconds = 0; - int invalidAttemptCount = 0; - int remainingTimeInSeconds = 0; - final _lockscreenSetting = LockScreenSettings.instance; - late Brightness _platformBrightness; - final bool isLoggedIn = Configuration.instance.isLoggedIn(); - - @override - void initState() { - _logger.info("initiatingState"); - super.initState(); - invalidAttemptCount = _lockscreenSetting.getInvalidAttemptCount(); - WidgetsBinding.instance.addObserver(this); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _showLockScreen(source: "postFrameInit"); - }); - _platformBrightness = - SchedulerBinding.instance.platformDispatcher.platformBrightness; - } - - @override - Widget build(BuildContext context) { - final colorTheme = getEnteColorScheme(context); - final textTheme = getEnteTextTheme(context); - return Scaffold( - appBar: AppBar( - elevation: 0, - leading: isLoggedIn - ? IconButton( - icon: const Icon(Icons.logout_outlined), - color: Theme.of(context).iconTheme.color, - onPressed: () { - _onLogoutTapped(context); - }, - ) - : const SizedBox.shrink(), - ), - body: GestureDetector( - onTap: () { - isTimerRunning ? null : _showLockScreen(source: "tap"); - }, - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - opacity: _platformBrightness == Brightness.light ? 0.08 : 0.12, - image: const ExactAssetImage( - 'assets/loading_photos_background.png', - ), - fit: BoxFit.cover, - ), - ), - child: Center( - child: Column( - children: [ - const Spacer(), - SizedBox( - height: 120, - width: 120, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 82, - height: 82, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - colors: [ - Colors.grey.shade500.withOpacity(0.2), - Colors.grey.shade50.withOpacity(0.1), - Colors.grey.shade400.withOpacity(0.2), - Colors.grey.shade300.withOpacity(0.4), - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorTheme.backgroundBase, - ), - ), - ), - ), - SizedBox( - height: 75, - width: 75, - child: TweenAnimationBuilder( - tween: Tween( - begin: isTimerRunning ? 0 : 1, - end: isTimerRunning - ? _getFractionOfTimeElapsed() - : 1, - ), - duration: const Duration(seconds: 1), - builder: (context, value, _) => - CircularProgressIndicator( - backgroundColor: colorTheme.fillFaintPressed, - value: value, - color: colorTheme.primary400, - strokeWidth: 1.5, - ), - ), - ), - Icon( - Icons.lock, - size: 30, - color: colorTheme.textBase, - ), - ], - ), - ), - const Spacer(), - isTimerRunning - ? Stack( - alignment: Alignment.center, - children: [ - Text( - context.l10n.tooManyIncorrectAttempts, - style: textTheme.small, - ) - .animate( - delay: const Duration(milliseconds: 2000), - ) - .fadeOut( - duration: 400.ms, - curve: Curves.easeInOutCirc, - ), - Text( - _formatTime(remainingTimeInSeconds), - style: textTheme.small, - ) - .animate( - delay: const Duration(milliseconds: 2250), - ) - .fadeIn( - duration: 400.ms, - curve: Curves.easeInOutCirc, - ), - ], - ) - : GestureDetector( - onTap: () => _showLockScreen(source: "tap"), - child: Text( - context.l10n.tapToUnlock, - style: textTheme.small, - ), - ), - const Padding( - padding: EdgeInsets.only(bottom: 24), - ), - ], - ), - ), - ), - ), - ); - } - - void _onLogoutTapped(BuildContext context) { - showChoiceActionSheet( - context, - title: context.l10n.areYouSureYouWantToLogout, - firstButtonLabel: context.l10n.yesLogout, - isCritical: true, - firstButtonOnTap: () async { - await UserService.instance.logout(context); - // To start the app afresh, resetting all state. - Process.killPid(pid, ProcessSignal.sigkill); - }, - ); - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - _logger.info(state.toString()); - if (state == AppLifecycleState.resumed && !_isShowingLockScreen) { - // This is triggered either when the lock screen is dismissed or when - // the app is brought to foreground - _hasPlacedAppInBackground = false; - final bool didAuthInLast5Seconds = lastAuthenticatingTime != null && - DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! < - 5000; - if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) { - // Show the lock screen again only if the app is resuming from the - // background, and not when the lock screen was explicitly dismissed - if (_lockscreenSetting.getlastInvalidAttemptTime() > - DateTime.now().millisecondsSinceEpoch && - !_isShowingLockScreen) { - final int time = (_lockscreenSetting.getlastInvalidAttemptTime() - - DateTime.now().millisecondsSinceEpoch) ~/ - 1000; - Future.delayed(Duration.zero, () { - startLockTimer(time); - _showLockScreen(source: "lifeCycle"); - }); - } - } else { - _hasAuthenticationFailed = false; // Reset failure state - } - } else if (state == AppLifecycleState.paused || - state == AppLifecycleState.inactive) { - // This is triggered either when the lock screen pops up or when - // the app is pushed to background - if (!_isShowingLockScreen) { - _hasPlacedAppInBackground = true; - _hasAuthenticationFailed = false; // reset failure state - } - } - } - - @override - void dispose() { - _logger.info('disposing'); - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } - - Future startLockTimer(int timeInSeconds) async { - if (isTimerRunning) { - return; - } - - setState(() { - isTimerRunning = true; - remainingTimeInSeconds = timeInSeconds; - }); - - while (remainingTimeInSeconds > 0) { - await Future.delayed(const Duration(seconds: 1)); - setState(() { - remainingTimeInSeconds--; - }); - } - - setState(() { - isTimerRunning = false; - }); - } - - double _getFractionOfTimeElapsed() { - final int totalLockedTime = - lockedTimeInSeconds = pow(2, invalidAttemptCount - 5).toInt() * 30; - if (remainingTimeInSeconds == 0) return 1; - - return 1 - remainingTimeInSeconds / totalLockedTime; - } - - String _formatTime(int seconds) { - final int hours = seconds ~/ 3600; - final int minutes = (seconds % 3600) ~/ 60; - final int remainingSeconds = seconds % 60; - - if (hours > 0) { - return "${hours}h ${minutes}m"; - } else if (minutes > 0) { - return "${minutes}m ${remainingSeconds}s"; - } else { - return "${remainingSeconds}s"; - } - } - - Future _autoLogoutOnMaxInvalidAttempts() async { - _logger.info("Auto logout on max invalid attempts"); - Navigator.of(context, rootNavigator: true).pop('dialog'); - Navigator.of(context).popUntil((route) => route.isFirst); - final dialog = createProgressDialog(context, "Logging out ..."); - await dialog.show(); - await Configuration.instance.logout(); - await dialog.hide(); - } - - Future _showLockScreen({String source = ''}) async { - final int currentTimestamp = DateTime.now().millisecondsSinceEpoch; - _logger.info("Showing lock screen $source $currentTimestamp"); - try { - if (currentTimestamp < _lockscreenSetting.getlastInvalidAttemptTime() && - !_isShowingLockScreen) { - final int remainingTime = - (_lockscreenSetting.getlastInvalidAttemptTime() - - currentTimestamp) ~/ - 1000; - - await startLockTimer(remainingTime); - } - _isShowingLockScreen = true; - final result = isTimerRunning - ? false - : await requestAuthentication( - context, - context.l10n.authToViewSecrets, - isOpeningApp: true, - ); - _logger.finest("LockScreen Result $result $currentTimestamp"); - _isShowingLockScreen = false; - if (result) { - lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch; - AppLock.of(context)?.didUnlock(); - await _lockscreenSetting.setInvalidAttemptCount(0); - setState(() { - lockedTimeInSeconds = 15; - isTimerRunning = false; - }); - } else { - if (!_hasPlacedAppInBackground) { - // Treat this as a failure only if user did not explicitly - // put the app in background - if (_lockscreenSetting.getInvalidAttemptCount() > 4 && - invalidAttemptCount != - _lockscreenSetting.getInvalidAttemptCount()) { - invalidAttemptCount = _lockscreenSetting.getInvalidAttemptCount(); - - if (invalidAttemptCount > 9) { - await _autoLogoutOnMaxInvalidAttempts(); - return; - } - - lockedTimeInSeconds = pow(2, invalidAttemptCount - 5).toInt() * 30; - await _lockscreenSetting.setLastInvalidAttemptTime( - DateTime.now().millisecondsSinceEpoch + - lockedTimeInSeconds * 1000, - ); - await startLockTimer(lockedTimeInSeconds); - } - _hasAuthenticationFailed = true; - _logger.info("Authentication failed"); - } - } - } catch (e, s) { - _isShowingLockScreen = false; - _logger.severe(e, s); - } - } -} diff --git a/mobile/apps/auth/lib/utils/auth_util.dart b/mobile/apps/auth/lib/utils/auth_util.dart deleted file mode 100644 index 6c797a4328..0000000000 --- a/mobile/apps/auth/lib/utils/auth_util.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'dart:io'; - -import 'package:ente_auth/l10n/l10n.dart'; -import 'package:ente_auth/services/local_authentication_service.dart'; -import 'package:ente_auth/utils/lock_screen_settings.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter_local_authentication/flutter_local_authentication.dart'; -import 'package:local_auth/local_auth.dart'; -import 'package:local_auth_android/local_auth_android.dart'; -import 'package:local_auth_darwin/types/auth_messages_ios.dart'; -import 'package:logging/logging.dart'; - -Future requestAuthentication( - BuildContext context, - String reason, { - bool isOpeningApp = false, - bool isAuthenticatingForInAppChange = false, -}) async { - Logger("AuthUtil").info("Requesting authentication"); - - final String? savedPin = await LockScreenSettings.instance.getPin(); - final String? savedPassword = await LockScreenSettings.instance.getPassword(); - if (savedPassword != null || savedPin != null) { - return await LocalAuthenticationService.instance - .requestEnteAuthForLockScreen( - context, - savedPin, - savedPassword, - isAuthenticatingOnAppLaunch: isOpeningApp, - isAuthenticatingForInAppChange: isAuthenticatingForInAppChange, - ); - } - if (Platform.isMacOS || Platform.isLinux) { - return await FlutterLocalAuthentication().authenticate(); - } else { - await LocalAuthentication().stopAuthentication(); - final l10n = context.l10n; - return await LocalAuthentication().authenticate( - localizedReason: reason, - authMessages: [ - AndroidAuthMessages( - biometricHint: l10n.androidBiometricHint, - biometricNotRecognized: l10n.androidBiometricNotRecognized, - biometricRequiredTitle: l10n.androidBiometricRequiredTitle, - biometricSuccess: l10n.androidBiometricSuccess, - cancelButton: l10n.androidCancelButton, - deviceCredentialsRequiredTitle: - l10n.androidDeviceCredentialsRequiredTitle, - deviceCredentialsSetupDescription: - l10n.androidDeviceCredentialsSetupDescription, - goToSettingsButton: l10n.goToSettings, - goToSettingsDescription: l10n.androidGoToSettingsDescription, - signInTitle: l10n.androidSignInTitle, - ), - IOSAuthMessages( - localizedFallbackTitle: l10n.enterPassword, - goToSettingsButton: l10n.goToSettings, - goToSettingsDescription: l10n.goToSettings, - lockOut: l10n.iOSLockOut, - // cancelButton default value is "Ok" - cancelButton: l10n.iOSOkButton, - ), - ], - ); - } -} diff --git a/mobile/apps/auth/lib/utils/lock_screen_settings.dart b/mobile/apps/auth/lib/utils/lock_screen_settings.dart deleted file mode 100644 index 4f2f81b11d..0000000000 --- a/mobile/apps/auth/lib/utils/lock_screen_settings.dart +++ /dev/null @@ -1,253 +0,0 @@ -import "dart:convert"; -import "dart:io"; -import "dart:typed_data"; - -import "package:ente_auth/core/configuration.dart"; -import "package:ente_auth/utils/platform_util.dart"; -import "package:ente_crypto_dart/ente_crypto_dart.dart"; -import "package:ente_events/event_bus.dart"; -import "package:ente_events/models/signed_out_event.dart"; -import "package:flutter/material.dart"; -import "package:flutter_secure_storage/flutter_secure_storage.dart"; -import "package:privacy_screen/privacy_screen.dart"; -import "package:shared_preferences/shared_preferences.dart"; - -class LockScreenSettings { - LockScreenSettings._privateConstructor(); - - static final LockScreenSettings instance = - LockScreenSettings._privateConstructor(); - static const password = "ls_password"; - static const pin = "ls_pin"; - static const saltKey = "ls_salt"; - static const keyInvalidAttempts = "ls_invalid_attempts"; - static const lastInvalidAttemptTime = "ls_last_invalid_attempt_time"; - static const autoLockTime = "ls_auto_lock_time"; - static const keyHideAppContent = "ls_hide_app_content"; - static const keyAppLockSet = "ls_is_app_lock_set"; - static const keyHasMigratedLockScreenChanges = - "ls_has_migrated_lock_screen_changes"; - static const keyShowOfflineModeWarning = "ls_show_offline_mode_warning"; - static const keyShouldShowLockScreen = "should_show_lock_screen"; - static const String kIsLightMode = "is_light_mode"; - - final List autoLockDurations = const [ - Duration(milliseconds: 650), - Duration(seconds: 5), - Duration(seconds: 15), - Duration(minutes: 1), - Duration(minutes: 5), - Duration(minutes: 30), - ]; - - late SharedPreferences _preferences; - late FlutterSecureStorage _secureStorage; - - Future init() async { - _secureStorage = const FlutterSecureStorage(); - _preferences = await SharedPreferences.getInstance(); - - ///Workaround for privacyScreen not working when app is killed and opened. - await setHideAppContent(getShouldHideAppContent()); - - /// Function to Check if the migration for lock screen changes has - /// already been done by checking a stored boolean value. - await runLockScreenChangesMigration(); - - await _clearLsDataInKeychainIfFreshInstall(); - - Bus.instance.on().listen((event) { - removePinAndPassword(); - }); - } - - Future setOfflineModeWarningStatus(bool value) async { - await _preferences.setBool(keyShowOfflineModeWarning, value); - } - - bool getOfflineModeWarningStatus() { - return _preferences.getBool(keyShowOfflineModeWarning) ?? true; - } - - Future runLockScreenChangesMigration() async { - if (_preferences.getBool(keyHasMigratedLockScreenChanges) != null) { - return; - } - - final bool passwordEnabled = await isPasswordSet(); - final bool pinEnabled = await isPinSet(); - final bool systemLockEnabled = shouldShowSystemLockScreen(); - - if (passwordEnabled || pinEnabled || systemLockEnabled) { - await setAppLockEnabled(true); - } - - await _preferences.setBool(keyHasMigratedLockScreenChanges, true); - } - - Future setLightMode(bool isLightMode) async { - if (isLightMode != (_preferences.getBool(kIsLightMode) ?? true)) { - await _preferences.setBool(kIsLightMode, isLightMode); - } - } - - Future setHideAppContent(bool hideContent) async { - if (PlatformUtil.isDesktop()) return; - final bool isLightMode = _preferences.getBool(kIsLightMode) ?? true; - !hideContent - ? PrivacyScreen.instance.disable() - : await PrivacyScreen.instance.enable( - iosOptions: const PrivacyIosOptions( - enablePrivacy: true, - ), - androidOptions: const PrivacyAndroidOptions( - enableSecure: true, - ), - backgroundColor: - isLightMode ? const Color(0xffffffff) : const Color(0xff000000), - blurEffect: isLightMode - ? PrivacyBlurEffect.extraLight - : PrivacyBlurEffect.extraLight, - ); - await _preferences.setBool(keyHideAppContent, hideContent); - } - - bool getShouldHideAppContent() { - return _preferences.getBool(keyHideAppContent) ?? true; - } - - Future setAutoLockTime(Duration duration) async { - await _preferences.setInt(autoLockTime, duration.inMilliseconds); - } - - int getAutoLockTime() { - return _preferences.getInt(autoLockTime) ?? 5000; - } - - Future setLastInvalidAttemptTime(int time) async { - await _preferences.setInt(lastInvalidAttemptTime, time); - } - - int getlastInvalidAttemptTime() { - return _preferences.getInt(lastInvalidAttemptTime) ?? 0; - } - - int getInvalidAttemptCount() { - return _preferences.getInt(keyInvalidAttempts) ?? 0; - } - - Future setInvalidAttemptCount(int count) async { - await _preferences.setInt(keyInvalidAttempts, count); - } - - Future setAppLockEnabled(bool value) async { - await _preferences.setBool(keyAppLockSet, value); - } - - bool getIsAppLockSet() { - return _preferences.getBool(keyAppLockSet) ?? false; - } - - static Uint8List _generateSalt() { - return sodium.randombytes.buf(sodium.crypto.pwhash.saltBytes); - } - - Future setPin(String userPin) async { - await _secureStorage.delete(key: saltKey); - final salt = _generateSalt(); - - final hash = cryptoPwHash( - utf8.encode(userPin), - salt, - sodium.crypto.pwhash.memLimitInteractive, - sodium.crypto.pwhash.opsLimitSensitive, - sodium, - ); - final String saltPin = base64Encode(salt); - final String hashedPin = base64Encode(hash); - - await _secureStorage.write(key: saltKey, value: saltPin); - await _secureStorage.write(key: pin, value: hashedPin); - await _secureStorage.delete(key: password); - - return; - } - - Future getSalt() async { - final String? salt = await _secureStorage.read(key: saltKey); - if (salt == null) return null; - return base64Decode(salt); - } - - Future getPin() async { - return _secureStorage.read(key: pin); - } - - Future setPassword(String pass) async { - await _secureStorage.delete(key: saltKey); - final salt = _generateSalt(); - - final hash = cryptoPwHash( - utf8.encode(pass), - salt, - sodium.crypto.pwhash.memLimitInteractive, - sodium.crypto.pwhash.opsLimitSensitive, - sodium, - ); - - await _secureStorage.write(key: saltKey, value: base64Encode(salt)); - await _secureStorage.write(key: password, value: base64Encode(hash)); - await _secureStorage.delete(key: pin); - - return; - } - - Future getPassword() async { - return _secureStorage.read(key: password); - } - - Future removePinAndPassword() async { - await _secureStorage.delete(key: saltKey); - await _secureStorage.delete(key: pin); - await _secureStorage.delete(key: password); - } - - Future isPinSet() async { - return await _secureStorage.containsKey(key: pin); - } - - Future isPasswordSet() async { - return await _secureStorage.containsKey(key: password); - } - - Future shouldShowLockScreen() async { - final bool isPin = await isPinSet(); - final bool isPass = await isPasswordSet(); - return isPin || isPass || shouldShowSystemLockScreen(); - } - - bool shouldShowSystemLockScreen() { - if (_preferences.containsKey(keyShouldShowLockScreen)) { - return _preferences.getBool(keyShouldShowLockScreen)!; - } else { - return false; - } - } - - Future setSystemLockScreen(bool value) { - return _preferences.setBool(keyShouldShowLockScreen, value); - } - - // If the app was uninstalled (without logging out if it was used with - // backups), keychain items of the app persist in the keychain. To avoid using - // old keychain items, we delete them on reinstall. - Future _clearLsDataInKeychainIfFreshInstall() async { - if ((Platform.isIOS || Platform.isMacOS) && - !Configuration.instance.isLoggedIn() && - !Configuration.instance.hasOptedForOfflineMode()) { - await _secureStorage.delete(key: password); - await _secureStorage.delete(key: pin); - await _secureStorage.delete(key: saltKey); - } - } -} diff --git a/mobile/apps/auth/pubspec.lock b/mobile/apps/auth/pubspec.lock index b670dcb123..676273f726 100644 --- a/mobile/apps/auth/pubspec.lock +++ b/mobile/apps/auth/pubspec.lock @@ -398,6 +398,13 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + ente_accounts: + dependency: transitive + description: + path: "../../packages/accounts" + relative: true + source: path + version: "1.0.0" ente_base: dependency: "direct main" description: @@ -428,6 +435,13 @@ packages: relative: true source: path version: "1.0.0" + ente_lock_screen: + dependency: "direct main" + description: + path: "../../packages/lock_screen" + relative: true + source: path + version: "1.0.0" ente_logging: dependency: "direct main" description: @@ -442,6 +456,27 @@ packages: relative: true source: path version: "1.0.0" + ente_strings: + dependency: transitive + description: + path: "../../packages/strings" + relative: true + source: path + version: "1.0.0" + ente_ui: + dependency: transitive + description: + path: "../../packages/ui" + relative: true + source: path + version: "1.0.0" + ente_utils: + dependency: transitive + description: + path: "../../packages/utils" + relative: true + source: path + version: "1.0.0" event_bus: dependency: "direct main" description: diff --git a/mobile/apps/auth/pubspec.yaml b/mobile/apps/auth/pubspec.yaml index 6cabe14406..c89781af75 100644 --- a/mobile/apps/auth/pubspec.yaml +++ b/mobile/apps/auth/pubspec.yaml @@ -34,6 +34,8 @@ dependencies: url: https://github.com/ente-io/ente_crypto_dart.git ente_events: path: ../../packages/events + ente_lock_screen: + path: ../../packages/lock_screen ente_logging: path: ../../packages/logging ente_network: diff --git a/mobile/packages/ui/pubspec.lock b/mobile/packages/ui/pubspec.lock index 56bcf90e1f..a07b26b3e9 100644 --- a/mobile/packages/ui/pubspec.lock +++ b/mobile/packages/ui/pubspec.lock @@ -252,19 +252,21 @@ packages: flutter_inappwebview: dependency: "direct main" description: - name: flutter_inappwebview - sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" - source: hosted - version: "6.1.5" + path: flutter_inappwebview + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "6.2.0-beta.3" flutter_inappwebview_android: dependency: transitive description: - name: flutter_inappwebview_android - sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" - source: hosted - version: "1.1.3" + path: flutter_inappwebview_android + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_internal_annotations: dependency: transitive description: @@ -276,43 +278,48 @@ packages: flutter_inappwebview_ios: dependency: transitive description: - name: flutter_inappwebview_ios - sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_ios + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_macos: dependency: transitive description: - name: flutter_inappwebview_macos - sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_macos + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_platform_interface: dependency: transitive description: - name: flutter_inappwebview_platform_interface - sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" - source: hosted - version: "1.3.0+1" + path: flutter_inappwebview_platform_interface + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.4.0-beta.3" flutter_inappwebview_web: dependency: transitive description: - name: flutter_inappwebview_web - sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" - source: hosted - version: "1.1.2" + path: flutter_inappwebview_web + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "1.2.0-beta.3" flutter_inappwebview_windows: dependency: transitive description: - name: flutter_inappwebview_windows - sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" - source: hosted - version: "0.6.0" + path: flutter_inappwebview_windows + ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + resolved-ref: "3e6c4c4a25340cd363af9d38891d88498b90be26" + url: "https://github.com/pichillilorenzo/flutter_inappwebview.git" + source: git + version: "0.7.0-beta.3" flutter_lints: dependency: "direct dev" description: diff --git a/mobile/packages/ui/pubspec.yaml b/mobile/packages/ui/pubspec.yaml index 15be90cfc2..8cc504a4b0 100644 --- a/mobile/packages/ui/pubspec.yaml +++ b/mobile/packages/ui/pubspec.yaml @@ -21,7 +21,11 @@ dependencies: path: ../../packages/utils flutter: sdk: flutter - flutter_inappwebview: ^6.1.5 + flutter_inappwebview: + git: + url: https://github.com/pichillilorenzo/flutter_inappwebview.git + path: flutter_inappwebview + ref: 3e6c4c4a25340cd363af9d38891d88498b90be26 fluttertoast: ^8.1.1 modal_bottom_sheet: ^3.0.0 shared_preferences: ^2.5.3