mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:37:11 -04:00 
			
		
		
		
	Implemented remembering login data with radio button (#126)
This commit is contained in:
		
							parent
							
								
									c1ccf026f0
								
							
						
					
					
						commit
						da9eb61532
					
				| @ -3,9 +3,9 @@ const String userInfoBox = "immichBoxUserInfo"; // Box | |||||||
| const String accessTokenKey = "immichBoxAccessTokenKey"; // Key 1 | const String accessTokenKey = "immichBoxAccessTokenKey"; // Key 1 | ||||||
| const String deviceIdKey = 'immichBoxDeviceIdKey'; // Key 2 | const String deviceIdKey = 'immichBoxDeviceIdKey'; // Key 2 | ||||||
| 
 | 
 | ||||||
| // SERVER ENDPOINT | // Server endpoint | ||||||
| const String serverEndpointKey = 'immichBoxServerEndpoint'; | const String serverEndpointKey = 'immichBoxServerEndpoint'; | ||||||
| 
 | 
 | ||||||
| // KEY | // Login Info | ||||||
| const String hiveAllAsssetKey = "allAssets"; | const String hiveLoginInfoBox = "immichLoginInfoBox"; | ||||||
| const String hiveBackupProgressKey = "backupProgressAssets"; | const String savedLoginInfoKey = "immichSavedLoginInfoKey"; | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import 'package:flutter/services.dart'; | |||||||
| import 'package:hive_flutter/hive_flutter.dart'; | import 'package:hive_flutter/hive_flutter.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:immich_mobile/constants/immich_colors.dart'; | import 'package:immich_mobile/constants/immich_colors.dart'; | ||||||
|  | import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart'; | ||||||
| import 'package:immich_mobile/shared/providers/asset.provider.dart'; | import 'package:immich_mobile/shared/providers/asset.provider.dart'; | ||||||
| import 'package:immich_mobile/routing/router.dart'; | import 'package:immich_mobile/routing/router.dart'; | ||||||
| import 'package:immich_mobile/routing/tab_navigation_observer.dart'; | import 'package:immich_mobile/routing/tab_navigation_observer.dart'; | ||||||
| @ -15,7 +16,9 @@ import 'constants/hive_box.dart'; | |||||||
| 
 | 
 | ||||||
| void main() async { | void main() async { | ||||||
|   await Hive.initFlutter(); |   await Hive.initFlutter(); | ||||||
|  |   Hive.registerAdapter(HiveSavedLoginInfoAdapter()); | ||||||
|   await Hive.openBox(userInfoBox); |   await Hive.openBox(userInfoBox); | ||||||
|  |   await Hive.openBox<HiveSavedLoginInfo>(hiveLoginInfoBox); | ||||||
| 
 | 
 | ||||||
|   SystemChrome.setSystemUIOverlayStyle( |   SystemChrome.setSystemUIOverlayStyle( | ||||||
|     const SystemUiOverlayStyle( |     const SystemUiOverlayStyle( | ||||||
|  | |||||||
| @ -0,0 +1,20 @@ | |||||||
|  | import 'package:hive/hive.dart'; | ||||||
|  | 
 | ||||||
|  | part 'hive_saved_login_info.model.g.dart'; | ||||||
|  | 
 | ||||||
|  | @HiveType(typeId: 0) | ||||||
|  | class HiveSavedLoginInfo { | ||||||
|  |   @HiveField(0) | ||||||
|  |   String email; | ||||||
|  | 
 | ||||||
|  |   @HiveField(1) | ||||||
|  |   String password; | ||||||
|  | 
 | ||||||
|  |   @HiveField(2) | ||||||
|  |   String serverUrl; | ||||||
|  | 
 | ||||||
|  |   @HiveField(3) | ||||||
|  |   bool isSaveLogin; | ||||||
|  | 
 | ||||||
|  |   HiveSavedLoginInfo({required this.email, required this.password, required this.serverUrl, required this.isSaveLogin}); | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  | 
 | ||||||
|  | part of 'hive_saved_login_info.model.dart'; | ||||||
|  | 
 | ||||||
|  | // ************************************************************************** | ||||||
|  | // TypeAdapterGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  | 
 | ||||||
|  | class HiveSavedLoginInfoAdapter extends TypeAdapter<HiveSavedLoginInfo> { | ||||||
|  |   @override | ||||||
|  |   final int typeId = 0; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   HiveSavedLoginInfo read(BinaryReader reader) { | ||||||
|  |     final numOfFields = reader.readByte(); | ||||||
|  |     final fields = <int, dynamic>{ | ||||||
|  |       for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), | ||||||
|  |     }; | ||||||
|  |     return HiveSavedLoginInfo( | ||||||
|  |       email: fields[0] as String, | ||||||
|  |       password: fields[1] as String, | ||||||
|  |       serverUrl: fields[2] as String, | ||||||
|  |       isSaveLogin: fields[3] as bool, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void write(BinaryWriter writer, HiveSavedLoginInfo obj) { | ||||||
|  |     writer | ||||||
|  |       ..writeByte(4) | ||||||
|  |       ..writeByte(0) | ||||||
|  |       ..write(obj.email) | ||||||
|  |       ..writeByte(1) | ||||||
|  |       ..write(obj.password) | ||||||
|  |       ..writeByte(2) | ||||||
|  |       ..write(obj.serverUrl) | ||||||
|  |       ..writeByte(3) | ||||||
|  |       ..write(obj.isSaveLogin); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   int get hashCode => typeId.hashCode; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) => | ||||||
|  |       identical(this, other) || | ||||||
|  |       other is HiveSavedLoginInfoAdapter && | ||||||
|  |           runtimeType == other.runtimeType && | ||||||
|  |           typeId == other.typeId; | ||||||
|  | } | ||||||
| @ -4,6 +4,7 @@ import 'package:hive/hive.dart'; | |||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:immich_mobile/constants/hive_box.dart'; | import 'package:immich_mobile/constants/hive_box.dart'; | ||||||
| import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; | import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; | ||||||
|  | import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart'; | ||||||
| import 'package:immich_mobile/modules/login/models/login_response.model.dart'; | import 'package:immich_mobile/modules/login/models/login_response.model.dart'; | ||||||
| import 'package:immich_mobile/shared/services/backup.service.dart'; | import 'package:immich_mobile/shared/services/backup.service.dart'; | ||||||
| import 'package:immich_mobile/shared/services/device_info.service.dart'; | import 'package:immich_mobile/shared/services/device_info.service.dart'; | ||||||
| @ -36,7 +37,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { | |||||||
|   final BackupService _backupService = BackupService(); |   final BackupService _backupService = BackupService(); | ||||||
|   final NetworkService _networkService = NetworkService(); |   final NetworkService _networkService = NetworkService(); | ||||||
| 
 | 
 | ||||||
|   Future<bool> login(String email, String password, String serverEndpoint) async { |   Future<bool> login(String email, String password, String serverEndpoint, bool isSavedLoginInfo) async { | ||||||
|     // Store server endpoint to Hive and test endpoint |     // Store server endpoint to Hive and test endpoint | ||||||
|     if (serverEndpoint[serverEndpoint.length - 1] == "/") { |     if (serverEndpoint[serverEndpoint.length - 1] == "/") { | ||||||
|       var validUrl = serverEndpoint.substring(0, serverEndpoint.length - 1); |       var validUrl = serverEndpoint.substring(0, serverEndpoint.length - 1); | ||||||
| @ -76,6 +77,20 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { | |||||||
|         userId: payload.userId, |         userId: payload.userId, | ||||||
|         userEmail: payload.userEmail, |         userEmail: payload.userEmail, | ||||||
|       ); |       ); | ||||||
|  | 
 | ||||||
|  |       if (isSavedLoginInfo) { | ||||||
|  |         // Save login info to local storage | ||||||
|  |         Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).put( | ||||||
|  |           savedLoginInfoKey, | ||||||
|  |           HiveSavedLoginInfo( | ||||||
|  |               email: email, | ||||||
|  |               password: password, | ||||||
|  |               isSaveLogin: true, | ||||||
|  |               serverUrl: Hive.box(userInfoBox).get(serverEndpointKey)), | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).delete(savedLoginInfoKey); | ||||||
|  |       } | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
| import 'package:auto_route/auto_route.dart'; | import 'package:auto_route/auto_route.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:hive/hive.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:immich_mobile/constants/hive_box.dart'; | ||||||
|  | import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart'; | ||||||
| import 'package:immich_mobile/shared/providers/asset.provider.dart'; | import 'package:immich_mobile/shared/providers/asset.provider.dart'; | ||||||
| import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; | import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; | ||||||
| import 'package:immich_mobile/shared/providers/backup.provider.dart'; | import 'package:immich_mobile/shared/providers/backup.provider.dart'; | ||||||
| @ -12,22 +15,36 @@ class LoginForm extends HookConsumerWidget { | |||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final usernameController = useTextEditingController(text: 'testuser@email.com'); |     final usernameController = useTextEditingController.fromValue(TextEditingValue.empty); | ||||||
|     final passwordController = useTextEditingController(text: 'password'); |     final passwordController = useTextEditingController.fromValue(TextEditingValue.empty); | ||||||
|     final serverEndpointController = useTextEditingController(text: 'http://192.168.1.216:2283'); |     final serverEndpointController = useTextEditingController(text: 'http://your-server-ip:2283'); | ||||||
|  |     final isSaveLoginInfo = useState<bool>(false); | ||||||
|  | 
 | ||||||
|  |     useEffect(() { | ||||||
|  |       var loginInfo = Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).get(savedLoginInfoKey); | ||||||
|  | 
 | ||||||
|  |       if (loginInfo != null) { | ||||||
|  |         usernameController.text = loginInfo.email; | ||||||
|  |         passwordController.text = loginInfo.password; | ||||||
|  |         serverEndpointController.text = loginInfo.serverUrl; | ||||||
|  |         isSaveLoginInfo.value = loginInfo.isSaveLogin; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return null; | ||||||
|  |     }, []); | ||||||
| 
 | 
 | ||||||
|     return Center( |     return Center( | ||||||
|       child: ConstrainedBox( |       child: ConstrainedBox( | ||||||
|         constraints: const BoxConstraints(maxWidth: 300), |         constraints: const BoxConstraints(maxWidth: 300), | ||||||
|         child: SingleChildScrollView( |         child: SingleChildScrollView( | ||||||
|           child: Wrap( |           child: Wrap( | ||||||
|             spacing: 32, |             spacing: 16, | ||||||
|             runSpacing: 32, |             runSpacing: 16, | ||||||
|             alignment: WrapAlignment.center, |             alignment: WrapAlignment.center, | ||||||
|             children: [ |             children: [ | ||||||
|               const Image( |               const Image( | ||||||
|                 image: AssetImage('assets/immich-logo-no-outline.png'), |                 image: AssetImage('assets/immich-logo-no-outline.png'), | ||||||
|                 width: 128, |                 width: 100, | ||||||
|                 filterQuality: FilterQuality.high, |                 filterQuality: FilterQuality.high, | ||||||
|               ), |               ), | ||||||
|               Text( |               Text( | ||||||
| @ -42,10 +59,29 @@ class LoginForm extends HookConsumerWidget { | |||||||
|               EmailInput(controller: usernameController), |               EmailInput(controller: usernameController), | ||||||
|               PasswordInput(controller: passwordController), |               PasswordInput(controller: passwordController), | ||||||
|               ServerEndpointInput(controller: serverEndpointController), |               ServerEndpointInput(controller: serverEndpointController), | ||||||
|  |               CheckboxListTile( | ||||||
|  |                 activeColor: Theme.of(context).primaryColor, | ||||||
|  |                 contentPadding: const EdgeInsets.symmetric(horizontal: 8), | ||||||
|  |                 dense: true, | ||||||
|  |                 side: const BorderSide(color: Colors.grey, width: 1.5), | ||||||
|  |                 shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), | ||||||
|  |                 enableFeedback: true, | ||||||
|  |                 title: const Text( | ||||||
|  |                   "Save login", | ||||||
|  |                   style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.grey), | ||||||
|  |                 ), | ||||||
|  |                 value: isSaveLoginInfo.value, | ||||||
|  |                 onChanged: (switchValue) { | ||||||
|  |                   if (switchValue != null) { | ||||||
|  |                     isSaveLoginInfo.value = switchValue; | ||||||
|  |                   } | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|               LoginButton( |               LoginButton( | ||||||
|                 emailController: usernameController, |                 emailController: usernameController, | ||||||
|                 passwordController: passwordController, |                 passwordController: passwordController, | ||||||
|                 serverEndpointController: serverEndpointController, |                 serverEndpointController: serverEndpointController, | ||||||
|  |                 isSavedLoginInfo: isSaveLoginInfo.value, | ||||||
|               ), |               ), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
| @ -104,29 +140,34 @@ class LoginButton extends ConsumerWidget { | |||||||
|   final TextEditingController emailController; |   final TextEditingController emailController; | ||||||
|   final TextEditingController passwordController; |   final TextEditingController passwordController; | ||||||
|   final TextEditingController serverEndpointController; |   final TextEditingController serverEndpointController; | ||||||
|  |   final bool isSavedLoginInfo; | ||||||
| 
 | 
 | ||||||
|   const LoginButton( |   const LoginButton({ | ||||||
|       {Key? key, |     Key? key, | ||||||
|       required this.emailController, |     required this.emailController, | ||||||
|       required this.passwordController, |     required this.passwordController, | ||||||
|       required this.serverEndpointController}) |     required this.serverEndpointController, | ||||||
|       : super(key: key); |     required this.isSavedLoginInfo, | ||||||
|  |   }) : super(key: key); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     return ElevatedButton( |     return ElevatedButton( | ||||||
|  |         style: ButtonStyle( | ||||||
|  |           visualDensity: VisualDensity.standard, | ||||||
|  |           padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.symmetric(vertical: 10, horizontal: 25)), | ||||||
|  |         ), | ||||||
|         onPressed: () async { |         onPressed: () async { | ||||||
|           // This will remove current cache asset state of previous user login. |           // This will remove current cache asset state of previous user login. | ||||||
|           ref.watch(assetProvider.notifier).clearAllAsset(); |           ref.watch(assetProvider.notifier).clearAllAsset(); | ||||||
| 
 | 
 | ||||||
|           var isAuthenticated = await ref |           var isAuthenticated = await ref | ||||||
|               .read(authenticationProvider.notifier) |               .read(authenticationProvider.notifier) | ||||||
|               .login(emailController.text, passwordController.text, serverEndpointController.text); |               .login(emailController.text, passwordController.text, serverEndpointController.text, isSavedLoginInfo); | ||||||
| 
 | 
 | ||||||
|           if (isAuthenticated) { |           if (isAuthenticated) { | ||||||
|             // Resume backup (if enable) then navigate |             // Resume backup (if enable) then navigate | ||||||
|             ref.watch(backupProvider.notifier).resumeBackup(); |             ref.watch(backupProvider.notifier).resumeBackup(); | ||||||
|             // AutoRouter.of(context).pushNamed("/home-page"); |  | ||||||
|             AutoRouter.of(context).pushNamed("/tab-controller-page"); |             AutoRouter.of(context).pushNamed("/tab-controller-page"); | ||||||
|           } else { |           } else { | ||||||
|             ImmichToast.show( |             ImmichToast.show( | ||||||
| @ -136,6 +177,9 @@ class LoginButton extends ConsumerWidget { | |||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         child: const Text("Login")); |         child: const Text( | ||||||
|  |           "Login", | ||||||
|  |           style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), | ||||||
|  |         )); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user