diff --git a/lib/screens/sign_in.dart b/lib/screens/sign_in.dart index 81ba373..5744ec0 100644 --- a/lib/screens/sign_in.dart +++ b/lib/screens/sign_in.dart @@ -47,6 +47,28 @@ class _SignInScreenState extends State { } else { newProfile(); } + usernameController.addListener(() { + _updateSignInButtonStatus(); + }); + passwordController.addListener(() { + _updateSignInButtonStatus(); + }); + serverNameController.addListener(() { + _updateSignInButtonStatus(); + }); + } + + void _updateSignInButtonStatus() { + setState(() { + signInButtonEnabled = switch (oauthType) { + usernamePasswordType => + serverNameController.text.isNotEmpty && + usernameController.text.isNotEmpty && + passwordController.text.isNotEmpty, + oauthType => serverNameController.text.isNotEmpty, + _ => false, + }; + }); } void newProfile() { @@ -54,7 +76,7 @@ class _SignInScreenState extends State { passwordController.clear(); serverNameController.clear(); authType = oauthType; - signInButtonEnabled = true; + signInButtonEnabled = false; existingProfile = null; } @@ -131,14 +153,14 @@ class _SignInScreenState extends State { onChanged: existingAccount ? null : (value) { - if (existingAccount) { - buildSnackbar(context, - "Can't change the type on an existing account"); - return; - } - authType = value!; - setState(() {}); - }), + if (existingAccount) { + buildSnackbar(context, + "Can't change the type on an existing account"); + return; + } + authType = value!; + setState(() {}); + }), ), const VerticalPadding(), TextFormField( @@ -147,12 +169,15 @@ class _SignInScreenState extends State { autovalidateMode: AutovalidateMode.onUserInteraction, controller: serverNameController, validator: (value) => - isFQDN(value ?? '') ? null : 'Not a valid server name', + isFQDN(value ?? '') ? null : 'Not a valid server name', decoration: InputDecoration( hintText: 'Server Name (friendica.example.com)', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).colorScheme.background, + color: Theme + .of(context) + .colorScheme + .background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -163,7 +188,8 @@ class _SignInScreenState extends State { if (!showUsernameAndPasswordFields) ...[ Text( existingAccount - ? 'Configured to sign in as user ${existingProfile?.handle}' + ? 'Configured to sign in as user ${existingProfile + ?.handle}' : 'Relatica will open the requested Friendica site in a web browser where you will be asked to authorize this client.', softWrap: true, ), @@ -195,7 +221,10 @@ class _SignInScreenState extends State { hintText: 'Username (user@example.com)', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).colorScheme.background, + color: Theme + .of(context) + .colorScheme + .background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -229,7 +258,10 @@ class _SignInScreenState extends State { hintText: 'Password', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).colorScheme.background, + color: Theme + .of(context) + .colorScheme + .background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -240,111 +272,117 @@ class _SignInScreenState extends State { ], signInButtonEnabled ? ElevatedButton( - onPressed: () => _signIn(context), - child: const Text('Signin'), - ) + onPressed: () async => await _signIn(context), + child: const Text('Signin'), + ) : SizedBox(), const VerticalPadding(), Text( 'Logged out:', - style: Theme.of(context).textTheme.headlineSmall, + style: Theme + .of(context) + .textTheme + .headlineSmall, ), loggedOutProfiles.isEmpty ? const Text( - 'No logged out profiles', - textAlign: TextAlign.center, - ) + 'No logged out profiles', + textAlign: TextAlign.center, + ) : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all( - width: 0.5, - )), - child: Column( - children: loggedOutProfiles.map((p) { - return ListTile( - onTap: () { - setCredentials(context, p); - setState(() {}); - }, - title: Text(p.handle), - subtitle: Text(p.credentials is BasicCredentials - ? usernamePasswordType - : oauthType), - trailing: ElevatedButton( - onPressed: () async { - final confirm = await showYesNoDialog(context, - 'Remove login information from app?'); - if (confirm ?? false) { - await service.removeProfile(p); - } - setState(() {}); - }, - child: const Text('Remove'), - ), - ); - }).toList(), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + width: 0.5, + )), + child: Column( + children: loggedOutProfiles.map((p) { + return ListTile( + onTap: () { + setCredentials(context, p); + setState(() {}); + }, + title: Text(p.handle), + subtitle: Text(p.credentials is BasicCredentials + ? usernamePasswordType + : oauthType), + trailing: ElevatedButton( + onPressed: () async { + final confirm = await showYesNoDialog(context, + 'Remove login information from app?'); + if (confirm ?? false) { + await service.removeProfile(p); + } + setState(() {}); + }, + child: const Text('Remove'), ), - ), + ); + }).toList(), + ), + ), const VerticalPadding(), Text( 'Logged in:', - style: Theme.of(context).textTheme.headlineSmall, + style: Theme + .of(context) + .textTheme + .headlineSmall, ), loggedInProfiles.isEmpty ? const Text( - 'No logged in profiles', - textAlign: TextAlign.center, - ) + 'No logged in profiles', + textAlign: TextAlign.center, + ) : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - border: Border.all( - width: 0.5, - )), - child: Column( - children: loggedInProfiles.map((p) { - final active = service.loggedIn - ? p.id == service.currentProfile.id - : false; - return ListTile( - onTap: () async { - setCredentials(context, p); - setState(() {}); - }, - title: Text( - p.handle, - style: active - ? const TextStyle( - fontWeight: FontWeight.bold, - fontStyle: FontStyle.italic) - : null, - ), - subtitle: Text( - p.credentials is BasicCredentials - ? usernamePasswordType - : oauthType, - style: active - ? const TextStyle( - fontWeight: FontWeight.bold, - fontStyle: FontStyle.italic) - : null, - ), - trailing: ElevatedButton( - onPressed: () async { - final confirm = await showYesNoDialog( - context, 'Log out account?'); - if (confirm == true) { - await getIt().signOut(p); - setState(() {}); - } - }, - child: const Text('Sign out'), - ), - ); - }).toList(), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all( + width: 0.5, + )), + child: Column( + children: loggedInProfiles.map((p) { + final active = service.loggedIn + ? p.id == service.currentProfile.id + : false; + return ListTile( + onTap: () async { + setCredentials(context, p); + setState(() {}); + }, + title: Text( + p.handle, + style: active + ? const TextStyle( + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic) + : null, ), - ), + subtitle: Text( + p.credentials is BasicCredentials + ? usernamePasswordType + : oauthType, + style: active + ? const TextStyle( + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic) + : null, + ), + trailing: ElevatedButton( + onPressed: () async { + final confirm = await showYesNoDialog( + context, 'Log out account?'); + if (confirm == true) { + await getIt().signOut(p); + setState(() {}); + } + }, + child: const Text('Sign out'), + ), + ); + }).toList(), + ), + ), ], ), ), @@ -353,7 +391,7 @@ class _SignInScreenState extends State { ); } - void _signIn(BuildContext context) async { + Future _signIn(BuildContext context) async { final valid = formKey.currentState?.validate() ?? false; if (!valid) { buildSnackbar( @@ -385,13 +423,19 @@ class _SignInScreenState extends State { return; } - print('Sign in credentials: ${creds.toJson()}'); - - final result = await getIt().signIn(creds); + buildSnackbar(context, 'Attempting to sign in account...'); + final result = await getIt().signIn( + creds, + withNotification: false, + ); if (mounted && result.isFailure) { buildSnackbar(context, 'Error signing in: ${result.error}'); return; } + + if (mounted) { + buildSnackbar(context, 'Account signed in...'); + } await getIt().setActiveProfile(result.value); if (mounted) { context.goNamed(ScreenPaths.timelines);