Merge branch 'lockscreen_options' of https://github.com/ente-io/ente into lockscreen_options

This commit is contained in:
Aman Raj Singh Mourya
2024-07-03 13:13:34 +05:30
13 changed files with 323 additions and 533 deletions

View File

@@ -34,7 +34,7 @@ import 'package:photos/services/search_service.dart';
import 'package:photos/services/sync_service.dart';
import 'package:photos/utils/crypto_util.dart';
import 'package:photos/utils/file_uploader.dart';
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
import 'package:photos/utils/validator_util.dart';
import "package:photos/utils/wakelock_util.dart";
import 'package:shared_preferences/shared_preferences.dart';
@@ -73,9 +73,6 @@ 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 const saltKey = "user_salt";
static final _logger = Logger("Configuration");
String? _cachedToken;
@@ -86,7 +83,6 @@ class Configuration {
late FlutterSecureStorage _secureStorage;
late String _tempDocumentsDirPath;
late String _thumbnailCacheDirectory;
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
// 6th July 22: Remove this after 3 months. Hopefully, active users
// will migrate to newer version of the app, where shared media is stored
// on appSupport directory which OS won't clean up automatically
@@ -624,8 +620,8 @@ class Configuration {
}
Future<bool> shouldShowLockScreen() async {
final bool isPin = await _lockscreenSetting.isPinSet();
final bool isPass = await _lockscreenSetting.isPasswordSet();
final bool isPin = await LockScreenSettings.instance.isPinSet();
final bool isPass = await LockScreenSettings.instance.isPasswordSet();
return isPin || isPass || shouldShowSystemLockScreen();
}

View File

@@ -9,7 +9,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import "package:flutter/rendering.dart";
import "package:flutter_displaymode/flutter_displaymode.dart";
import "package:flutter_secure_storage/flutter_secure_storage.dart";
import 'package:logging/logging.dart';
import "package:media_kit/media_kit.dart";
import 'package:path_provider/path_provider.dart';
@@ -54,7 +53,7 @@ import 'package:photos/utils/crypto_util.dart';
import "package:photos/utils/email_util.dart";
import 'package:photos/utils/file_uploader.dart';
import 'package:photos/utils/local_settings.dart';
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
import 'package:shared_preferences/shared_preferences.dart';
final _logger = Logger("main");
@@ -197,7 +196,6 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
_isProcessRunning = true;
_logger.info("Initializing... inBG =$isBackground via: $via");
final SharedPreferences preferences = await SharedPreferences.getInstance();
const secureStorage = FlutterSecureStorage();
await _logFGHeartBeatInfo();
_logger.info("_logFGHeartBeatInfo done");
unawaited(_scheduleHeartBeat(preferences, isBackground));
@@ -212,7 +210,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
CryptoUtil.init();
_logger.info("Lockscreen init");
LockscreenSetting.instance.init(secureStorage, preferences);
LockScreenSettings.instance.init(preferences);
_logger.info("Configuration init");
await Configuration.instance.init();

View File

@@ -3,8 +3,8 @@ import "dart:async";
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:photos/core/configuration.dart';
import "package:photos/ui/settings/lockscreen/lockscreen_password.dart";
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_password.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_pin.dart";
import 'package:photos/ui/tools/app_lock.dart';
import 'package:photos/utils/auth_util.dart';
import 'package:photos/utils/dialog_util.dart';
@@ -39,7 +39,7 @@ class LocalAuthenticationService {
BuildContext context,
String? savedPin,
String? savedPassword, {
bool isLockscreenAuth = false,
bool isOnOpeningApp = false,
}) async {
if (savedPassword != null) {
final result = await Navigator.of(context).push(
@@ -47,7 +47,7 @@ class LocalAuthenticationService {
builder: (BuildContext context) {
return LockScreenPassword(
isAuthenticating: true,
isLockscreenAuth: isLockscreenAuth,
isOnOpeningApp: isOnOpeningApp,
authPass: savedPassword,
);
},
@@ -63,7 +63,7 @@ class LocalAuthenticationService {
builder: (BuildContext context) {
return LockScreenPin(
isAuthenticating: true,
isLockscreenAuth: isLockscreenAuth,
isOnOpeningApp: isOnOpeningApp,
authPin: savedPin,
);
},

View File

@@ -0,0 +1,196 @@
import "package:flutter/material.dart";
import "package:photos/theme/ente_theme.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),
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 StatelessWidget {
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
Widget build(BuildContext context) {
final colorScheme = getEnteColorScheme(context);
final textTheme = getEnteTextTheme(context);
return Expanded(
child: GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(6),
color: muteButton
? colorScheme.fillFaintPressed
: icon == null
? colorScheme.backgroundElevated2
: null,
),
child: Center(
child: muteButton
? const SizedBox.shrink()
: icon != null
? Container(
child: icon,
)
: Container(
padding: const EdgeInsets.all(4),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
number,
style: textTheme.h3,
),
Text(
text,
style: textTheme.tinyBold,
),
],
),
),
),
),
),
);
}
}

View File

@@ -5,7 +5,7 @@ import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/common/dynamic_fab.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/components/text_input_widget.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
class LockScreenConfirmPassword extends StatefulWidget {
const LockScreenConfirmPassword({
@@ -23,7 +23,7 @@ class _LockScreenConfirmPasswordState extends State<LockScreenConfirmPassword> {
/// _confirmPasswordController is disposed by the [TextInputWidget]
final _confirmPasswordController = TextEditingController(text: null);
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
final _focusNode = FocusNode();
final _isFormValid = ValueNotifier<bool>(false);
final _submitNotifier = ValueNotifier(false);

View File

@@ -1,10 +1,9 @@
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:photos/theme/colors.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/theme/text_style.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/ui/settings/lock_screen/custom_pin_keypad.dart";
import "package:photos/utils/lock_screen_settings.dart";
import "package:pinput/pinput.dart";
class LockScreenConfirmPin extends StatefulWidget {
@@ -17,7 +16,8 @@ class LockScreenConfirmPin extends StatefulWidget {
class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
final _confirmPinController = TextEditingController(text: null);
bool isConfirmPinValid = false;
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
final _pinPutDecoration = PinTheme(
height: 48,
width: 48,
@@ -34,19 +34,6 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
_confirmPinController.dispose();
}
void _onKeyTap(String number) {
_confirmPinController.text += number;
return;
}
void _onBackspace() {
if (_confirmPinController.text.isNotEmpty) {
_confirmPinController.text = _confirmPinController.text
.substring(0, _confirmPinController.text.length - 1);
}
return;
}
Future<void> _confirmPinMatch() async {
if (widget.pin == _confirmPinController.text) {
await _lockscreenSetting.setPin(_confirmPinController.text);
@@ -214,197 +201,9 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
isPortrait
? const Spacer()
: const Padding(padding: EdgeInsets.all(12)),
customKeyPad(colorTheme, textTheme),
CustomPinKeypad(controller: _confirmPinController),
],
),
);
}
Widget customKeyPad(EnteColorScheme colorTheme, EnteTextTheme textTheme) {
return SafeArea(
child: Container(
padding: const EdgeInsets.all(2),
color: colorTheme.strokeFainter,
child: Column(
children: [
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: '',
number: '1',
onTap: () {
_onKeyTap('1');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: "ABC",
number: '2',
onTap: () {
_onKeyTap('2');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: "DEF",
number: '3',
onTap: () {
_onKeyTap('3');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '4',
text: "GHI",
onTap: () {
_onKeyTap('4');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '5',
text: 'JKL',
onTap: () {
_onKeyTap('5');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '6',
text: 'MNO',
onTap: () {
_onKeyTap('6');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '7',
text: 'PQRS',
onTap: () {
_onKeyTap('7');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '8',
text: 'TUV',
onTap: () {
_onKeyTap('8');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '9',
text: 'WXYZ',
onTap: () {
_onKeyTap('9');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '',
text: '',
muteButton: true,
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '0',
text: '',
onTap: () {
_onKeyTap('0');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '',
text: '',
icons: const Icon(Icons.backspace_outlined),
onTap: () {
_onBackspace();
},
),
],
),
],
),
),
);
}
Widget buttonWidget({
colorTheme,
textTheme,
text,
number,
muteButton = false,
icons,
onTap,
}) {
return Expanded(
child: GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(6),
color: muteButton
? colorTheme.fillFaintPressed
: icons == null
? colorTheme.backgroundElevated2
: null,
),
child: Center(
child: muteButton
? Container()
: icons != null
? Container(
child: icons,
)
: Container(
padding: const EdgeInsets.all(4),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
number,
style: textTheme.h3,
),
Text(
text,
style: textTheme.small,
),
],
),
),
),
),
),
);
}
}

View File

@@ -7,21 +7,21 @@ import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart";
import "package:photos/ui/components/title_bar_title_widget.dart";
import "package:photos/ui/components/title_bar_widget.dart";
import "package:photos/ui/components/toggle_switch_widget.dart";
import "package:photos/ui/settings/lockscreen/lockscreen_password.dart";
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_password.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_pin.dart";
import "package:photos/ui/tools/app_lock.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
class LockScreenOption extends StatefulWidget {
const LockScreenOption({super.key});
class LockScreenOptions extends StatefulWidget {
const LockScreenOptions({super.key});
@override
State<LockScreenOption> createState() => _LockScreenOptionState();
State<LockScreenOptions> createState() => _LockScreenOptionsState();
}
class _LockScreenOptionState extends State<LockScreenOption> {
class _LockScreenOptionsState extends State<LockScreenOptions> {
final Configuration _configuration = Configuration.instance;
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
late bool appLock;
bool isPinEnabled = false;
bool isPasswordEnabled = false;

View File

@@ -8,23 +8,22 @@ import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/common/dynamic_fab.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/components/text_input_widget.dart";
import "package:photos/ui/settings/lockscreen/lock_screen_option.dart";
import "package:photos/ui/settings/lockscreen/lockscreen_confirm_password.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_confirm_password.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_options.dart";
import "package:photos/utils/crypto_util.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
class LockScreenPassword extends StatefulWidget {
const LockScreenPassword({
super.key,
this.isAuthenticating = false,
this.isLockscreenAuth = false,
this.isOnOpeningApp = false,
this.authPass,
});
/// If [isLockscreenAuth] is true then we are authenticating the user at Lock screen
/// If [isAuthenticating] is true then we are authenticating the user at Setting screen
//Is false when setting a new password
final bool isAuthenticating;
final bool isLockscreenAuth;
final bool isOnOpeningApp;
final String? authPass;
@override
State<LockScreenPassword> createState() => _LockScreenPasswordState();
@@ -38,8 +37,7 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
final _submitNotifier = ValueNotifier(false);
int invalidAttemptsCount = 0;
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
late String enteredHashedPassword;
final _lockscreenSetting = LockScreenSettings.instance;
@override
void initState() {
super.initState();
@@ -57,57 +55,6 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
_isFormValid.dispose();
}
Future<bool> confirmPasswordAuth(String code) async {
final Uint8List? salt = await _lockscreenSetting.getSalt();
final hash = cryptoPwHash({
"password": utf8.encode(code),
"salt": salt,
"opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
});
enteredHashedPassword = base64Encode(hash);
if (widget.authPass == enteredHashedPassword) {
await _lockscreenSetting.setInvalidAttemptCount(0);
widget.isLockscreenAuth
? Navigator.of(context).pop(true)
: Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const LockScreenOption(),
),
);
return true;
} else {
if (widget.isLockscreenAuth) {
invalidAttemptsCount++;
if (invalidAttemptsCount > 4) {
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
Navigator.of(context).pop(false);
}
}
await HapticFeedback.vibrate();
throw Exception("Incorrect password");
}
}
Future<void> _confirmPassword() async {
if (widget.isAuthenticating) {
await confirmPasswordAuth(_passwordController.text);
return;
} else {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => LockScreenConfirmPassword(
password: _passwordController.text,
),
),
);
_passwordController.clear();
}
}
@override
Widget build(BuildContext context) {
final colorTheme = getEnteColorScheme(context);
@@ -239,4 +186,54 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
),
);
}
Future<bool> _confirmPasswordAuth(String inputtedPassword) async {
final Uint8List? salt = await _lockscreenSetting.getSalt();
final hash = cryptoPwHash({
"password": utf8.encode(inputtedPassword),
"salt": salt,
"opsLimit": Sodium.cryptoPwhashOpslimitInteractive,
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
});
if (widget.authPass == base64Encode(hash)) {
await _lockscreenSetting.setInvalidAttemptCount(0);
widget.isOnOpeningApp
? Navigator.of(context).pop(true)
: Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const LockScreenOptions(),
),
);
return true;
} else {
if (widget.isOnOpeningApp) {
invalidAttemptsCount++;
if (invalidAttemptsCount > 4) {
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
Navigator.of(context).pop(false);
}
}
await HapticFeedback.vibrate();
throw Exception("Incorrect password");
}
}
Future<void> _confirmPassword() async {
if (widget.isAuthenticating) {
await _confirmPasswordAuth(_passwordController.text);
return;
} else {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => LockScreenConfirmPassword(
password: _passwordController.text,
),
),
);
_passwordController.clear();
}
}
}

View File

@@ -7,24 +7,24 @@ import "package:photos/theme/colors.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/theme/text_style.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/settings/lockscreen/lock_screen_option.dart";
import "package:photos/ui/settings/lockscreen/lockscreen_confirm_pin.dart";
import "package:photos/ui/settings/lock_screen/custom_pin_keypad.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_confirm_pin.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_options.dart";
import "package:photos/utils/crypto_util.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
import 'package:pinput/pinput.dart';
class LockScreenPin extends StatefulWidget {
const LockScreenPin({
super.key,
this.isAuthenticating = false,
this.isLockscreenAuth = false,
this.isOnOpeningApp = false,
this.authPin,
});
/// If [isLockscreenAuth] is true then we are authenticating the user at the Lock screen
/// If [isAuthenticating] is true then we are authenticating the user at the Setting screen
//Is false when setting a new password
final bool isAuthenticating;
final bool isLockscreenAuth;
final bool isOnOpeningApp;
final String? authPin;
@override
State<LockScreenPin> createState() => _LockScreenPinState();
@@ -33,8 +33,7 @@ class LockScreenPin extends StatefulWidget {
class _LockScreenPinState extends State<LockScreenPin> {
final _pinController = TextEditingController(text: null);
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
late String enteredHashedPin;
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
bool isPinValid = false;
int invalidAttemptsCount = 0;
@@ -50,19 +49,6 @@ class _LockScreenPinState extends State<LockScreenPin> {
_pinController.dispose();
}
void _onKeyTap(String number) {
_pinController.text += number;
return;
}
void _onBackspace() {
if (_pinController.text.isNotEmpty) {
_pinController.text =
_pinController.text.substring(0, _pinController.text.length - 1);
}
return;
}
Future<bool> confirmPinAuth(String code) async {
final Uint8List? salt = await _lockscreenSetting.getSalt();
final hash = cryptoPwHash({
@@ -72,15 +58,14 @@ class _LockScreenPinState extends State<LockScreenPin> {
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
});
enteredHashedPin = base64Encode(hash);
if (widget.authPin == enteredHashedPin) {
if (widget.authPin == base64Encode(hash)) {
invalidAttemptsCount = 0;
await _lockscreenSetting.setInvalidAttemptCount(0);
widget.isLockscreenAuth
widget.isOnOpeningApp
? Navigator.of(context).pop(true)
: Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const LockScreenOption(),
builder: (context) => const LockScreenOptions(),
),
);
return true;
@@ -95,7 +80,7 @@ class _LockScreenPinState extends State<LockScreenPin> {
isPinValid = false;
});
if (widget.isLockscreenAuth) {
if (widget.isOnOpeningApp) {
invalidAttemptsCount++;
if (invalidAttemptsCount > 4) {
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
@@ -282,197 +267,9 @@ class _LockScreenPinState extends State<LockScreenPin> {
isPortrait
? const Spacer()
: const Padding(padding: EdgeInsets.all(12)),
customKeyPad(colorTheme, textTheme),
CustomPinKeypad(controller: _pinController),
],
),
);
}
Widget customKeyPad(EnteColorScheme colorTheme, EnteTextTheme textTheme) {
return SafeArea(
child: Container(
padding: const EdgeInsets.all(2),
color: colorTheme.strokeFainter,
child: Column(
children: [
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: '',
number: '1',
onTap: () {
_onKeyTap('1');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: "ABC",
number: '2',
onTap: () {
_onKeyTap('2');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
text: "DEF",
number: '3',
onTap: () {
_onKeyTap('3');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '4',
text: "GHI",
onTap: () {
_onKeyTap('4');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '5',
text: 'JKL',
onTap: () {
_onKeyTap('5');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '6',
text: 'MNO',
onTap: () {
_onKeyTap('6');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '7',
text: 'PQRS',
onTap: () {
_onKeyTap('7');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '8',
text: 'TUV',
onTap: () {
_onKeyTap('8');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '9',
text: 'WXYZ',
onTap: () {
_onKeyTap('9');
},
),
],
),
Row(
children: [
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '',
text: '',
muteButton: true,
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '0',
text: '',
onTap: () {
_onKeyTap('0');
},
),
buttonWidget(
colorTheme: colorTheme,
textTheme: textTheme,
number: '',
text: '',
icons: const Icon(Icons.backspace_outlined),
onTap: () {
_onBackspace();
},
),
],
),
],
),
),
);
}
Widget buttonWidget({
colorTheme,
textTheme,
text,
number,
muteButton = false,
icons,
onTap,
}) {
return Expanded(
child: GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(6),
color: muteButton
? colorTheme.fillFaintPressed
: icons == null
? colorTheme.backgroundElevated2
: null,
),
child: Center(
child: muteButton
? Container()
: icons != null
? Container(
child: icons,
)
: Container(
padding: const EdgeInsets.all(4),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
number,
style: textTheme.h3,
),
Text(
text,
style: textTheme.miniBold,
),
],
),
),
),
),
),
);
}
}

View File

@@ -21,7 +21,7 @@ import 'package:photos/ui/components/expandable_menu_item_widget.dart';
import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart';
import 'package:photos/ui/components/toggle_switch_widget.dart';
import 'package:photos/ui/settings/common_settings.dart';
import "package:photos/ui/settings/lockscreen/lock_screen_option.dart";
import "package:photos/ui/settings/lock_screen/lock_screen_options.dart";
import "package:photos/utils/auth_util.dart";
import "package:photos/utils/crypto_util.dart";
import "package:photos/utils/dialog_util.dart";
@@ -154,7 +154,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const LockScreenOption();
return const LockScreenOptions();
},
),
);

View File

@@ -13,7 +13,6 @@ import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import 'package:photos/ui/tools/app_lock.dart';
import 'package:photos/utils/auth_util.dart';
import "package:photos/utils/dialog_util.dart";
import "package:photos/utils/lockscreen_setting.dart";
class LockScreen extends StatefulWidget {
@@ -34,7 +33,16 @@ class _LockScreenState extends State<LockScreen>
int lockedTime = 0;
int invalidAttemptCount = 0;
int remainingTime = 0;
bool showErrorMessage = true;
final _lockscreenSetting = LockscreenSetting.instance;
late final AnimationController _controller = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
late final animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
@override
void initState() {
@@ -169,7 +177,7 @@ class _LockScreenState extends State<LockScreen>
if (Platform.isAndroid) {
return false;
}
final shortestSide = MediaQuery.of(context).size.shortestSide;
final shortestSide = MediaQuery.sizeOf(context).shortestSide;
return shortestSide > 600 ? true : false;
}
@@ -311,7 +319,7 @@ class _LockScreenState extends State<LockScreen>
: await requestAuthentication(
context,
context.l10n.authToViewYourMemories,
isLockscreenAuth: true,
isOpeningApp: true,
);
_logger.finest("LockScreen Result $result $id");
_isShowingLockScreen = false;

View File

@@ -5,26 +5,25 @@ import 'package:local_auth_ios/local_auth_ios.dart';
import 'package:logging/logging.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/services/local_authentication_service.dart";
import "package:photos/utils/lockscreen_setting.dart";
import "package:photos/utils/lock_screen_settings.dart";
Future<bool> requestAuthentication(
BuildContext context,
String reason, {
bool isLockscreenAuth = false,
bool isOpeningApp = false,
}) async {
Logger("AuthUtil").info("Requesting authentication");
await LocalAuthentication().stopAuthentication();
final LockscreenSetting lockscreenSetting = LockscreenSetting.instance;
final String? savedPin = await lockscreenSetting.getPin();
final String? savedPassword = await lockscreenSetting.getPassword();
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,
isLockscreenAuth: isLockscreenAuth,
isOnOpeningApp: isOpeningApp,
);
} else {
return await LocalAuthentication().authenticate(

View File

@@ -6,21 +6,21 @@ import "package:flutter_sodium/flutter_sodium.dart";
import "package:photos/utils/crypto_util.dart";
import "package:shared_preferences/shared_preferences.dart";
class LockscreenSetting {
LockscreenSetting._privateConstructor();
class LockScreenSettings {
LockScreenSettings._privateConstructor();
static final LockscreenSetting instance =
LockscreenSetting._privateConstructor();
static const password = "user_pass";
static const pin = "user_pin";
static const saltKey = "user_salt";
static const keyInvalidAttempts = "invalid_attempts";
static const lastInvalidAttemptTime = "last_invalid_attempt_time";
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";
late FlutterSecureStorage _secureStorage;
late SharedPreferences _preferences;
void init(FlutterSecureStorage secureStorage, SharedPreferences prefs) async {
_secureStorage = secureStorage;
void init(SharedPreferences prefs) async {
_secureStorage = const FlutterSecureStorage();
_preferences = prefs;
}
@@ -40,14 +40,14 @@ class LockscreenSetting {
await _preferences.setInt(keyInvalidAttempts, count);
}
static Uint8List generateSalt() {
static Uint8List _generateSalt() {
return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
}
Future<void> setPin(String userPin) async {
await _secureStorage.delete(key: saltKey);
final salt = generateSalt();
final salt = _generateSalt();
final hash = cryptoPwHash({
"password": utf8.encode(userPin),
"salt": salt,
@@ -78,7 +78,7 @@ class LockscreenSetting {
Future<void> setPassword(String pass) async {
await _secureStorage.delete(key: saltKey);
final salt = generateSalt();
final salt = _generateSalt();
final hash = cryptoPwHash({
"password": utf8.encode(pass),
"salt": salt,