mirror of
https://github.com/ente-io/ente.git
synced 2025-08-13 17:57:31 +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/services/sync_service.dart';
|
||||||
import 'package:photos/utils/crypto_util.dart';
|
import 'package:photos/utils/crypto_util.dart';
|
||||||
import 'package:photos/utils/file_uploader.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/validator_util.dart';
|
||||||
import "package:photos/utils/wakelock_util.dart";
|
import "package:photos/utils/wakelock_util.dart";
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@@ -73,9 +73,6 @@ class Configuration {
|
|||||||
"has_selected_all_folders_for_backup";
|
"has_selected_all_folders_for_backup";
|
||||||
static const anonymousUserIDKey = "anonymous_user_id";
|
static const anonymousUserIDKey = "anonymous_user_id";
|
||||||
static const endPointKey = "endpoint";
|
static const endPointKey = "endpoint";
|
||||||
static const password = "user_pass";
|
|
||||||
static const pin = "user_pin";
|
|
||||||
static const saltKey = "user_salt";
|
|
||||||
static final _logger = Logger("Configuration");
|
static final _logger = Logger("Configuration");
|
||||||
|
|
||||||
String? _cachedToken;
|
String? _cachedToken;
|
||||||
@@ -86,7 +83,6 @@ class Configuration {
|
|||||||
late FlutterSecureStorage _secureStorage;
|
late FlutterSecureStorage _secureStorage;
|
||||||
late String _tempDocumentsDirPath;
|
late String _tempDocumentsDirPath;
|
||||||
late String _thumbnailCacheDirectory;
|
late String _thumbnailCacheDirectory;
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
|
||||||
// 6th July 22: Remove this after 3 months. Hopefully, active users
|
// 6th July 22: Remove this after 3 months. Hopefully, active users
|
||||||
// will migrate to newer version of the app, where shared media is stored
|
// will migrate to newer version of the app, where shared media is stored
|
||||||
// on appSupport directory which OS won't clean up automatically
|
// on appSupport directory which OS won't clean up automatically
|
||||||
@@ -624,8 +620,8 @@ class Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> shouldShowLockScreen() async {
|
Future<bool> shouldShowLockScreen() async {
|
||||||
final bool isPin = await _lockscreenSetting.isPinSet();
|
final bool isPin = await LockScreenSettings.instance.isPinSet();
|
||||||
final bool isPass = await _lockscreenSetting.isPasswordSet();
|
final bool isPass = await LockScreenSettings.instance.isPasswordSet();
|
||||||
return isPin || isPass || shouldShowSystemLockScreen();
|
return isPin || isPass || shouldShowSystemLockScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,6 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import "package:flutter/rendering.dart";
|
import "package:flutter/rendering.dart";
|
||||||
import "package:flutter_displaymode/flutter_displaymode.dart";
|
import "package:flutter_displaymode/flutter_displaymode.dart";
|
||||||
import "package:flutter_secure_storage/flutter_secure_storage.dart";
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import "package:media_kit/media_kit.dart";
|
import "package:media_kit/media_kit.dart";
|
||||||
import 'package:path_provider/path_provider.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/email_util.dart";
|
||||||
import 'package:photos/utils/file_uploader.dart';
|
import 'package:photos/utils/file_uploader.dart';
|
||||||
import 'package:photos/utils/local_settings.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';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
final _logger = Logger("main");
|
final _logger = Logger("main");
|
||||||
@@ -197,7 +196,6 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
|||||||
_isProcessRunning = true;
|
_isProcessRunning = true;
|
||||||
_logger.info("Initializing... inBG =$isBackground via: $via");
|
_logger.info("Initializing... inBG =$isBackground via: $via");
|
||||||
final SharedPreferences preferences = await SharedPreferences.getInstance();
|
final SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||||
const secureStorage = FlutterSecureStorage();
|
|
||||||
await _logFGHeartBeatInfo();
|
await _logFGHeartBeatInfo();
|
||||||
_logger.info("_logFGHeartBeatInfo done");
|
_logger.info("_logFGHeartBeatInfo done");
|
||||||
unawaited(_scheduleHeartBeat(preferences, isBackground));
|
unawaited(_scheduleHeartBeat(preferences, isBackground));
|
||||||
@@ -212,7 +210,7 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
|||||||
CryptoUtil.init();
|
CryptoUtil.init();
|
||||||
|
|
||||||
_logger.info("Lockscreen init");
|
_logger.info("Lockscreen init");
|
||||||
LockscreenSetting.instance.init(secureStorage, preferences);
|
LockScreenSettings.instance.init(preferences);
|
||||||
|
|
||||||
_logger.info("Configuration init");
|
_logger.info("Configuration init");
|
||||||
await Configuration.instance.init();
|
await Configuration.instance.init();
|
||||||
|
@@ -3,8 +3,8 @@ import "dart:async";
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
import 'package:photos/core/configuration.dart';
|
import 'package:photos/core/configuration.dart';
|
||||||
import "package:photos/ui/settings/lockscreen/lockscreen_password.dart";
|
import "package:photos/ui/settings/lock_screen/lock_screen_password.dart";
|
||||||
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
|
import "package:photos/ui/settings/lock_screen/lock_screen_pin.dart";
|
||||||
import 'package:photos/ui/tools/app_lock.dart';
|
import 'package:photos/ui/tools/app_lock.dart';
|
||||||
import 'package:photos/utils/auth_util.dart';
|
import 'package:photos/utils/auth_util.dart';
|
||||||
import 'package:photos/utils/dialog_util.dart';
|
import 'package:photos/utils/dialog_util.dart';
|
||||||
@@ -39,7 +39,7 @@ class LocalAuthenticationService {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
String? savedPin,
|
String? savedPin,
|
||||||
String? savedPassword, {
|
String? savedPassword, {
|
||||||
bool isLockscreenAuth = false,
|
bool isOnOpeningApp = false,
|
||||||
}) async {
|
}) async {
|
||||||
if (savedPassword != null) {
|
if (savedPassword != null) {
|
||||||
final result = await Navigator.of(context).push(
|
final result = await Navigator.of(context).push(
|
||||||
@@ -47,7 +47,7 @@ class LocalAuthenticationService {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return LockScreenPassword(
|
return LockScreenPassword(
|
||||||
isAuthenticating: true,
|
isAuthenticating: true,
|
||||||
isLockscreenAuth: isLockscreenAuth,
|
isOnOpeningApp: isOnOpeningApp,
|
||||||
authPass: savedPassword,
|
authPass: savedPassword,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -63,7 +63,7 @@ class LocalAuthenticationService {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return LockScreenPin(
|
return LockScreenPin(
|
||||||
isAuthenticating: true,
|
isAuthenticating: true,
|
||||||
isLockscreenAuth: isLockscreenAuth,
|
isOnOpeningApp: isOnOpeningApp,
|
||||||
authPin: savedPin,
|
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/common/dynamic_fab.dart";
|
||||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||||
import "package:photos/ui/components/text_input_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 {
|
class LockScreenConfirmPassword extends StatefulWidget {
|
||||||
const LockScreenConfirmPassword({
|
const LockScreenConfirmPassword({
|
||||||
@@ -23,7 +23,7 @@ class _LockScreenConfirmPasswordState extends State<LockScreenConfirmPassword> {
|
|||||||
/// _confirmPasswordController is disposed by the [TextInputWidget]
|
/// _confirmPasswordController is disposed by the [TextInputWidget]
|
||||||
final _confirmPasswordController = TextEditingController(text: null);
|
final _confirmPasswordController = TextEditingController(text: null);
|
||||||
|
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
|
||||||
final _focusNode = FocusNode();
|
final _focusNode = FocusNode();
|
||||||
final _isFormValid = ValueNotifier<bool>(false);
|
final _isFormValid = ValueNotifier<bool>(false);
|
||||||
final _submitNotifier = ValueNotifier(false);
|
final _submitNotifier = ValueNotifier(false);
|
@@ -1,10 +1,9 @@
|
|||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter/services.dart";
|
import "package:flutter/services.dart";
|
||||||
import "package:photos/theme/colors.dart";
|
|
||||||
import "package:photos/theme/ente_theme.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/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";
|
import "package:pinput/pinput.dart";
|
||||||
|
|
||||||
class LockScreenConfirmPin extends StatefulWidget {
|
class LockScreenConfirmPin extends StatefulWidget {
|
||||||
@@ -17,7 +16,8 @@ class LockScreenConfirmPin extends StatefulWidget {
|
|||||||
class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
||||||
final _confirmPinController = TextEditingController(text: null);
|
final _confirmPinController = TextEditingController(text: null);
|
||||||
bool isConfirmPinValid = false;
|
bool isConfirmPinValid = false;
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
|
||||||
|
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
|
||||||
final _pinPutDecoration = PinTheme(
|
final _pinPutDecoration = PinTheme(
|
||||||
height: 48,
|
height: 48,
|
||||||
width: 48,
|
width: 48,
|
||||||
@@ -34,19 +34,6 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
|||||||
_confirmPinController.dispose();
|
_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 {
|
Future<void> _confirmPinMatch() async {
|
||||||
if (widget.pin == _confirmPinController.text) {
|
if (widget.pin == _confirmPinController.text) {
|
||||||
await _lockscreenSetting.setPin(_confirmPinController.text);
|
await _lockscreenSetting.setPin(_confirmPinController.text);
|
||||||
@@ -214,197 +201,9 @@ class _LockScreenConfirmPinState extends State<LockScreenConfirmPin> {
|
|||||||
isPortrait
|
isPortrait
|
||||||
? const Spacer()
|
? const Spacer()
|
||||||
: const Padding(padding: EdgeInsets.all(12)),
|
: 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_title_widget.dart";
|
||||||
import "package:photos/ui/components/title_bar_widget.dart";
|
import "package:photos/ui/components/title_bar_widget.dart";
|
||||||
import "package:photos/ui/components/toggle_switch_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/lock_screen/lock_screen_password.dart";
|
||||||
import "package:photos/ui/settings/lockscreen/lockscreen_pin.dart";
|
import "package:photos/ui/settings/lock_screen/lock_screen_pin.dart";
|
||||||
import "package:photos/ui/tools/app_lock.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 {
|
class LockScreenOptions extends StatefulWidget {
|
||||||
const LockScreenOption({super.key});
|
const LockScreenOptions({super.key});
|
||||||
|
|
||||||
@override
|
@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 Configuration _configuration = Configuration.instance;
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
|
||||||
late bool appLock;
|
late bool appLock;
|
||||||
bool isPinEnabled = false;
|
bool isPinEnabled = false;
|
||||||
bool isPasswordEnabled = 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/common/dynamic_fab.dart";
|
||||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||||
import "package:photos/ui/components/text_input_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/lock_screen/lock_screen_confirm_password.dart";
|
||||||
import "package:photos/ui/settings/lockscreen/lockscreen_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/crypto_util.dart";
|
||||||
import "package:photos/utils/lockscreen_setting.dart";
|
import "package:photos/utils/lock_screen_settings.dart";
|
||||||
|
|
||||||
class LockScreenPassword extends StatefulWidget {
|
class LockScreenPassword extends StatefulWidget {
|
||||||
const LockScreenPassword({
|
const LockScreenPassword({
|
||||||
super.key,
|
super.key,
|
||||||
this.isAuthenticating = false,
|
this.isAuthenticating = false,
|
||||||
this.isLockscreenAuth = false,
|
this.isOnOpeningApp = false,
|
||||||
this.authPass,
|
this.authPass,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// If [isLockscreenAuth] is true then we are authenticating the user at Lock screen
|
//Is false when setting a new password
|
||||||
/// If [isAuthenticating] is true then we are authenticating the user at Setting screen
|
|
||||||
final bool isAuthenticating;
|
final bool isAuthenticating;
|
||||||
final bool isLockscreenAuth;
|
final bool isOnOpeningApp;
|
||||||
final String? authPass;
|
final String? authPass;
|
||||||
@override
|
@override
|
||||||
State<LockScreenPassword> createState() => _LockScreenPasswordState();
|
State<LockScreenPassword> createState() => _LockScreenPasswordState();
|
||||||
@@ -38,8 +37,7 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
|||||||
final _submitNotifier = ValueNotifier(false);
|
final _submitNotifier = ValueNotifier(false);
|
||||||
int invalidAttemptsCount = 0;
|
int invalidAttemptsCount = 0;
|
||||||
|
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
final _lockscreenSetting = LockScreenSettings.instance;
|
||||||
late String enteredHashedPassword;
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -57,57 +55,6 @@ class _LockScreenPasswordState extends State<LockScreenPassword> {
|
|||||||
_isFormValid.dispose();
|
_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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorTheme = getEnteColorScheme(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/ente_theme.dart";
|
||||||
import "package:photos/theme/text_style.dart";
|
import "package:photos/theme/text_style.dart";
|
||||||
import "package:photos/ui/components/buttons/icon_button_widget.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/lock_screen/custom_pin_keypad.dart";
|
||||||
import "package:photos/ui/settings/lockscreen/lockscreen_confirm_pin.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/crypto_util.dart";
|
||||||
import "package:photos/utils/lockscreen_setting.dart";
|
import "package:photos/utils/lock_screen_settings.dart";
|
||||||
import 'package:pinput/pinput.dart';
|
import 'package:pinput/pinput.dart';
|
||||||
|
|
||||||
class LockScreenPin extends StatefulWidget {
|
class LockScreenPin extends StatefulWidget {
|
||||||
const LockScreenPin({
|
const LockScreenPin({
|
||||||
super.key,
|
super.key,
|
||||||
this.isAuthenticating = false,
|
this.isAuthenticating = false,
|
||||||
this.isLockscreenAuth = false,
|
this.isOnOpeningApp = false,
|
||||||
this.authPin,
|
this.authPin,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// If [isLockscreenAuth] is true then we are authenticating the user at the Lock screen
|
//Is false when setting a new password
|
||||||
/// If [isAuthenticating] is true then we are authenticating the user at the Setting screen
|
|
||||||
final bool isAuthenticating;
|
final bool isAuthenticating;
|
||||||
final bool isLockscreenAuth;
|
final bool isOnOpeningApp;
|
||||||
final String? authPin;
|
final String? authPin;
|
||||||
@override
|
@override
|
||||||
State<LockScreenPin> createState() => _LockScreenPinState();
|
State<LockScreenPin> createState() => _LockScreenPinState();
|
||||||
@@ -33,8 +33,7 @@ class LockScreenPin extends StatefulWidget {
|
|||||||
class _LockScreenPinState extends State<LockScreenPin> {
|
class _LockScreenPinState extends State<LockScreenPin> {
|
||||||
final _pinController = TextEditingController(text: null);
|
final _pinController = TextEditingController(text: null);
|
||||||
|
|
||||||
final LockscreenSetting _lockscreenSetting = LockscreenSetting.instance;
|
final LockScreenSettings _lockscreenSetting = LockScreenSettings.instance;
|
||||||
late String enteredHashedPin;
|
|
||||||
bool isPinValid = false;
|
bool isPinValid = false;
|
||||||
int invalidAttemptsCount = 0;
|
int invalidAttemptsCount = 0;
|
||||||
|
|
||||||
@@ -50,19 +49,6 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
|||||||
_pinController.dispose();
|
_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 {
|
Future<bool> confirmPinAuth(String code) async {
|
||||||
final Uint8List? salt = await _lockscreenSetting.getSalt();
|
final Uint8List? salt = await _lockscreenSetting.getSalt();
|
||||||
final hash = cryptoPwHash({
|
final hash = cryptoPwHash({
|
||||||
@@ -72,15 +58,14 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
|||||||
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
"memLimit": Sodium.cryptoPwhashMemlimitInteractive,
|
||||||
});
|
});
|
||||||
|
|
||||||
enteredHashedPin = base64Encode(hash);
|
if (widget.authPin == base64Encode(hash)) {
|
||||||
if (widget.authPin == enteredHashedPin) {
|
|
||||||
invalidAttemptsCount = 0;
|
invalidAttemptsCount = 0;
|
||||||
await _lockscreenSetting.setInvalidAttemptCount(0);
|
await _lockscreenSetting.setInvalidAttemptCount(0);
|
||||||
widget.isLockscreenAuth
|
widget.isOnOpeningApp
|
||||||
? Navigator.of(context).pop(true)
|
? Navigator.of(context).pop(true)
|
||||||
: Navigator.of(context).pushReplacement(
|
: Navigator.of(context).pushReplacement(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => const LockScreenOption(),
|
builder: (context) => const LockScreenOptions(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@@ -95,7 +80,7 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
|||||||
isPinValid = false;
|
isPinValid = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (widget.isLockscreenAuth) {
|
if (widget.isOnOpeningApp) {
|
||||||
invalidAttemptsCount++;
|
invalidAttemptsCount++;
|
||||||
if (invalidAttemptsCount > 4) {
|
if (invalidAttemptsCount > 4) {
|
||||||
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
await _lockscreenSetting.setInvalidAttemptCount(invalidAttemptsCount);
|
||||||
@@ -282,197 +267,9 @@ class _LockScreenPinState extends State<LockScreenPin> {
|
|||||||
isPortrait
|
isPortrait
|
||||||
? const Spacer()
|
? const Spacer()
|
||||||
: const Padding(padding: EdgeInsets.all(12)),
|
: 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/menu_item_widget/menu_item_widget.dart';
|
||||||
import 'package:photos/ui/components/toggle_switch_widget.dart';
|
import 'package:photos/ui/components/toggle_switch_widget.dart';
|
||||||
import 'package:photos/ui/settings/common_settings.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/auth_util.dart";
|
||||||
import "package:photos/utils/crypto_util.dart";
|
import "package:photos/utils/crypto_util.dart";
|
||||||
import "package:photos/utils/dialog_util.dart";
|
import "package:photos/utils/dialog_util.dart";
|
||||||
@@ -154,7 +154,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
|||||||
await Navigator.of(context).push(
|
await Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (BuildContext context) {
|
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/components/buttons/icon_button_widget.dart";
|
||||||
import 'package:photos/ui/tools/app_lock.dart';
|
import 'package:photos/ui/tools/app_lock.dart';
|
||||||
import 'package:photos/utils/auth_util.dart';
|
import 'package:photos/utils/auth_util.dart';
|
||||||
import "package:photos/utils/dialog_util.dart";
|
|
||||||
import "package:photos/utils/lockscreen_setting.dart";
|
import "package:photos/utils/lockscreen_setting.dart";
|
||||||
|
|
||||||
class LockScreen extends StatefulWidget {
|
class LockScreen extends StatefulWidget {
|
||||||
@@ -34,7 +33,16 @@ class _LockScreenState extends State<LockScreen>
|
|||||||
int lockedTime = 0;
|
int lockedTime = 0;
|
||||||
int invalidAttemptCount = 0;
|
int invalidAttemptCount = 0;
|
||||||
int remainingTime = 0;
|
int remainingTime = 0;
|
||||||
|
bool showErrorMessage = true;
|
||||||
final _lockscreenSetting = LockscreenSetting.instance;
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -169,7 +177,7 @@ class _LockScreenState extends State<LockScreen>
|
|||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final shortestSide = MediaQuery.of(context).size.shortestSide;
|
final shortestSide = MediaQuery.sizeOf(context).shortestSide;
|
||||||
return shortestSide > 600 ? true : false;
|
return shortestSide > 600 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +319,7 @@ class _LockScreenState extends State<LockScreen>
|
|||||||
: await requestAuthentication(
|
: await requestAuthentication(
|
||||||
context,
|
context,
|
||||||
context.l10n.authToViewYourMemories,
|
context.l10n.authToViewYourMemories,
|
||||||
isLockscreenAuth: true,
|
isOpeningApp: true,
|
||||||
);
|
);
|
||||||
_logger.finest("LockScreen Result $result $id");
|
_logger.finest("LockScreen Result $result $id");
|
||||||
_isShowingLockScreen = false;
|
_isShowingLockScreen = false;
|
||||||
|
@@ -5,26 +5,25 @@ import 'package:local_auth_ios/local_auth_ios.dart';
|
|||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import "package:photos/generated/l10n.dart";
|
import "package:photos/generated/l10n.dart";
|
||||||
import "package:photos/services/local_authentication_service.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(
|
Future<bool> requestAuthentication(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String reason, {
|
String reason, {
|
||||||
bool isLockscreenAuth = false,
|
bool isOpeningApp = false,
|
||||||
}) async {
|
}) async {
|
||||||
Logger("AuthUtil").info("Requesting authentication");
|
Logger("AuthUtil").info("Requesting authentication");
|
||||||
await LocalAuthentication().stopAuthentication();
|
await LocalAuthentication().stopAuthentication();
|
||||||
|
|
||||||
final LockscreenSetting lockscreenSetting = LockscreenSetting.instance;
|
final String? savedPin = await LockScreenSettings.instance.getPin();
|
||||||
final String? savedPin = await lockscreenSetting.getPin();
|
final String? savedPassword = await LockScreenSettings.instance.getPassword();
|
||||||
final String? savedPassword = await lockscreenSetting.getPassword();
|
|
||||||
if (savedPassword != null || savedPin != null) {
|
if (savedPassword != null || savedPin != null) {
|
||||||
return await LocalAuthenticationService.instance
|
return await LocalAuthenticationService.instance
|
||||||
.requestEnteAuthForLockScreen(
|
.requestEnteAuthForLockScreen(
|
||||||
context,
|
context,
|
||||||
savedPin,
|
savedPin,
|
||||||
savedPassword,
|
savedPassword,
|
||||||
isLockscreenAuth: isLockscreenAuth,
|
isOnOpeningApp: isOpeningApp,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return await LocalAuthentication().authenticate(
|
return await LocalAuthentication().authenticate(
|
||||||
|
@@ -6,21 +6,21 @@ import "package:flutter_sodium/flutter_sodium.dart";
|
|||||||
import "package:photos/utils/crypto_util.dart";
|
import "package:photos/utils/crypto_util.dart";
|
||||||
import "package:shared_preferences/shared_preferences.dart";
|
import "package:shared_preferences/shared_preferences.dart";
|
||||||
|
|
||||||
class LockscreenSetting {
|
class LockScreenSettings {
|
||||||
LockscreenSetting._privateConstructor();
|
LockScreenSettings._privateConstructor();
|
||||||
|
|
||||||
static final LockscreenSetting instance =
|
static final LockScreenSettings instance =
|
||||||
LockscreenSetting._privateConstructor();
|
LockScreenSettings._privateConstructor();
|
||||||
static const password = "user_pass";
|
static const password = "ls_password";
|
||||||
static const pin = "user_pin";
|
static const pin = "ls_pin";
|
||||||
static const saltKey = "user_salt";
|
static const saltKey = "ls_salt";
|
||||||
static const keyInvalidAttempts = "invalid_attempts";
|
static const keyInvalidAttempts = "ls_invalid_attempts";
|
||||||
static const lastInvalidAttemptTime = "last_invalid_attempt_time";
|
static const lastInvalidAttemptTime = "ls_last_invalid_attempt_time";
|
||||||
late FlutterSecureStorage _secureStorage;
|
late FlutterSecureStorage _secureStorage;
|
||||||
late SharedPreferences _preferences;
|
late SharedPreferences _preferences;
|
||||||
|
|
||||||
void init(FlutterSecureStorage secureStorage, SharedPreferences prefs) async {
|
void init(SharedPreferences prefs) async {
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = const FlutterSecureStorage();
|
||||||
_preferences = prefs;
|
_preferences = prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ class LockscreenSetting {
|
|||||||
await _preferences.setInt(keyInvalidAttempts, count);
|
await _preferences.setInt(keyInvalidAttempts, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8List generateSalt() {
|
static Uint8List _generateSalt() {
|
||||||
return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
|
return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setPin(String userPin) async {
|
Future<void> setPin(String userPin) async {
|
||||||
await _secureStorage.delete(key: saltKey);
|
await _secureStorage.delete(key: saltKey);
|
||||||
|
|
||||||
final salt = generateSalt();
|
final salt = _generateSalt();
|
||||||
final hash = cryptoPwHash({
|
final hash = cryptoPwHash({
|
||||||
"password": utf8.encode(userPin),
|
"password": utf8.encode(userPin),
|
||||||
"salt": salt,
|
"salt": salt,
|
||||||
@@ -78,7 +78,7 @@ class LockscreenSetting {
|
|||||||
Future<void> setPassword(String pass) async {
|
Future<void> setPassword(String pass) async {
|
||||||
await _secureStorage.delete(key: saltKey);
|
await _secureStorage.delete(key: saltKey);
|
||||||
|
|
||||||
final salt = generateSalt();
|
final salt = _generateSalt();
|
||||||
final hash = cryptoPwHash({
|
final hash = cryptoPwHash({
|
||||||
"password": utf8.encode(pass),
|
"password": utf8.encode(pass),
|
||||||
"salt": salt,
|
"salt": salt,
|
Reference in New Issue
Block a user