mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-30 21:05:42 +00:00 
			
		
		
		
	UserProfile
This commit is contained in:
		| @@ -227,10 +227,8 @@ class InvenTreeAPI { | |||||||
|         errorMessage = "Server timeout"; |         errorMessage = "Server timeout"; | ||||||
|         return null; |         return null; | ||||||
|       } else { |       } else { | ||||||
|         // Unknown error type |         // Unknown error type - re-throw the error and Sentry will catch it | ||||||
|         errorMessage = error.toString(); |         throw error; | ||||||
|         // Unknown error type, re-throw error |  | ||||||
|         return null; |  | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,9 @@ import 'package:InvenTree/widget/dialogs.dart'; | |||||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||||
| import 'package:url_launcher/url_launcher.dart'; | import 'package:url_launcher/url_launcher.dart'; | ||||||
|  |  | ||||||
|  | import 'package:flutter_localizations/flutter_localizations.dart'; | ||||||
|  | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  |  | ||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:path/path.dart' as path; | import 'package:path/path.dart' as path; | ||||||
| @@ -108,7 +111,7 @@ class InvenTreeModel { | |||||||
|   Future<bool> reload(BuildContext context, {bool dialog = false}) async { |   Future<bool> reload(BuildContext context, {bool dialog = false}) async { | ||||||
|  |  | ||||||
|     if (dialog) { |     if (dialog) { | ||||||
|       showProgressDialog(context, "Refreshing data", "Refreshing data for ${NAME}"); |       showProgressDialog(context, I18N.of(context).refreshing, "Refreshing data for ${NAME}"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var response = await api.get(url, params: defaultGetFilters()) |     var response = await api.get(url, params: defaultGetFilters()) | ||||||
| @@ -120,9 +123,10 @@ class InvenTreeModel { | |||||||
|           } |           } | ||||||
|  |  | ||||||
|           if (e is TimeoutException) { |           if (e is TimeoutException) { | ||||||
|             showErrorDialog(context, "Timeout", "No response from server"); |             showTimeoutDialog(context); | ||||||
|           } else { |           } else { | ||||||
|             showErrorDialog(context, "Error", e.toString()); |             // Re-throw the error (Sentry will catch) | ||||||
|  |             throw e; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           return null; |           return null; | ||||||
| @@ -137,6 +141,12 @@ class InvenTreeModel { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (response.statusCode != 200) { |     if (response.statusCode != 200) { | ||||||
|  |       showErrorDialog( | ||||||
|  |         context, | ||||||
|  |         I18N.of(context).serverError, | ||||||
|  |         "${I18N.of(context).statusCode}: ${response.statusCode}" | ||||||
|  |       ); | ||||||
|  |  | ||||||
|       print("Error retrieving data"); |       print("Error retrieving data"); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| @@ -170,9 +180,10 @@ class InvenTreeModel { | |||||||
|           } |           } | ||||||
|  |  | ||||||
|           if (e is TimeoutException) { |           if (e is TimeoutException) { | ||||||
|             showErrorDialog(context, "Timeout", "No response from server"); |             showTimeoutDialog(context); | ||||||
|           } else { |           } else { | ||||||
|             showErrorDialog(context, "Error", e.toString()); |             // Re-throw the error, let Sentry report it | ||||||
|  |             throw e; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           return null; |           return null; | ||||||
| @@ -185,7 +196,7 @@ class InvenTreeModel { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (response.statusCode != 200) { |     if (response.statusCode != 200) { | ||||||
|       print("Error updating ${NAME}: Status code ${response.statusCode}"); |       showErrorDialog(context, I18N.of(context).serverError, "${I18N.of(context).statusCode}: ${response.statusCode}"); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -217,7 +228,7 @@ class InvenTreeModel { | |||||||
|     print("GET: $addr ${params.toString()}"); |     print("GET: $addr ${params.toString()}"); | ||||||
|  |  | ||||||
|     if (dialog) { |     if (dialog) { | ||||||
|       showProgressDialog(context, "Requesting Data", "Requesting ${NAME} data from server"); |       showProgressDialog(context, I18N.of(context).requestingData, "Requesting ${NAME} data from server"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var response = await api.get(addr, params: params) |     var response = await api.get(addr, params: params) | ||||||
| @@ -229,9 +240,10 @@ class InvenTreeModel { | |||||||
|           } |           } | ||||||
|  |  | ||||||
|           if (e is TimeoutException) { |           if (e is TimeoutException) { | ||||||
|             showErrorDialog(context, "Timeout", "No response from server"); |             showTimeoutDialog(context); | ||||||
|           } else { |           } else { | ||||||
|             showErrorDialog(context, "Error", e.toString()); |             // Re-throw the error (handled by Sentry) | ||||||
|  |             throw e; | ||||||
|           } |           } | ||||||
|           return null; |           return null; | ||||||
|       }); |       }); | ||||||
| @@ -243,7 +255,7 @@ class InvenTreeModel { | |||||||
|     hideProgressDialog(context); |     hideProgressDialog(context); | ||||||
|  |  | ||||||
|     if (response.statusCode != 200) { |     if (response.statusCode != 200) { | ||||||
|       print("Error retrieving data"); |       showErrorDialog(context, I18N.of(context).serverError, "${I18N.of(context).statusCode}: ${response.statusCode}"); | ||||||
|       return null; |       return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -269,8 +281,12 @@ class InvenTreeModel { | |||||||
|     await api.post(URL, body: data) |     await api.post(URL, body: data) | ||||||
|     .timeout(Duration(seconds: 5)) |     .timeout(Duration(seconds: 5)) | ||||||
|     .catchError((e) { |     .catchError((e) { | ||||||
|       print("Error creating new ${NAME}:"); |  | ||||||
|       print(e.toString()); |       print(e.toString()); | ||||||
|  |       showErrorDialog( | ||||||
|  |         context, | ||||||
|  |         I18N.of(context).serverError, | ||||||
|  |         e.toString() | ||||||
|  |       ); | ||||||
|       return null; |       return null; | ||||||
|     }) |     }) | ||||||
|     .then((http.Response response) { |     .then((http.Response response) { | ||||||
| @@ -279,8 +295,11 @@ class InvenTreeModel { | |||||||
|         var decoded = json.decode(response.body); |         var decoded = json.decode(response.body); | ||||||
|         _model = createFromJson(decoded); |         _model = createFromJson(decoded); | ||||||
|       } else { |       } else { | ||||||
|         print("Error creating object: Status Code ${response.statusCode}"); |         showErrorDialog( | ||||||
|         print(response.body); |           context, | ||||||
|  |           I18N.of(context).serverError, | ||||||
|  |           "${I18N.of(context).statusCode}: ${response.statusCode}" | ||||||
|  |         ); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -308,7 +327,7 @@ class InvenTreeModel { | |||||||
|     // TODO - Add error catching |     // TODO - Add error catching | ||||||
|  |  | ||||||
|     if (dialog) { |     if (dialog) { | ||||||
|       showProgressDialog(context, "Requesting Data", "Requesting ${NAME} data from server"); |       showProgressDialog(context, I18N.of(context).requestingData, "Requesting ${NAME} data from server"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var response = await api.get(URL, params:params) |     var response = await api.get(URL, params:params) | ||||||
| @@ -320,7 +339,7 @@ class InvenTreeModel { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (e is TimeoutException) { |         if (e is TimeoutException) { | ||||||
|           showErrorDialog(context, "Timeout", "No response from server"); |           showTimeoutDialog(context); | ||||||
|         } else { |         } else { | ||||||
|           // Re-throw the error |           // Re-throw the error | ||||||
|           throw e; |           throw e; | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								lib/l10n
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								lib/l10n
									
									
									
									
									
								
							 Submodule lib/l10n updated: 58e2c5027b...86fbf66aea
									
								
							| @@ -1,8 +1,57 @@ | |||||||
| import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
| import 'api.dart'; | import 'api.dart'; | ||||||
|  | import 'package:path_provider/path_provider.dart'; | ||||||
|  | import 'package:sembast/sembast.dart'; | ||||||
|  | import 'package:sembast/sembast_io.dart'; | ||||||
|  | import 'package:path/path.dart'; | ||||||
|  | import 'dart:async'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Class for storing InvenTree preferences in a NoSql DB | ||||||
|  |  */ | ||||||
|  | class InvenTreePreferencesDB { | ||||||
|  |  | ||||||
|  |   static final InvenTreePreferencesDB _singleton = InvenTreePreferencesDB._(); | ||||||
|  |  | ||||||
|  |   static InvenTreePreferencesDB get instance => _singleton; | ||||||
|  |  | ||||||
|  |   InvenTreePreferencesDB._(); | ||||||
|  |  | ||||||
|  |   Completer<Database> _dbOpenCompleter; | ||||||
|  |  | ||||||
|  |   Future<Database> get database async { | ||||||
|  |     // If completer is null, AppDatabaseClass is newly instantiated, so database is not yet opened | ||||||
|  |     if (_dbOpenCompleter == null) { | ||||||
|  |       _dbOpenCompleter = Completer(); | ||||||
|  |       // Calling _openDatabase will also complete the completer with database instance | ||||||
|  |       _openDatabase(); | ||||||
|  |     } | ||||||
|  |     // If the database is already opened, awaiting the future will happen instantly. | ||||||
|  |     // Otherwise, awaiting the returned future will take some time - until complete() is called | ||||||
|  |     // on the Completer in _openDatabase() below. | ||||||
|  |     return _dbOpenCompleter.future; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future _openDatabase() async { | ||||||
|  |     // Get a platform-specific directory where persistent app data can be stored | ||||||
|  |     final appDocumentDir = await getApplicationDocumentsDirectory(); | ||||||
|  |  | ||||||
|  |     print("Documents Dir: ${appDocumentDir.toString()}"); | ||||||
|  |  | ||||||
|  |     print("Path: ${appDocumentDir.path}"); | ||||||
|  |  | ||||||
|  |     // Path with the form: /platform-specific-directory/demo.db | ||||||
|  |     final dbPath = join(appDocumentDir.path, 'InvenTreeSettings.db'); | ||||||
|  |  | ||||||
|  |     final database = await databaseFactoryIo.openDatabase(dbPath); | ||||||
|  |  | ||||||
|  |     // Any code awaiting the Completer's future will now start executing | ||||||
|  |     _dbOpenCompleter.complete(database); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| class InvenTreePreferences { | class InvenTreePreferences { | ||||||
|  |  | ||||||
|   static const String _SERVER = 'server'; |   static const String _SERVER = 'server'; | ||||||
|   | |||||||
| @@ -1,18 +1,27 @@ | |||||||
|  | import 'dart:ffi'; | ||||||
|  |  | ||||||
|  | import 'package:InvenTree/widget/dialogs.dart'; | ||||||
|  | import 'package:InvenTree/widget/fields.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_speed_dial/flutter_speed_dial.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | ||||||
|  |  | ||||||
| import '../api.dart'; | import '../api.dart'; | ||||||
| import '../preferences.dart'; | import '../preferences.dart'; | ||||||
|  | import '../user_profile.dart'; | ||||||
|  |  | ||||||
| class InvenTreeLoginSettingsWidget extends StatefulWidget { | class InvenTreeLoginSettingsWidget extends StatefulWidget { | ||||||
|  |  | ||||||
|   final SharedPreferences _preferences; |   final SharedPreferences _preferences; | ||||||
|  |  | ||||||
|   InvenTreeLoginSettingsWidget(this._preferences) : super(); |   final List<UserProfile> _profiles; | ||||||
|  |  | ||||||
|  |   InvenTreeLoginSettingsWidget(this._profiles, this._preferences) : super(); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   _InvenTreeLoginSettingsState createState() => _InvenTreeLoginSettingsState(_preferences); |   _InvenTreeLoginSettingsState createState() => _InvenTreeLoginSettingsState(_profiles, _preferences); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -20,18 +29,61 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> { | |||||||
|  |  | ||||||
|   final GlobalKey<FormState> _formKey = new GlobalKey<FormState>(); |   final GlobalKey<FormState> _formKey = new GlobalKey<FormState>(); | ||||||
|  |  | ||||||
|  |   final _addProfileKey = new GlobalKey<FormState>(); | ||||||
|  |  | ||||||
|   final SharedPreferences _preferences; |   final SharedPreferences _preferences; | ||||||
|  |  | ||||||
|  |   List<UserProfile> profiles; | ||||||
|  |  | ||||||
|   String _server = ''; |   String _server = ''; | ||||||
|   String _username = ''; |   String _username = ''; | ||||||
|   String _password = ''; |   String _password = ''; | ||||||
|  |  | ||||||
|   _InvenTreeLoginSettingsState(this._preferences) : super() { |   _InvenTreeLoginSettingsState(this.profiles, this._preferences) : super() { | ||||||
|     _server = _preferences.getString('server') ?? ''; |     _server = _preferences.getString('server') ?? ''; | ||||||
|     _username = _preferences.getString('username') ?? ''; |     _username = _preferences.getString('username') ?? ''; | ||||||
|     _password = _preferences.getString('password') ?? ''; |     _password = _preferences.getString('password') ?? ''; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void _createProfile(BuildContext context) { | ||||||
|  |  | ||||||
|  |     showFormDialog( | ||||||
|  |       context, | ||||||
|  |       I18N.of(context).profileAdd, | ||||||
|  |       key: _addProfileKey, | ||||||
|  |       actions: <Widget> [ | ||||||
|  |         FlatButton( | ||||||
|  |           child: Text(I18N.of(context).cancel), | ||||||
|  |           onPressed: () { | ||||||
|  |             Navigator.of(context).pop(); | ||||||
|  |           } | ||||||
|  |         ), | ||||||
|  |         FlatButton( | ||||||
|  |           child: Text(I18N.of(context).save), | ||||||
|  |           onPressed: () { | ||||||
|  |             // TODO | ||||||
|  |           } | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |       fields: <Widget> [ | ||||||
|  |         StringField( | ||||||
|  |           label: I18N.of(context).name, | ||||||
|  |           initial: "profile", | ||||||
|  |         ), | ||||||
|  |         StringField( | ||||||
|  |           label: "Server", | ||||||
|  |           initial: "http://127.0.0.1:8000", | ||||||
|  |         ), | ||||||
|  |         StringField( | ||||||
|  |           label: "Username", | ||||||
|  |         ), | ||||||
|  |         StringField( | ||||||
|  |           label: "Password" | ||||||
|  |         ) | ||||||
|  |       ] | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   String _validateServer(String value) { |   String _validateServer(String value) { | ||||||
|  |  | ||||||
| @@ -71,11 +123,95 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void _deleteProfile(UserProfile profile) async { | ||||||
|  |  | ||||||
|  |     await UserProfileDBManager().deleteProfile(profile); | ||||||
|  |  | ||||||
|  |     // Reload profiles | ||||||
|  |     profiles = await UserProfileDBManager().getAllProfiles(); | ||||||
|  |  | ||||||
|  |     setState(() { | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |  | ||||||
|     final Size screenSize = MediaQuery.of(context).size; |     final Size screenSize = MediaQuery.of(context).size; | ||||||
|  |  | ||||||
|  |     List<Widget> children = []; | ||||||
|  |  | ||||||
|  |     for (int idx = 0; idx < profiles.length; idx++) { | ||||||
|  |  | ||||||
|  |       UserProfile profile = profiles[idx]; | ||||||
|  |  | ||||||
|  |       children.add(ListTile( | ||||||
|  |         title: Text(profile.name), | ||||||
|  |         subtitle: Text(profile.server), | ||||||
|  |         trailing: FaIcon(FontAwesomeIcons.checkCircle), | ||||||
|  |         onLongPress: () { | ||||||
|  |           showDialog( | ||||||
|  |             context: context, | ||||||
|  |             builder: (BuildContext context) { | ||||||
|  |               return SimpleDialog( | ||||||
|  |                 title: Text(profile.name), | ||||||
|  |                 children: <Widget> [ | ||||||
|  |                   SimpleDialogOption( | ||||||
|  |                     onPressed: () { | ||||||
|  |                       Navigator.of(context).pop(); | ||||||
|  |                       // TODO - Mark profile as selected | ||||||
|  |                     }, | ||||||
|  |                     child: Text(I18N.of(context).profileSelect), | ||||||
|  |                   ), | ||||||
|  |                   SimpleDialogOption( | ||||||
|  |                     onPressed: () { | ||||||
|  |                       //Navigator.of(context).pop(); | ||||||
|  |                       // TODO - Edit profile! | ||||||
|  |                     }, | ||||||
|  |                     child: Text(I18N.of(context).profileEdit), | ||||||
|  |                   ), | ||||||
|  |                   SimpleDialogOption( | ||||||
|  |                     onPressed: () { | ||||||
|  |                       // Navigator.of(context, rootNavigator: true).pop(); | ||||||
|  |                       confirmationDialog( | ||||||
|  |                           context, | ||||||
|  |                           "Delete", | ||||||
|  |                           "Delete this profile?", | ||||||
|  |                           onAccept: () { | ||||||
|  |                             _deleteProfile(profile); | ||||||
|  |                           } | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                     child: Text(I18N.of(context).profileDelete), | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ); | ||||||
|  |             } | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |         onTap: () { | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return Scaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text(I18N.of(context).profile), | ||||||
|  |       ), | ||||||
|  |       body: Container( | ||||||
|  |         child: ListView( | ||||||
|  |           children: children, | ||||||
|  |         ) | ||||||
|  |       ), | ||||||
|  |       floatingActionButton: FloatingActionButton( | ||||||
|  |         child: Icon(FontAwesomeIcons.plus), | ||||||
|  |         onPressed: () { | ||||||
|  |           _createProfile(context); | ||||||
|  |         }, | ||||||
|  |       ) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
|         title: Text("Login Settings"), |         title: Text("Login Settings"), | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| import 'package:InvenTree/settings/about.dart'; | import 'package:InvenTree/settings/about.dart'; | ||||||
| import 'package:InvenTree/settings/login.dart'; | import 'package:InvenTree/settings/login.dart'; | ||||||
| import 'package:InvenTree/settings/release.dart'; | import 'package:InvenTree/settings/release.dart'; | ||||||
|  | import 'package:InvenTree/user_profile.dart'; | ||||||
|  | import 'package:InvenTree/preferences.dart'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
| @@ -58,6 +60,25 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> { | |||||||
|               leading: FaIcon(FontAwesomeIcons.bug), |               leading: FaIcon(FontAwesomeIcons.bug), | ||||||
|               onTap: null, |               onTap: null, | ||||||
|             ), |             ), | ||||||
|  |             ListTile( | ||||||
|  |               title: Text("Throw Error"), | ||||||
|  |               onTap: () { | ||||||
|  |                 throw("My custom error"); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |             ListTile( | ||||||
|  |               title: Text("add profile"), | ||||||
|  |               onTap: () { | ||||||
|  |                 UserProfileDBManager().addProfile( | ||||||
|  |                   UserProfile( | ||||||
|  |                     name: "My Profile", | ||||||
|  |                     server: "https://127.0.0.1:8000", | ||||||
|  |                     username: "Oliver", | ||||||
|  |                     password: "hunter2", | ||||||
|  |                   ) | ||||||
|  |                 ); | ||||||
|  |               }, | ||||||
|  |             ) | ||||||
|           ], |           ], | ||||||
|         ) |         ) | ||||||
|       ) |       ) | ||||||
| @@ -68,7 +89,9 @@ class _InvenTreeSettingsState extends State<InvenTreeSettingsWidget> { | |||||||
|  |  | ||||||
|     var prefs = await SharedPreferences.getInstance(); |     var prefs = await SharedPreferences.getInstance(); | ||||||
|  |  | ||||||
|     Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget(prefs))); |     List<UserProfile> profiles = await UserProfileDBManager().getAllProfiles(); | ||||||
|  |  | ||||||
|  |     Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeLoginSettingsWidget(profiles, prefs))); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void _about() async { |   void _about() async { | ||||||
|   | |||||||
							
								
								
									
										109
									
								
								lib/user_profile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								lib/user_profile.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Class for InvenTree user / login details | ||||||
|  |  */ | ||||||
|  | import 'package:sembast/sembast.dart'; | ||||||
|  | import 'preferences.dart'; | ||||||
|  |  | ||||||
|  | class UserProfile { | ||||||
|  |  | ||||||
|  |   UserProfile({ | ||||||
|  |     this.name, | ||||||
|  |     this.server, | ||||||
|  |     this.username, | ||||||
|  |     this.password | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   // Name of the user profile | ||||||
|  |   String name; | ||||||
|  |  | ||||||
|  |   // Base address of the InvenTree server | ||||||
|  |   String server; | ||||||
|  |  | ||||||
|  |   // Username | ||||||
|  |   String username; | ||||||
|  |  | ||||||
|  |   // Password | ||||||
|  |   String password; | ||||||
|  |  | ||||||
|  |   // User ID (will be provided by the server on log-in) | ||||||
|  |   int user_id; | ||||||
|  |  | ||||||
|  |   factory UserProfile.fromJson(Map<String, dynamic> json) => UserProfile( | ||||||
|  |     name: json['name'], | ||||||
|  |     server: json['server'], | ||||||
|  |     username: json['username'], | ||||||
|  |     password: json['password'], | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   Map<String, dynamic> toJson() => { | ||||||
|  |     "name": name, | ||||||
|  |     "server": server, | ||||||
|  |     "username": username, | ||||||
|  |     "password": password, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String toString() { | ||||||
|  |     return "${server} - ${username}:${password}"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class UserProfileDBManager { | ||||||
|  |  | ||||||
|  |   static const String folder_name = "profiles"; | ||||||
|  |  | ||||||
|  |   final _folder = intMapStoreFactory.store(folder_name); | ||||||
|  |  | ||||||
|  |   Future<Database> get _db async => await InvenTreePreferencesDB.instance.database; | ||||||
|  |  | ||||||
|  |   Future addProfile(UserProfile profile) async { | ||||||
|  |  | ||||||
|  |     UserProfile existingProfile = await getProfile(profile.name); | ||||||
|  |  | ||||||
|  |     if (existingProfile != null) { | ||||||
|  |       print("UserProfile '${profile.name}' already exists"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     await _folder.add(await _db, profile.toJson()); | ||||||
|  |  | ||||||
|  |     print("Added user profile '${profile.name}'"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future deleteProfile(UserProfile profile) async { | ||||||
|  |     final finder = Finder(filter: Filter.equals("name", profile.name)); | ||||||
|  |     await _folder.delete(await _db, finder: finder); | ||||||
|  |  | ||||||
|  |     print("Deleted user profile ${profile.name}"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<UserProfile> getProfile(String name) async { | ||||||
|  |     // Lookup profile by name (or return null if does not exist) | ||||||
|  |     final finder = Finder(filter: Filter.equals("name", name)); | ||||||
|  |  | ||||||
|  |     final profiles = await _folder.find(await _db, finder: finder); | ||||||
|  |  | ||||||
|  |     if (profiles.length == 0) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Return the first matching profile object | ||||||
|  |     return UserProfile.fromJson(profiles[0].value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Return all user profile objects | ||||||
|  |    */ | ||||||
|  |   Future<List<UserProfile>> getAllProfiles() async { | ||||||
|  |     final profiles = await _folder.find(await _db); | ||||||
|  |  | ||||||
|  |     List<UserProfile> profileList = new List<UserProfile>(); | ||||||
|  |  | ||||||
|  |     for (int idx = 0; idx < profiles.length; idx++) { | ||||||
|  |       profileList.add(UserProfile.fromJson(profiles[idx].value)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return profileList; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -4,6 +4,53 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | ||||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Future<void> confirmationDialog(BuildContext context, String title, String text, {String acceptText, String rejectText, Function onAccept, Function onReject}) async { | ||||||
|  |  | ||||||
|  |   if (acceptText == null || acceptText.isEmpty) { | ||||||
|  |     acceptText = I18N.of(context).ok; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (rejectText == null || rejectText.isEmpty) { | ||||||
|  |     rejectText = I18N.of(context).cancel; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   AlertDialog dialog = AlertDialog( | ||||||
|  |     title: ListTile( | ||||||
|  |       title: Text(title), | ||||||
|  |       leading: FaIcon(FontAwesomeIcons.questionCircle), | ||||||
|  |     ), | ||||||
|  |     content: Text(text), | ||||||
|  |     actions: [ | ||||||
|  |       FlatButton( | ||||||
|  |         child: Text(rejectText), | ||||||
|  |         onPressed: () { | ||||||
|  |           Navigator.of(context, rootNavigator: true).pop(); | ||||||
|  |           if (onReject != null) { | ||||||
|  |             onReject(); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ), | ||||||
|  |       FlatButton( | ||||||
|  |         child: Text(acceptText), | ||||||
|  |         onPressed: () { | ||||||
|  |           Navigator.of(context, rootNavigator: true).pop(); | ||||||
|  |           if (onAccept != null) { | ||||||
|  |             onAccept(); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     ], | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   showDialog( | ||||||
|  |     context: context, | ||||||
|  |     builder: (BuildContext context) { | ||||||
|  |       return dialog; | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
| void showMessage(BuildContext context, String message) { | void showMessage(BuildContext context, String message) { | ||||||
|   Scaffold.of(context).showSnackBar(SnackBar( |   Scaffold.of(context).showSnackBar(SnackBar( | ||||||
|     content: Text(message), |     content: Text(message), | ||||||
| @@ -64,6 +111,18 @@ Future<void> showErrorDialog(BuildContext context, String title, String descript | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void showTimeoutDialog(BuildContext context) { | ||||||
|  |   /* | ||||||
|  |   Show a server timeout dialog | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   showErrorDialog( | ||||||
|  |       context, | ||||||
|  |       I18N.of(context).timeout, | ||||||
|  |       I18N.of(context).noResponse | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
| void showProgressDialog(BuildContext context, String title, String description) { | void showProgressDialog(BuildContext context, String title, String description) { | ||||||
|  |  | ||||||
|   showDialog( |   showDialog( | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -42,7 +42,7 @@ packages: | |||||||
|       name: camera |       name: camera | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.6.4+5" |     version: "0.7.0+2" | ||||||
|   camera_platform_interface: |   camera_platform_interface: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -106,6 +106,20 @@ packages: | |||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.1.3" |     version: "0.1.3" | ||||||
|  |   device_info: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: device_info | ||||||
|  |       url: "https://pub.dartlang.org" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.0.0" | ||||||
|  |   device_info_platform_interface: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: device_info_platform_interface | ||||||
|  |       url: "https://pub.dartlang.org" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.0.1" | ||||||
|   fake_async: |   fake_async: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -152,7 +166,7 @@ packages: | |||||||
|       name: flutter_keyboard_visibility |       name: flutter_keyboard_visibility | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "4.0.2" |     version: "4.0.3" | ||||||
|   flutter_keyboard_visibility_platform_interface: |   flutter_keyboard_visibility_platform_interface: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -251,14 +265,14 @@ packages: | |||||||
|       name: image_picker |       name: image_picker | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.6.7+21" |     version: "0.6.7+22" | ||||||
|   image_picker_platform_interface: |   image_picker_platform_interface: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: image_picker_platform_interface |       name: image_picker_platform_interface | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.1.1" |     version: "1.1.6" | ||||||
|   intl: |   intl: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -300,7 +314,7 @@ packages: | |||||||
|       name: package_info |       name: package_info | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.4.3+2" |     version: "0.4.3+4" | ||||||
|   path: |   path: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -392,6 +406,13 @@ packages: | |||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.0.14" |     version: "0.0.14" | ||||||
|  |   quiver: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: quiver | ||||||
|  |       url: "https://pub.dartlang.org" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.1.5" | ||||||
|   rxdart: |   rxdart: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -399,13 +420,20 @@ packages: | |||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.25.0" |     version: "0.25.0" | ||||||
|  |   sembast: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: sembast | ||||||
|  |       url: "https://pub.dartlang.org" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.4.9" | ||||||
|   sentry: |   sentry: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
|       name: sentry |       name: sentry | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "3.0.1" |     version: "4.0.4" | ||||||
|   shared_preferences: |   shared_preferences: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -447,7 +475,7 @@ packages: | |||||||
|       name: shared_preferences_windows |       name: shared_preferences_windows | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.0.1+3" |     version: "0.0.2+3" | ||||||
|   sky_engine: |   sky_engine: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: flutter |     description: flutter | ||||||
| @@ -466,14 +494,14 @@ packages: | |||||||
|       name: sqflite |       name: sqflite | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.3.2+2" |     version: "1.3.2+3" | ||||||
|   sqflite_common: |   sqflite_common: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: sqflite_common |       name: sqflite_common | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.0.3" |     version: "1.0.3+1" | ||||||
|   stack_trace: |   stack_trace: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -564,7 +592,7 @@ packages: | |||||||
|       name: url_launcher_web |       name: url_launcher_web | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.1.5+1" |     version: "0.1.5+3" | ||||||
|   url_launcher_windows: |   url_launcher_windows: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -572,13 +600,6 @@ packages: | |||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.0.1+3" |     version: "0.0.1+3" | ||||||
|   usage: |  | ||||||
|     dependency: transitive |  | ||||||
|     description: |  | ||||||
|       name: usage |  | ||||||
|       url: "https://pub.dartlang.org" |  | ||||||
|     source: hosted |  | ||||||
|     version: "3.4.2" |  | ||||||
|   uuid: |   uuid: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -599,7 +620,7 @@ packages: | |||||||
|       name: win32 |       name: win32 | ||||||
|       url: "https://pub.dartlang.org" |       url: "https://pub.dartlang.org" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.7.4" |     version: "1.7.4+1" | ||||||
|   xdg_directories: |   xdg_directories: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|   | |||||||
| @@ -33,15 +33,17 @@ dependencies: | |||||||
|   preferences: ^5.2.0                     # Persistent settings storage |   preferences: ^5.2.0                     # Persistent settings storage | ||||||
|   qr_code_scanner: ^0.0.13 |   qr_code_scanner: ^0.0.13 | ||||||
|   package_info: ^0.4.0                    # App information introspection |   package_info: ^0.4.0                    # App information introspection | ||||||
|  |   device_info: ^1.0.0                     # Information about the device | ||||||
|   font_awesome_flutter: ^8.8.1            # FontAwesome icon set |   font_awesome_flutter: ^8.8.1            # FontAwesome icon set | ||||||
|   flutter_speed_dial: ^1.2.5              # FAB menu elements |   flutter_speed_dial: ^1.2.5              # FAB menu elements | ||||||
|   sentry: ^3.0.1                          # Error reporting |   sentry: ^4.0.4                          # Error reporting | ||||||
|   flutter_typeahead: ^1.8.1               # Auto-complete input field |   flutter_typeahead: ^1.8.1               # Auto-complete input field | ||||||
|   image_picker: ^0.6.6                    # Select or take photos |   image_picker: ^0.6.6                    # Select or take photos | ||||||
|   url_launcher: ^5.7.10                   # Open link in system browser |   url_launcher: ^5.7.10                   # Open link in system browser | ||||||
|   flutter_markdown: ^0.5.2                # Rendering markdown |   flutter_markdown: ^0.5.2                # Rendering markdown | ||||||
|   camera: |   camera: | ||||||
|   path_provider: |   path_provider: ^1.6.27                  # Local file storage | ||||||
|  |   sembast: ^2.4.9                         # NoSQL data storage | ||||||
|   path: |   path: | ||||||
|  |  | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user