From 638848092bab980a6362301b971b8078ee1d4246 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 16 Aug 2021 16:28:11 +1000 Subject: [PATCH] Refactor profile selection screen - Launch a new window, instead of a modal - Improved host validation - Better keyboard inputs --- assets/release_notes.md | 6 + lib/l10n | 2 +- lib/settings/login.dart | 293 ++++++++++++++++++++++++++-------------- 3 files changed, 195 insertions(+), 106 deletions(-) diff --git a/assets/release_notes.md b/assets/release_notes.md index 41e98b2e..db6b20b5 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,12 @@ ## InvenTree App Release Notes --- +### 0.4.6 - August 2021 +--- + +- Improved profile selection screen +- Fixed a number of incorrect labels + ### 0.4.5 - August 2021 --- diff --git a/lib/l10n b/lib/l10n index 951063e0..48ed29ca 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 951063e039d4659159f42ec6425092f4f3bb808c +Subproject commit 48ed29ca98d35585721e6af5718d7dcb08869705 diff --git a/lib/settings/login.dart b/lib/settings/login.dart index 5112161a..13db320e 100644 --- a/lib/settings/login.dart +++ b/lib/settings/login.dart @@ -51,104 +51,14 @@ class _InvenTreeLoginSettingsState extends State { profile = userProfile; } - showFormDialog( - createNew ? L10().profileAdd : L10().profileEdit, - key: _addProfileKey, - callback: () { - if (createNew) { - - UserProfile profile = UserProfile( - name: _name, - server: _server, - username: _username, - password: _password - ); - - _addProfile(profile); - } else { - - profile?.name = _name; - profile?.server = _server; - profile?.username = _username; - profile?.password = _password; - - _updateProfile(profile); - - } - }, - fields: [ - StringField( - label: L10().name, - hint: "Enter profile name", - initial: createNew ? '' : profile?.name ?? '', - onSaved: (value) => _name = value, - validator: _validateProfileName, - ), - StringField( - label: L10().server, - hint: "http[s]://:", - initial: createNew ? '' : profile?.server ?? '', - validator: _validateServer, - onSaved: (value) => _server = value, - ), - StringField( - label: L10().username, - hint: L10().enterPassword, - initial: createNew ? '' : profile?.username ?? '', - onSaved: (value) => _username = value, - validator: _validateUsername, - ), - StringField( - label: L10().password, - hint: L10().enterUsername, - initial: createNew ? '' : profile?.password ?? '', - onSaved: (value) => _password = value, - validator: _validatePassword, - ) - ] - ); - } - - String? _validateProfileName(String value) { - - if (value.isEmpty) { - return 'Profile name cannot be empty'; - } - - // TODO: Check if a profile already exists with ths name - - return null; - } - - String? _validateServer(String value) { - - if (value.isEmpty) { - return L10().serverEmpty; - } - - if (!value.startsWith("http:") && !value.startsWith("https:")) { - return L10().serverStart; - } - - // TODO: URL validator - - return null; - } - - String? _validateUsername(String value) { - if (value.isEmpty) { - return L10().usernameEmpty; - } - - return null; - } - - String? _validatePassword(String value) { - if (value.isEmpty) { - return L10().passwordEmpty; - } - - return null; + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProfileEditWidget(userProfile) + ) + ).then((context) { + _reload(); + }); } void _selectProfile(BuildContext context, UserProfile profile) async { @@ -191,7 +101,7 @@ class _InvenTreeLoginSettingsState extends State { return; } - await UserProfileDBManager().updateProfile(profile); + _reload(); @@ -204,12 +114,6 @@ class _InvenTreeLoginSettingsState extends State { } } - void _addProfile(UserProfile profile) async { - - await UserProfileDBManager().addProfile(profile); - - _reload(); - } Widget? _getProfileIcon(UserProfile profile) { @@ -335,4 +239,183 @@ class _InvenTreeLoginSettingsState extends State { ) ); } +} + + +class ProfileEditWidget extends StatefulWidget { + + UserProfile? profile; + + ProfileEditWidget(this.profile) : super(); + + @override + _ProfileEditState createState() => _ProfileEditState(profile); +} + +class _ProfileEditState extends State { + + UserProfile? profile; + + _ProfileEditState(this.profile) : super(); + + final formKey = new GlobalKey(); + + String name = ""; + String server = ""; + String username = ""; + String password = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(profile == null ? L10().profileAdd : L10().profileEdit), + actions: [ + IconButton( + icon: FaIcon(FontAwesomeIcons.save), + onPressed: () async { + if (formKey.currentState!.validate()) { + formKey.currentState!.save(); + + UserProfile? prf = profile; + + if (prf == null) { + UserProfile profile = UserProfile( + name: name, + server: server, + username: username, + password: password, + ); + + await UserProfileDBManager().addProfile(profile); + } else { + + prf.name = name; + prf.server = server; + prf.username = username; + prf.password = password; + + await UserProfileDBManager().updateProfile(prf); + } + + // Close the window + Navigator.of(context).pop(); + } + }, + ) + ] + ), + body: Form( + key: formKey, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextFormField( + decoration: InputDecoration( + labelText: L10().profileName, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + ), + initialValue: profile?.name ?? "", + maxLines: 1, + keyboardType: TextInputType.text, + onSaved: (value) { + name = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().valueCannotBeEmpty; + } + } + ), + TextFormField( + decoration: InputDecoration( + labelText: L10().server, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: "http[s]://:", + ), + initialValue: profile?.server ?? "", + keyboardType: TextInputType.url, + onSaved: (value) { + server = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().serverEmpty; + } + + value = value.trim(); + + // Spaces are bad + if (value.contains(" ")) { + return L10().invalidHost; + } + + if (!value.startsWith("http:") && !value.startsWith("https:")) { + // return L10().serverStart; + } + + Uri? _uri = Uri.tryParse(value); + + if (_uri == null || _uri.host.isEmpty) { + return L10().invalidHost; + } else { + Uri uri = Uri.parse(value); + + if (uri.hasScheme) { + print("Scheme: ${uri.scheme}"); + if (!(["http", "https"].contains(uri.scheme.toLowerCase()))) { + return L10().serverStart; + } + } else { + return L10().invalidHost; + } + } + }, + ), + TextFormField( + decoration: InputDecoration( + labelText: L10().username, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterUsername + ), + initialValue: profile?.username ?? "", + keyboardType: TextInputType.text, + onSaved: (value) { + username = value?.trim() ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().usernameEmpty; + } + }, + ), + TextFormField( + decoration: InputDecoration( + labelText: L10().password, + labelStyle: TextStyle(fontWeight: FontWeight.bold), + hintText: L10().enterPassword, + ), + initialValue: profile?.password ?? "", + keyboardType: TextInputType.visiblePassword, + obscureText: true, + onSaved: (value) { + password = value ?? ""; + }, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return L10().passwordEmpty; + } + } + ) + ] + ), + padding: EdgeInsets.all(16), + ), + ) + ); + } + } \ No newline at end of file