From 90789d9feb706a3b6622a03753684c800f88a6e1 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sat, 23 Sep 2023 07:49:34 +0200 Subject: [PATCH] feat: New simplified lockscreen design --- assets/l10n/intl_en.arb | 10 +- lib/widgets/lock_screen.dart | 178 ++++++++++++++++++++++------------- pubspec.lock | 8 -- pubspec.yaml | 1 - 4 files changed, 121 insertions(+), 76 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 5269c493b..78a315041 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2519,5 +2519,13 @@ "invite": "Invite", "requests": "Requests", "inviteGroupChat": "📨 Invite group chat", - "invitePrivateChat": "📨 Invite private chat" + "invitePrivateChat": "📨 Invite private chat", + "invalidInput": "Invalid input!", + "wrongPinEntered": "Wrong pin entered! Try again in {seconds} seconds...", + "@wrongPinEntered": { + "type": "text", + "placeholders": { + "seconds": {} + } + } } diff --git a/lib/widgets/lock_screen.dart b/lib/widgets/lock_screen.dart index 70db44e02..547940365 100644 --- a/lib/widgets/lock_screen.dart +++ b/lib/widgets/lock_screen.dart @@ -1,88 +1,134 @@ +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:pin_code_text_field/pin_code_text_field.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; -import 'layouts/login_scaffold.dart'; +import 'package:fluffychat/utils/error_reporter.dart'; +import 'package:fluffychat/widgets/theme_builder.dart'; class LockScreen extends StatefulWidget { - const LockScreen({Key? key}) : super(key: key); + const LockScreen({super.key}); @override - LockScreenState createState() => LockScreenState(); + State createState() => _LockScreenState(); } -class LockScreenState extends State { +class _LockScreenState extends State { + String? _errorText; + int _coolDownSeconds = 5; + bool _inputBlocked = false; final TextEditingController _textEditingController = TextEditingController(); - final FocusNode _focusNode = FocusNode(); - bool _wrongInput = false; + + void tryUnlock(BuildContext context) async { + setState(() { + _errorText = null; + }); + if (_textEditingController.text.length < 4) return; + + final enteredPin = int.tryParse(_textEditingController.text); + if (enteredPin == null || _textEditingController.text.length != 4) { + setState(() { + _errorText = L10n.of(context)!.invalidInput; + }); + _textEditingController.clear(); + 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(); + return; + } + + if (correctPin == enteredPin) { + AppLock.of(context)!.didUnlock(); + return; + } + setState(() { + _errorText = L10n.of(context)!.wrongPinEntered(_coolDownSeconds); + _inputBlocked = true; + }); + Future.delayed(Duration(seconds: _coolDownSeconds)).then((_) { + setState(() { + _inputBlocked = false; + _coolDownSeconds *= 2; + _errorText = null; + }); + }); + _textEditingController.clear(); + } + @override Widget build(BuildContext context) { - return MaterialApp( - theme: FluffyThemes.buildTheme(context, Brightness.light), - darkTheme: FluffyThemes.buildTheme(context, Brightness.dark), - localizationsDelegates: L10n.localizationsDelegates, - supportedLocales: L10n.supportedLocales, - home: Builder( - builder: (context) => LoginScaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - elevation: 0, - centerTitle: true, - title: Text(L10n.of(context)!.pleaseEnterYourPin), - backgroundColor: Colors.transparent, - ), - body: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - gradient: LinearGradient( - begin: Alignment.topRight, - end: Alignment.bottomLeft, - stops: const [ - 0.1, - 0.4, - 0.6, - 0.9, - ], - colors: [ - Theme.of(context).secondaryHeaderColor.withAlpha(16), - Theme.of(context).primaryColor.withAlpha(16), - Theme.of(context).colorScheme.secondary.withAlpha(16), - Theme.of(context).colorScheme.background.withAlpha(16), - ], - ), + return ThemeBuilder( + builder: (context, themeMode, primaryColor) => MaterialApp( + title: AppConfig.applicationName, + themeMode: themeMode, + theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor), + darkTheme: + FluffyThemes.buildTheme(context, Brightness.dark, primaryColor), + localizationsDelegates: L10n.localizationsDelegates, + supportedLocales: L10n.supportedLocales, + home: Builder( + builder: (context) => Scaffold( + appBar: AppBar( + title: Text(L10n.of(context)!.pleaseEnterYourPin), + centerTitle: true, ), - alignment: Alignment.center, - child: PinCodeTextField( - autofocus: true, - controller: _textEditingController, - focusNode: _focusNode, - pinBoxRadius: AppConfig.borderRadius, - pinTextStyle: const TextStyle(fontSize: 32), - hideCharacter: true, - hasError: _wrongInput, - onDone: (String input) async { - if (input == - await ([TargetPlatform.linux] - .contains(Theme.of(context).platform) - ? SharedPreferences.getInstance().then( - (prefs) => prefs.getString(SettingKeys.appLockKey), - ) - : const FlutterSecureStorage() - .read(key: SettingKeys.appLockKey))) { - AppLock.of(context)!.didUnlock(); - } else { - _textEditingController.clear(); - setState(() => _wrongInput = true); - _focusNode.requestFocus(); - } - }, + extendBodyBehindAppBar: true, + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth, + ), + child: ListView( + shrinkWrap: true, + children: [ + Center( + child: _inputBlocked + ? const CircularProgressIndicator.adaptive() + : Image.asset( + 'assets/info-logo.png', + width: 256, + ), + ), + TextField( + controller: _textEditingController, + textInputAction: TextInputAction.done, + keyboardType: TextInputType.number, + obscureText: true, + autofocus: true, + textAlign: TextAlign.center, + readOnly: _inputBlocked, + onChanged: (_) => tryUnlock(context), + onSubmitted: (_) => tryUnlock(context), + style: const TextStyle(fontSize: 40), + decoration: InputDecoration( + errorText: _errorText, + hintText: '****', + ), + ), + ], + ), + ), + ), ), ), ), diff --git a/pubspec.lock b/pubspec.lock index cb4d2e046..7a7bb9cef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1357,14 +1357,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.0" - pin_code_text_field: - dependency: "direct main" - description: - name: pin_code_text_field - sha256: "3484c3ed4731327688734596d1fba1741f75da19366055116ecedcdffd87741a" - url: "https://pub.dev" - source: hosted - version: "1.8.0" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5cf818ca7..5132fd79d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,7 +70,6 @@ dependencies: pasteboard: ^0.2.0 path_provider: ^2.0.9 permission_handler: ^10.0.0 - pin_code_text_field: ^1.8.0 provider: ^6.0.2 punycode: ^1.0.0 qr_code_scanner: ^1.0.0