From 9a808abdc6a23e282116173a2c1cab3867a7acdb Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sun, 24 Sep 2023 08:39:04 +0200 Subject: [PATCH] refactor: Remove flutter_app_lock package and use own AppLock implementation --- lib/main.dart | 15 +--- .../settings_security/settings_security.dart | 13 +-- lib/widgets/app_lock.dart | 88 +++++++++++++++++++ lib/widgets/fluffy_chat_app.dart | 14 +-- lib/widgets/lock_screen.dart | 42 ++++----- pubspec.lock | 8 -- pubspec.yaml | 1 - 7 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 lib/widgets/app_lock.dart diff --git a/lib/main.dart b/lib/main.dart index 5f451c0a6..933522f8c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; -import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:matrix/matrix.dart'; @@ -11,7 +10,6 @@ import 'package:fluffychat/utils/platform_infos.dart'; import 'config/setting_keys.dart'; import 'utils/background_push.dart'; import 'widgets/fluffy_chat_app.dart'; -import 'widgets/lock_screen.dart'; void main() async { Logs().i('Welcome to ${AppConfig.applicationName} <3'); @@ -65,18 +63,7 @@ Future startGui(List clients) async { } } - // Start rendering the Flutter app and wrap it in an Applock. - // We do this only for mobile applications as we saw routing - // problems on other platforms if we wrap it always. - runApp( - PlatformInfos.isMobile - ? AppLock( - builder: (args) => FluffyChatApp(clients: clients), - lockScreen: const LockScreen(), - enabled: pin?.isNotEmpty ?? false, - ) - : FluffyChatApp(clients: clients), - ); + runApp(FluffyChatApp(clients: clients, pincode: pin)); } /// Watches the lifecycle changes to start the application when it diff --git a/lib/pages/settings_security/settings_security.dart b/lib/pages/settings_security/settings_security.dart index 183c01ea0..1f184fb13 100644 --- a/lib/pages/settings_security/settings_security.dart +++ b/lib/pages/settings_security/settings_security.dart @@ -4,7 +4,6 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; -import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; @@ -13,6 +12,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart'; +import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; import '../bootstrap/bootstrap_dialog.dart'; import 'settings_security_view.dart'; @@ -65,7 +65,7 @@ class SettingsSecurityController extends State { final currentLock = await const FlutterSecureStorage().read(key: SettingKeys.appLockKey); if (currentLock?.isNotEmpty ?? false) { - await AppLock.of(context)!.showLockScreen(); + AppLock.of(context).showLockScreen(); } final newLock = await showTextInputDialog( useRootNavigator: false, @@ -86,17 +86,12 @@ class SettingsSecurityController extends State { obscureText: true, maxLines: 1, minLines: 1, + maxLength: 4, ), ], ); if (newLock != null) { - await const FlutterSecureStorage() - .write(key: SettingKeys.appLockKey, value: newLock.single); - if (newLock.single.isEmpty) { - AppLock.of(context)!.disable(); - } else { - AppLock.of(context)!.enable(); - } + await AppLock.of(context).changePincode(newLock.single); } } diff --git a/lib/widgets/app_lock.dart b/lib/widgets/app_lock.dart new file mode 100644 index 000000000..a598b74fb --- /dev/null +++ b/lib/widgets/app_lock.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:provider/provider.dart'; + +import 'package:fluffychat/config/setting_keys.dart'; +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/widgets/lock_screen.dart'; + +class AppLockWidget extends StatefulWidget { + const AppLockWidget({ + required this.child, + required this.pincode, + super.key, + }); + + final String? pincode; + final Widget child; + + @override + State createState() => AppLock(); +} + +class AppLock extends State with WidgetsBindingObserver { + String? _pincode; + bool _isLocked = false; + bool get isActive => _pincode != null; + + @override + void initState() { + _pincode = widget.pincode; + _isLocked = widget.pincode != null; + super.initState(); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (isActive && state == AppLifecycleState.hidden && !_isLocked) { + setState(() { + _isLocked = true; + }); + } + } + + bool get isLocked => _isLocked; + CrossFadeState get _crossFadeState => + _isLocked ? CrossFadeState.showSecond : CrossFadeState.showFirst; + + Future changePincode(String? pincode) async { + await const FlutterSecureStorage().write( + key: SettingKeys.appLockKey, + value: pincode, + ); + _pincode = pincode; + return; + } + + bool unlock(String pincode) { + final isCorrect = pincode == _pincode; + if (isCorrect) { + setState(() { + _isLocked = false; + }); + } + return isCorrect; + } + + void showLockScreen() => setState(() { + _isLocked = true; + }); + + static AppLock of(BuildContext context) => Provider.of( + context, + listen: false, + ); + + @override + Widget build(BuildContext context) => Provider( + create: (_) => this, + child: AnimatedCrossFade( + firstChild: widget.child, + secondChild: const LockScreen(), + crossFadeState: _crossFadeState, + duration: FluffyThemes.animationDuration, + ), + ); +} diff --git a/lib/widgets/fluffy_chat_app.dart b/lib/widgets/fluffy_chat_app.dart index bc0cad858..eb9f0f657 100644 --- a/lib/widgets/fluffy_chat_app.dart +++ b/lib/widgets/fluffy_chat_app.dart @@ -6,6 +6,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/routes.dart'; import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/theme_builder.dart'; import '../config/app_config.dart'; import '../utils/custom_scroll_behaviour.dart'; @@ -14,11 +15,13 @@ import 'matrix.dart'; class FluffyChatApp extends StatelessWidget { final Widget? testWidget; final List clients; + final String? pincode; const FluffyChatApp({ Key? key, this.testWidget, required this.clients, + this.pincode, }) : super(key: key); /// getInitialLink may rereturn the value multiple times if this view is @@ -43,12 +46,11 @@ class FluffyChatApp extends StatelessWidget { localizationsDelegates: L10n.localizationsDelegates, supportedLocales: L10n.supportedLocales, routerConfig: router, - builder: (context, child) => Navigator( - onGenerateRoute: (_) => MaterialPageRoute( - builder: (_) => Matrix( - clients: clients, - child: testWidget ?? child, - ), + builder: (context, child) => AppLockWidget( + pincode: pincode, + child: Matrix( + clients: clients, + child: testWidget ?? child, ), ), ), diff --git a/lib/widgets/lock_screen.dart b/lib/widgets/lock_screen.dart index 547940365..8825f6cd8 100644 --- a/lib/widgets/lock_screen.dart +++ b/lib/widgets/lock_screen.dart @@ -2,14 +2,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; -import 'package:fluffychat/utils/error_reporter.dart'; +import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/theme_builder.dart'; class LockScreen extends StatefulWidget { @@ -40,25 +37,15 @@ class _LockScreenState extends State { return; } - final correctPin = int.tryParse( - await const FlutterSecureStorage().read(key: SettingKeys.appLockKey) ?? - '', - ); - if (correctPin == null) { - ErrorReporter( - context, - 'Lockscreen was displayed but pin was not stored correctly', - ).onErrorCallback( - Exception(), - ); - AppLock.of(context)!.didUnlock(); + if (AppLock.of(context).unlock(enteredPin.toString())) { + setState(() { + _inputBlocked = false; + _errorText = null; + }); + _textEditingController.clear(); return; } - if (correctPin == enteredPin) { - AppLock.of(context)!.didUnlock(); - return; - } setState(() { _errorText = L10n.of(context)!.wrongPinEntered(_coolDownSeconds); _inputBlocked = true; @@ -102,12 +89,10 @@ class _LockScreenState extends State { shrinkWrap: true, children: [ Center( - child: _inputBlocked - ? const CircularProgressIndicator.adaptive() - : Image.asset( - 'assets/info-logo.png', - width: 256, - ), + child: Image.asset( + 'assets/info-logo.png', + width: 256, + ), ), TextField( controller: _textEditingController, @@ -125,6 +110,11 @@ class _LockScreenState extends State { hintText: '****', ), ), + if (_inputBlocked) + const Padding( + padding: EdgeInsets.all(8.0), + child: LinearProgressIndicator(), + ), ], ), ), diff --git a/pubspec.lock b/pubspec.lock index 7a7bb9cef..72d1c6ce5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -438,14 +438,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" - flutter_app_lock: - dependency: "direct main" - description: - name: flutter_app_lock - sha256: "98890a2a2bc507b2f85165515189750e134921f8f4022ec10bd223033633a3ba" - url: "https://pub.dev" - source: hosted - version: "3.0.0" flutter_blurhash: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 5132fd79d..5c344e6cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,6 @@ dependencies: flutter: sdk: flutter flutter_app_badger: ^1.5.0 - flutter_app_lock: ^3.0.0 flutter_blurhash: ^0.7.0 flutter_cache_manager: ^3.3.0 flutter_foreground_task: ^6.0.0+1