Merge branch 'signin-flow-tweaks' into 'main'

Make sign in screen flow cleaner on logins.

See merge request mysocialportal/relatica!52
main
HankG 2023-11-29 18:23:31 +00:00
commit 51bf1a29c8
1 zmienionych plików z 150 dodań i 106 usunięć

Wyświetl plik

@ -47,6 +47,28 @@ class _SignInScreenState extends State<SignInScreen> {
} 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<SignInScreen> {
passwordController.clear();
serverNameController.clear();
authType = oauthType;
signInButtonEnabled = true;
signInButtonEnabled = false;
existingProfile = null;
}
@ -131,14 +153,14 @@ class _SignInScreenState extends State<SignInScreen> {
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<SignInScreen> {
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<SignInScreen> {
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<SignInScreen> {
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<SignInScreen> {
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<SignInScreen> {
],
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<AccountsService>().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<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;
if (!valid) {
buildSnackbar(
@ -385,13 +423,19 @@ class _SignInScreenState extends State<SignInScreen> {
return;
}
print('Sign in credentials: ${creds.toJson()}');
final result = await getIt<AccountsService>().signIn(creds);
buildSnackbar(context, 'Attempting to sign in account...');
final result = await getIt<AccountsService>().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<AccountsService>().setActiveProfile(result.value);
if (mounted) {
context.goNamed(ScreenPaths.timelines);