mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:37:11 -04:00 
			
		
		
		
	* feat: locked/private view * feat: locked/private view * feat: mobile lock/private view * feat: mobile lock/private view * merge main * pr feedback * pr feedback * bottom sheet sizing * always lock when navigating away
		
			
				
	
	
		
			95 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:easy_localization/easy_localization.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:flutter_hooks/flutter_hooks.dart';
 | |
| import 'package:hooks_riverpod/hooks_riverpod.dart';
 | |
| import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | |
| import 'package:immich_mobile/providers/auth.provider.dart';
 | |
| import 'package:immich_mobile/widgets/forms/pin_input.dart';
 | |
| 
 | |
| class PinVerificationForm extends HookConsumerWidget {
 | |
|   final Function(String) onSuccess;
 | |
|   final VoidCallback? onError;
 | |
|   final bool? autoFocus;
 | |
|   final String? description;
 | |
|   final IconData? icon;
 | |
|   final IconData? successIcon;
 | |
| 
 | |
|   const PinVerificationForm({
 | |
|     super.key,
 | |
|     required this.onSuccess,
 | |
|     this.onError,
 | |
|     this.autoFocus,
 | |
|     this.description,
 | |
|     this.icon,
 | |
|     this.successIcon,
 | |
|   });
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context, WidgetRef ref) {
 | |
|     final hasError = useState(false);
 | |
|     final isVerified = useState(false);
 | |
| 
 | |
|     verifyPin(String pinCode) async {
 | |
|       final isUnlocked =
 | |
|           await ref.read(authProvider.notifier).unlockPinCode(pinCode);
 | |
| 
 | |
|       if (isUnlocked) {
 | |
|         isVerified.value = true;
 | |
| 
 | |
|         await Future.delayed(const Duration(seconds: 1));
 | |
|         onSuccess(pinCode);
 | |
|       } else {
 | |
|         hasError.value = true;
 | |
|         onError?.call();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return Form(
 | |
|       child: Column(
 | |
|         children: [
 | |
|           AnimatedSwitcher(
 | |
|             duration: const Duration(milliseconds: 200),
 | |
|             child: isVerified.value
 | |
|                 ? Icon(
 | |
|                     successIcon ?? Icons.lock_open_rounded,
 | |
|                     size: 64,
 | |
|                     color: Colors.green[300],
 | |
|                   )
 | |
|                 : Icon(
 | |
|                     icon ?? Icons.lock_outline_rounded,
 | |
|                     size: 64,
 | |
|                     color: hasError.value
 | |
|                         ? context.colorScheme.error
 | |
|                         : context.primaryColor,
 | |
|                   ),
 | |
|           ),
 | |
|           const SizedBox(height: 36),
 | |
|           SizedBox(
 | |
|             width: context.width * 0.7,
 | |
|             child: Text(
 | |
|               description ?? 'enter_your_pin_code_subtitle'.tr(),
 | |
|               style: context.textTheme.labelLarge!.copyWith(
 | |
|                 fontSize: 18,
 | |
|               ),
 | |
|               textAlign: TextAlign.center,
 | |
|             ),
 | |
|           ),
 | |
|           const SizedBox(height: 18),
 | |
|           PinInput(
 | |
|             obscureText: true,
 | |
|             autoFocus: autoFocus,
 | |
|             hasError: hasError.value,
 | |
|             length: 6,
 | |
|             onChanged: (pinCode) {
 | |
|               if (pinCode.length < 6) {
 | |
|                 hasError.value = false;
 | |
|               }
 | |
|             },
 | |
|             onCompleted: verifyPin,
 | |
|           ),
 | |
|         ],
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 |