feat: New simplified lockscreen design
This commit is contained in:
parent
1c863fe769
commit
90789d9feb
4 changed files with 121 additions and 76 deletions
|
|
@ -2519,5 +2519,13 @@
|
||||||
"invite": "Invite",
|
"invite": "Invite",
|
||||||
"requests": "Requests",
|
"requests": "Requests",
|
||||||
"inviteGroupChat": "📨 Invite group chat",
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,88 +1,134 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flutter_app_lock/flutter_app_lock.dart';
|
import 'package:flutter_app_lock/flutter_app_lock.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.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/app_config.dart';
|
||||||
import 'package:fluffychat/config/setting_keys.dart';
|
import 'package:fluffychat/config/setting_keys.dart';
|
||||||
import 'package:fluffychat/config/themes.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 {
|
class LockScreen extends StatefulWidget {
|
||||||
const LockScreen({Key? key}) : super(key: key);
|
const LockScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LockScreenState createState() => LockScreenState();
|
State<LockScreen> createState() => _LockScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class LockScreenState extends State<LockScreen> {
|
class _LockScreenState extends State<LockScreen> {
|
||||||
|
String? _errorText;
|
||||||
|
int _coolDownSeconds = 5;
|
||||||
|
bool _inputBlocked = false;
|
||||||
final TextEditingController _textEditingController = TextEditingController();
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return ThemeBuilder(
|
||||||
theme: FluffyThemes.buildTheme(context, Brightness.light),
|
builder: (context, themeMode, primaryColor) => MaterialApp(
|
||||||
darkTheme: FluffyThemes.buildTheme(context, Brightness.dark),
|
title: AppConfig.applicationName,
|
||||||
localizationsDelegates: L10n.localizationsDelegates,
|
themeMode: themeMode,
|
||||||
supportedLocales: L10n.supportedLocales,
|
theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor),
|
||||||
home: Builder(
|
darkTheme:
|
||||||
builder: (context) => LoginScaffold(
|
FluffyThemes.buildTheme(context, Brightness.dark, primaryColor),
|
||||||
appBar: AppBar(
|
localizationsDelegates: L10n.localizationsDelegates,
|
||||||
automaticallyImplyLeading: false,
|
supportedLocales: L10n.supportedLocales,
|
||||||
elevation: 0,
|
home: Builder(
|
||||||
centerTitle: true,
|
builder: (context) => Scaffold(
|
||||||
title: Text(L10n.of(context)!.pleaseEnterYourPin),
|
appBar: AppBar(
|
||||||
backgroundColor: Colors.transparent,
|
title: Text(L10n.of(context)!.pleaseEnterYourPin),
|
||||||
),
|
centerTitle: true,
|
||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
extendBodyBehindAppBar: true,
|
||||||
child: PinCodeTextField(
|
body: Center(
|
||||||
autofocus: true,
|
child: Padding(
|
||||||
controller: _textEditingController,
|
padding: const EdgeInsets.all(16.0),
|
||||||
focusNode: _focusNode,
|
child: ConstrainedBox(
|
||||||
pinBoxRadius: AppConfig.borderRadius,
|
constraints: const BoxConstraints(
|
||||||
pinTextStyle: const TextStyle(fontSize: 32),
|
maxWidth: FluffyThemes.columnWidth,
|
||||||
hideCharacter: true,
|
),
|
||||||
hasError: _wrongInput,
|
child: ListView(
|
||||||
onDone: (String input) async {
|
shrinkWrap: true,
|
||||||
if (input ==
|
children: [
|
||||||
await ([TargetPlatform.linux]
|
Center(
|
||||||
.contains(Theme.of(context).platform)
|
child: _inputBlocked
|
||||||
? SharedPreferences.getInstance().then(
|
? const CircularProgressIndicator.adaptive()
|
||||||
(prefs) => prefs.getString(SettingKeys.appLockKey),
|
: Image.asset(
|
||||||
)
|
'assets/info-logo.png',
|
||||||
: const FlutterSecureStorage()
|
width: 256,
|
||||||
.read(key: SettingKeys.appLockKey))) {
|
),
|
||||||
AppLock.of(context)!.didUnlock();
|
),
|
||||||
} else {
|
TextField(
|
||||||
_textEditingController.clear();
|
controller: _textEditingController,
|
||||||
setState(() => _wrongInput = true);
|
textInputAction: TextInputAction.done,
|
||||||
_focusNode.requestFocus();
|
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: '****',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1357,14 +1357,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.4.0"
|
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:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ dependencies:
|
||||||
pasteboard: ^0.2.0
|
pasteboard: ^0.2.0
|
||||||
path_provider: ^2.0.9
|
path_provider: ^2.0.9
|
||||||
permission_handler: ^10.0.0
|
permission_handler: ^10.0.0
|
||||||
pin_code_text_field: ^1.8.0
|
|
||||||
provider: ^6.0.2
|
provider: ^6.0.2
|
||||||
punycode: ^1.0.0
|
punycode: ^1.0.0
|
||||||
qr_code_scanner: ^1.0.0
|
qr_code_scanner: ^1.0.0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue