mirror of
https://github.com/ente-io/ente.git
synced 2025-08-14 02:07:33 +00:00
Merge branch 'lockscreen_options' of https://github.com/ente-io/ente into lockscreen_options
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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,
|
||||
);
|
||||
},
|
||||
|
196
mobile/lib/ui/settings/lock_screen/custom_pin_keypad.dart
Normal file
196
mobile/lib/ui/settings/lock_screen/custom_pin_keypad.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -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);
|
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -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();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@@ -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;
|
||||
|
@@ -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(
|
||||
|
@@ -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,
|
Reference in New Issue
Block a user