[mob][photos] added logic of Pin and Password screen

This commit is contained in:
Aman Raj Singh Mourya
2024-06-07 01:57:59 +05:30
parent 356d119fb9
commit 1cd0440453
9 changed files with 273 additions and 162 deletions

View File

@@ -72,7 +72,8 @@ class Configuration {
"has_selected_all_folders_for_backup";
static const anonymousUserIDKey = "anonymous_user_id";
static const endPointKey = "endpoint";
static const password = "user_pass";
static const pin = "user_pin";
static final _logger = Logger("Configuration");
String? _cachedToken;
@@ -151,6 +152,29 @@ class Configuration {
}
}
Future<void> savePin(String userPin) async {
await _preferences.setString(pin, userPin);
await _preferences.remove(password);
}
Future<String?> loadSavedPin() async {
return _preferences.getString(pin);
}
Future<void> savePassword(String pass) async {
await _preferences.setString(password, pass);
await _preferences.remove(pin);
}
Future<String?> loadSavedPassword() async {
return _preferences.getString(password);
}
Future<void> removePinAndPassword() async {
await _preferences.remove(pin);
await _preferences.remove(password);
}
// _cleanUpStaleFiles deletes all files in the temp directory that are older
// than kTempFolderDeletionTimeBuffer except the the temp encrypted files for upload.
// Those file are deleted by file uploader after the upload is complete or those

View File

@@ -60,86 +60,6 @@ class S {
);
}
/// `Device Lock`
String get deviceLock {
return Intl.message(
'Device lock',
name: 'deviceLock',
desc: '',
args: [],
);
}
/// `PIN Lock`
String get pinLock {
return Intl.message(
'PIN lock',
name: 'pinLock',
desc: '',
args: [],
);
}
/// `Enter the pin to lock the app`
String get enterThePinToLockTheApp {
return Intl.message(
'Enter the pin to lock the app',
name: 'enterThePinToLockTheApp',
desc: '',
args: [],
);
}
/// `Re-enter to confirm the pin`
String get reEnterToConfirmPin {
return Intl.message(
'Re-enter to confirm the pin',
name: 'reEnterToConfirmPin',
desc: '',
args: [],
);
}
/// `Enter the password to lock the app`
String get enterPasswordToLockApp {
return Intl.message(
'Enter the password to lock the app',
name: 'enterPasswordToLockApp',
desc: '',
args: [],
);
}
/// `Next`
String get next {
return Intl.message(
'Next',
name: 'next',
desc: '',
args: [],
);
}
/// `When a pin is set , you need to enter password\n whenever you open the app .`
String get whenPinIsSetYouNeedToEnterPassword {
return Intl.message(
'When a pin is set , you need to enter password\n whenever you open the app .',
name: 'whenPinIsSetYouNeedToEnterPassword',
desc: '',
args: [],
);
}
/// `Enable PIN`
String get enablePin {
return Intl.message(
'Enable PIN',
name: 'enablePin',
desc: '',
args: [],
);
}
/// `Welcome back!`
String get accountWelcomeBack {
return Intl.message(

View File

@@ -3,7 +3,13 @@ import "dart:async";
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/ui/components/buttons/button_widget.dart";
import "package:photos/ui/components/dialog_widget.dart";
import "package:photos/ui/components/models/button_type.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_password.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_pin.dart";
import 'package:photos/ui/tools/app_lock.dart';
import 'package:photos/utils/auth_util.dart';
import 'package:photos/utils/dialog_util.dart';
@@ -14,6 +20,8 @@ class LocalAuthenticationService {
static final LocalAuthenticationService instance =
LocalAuthenticationService._privateConstructor();
final Configuration _configuration = Configuration.instance;
Future<bool> requestLocalAuthentication(
BuildContext context,
String infoMessage,
@@ -41,6 +49,87 @@ class LocalAuthenticationService {
String errorDialogContent, [
String errorDialogTitle = "",
]) async {
final String? savedPin = await _configuration.loadSavedPin();
final String? savedPassword = await _configuration.loadSavedPassword();
if (savedPassword != null) {
final result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return LockScreenOptionPassword(
isAuthenticating: true,
authPass: savedPassword,
);
},
),
);
if (result) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const LockScreenOption();
},
),
);
return true;
} else {
await showDialogWidget(
context: context,
title: 'Password does not match',
icon: Icons.lock,
body: 'Please re-enter the password.',
isDismissible: true,
buttons: [
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: S.of(context).ok,
isInAlert: true,
buttonAction: ButtonAction.first,
),
],
);
}
return false;
} else if (savedPin != null) {
final result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return LockScreenOptionPin(
isAuthenticating: true,
authPin: savedPin,
);
},
),
);
if (result) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const LockScreenOption();
},
),
);
return true;
} else {
await showDialogWidget(
context: context,
title: 'Pin does not match',
icon: Icons.lock,
body: 'Please re-enter the pin.',
isDismissible: true,
buttons: [
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: S.of(context).ok,
isInAlert: true,
buttonAction: ButtonAction.first,
),
],
);
}
return false;
}
if (await _isLocalAuthSupportedOnDevice()) {
AppLock.of(context)!.disable();
final result = await requestAuthentication(

View File

@@ -52,8 +52,8 @@ class LockScreenOption extends StatelessWidget {
bgColor: colorScheme.fillFaint,
),
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).deviceLock,
captionedTextWidget: const CaptionedTextWidget(
title: 'Device Lock',
),
alignCaptionedTextToLeft: true,
isTopBorderRadiusRemoved: true,
@@ -67,8 +67,8 @@ class LockScreenOption extends StatelessWidget {
bgColor: colorScheme.fillFaint,
),
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).pinLock,
captionedTextWidget: const CaptionedTextWidget(
title: 'PIN lock',
),
alignCaptionedTextToLeft: true,
isTopBorderRadiusRemoved: true,
@@ -89,8 +89,8 @@ class LockScreenOption extends StatelessWidget {
bgColor: colorScheme.fillFaint,
),
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: S.of(context).passwordLock,
captionedTextWidget: const CaptionedTextWidget(
title: 'Password lock',
),
alignCaptionedTextToLeft: true,
isTopBorderRadiusRemoved: true,

View File

@@ -1,4 +1,5 @@
import "package:flutter/material.dart";
import "package:photos/core/configuration.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/button_widget.dart";
@@ -6,7 +7,6 @@ import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/components/dialog_widget.dart";
import "package:photos/ui/components/models/button_type.dart";
import "package:photos/ui/components/text_input_widget.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option.dart";
class LockScreenOptionConfirmPassword extends StatefulWidget {
const LockScreenOptionConfirmPassword({super.key, required this.password});
@@ -18,22 +18,30 @@ class LockScreenOptionConfirmPassword extends StatefulWidget {
class _LockScreenOptionConfirmPasswordState
extends State<LockScreenOptionConfirmPassword> {
String confirmPassword = "";
String _confirmPassword = "";
final _confirmPasswordController = TextEditingController(text: null);
@override
void dispose() {
super.dispose();
_confirmPasswordController.dispose();
}
final Configuration _configuration = Configuration.instance;
final _focusNode = FocusNode();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future.delayed(const Duration(seconds: 1));
_focusNode.requestFocus();
});
}
Future<void> _confirmPassword() async {
if (widget.password == confirmPassword) {
@override
void dispose() {
super.dispose();
_focusNode.dispose();
_confirmPasswordController.dispose();
}
Future<void> _confirmPasswordMatch() async {
if (widget.password == _confirmPassword) {
await _configuration.savePassword(_confirmPassword);
await showDialogWidget(
context: context,
title: 'Password has been set',
@@ -49,11 +57,8 @@ class _LockScreenOptionConfirmPasswordState
),
],
);
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => const LockScreenOption(),
),
);
Navigator.of(context).pop();
Navigator.of(context).pop();
} else {
await showDialogWidget(
context: context,
@@ -79,7 +84,6 @@ class _LockScreenOptionConfirmPasswordState
final colorTheme = getEnteColorScheme(context);
final textTheme = getEnteTextTheme(context);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -117,7 +121,7 @@ class _LockScreenOptionConfirmPasswordState
),
),
Text(
S.of(context).enterPasswordToLockApp,
'Enter the password to lock the app',
style: textTheme.bodyBold,
),
const Padding(padding: EdgeInsets.all(24)),
@@ -126,6 +130,7 @@ class _LockScreenOptionConfirmPasswordState
child: TextInputWidget(
hintText: S.of(context).confirmPassword,
borderRadius: 2,
focusNode: _focusNode,
isClearable: true,
textCapitalization: TextCapitalization.words,
textEditingController: _confirmPasswordController,
@@ -133,7 +138,7 @@ class _LockScreenOptionConfirmPasswordState
isPasswordInput: true,
onChange: (String p0) {
setState(() {
confirmPassword = p0;
_confirmPassword = p0;
});
},
),
@@ -142,12 +147,12 @@ class _LockScreenOptionConfirmPasswordState
Padding(
padding: const EdgeInsets.all(18.0),
child: ButtonWidget(
labelText: S.of(context).next,
buttonType: confirmPassword.length > 8
labelText: 'Next',
buttonType: _confirmPassword.length > 3
? ButtonType.primary
: ButtonType.secondary,
buttonSize: ButtonSize.large,
onTap: () => _confirmPassword(),
onTap: () => _confirmPasswordMatch(),
),
),
const Padding(padding: EdgeInsets.only(bottom: 24)),

View File

@@ -1,11 +1,11 @@
import "package:flutter/material.dart";
import "package:photos/core/configuration.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/button_widget.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/components/dialog_widget.dart";
import "package:photos/ui/components/models/button_type.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option.dart";
import "package:pinput/pin_put/pin_put.dart";
class LockScreenOptionConfirmPin extends StatefulWidget {
@@ -19,19 +19,34 @@ class LockScreenOptionConfirmPin extends StatefulWidget {
class _LockScreenOptionConfirmPinState
extends State<LockScreenOptionConfirmPin> {
final _confirmPinController = TextEditingController(text: null);
String _confirmPin = "";
final Configuration _configuration = Configuration.instance;
final _focusNode = FocusNode();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future.delayed(const Duration(seconds: 1));
_focusNode.requestFocus();
});
}
@override
void dispose() {
super.dispose();
_focusNode.dispose();
_confirmPinController.dispose();
}
Future<void> confirmPin() async {
if (widget.pin == _confirmCode) {
Future<void> _confirmPinMatch() async {
if (widget.pin == _confirmPin) {
await _configuration.savePin(_confirmPin);
await showDialogWidget(
context: context,
title: 'Pin has been set',
@@ -47,11 +62,8 @@ class _LockScreenOptionConfirmPinState
),
],
);
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => const LockScreenOption(),
),
);
Navigator.of(context).pop();
Navigator.of(context).pop();
} else {
await showDialogWidget(
context: context,
@@ -72,8 +84,6 @@ class _LockScreenOptionConfirmPinState
_confirmPinController.clear();
}
String _confirmCode = "";
@override
Widget build(BuildContext context) {
final colorTheme = getEnteColorScheme(context);
@@ -123,7 +133,7 @@ class _LockScreenOptionConfirmPinState
),
),
Text(
S.of(context).reEnterToConfirmPin,
'Re-enter to confirm the pin',
style: textTheme.bodyBold,
),
const Padding(padding: EdgeInsets.all(12)),
@@ -132,6 +142,7 @@ class _LockScreenOptionConfirmPinState
child: PinPut(
fieldsCount: 4,
controller: _confirmPinController,
focusNode: _focusNode,
submittedFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(20.0),
),
@@ -151,7 +162,7 @@ class _LockScreenOptionConfirmPinState
obscureText: '*',
onChanged: (String pin) {
setState(() {
_confirmCode = pin;
_confirmPin = pin;
});
},
onSubmit: (value) {
@@ -164,11 +175,11 @@ class _LockScreenOptionConfirmPinState
padding: const EdgeInsets.all(18.0),
child: ButtonWidget(
labelText: S.of(context).confirm,
buttonType: _confirmCode.length == 4
buttonType: _confirmPin.length == 4
? ButtonType.primary
: ButtonType.secondary,
buttonSize: ButtonSize.large,
onTap: () => confirmPin(),
onTap: () => _confirmPinMatch(),
),
),
const Padding(padding: EdgeInsets.only(bottom: 24)),

View File

@@ -3,14 +3,18 @@ import "package:photos/generated/l10n.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/button_widget.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/components/dialog_widget.dart";
import "package:photos/ui/components/models/button_type.dart";
import "package:photos/ui/components/text_input_widget.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_confirm_password.dart";
class LockScreenOptionPassword extends StatefulWidget {
const LockScreenOptionPassword({super.key});
const LockScreenOptionPassword({
super.key,
this.isAuthenticating = false,
this.authPass,
});
final bool isAuthenticating;
final String? authPass;
@override
State<LockScreenOptionPassword> createState() =>
_LockScreenOptionPasswordState();
@@ -19,19 +23,38 @@ class LockScreenOptionPassword extends StatefulWidget {
class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
final _passwordController = TextEditingController(text: null);
String password = "";
@override
void dispose() {
super.dispose();
_passwordController.dispose();
}
final _focusNode = FocusNode();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future.delayed(const Duration(seconds: 1));
_focusNode.requestFocus();
});
}
@override
void dispose() {
super.dispose();
_passwordController.dispose();
_focusNode.dispose();
}
Future<bool> confirmPasswordAuth(String code) async {
if (widget.authPass == code) {
Navigator.of(context).pop(true);
return true;
}
Navigator.of(context).pop(false);
return false;
}
Future<void> _confirmPassword() async {
if (password.length > 8) {
if (widget.isAuthenticating) {
await confirmPasswordAuth(password);
return;
} else {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => LockScreenOptionConfirmPassword(
@@ -39,22 +62,6 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
),
),
);
} else {
await showDialogWidget(
context: context,
title: 'Password must have at least 8 characters',
icon: Icons.lock,
body: 'Please re-enter the password.',
isDismissible: true,
buttons: [
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: S.of(context).ok,
isInAlert: true,
buttonAction: ButtonAction.first,
),
],
);
}
}
@@ -63,7 +70,6 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
final colorTheme = getEnteColorScheme(context);
final textTheme = getEnteTextTheme(context);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -101,7 +107,10 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
),
),
Text(
S.of(context).enterPasswordToLockApp,
widget.isAuthenticating
? 'Enter the password to change \nLockscreen settings.'
: 'Enter the password to lock the app',
textAlign: TextAlign.center,
style: textTheme.bodyBold,
),
const Padding(padding: EdgeInsets.all(24)),
@@ -111,6 +120,7 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
hintText: S.of(context).password,
borderRadius: 2,
isClearable: true,
focusNode: _focusNode,
textCapitalization: TextCapitalization.words,
textEditingController: _passwordController,
prefixIcon: Icons.lock_outline,
@@ -126,7 +136,7 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
Padding(
padding: const EdgeInsets.all(18.0),
child: ButtonWidget(
labelText: S.of(context).next,
labelText: 'Next',
buttonType: password.length > 8
? ButtonType.primary
: ButtonType.secondary,

View File

@@ -1,5 +1,4 @@
import "package:flutter/material.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/button_widget.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
@@ -8,32 +7,65 @@ import "package:photos/ui/settings/TEMP/lock_screen_option_confirm_pin.dart";
import "package:pinput/pin_put/pin_put.dart";
class LockScreenOptionPin extends StatefulWidget {
const LockScreenOptionPin({super.key});
const LockScreenOptionPin({
super.key,
this.isAuthenticating = false,
this.authPin,
});
final bool isAuthenticating;
final String? authPin;
@override
State<LockScreenOptionPin> createState() => _LockScreenOptionPinState();
}
class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
final _pinController = TextEditingController(text: null);
String _code = "";
final _focusNode = FocusNode();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future.delayed(const Duration(seconds: 1));
_focusNode.requestFocus();
});
}
@override
void dispose() {
super.dispose();
_pinController.dispose();
_focusNode.dispose();
}
String _code = "";
Future<void> confirmPin(String code) async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) =>
LockScreenOptionConfirmPin(pin: code),
),
);
Future<bool> confirmPinAuth(String code) async {
if (widget.authPin == code) {
Navigator.of(context).pop(true);
return true;
}
Navigator.of(context).pop(false);
return false;
}
Future<void> _confirmPin(String code) async {
if (widget.isAuthenticating) {
await confirmPinAuth(code);
return;
} else {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) =>
LockScreenOptionConfirmPin(pin: code),
),
);
}
}
@override
@@ -85,13 +117,16 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
),
),
Text(
S.of(context).enterThePinToLockTheApp,
widget.isAuthenticating
? 'Enter the pin to change Lockscreen settings.'
: 'Enter the pin to lock the app',
style: textTheme.bodyBold,
),
const Padding(padding: EdgeInsets.all(12)),
Padding(
padding: const EdgeInsets.fromLTRB(80, 0, 80, 0),
child: PinPut(
focusNode: _focusNode,
fieldsCount: 4,
controller: _pinController,
submittedFieldDecoration: _pinPutDecoration.copyWith(
@@ -130,7 +165,7 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
? ButtonType.primary
: ButtonType.secondary,
buttonSize: ButtonSize.large,
onTap: () => confirmPin(_code),
onTap: () => _confirmPin(_code),
),
),
const Padding(padding: EdgeInsets.only(bottom: 24)),

View File

@@ -0,0 +1,17 @@
import "package:flutter/widgets.dart";
class LockScreenOptionPinSetting extends StatefulWidget {
const LockScreenOptionPinSetting({super.key});
@override
State<LockScreenOptionPinSetting> createState() =>
_LockScreenOptionPinSettingState();
}
class _LockScreenOptionPinSettingState
extends State<LockScreenOptionPinSetting> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}