Make sign in screen flow cleaner on logins.

main
Hank Grabowski 2023-11-27 13:39:57 -06:00
rodzic b13b66ec48
commit ff6275d079
1 zmienionych plików z 150 dodań i 106 usunięć

Wyświetl plik

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