[mob][photos] upgraded Pinput pakage and Added custom password input widget

This commit is contained in:
Aman Raj Singh Mourya
2024-06-13 01:21:06 +05:30
parent 11da0704c6
commit b20e8a5d17
13 changed files with 300 additions and 155 deletions

View File

@@ -152,21 +152,21 @@ class Configuration {
}
}
Future<void> savePin(String userPin) async {
Future<void> setPin(String userPin) async {
await _preferences.setString(pin, userPin);
await _preferences.remove(password);
}
Future<String?> loadSavedPin() async {
Future<String?> getPin() async {
return _preferences.getString(pin);
}
Future<void> savePassword(String pass) async {
Future<void> setPassword(String pass) async {
await _preferences.setString(password, pass);
await _preferences.remove(pin);
}
Future<String?> loadSavedPassword() async {
Future<String?> getPassword() async {
return _preferences.getString(password);
}

View File

@@ -38,8 +38,8 @@ class LocalAuthenticationService {
}
Future<bool> requestEnteAuthForLockScreen(BuildContext context) async {
final String? savedPin = await _configuration.loadSavedPin();
final String? savedPassword = await _configuration.loadSavedPassword();
final String? savedPin = await _configuration.getPin();
final String? savedPassword = await _configuration.getPassword();
if (savedPassword != null) {
final result = await Navigator.of(context).push(

View File

@@ -4,7 +4,7 @@ import "package:photos/generated/l10n.dart";
import "package:photos/models/account/two_factor.dart";
import 'package:photos/services/user_service.dart';
import 'package:photos/ui/lifecycle_event_handler.dart';
import 'package:pinput/pin_put/pin_put.dart';
import "package:pinput/pinput.dart";
class TwoFactorAuthenticationPage extends StatefulWidget {
final String sessionID;
@@ -20,9 +20,14 @@ class TwoFactorAuthenticationPage extends StatefulWidget {
class _TwoFactorAuthenticationPageState
extends State<TwoFactorAuthenticationPage> {
final _pinController = TextEditingController();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
final _pinPutDecoration = PinTheme(
height: 48,
width: 48,
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
),
);
String _code = "";
late LifecycleEventHandler _lifecycleEventHandler;
@@ -78,9 +83,9 @@ class _TwoFactorAuthenticationPageState
const Padding(padding: EdgeInsets.all(32)),
Padding(
padding: const EdgeInsets.fromLTRB(40, 0, 40, 0),
child: PinPut(
fieldsCount: 6,
onSubmit: (String code) {
child: Pinput(
length: 6,
onCompleted: (String code) {
_verifyTwoFactorCode(code);
},
onChanged: (String pin) {
@@ -88,23 +93,33 @@ class _TwoFactorAuthenticationPageState
_code = pin;
});
},
autofocus: true,
controller: _pinController,
submittedFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(20.0),
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
defaultPinTheme: _pinPutDecoration,
submittedPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
inputDecoration: const InputDecoration(
focusedBorder: InputBorder.none,
border: InputBorder.none,
counterText: '',
followingPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
focusedPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
autofocus: true,
),
),
const Padding(padding: EdgeInsets.all(24)),

View File

@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
import 'package:flutter/services.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/ente_theme_data.dart';
@@ -12,7 +11,7 @@ import 'package:photos/ui/lifecycle_event_handler.dart';
import 'package:photos/utils/crypto_util.dart';
import 'package:photos/utils/navigation_util.dart';
import 'package:photos/utils/toast_util.dart';
import 'package:pinput/pin_put/pin_put.dart';
import "package:pinput/pinput.dart";
class TwoFactorSetupPage extends StatefulWidget {
final String secretCode;
@@ -34,9 +33,13 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final _pinController = TextEditingController();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
final _pinPutDecoration = PinTheme(
height: 48,
width: 48,
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
),
);
String _code = "";
late ImageProvider _imageProvider;
@@ -219,9 +222,9 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
const Padding(padding: EdgeInsets.all(16)),
Padding(
padding: const EdgeInsets.fromLTRB(40, 0, 40, 0),
child: PinPut(
fieldsCount: 6,
onSubmit: (String code) {
child: Pinput(
length: 6,
onCompleted: (String code) {
_enableTwoFactor(code);
},
onChanged: (String pin) {
@@ -230,20 +233,22 @@ class _TwoFactorSetupPageState extends State<TwoFactorSetupPage>
});
},
controller: _pinController,
submittedFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(20.0),
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
submittedPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
inputDecoration: const InputDecoration(
focusedBorder: InputBorder.none,
border: InputBorder.none,
counterText: '',
defaultPinTheme: _pinPutDecoration,
followingPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
),
),

View File

@@ -9,6 +9,7 @@ import "package:photos/ui/components/title_bar_widget.dart";
import "package:photos/ui/components/toggle_switch_widget.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_password.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_pin.dart";
import "package:photos/ui/tools/app_lock.dart";
class LockScreenOption extends StatefulWidget {
const LockScreenOption({super.key});
@@ -29,7 +30,7 @@ class _LockScreenOptionState extends State<LockScreenOption> {
isPinEnabled = _configuration.isPinSet();
appLock = isPinEnabled ||
isPasswordEnabled ||
!_configuration.shouldShowLockScreen();
_configuration.shouldShowLockScreen();
super.initState();
}
@@ -55,7 +56,9 @@ class _LockScreenOptionState extends State<LockScreenOption> {
if (result == false) {
appLock = appLock;
} else {
appLock = isPinEnabled || isPasswordEnabled;
appLock = isPinEnabled ||
isPasswordEnabled ||
_configuration.shouldShowLockScreen();
}
});
}
@@ -79,38 +82,21 @@ class _LockScreenOptionState extends State<LockScreenOption> {
});
}
// Future<void> _onToggleSwitch() async {
// bool result;
// if ((isPinEnabled || isPasswordEnabled) && appLock == true) {
// // result = await LocalAuthenticationService.instance
// // .requestEnteAuthForLockScreen(context);
// result = await requestAuthentication(
// context,
// S.of(context).authToChangeLockscreenSetting,
// );
// await _configuration.removePinAndPassword();
// isPasswordEnabled = _configuration.isPasswordSet();
// isPinEnabled = _configuration.isPinSet();
// } else {
// result = await LocalAuthenticationService.instance
// .requestLocalAuthForLockScreen(
// context,
// !_configuration.shouldShowLockScreen(),
// S.of(context).authToChangeLockscreenSetting,
// S.of(context).lockScreenEnablePreSteps,
// );
// await _configuration.removePinAndPassword();
// isPasswordEnabled = _configuration.isPasswordSet();
// isPinEnabled = _configuration.isPinSet();
// }
// setState(() {
// if (result) {
// appLock = !appLock!;
// } else {
// appLock = appLock;
// }
// });
// }
Future<void> _onToggleSwitch() async {
if (appLock == false && !(isPasswordEnabled || isPinEnabled)) {
AppLock.of(context)!.setEnabled(!appLock!);
await Configuration.instance.setShouldShowLockScreen(!appLock!);
} else {
AppLock.of(context)!.setEnabled(!appLock!);
await Configuration.instance.setShouldShowLockScreen(!appLock!);
}
setState(() {
_configuration.removePinAndPassword();
isPasswordEnabled = _configuration.isPasswordSet();
isPinEnabled = _configuration.isPinSet();
appLock = !appLock!;
});
}
@override
Widget build(BuildContext context) {
@@ -147,15 +133,7 @@ class _LockScreenOptionState extends State<LockScreenOption> {
menuItemColor: colorTheme.fillFaint,
trailingWidget: ToggleSwitchWidget(
value: () => appLock!,
onChanged: () async {
setState(() {
_configuration.removePinAndPassword();
isPasswordEnabled =
_configuration.isPasswordSet();
isPinEnabled = _configuration.isPinSet();
appLock = !appLock!;
});
},
onChanged: () => _onToggleSwitch(),
),
),
const Padding(

View File

@@ -42,7 +42,7 @@ class _LockScreenOptionConfirmPasswordState
Future<void> _confirmPasswordMatch() async {
if (widget.password == _confirmPasswordController.text) {
await _configuration.savePassword(_confirmPasswordController.text);
await _configuration.setPassword(_confirmPasswordController.text);
Navigator.of(context).pop(true);
Navigator.of(context).pop(true);
@@ -70,6 +70,7 @@ class _LockScreenOptionConfirmPasswordState
elevation: 0,
leading: IconButton(
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(context).pop();
},
icon: Icon(

View File

@@ -4,7 +4,7 @@ import "package:photos/generated/l10n.dart";
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:pinput/pin_put/pin_put.dart";
import "package:pinput/pinput.dart";
class LockScreenOptionConfirmPin extends StatefulWidget {
const LockScreenOptionConfirmPin({super.key, required this.pin});
@@ -19,11 +19,14 @@ class _LockScreenOptionConfirmPinState
final _confirmPinController = TextEditingController(text: null);
final Configuration _configuration = Configuration.instance;
final _focusNode = FocusNode();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
final _pinPutDecoration = PinTheme(
height: 50,
width: 50,
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
),
);
@override
void initState() {
super.initState();
@@ -42,12 +45,14 @@ class _LockScreenOptionConfirmPinState
Future<void> _confirmPinMatch() async {
if (widget.pin == _confirmPinController.text) {
await _configuration.savePin(_confirmPinController.text);
await _configuration.setPin(_confirmPinController.text);
Navigator.of(context).pop(true);
Navigator.of(context).pop(true);
return;
} else {
_confirmPinController.clear();
}
_confirmPinController.clear();
}
@override
@@ -70,6 +75,7 @@ class _LockScreenOptionConfirmPinState
elevation: 0,
leading: IconButton(
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(context).pop(false);
},
icon: Icon(
@@ -136,29 +142,46 @@ class _LockScreenOptionConfirmPinState
),
const Padding(padding: EdgeInsets.all(12)),
Padding(
padding: const EdgeInsets.fromLTRB(80, 0, 80, 0),
child: PinPut(
fieldsCount: 4,
padding: const EdgeInsets.fromLTRB(70, 0, 70, 0),
child: Pinput(
length: 4,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
controller: _confirmPinController,
focusNode: _focusNode,
submittedFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(20.0),
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
submittedPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
inputDecoration: const InputDecoration(
focusedBorder: InputBorder.none,
border: InputBorder.none,
counterText: '',
defaultPinTheme: _pinPutDecoration,
followingPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
textStyle: textTheme.h3,
obscureText: '*',
onSubmit: (value) {
errorPinTheme: _pinPutDecoration.copyWith(
textStyle: TextStyle(color: colorTheme.warning400),
),
errorText: '',
focusedPinTheme: _pinPutDecoration,
obscureText: true,
obscuringCharacter: '*',
validator: (value) {
if (value == widget.pin) {
return null;
} else {
return 'PIN does not match';
}
},
onSubmitted: (value) {
_confirmPinMatch();
FocusScope.of(context).unfocus();
},
),

View File

@@ -85,6 +85,7 @@ class _LockScreenOptionPasswordState extends State<LockScreenOptionPassword> {
elevation: 0,
leading: IconButton(
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(context).pop(false);
},
icon: Icon(

View File

@@ -2,7 +2,7 @@ import "package:flutter/material.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/components/buttons/icon_button_widget.dart";
import "package:photos/ui/settings/TEMP/lock_screen_option_confirm_pin.dart";
import "package:pinput/pin_put/pin_put.dart";
import 'package:pinput/pinput.dart';
class LockScreenOptionPin extends StatefulWidget {
const LockScreenOptionPin({
@@ -21,11 +21,6 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
final _pinController = TextEditingController(text: null);
final _focusNode = FocusNode();
final _pinPutDecoration = BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
);
@override
void initState() {
super.initState();
@@ -66,6 +61,14 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
}
}
final _pinPutDecoration = PinTheme(
height: 50,
width: 50,
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(45, 194, 98, 1.0)),
borderRadius: BorderRadius.circular(15.0),
),
);
@override
Widget build(BuildContext context) {
final colorTheme = getEnteColorScheme(context);
@@ -75,6 +78,7 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
elevation: 0,
leading: IconButton(
onPressed: () {
FocusScope.of(context).unfocus();
Navigator.of(context).pop(false);
},
icon: Icon(
@@ -130,34 +134,52 @@ class _LockScreenOptionPinState extends State<LockScreenOptionPin> {
style: textTheme.bodyBold,
),
const Padding(padding: EdgeInsets.all(12)),
Padding(
padding: const EdgeInsets.fromLTRB(80, 0, 80, 0),
child: PinPut(
focusNode: _focusNode,
fieldsCount: 4,
controller: _pinController,
submittedFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(20.0),
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration.copyWith(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(70, 0, 70, 0),
child: Pinput(
length: 4,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
focusNode: _focusNode,
controller: _pinController,
defaultPinTheme: _pinPutDecoration,
submittedPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
followingPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: const Color.fromRGBO(45, 194, 98, 0.5),
),
),
),
focusedPinTheme: _pinPutDecoration,
errorPinTheme: _pinPutDecoration.copyWith(
decoration: BoxDecoration(
border: Border.all(
color: colorTheme.warning400,
),
),
),
autofocus: true,
errorText: '*',
obscureText: true,
obscuringCharacter: '*',
onCompleted: (value) {
FocusScope.of(context).unfocus();
_confirmPin(_pinController.text);
},
),
),
inputDecoration: const InputDecoration(
focusedBorder: InputBorder.none,
border: InputBorder.none,
counterText: '',
),
textStyle: textTheme.h3,
obscureText: '*',
onSubmit: (value) {
FocusScope.of(context).unfocus();
_confirmPin(_pinController.text);
},
),
],
),
],
),

View File

@@ -0,0 +1,92 @@
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:photos/models/execution_states.dart";
import "package:photos/models/typedefs.dart";
import "package:photos/theme/ente_theme.dart";
import "package:photos/utils/debouncer.dart";
class PasswordInputWidget extends StatefulWidget {
final String? label;
final String? message;
final String? hintText;
final IconData? prefixIcon;
final String? initialValue;
final Alignment? alignMessage;
final bool? autoFocus;
final int? maxLength;
final double borderRadius;
final ValueNotifier? submitNotifier;
final FutureVoidCallbackParamStr? onSubmit;
final VoidCallbackParamStr? onChange;
final bool isPasswordInput;
final FocusNode? focusNode;
final TextEditingController? textEditingController;
final TextInputType? textInputType;
final List<TextInputFormatter>? textInputFormatter;
const PasswordInputWidget({
Key? key,
this.label,
this.message,
this.hintText,
this.prefixIcon,
this.initialValue,
this.alignMessage,
this.autoFocus,
this.maxLength,
this.borderRadius = 10.0,
this.submitNotifier,
this.onSubmit,
this.onChange,
required this.isPasswordInput,
this.focusNode,
this.textEditingController,
this.textInputType,
this.textInputFormatter,
}) : super(key: key);
@override
State<PasswordInputWidget> createState() => _PasswordInputWidgetState();
}
class _PasswordInputWidgetState extends State<PasswordInputWidget> {
ExecutionState executionState = ExecutionState.idle;
late final TextEditingController _textController;
final _debouncer = Debouncer(const Duration(milliseconds: 300));
late final ValueNotifier<bool> _obscureTextNotifier;
@override
void initState() {
super.initState();
// widget.submitNotifier?.addListener(_onSubmit);
// widget.cancelNotifier?.addListener(_onCancel);
_textController = widget.textEditingController ?? TextEditingController();
// _setInitialValue();
if (widget.onChange != null) {
_textController.addListener(() {
widget.onChange!.call(_textController.text);
});
}
_obscureTextNotifier = ValueNotifier(widget.isPasswordInput);
// _obscureTextNotifier.addListener(_safeRefresh);
// if (widget.isEmptyNotifier != null) {
// _textController.addListener(() {
// widget.isEmptyNotifier!.value = _textController.text.isEmpty;
// });
// }
}
@override
Widget build(BuildContext context) {
final colorScheme = getEnteColorScheme(context);
final textTheme = getEnteTextTheme(context);
var textInputChildren = <Widget>[];
return const Placeholder();
}
}

View File

@@ -11,8 +11,8 @@ Future<bool> requestAuthentication(BuildContext context, String reason) async {
Logger("AuthUtil").info("Requesting authentication");
await LocalAuthentication().stopAuthentication();
final Configuration configuration = Configuration.instance;
final String? savedPin = await configuration.loadSavedPin();
final String? savedPassword = await configuration.loadSavedPassword();
final String? savedPin = await configuration.getPin();
final String? savedPassword = await configuration.getPassword();
if (savedPassword != null || savedPin != null) {
return await LocalAuthenticationService.instance
.requestEnteAuthForLockScreen(context);

View File

@@ -1699,10 +1699,10 @@ packages:
dependency: "direct main"
description:
name: pinput
sha256: "27eb69042f75755bdb6544f6e79a50a6ed09d6e97e2d75c8421744df1e392949"
sha256: "543da5bfdefd9e06914a12100f8c9156f84cef3efc14bca507c49e966c5b813b"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "2.3.0"
platform:
dependency: transitive
description:
@@ -2020,6 +2020,14 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
smart_auth:
dependency: transitive
description:
name: smart_auth
sha256: a25229b38c02f733d0a4e98d941b42bed91a976cb589e934895e60ccfa674cf6
url: "https://pub.dev"
source: hosted
version: "1.1.1"
source_gen:
dependency: transitive
description:
@@ -2304,10 +2312,10 @@ packages:
dependency: transitive
description:
name: universal_platform
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
url: "https://pub.dev"
source: hosted
version: "1.0.0+1"
version: "1.1.0"
uri_parser:
dependency: transitive
description:

View File

@@ -134,7 +134,7 @@ dependencies:
permission_handler: ^11.0.1
photo_manager: ^3.0.0
photo_view: ^0.14.0
pinput: ^1.2.2
pinput: ^2.0.2
pointycastle: ^3.7.3
pool: ^1.5.1
protobuf: ^3.1.0