Add autofill to kitsu login dialog

- Wrap login fields in AutofillGroup and add proper autofillHints for email, username, and password
- Add keyboard types, textInputAction, and onFieldSubmitted to improve form navigation
- Disable suggestions/autocorrect for password field
- Add TextInput.finishAutofillContext() on successful login
- Improve focus handling and overall form behavior
- Minor UI/structure adjustments for clarity and consistency
This commit is contained in:
NBA2K1 2026-02-27 12:18:25 +01:00
parent df99d72022
commit f85e661c8e

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:isar_community/isar.dart';
@ -187,116 +188,132 @@ void _showDialogLogin(BuildContext context, WidgetRef ref) {
content: SizedBox(
height: 300,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: emailController,
autofocus: true,
onChanged: (value) => setState(() {
email = value;
}),
decoration: InputDecoration(
hintText: l10n.email_adress,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: passwordController,
obscureText: obscureText,
onChanged: (value) => setState(() {
password = value;
}),
decoration: InputDecoration(
hintText: l10n.password,
suffixIcon: IconButton(
onPressed: () => setState(() {
obscureText = !obscureText;
}),
icon: Icon(
obscureText
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
child: AutofillGroup(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autofillHints: const [
AutofillHints.email,
AutofillHints.username,
],
autofocus: true,
onFieldSubmitted: (_) =>
FocusScope.of(context).nextFocus(),
onChanged: (value) => setState(() {
email = value;
}),
decoration: InputDecoration(
hintText: l10n.email_adress,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: passwordController,
obscureText: obscureText,
keyboardType: TextInputType.visiblePassword,
textInputAction: TextInputAction.done,
enableSuggestions: false,
autocorrect: false,
autofillHints: const [AutofillHints.password],
onChanged: (value) => setState(() {
password = value;
}),
decoration: InputDecoration(
hintText: l10n.password,
suffixIcon: IconButton(
onPressed: () => setState(() {
obscureText = !obscureText;
}),
icon: Icon(
obscureText
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
),
),
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
),
const SizedBox(height: 10),
Text(errorMessage, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: context.width(1),
height: 50,
child: ElevatedButton(
onPressed: isLoading
? null
: () async {
setState(() {
isLoading = true;
});
final res = await ref
.read(
kitsuProvider(
syncId: TrackerProviders.kitsu.syncId,
widgetRef: ref,
).notifier,
)
.login(email, password);
if (!res.$1) {
const SizedBox(height: 10),
Text(errorMessage, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: context.width(1),
height: 50,
child: ElevatedButton(
onPressed: isLoading
? null
: () async {
setState(() {
isLoading = false;
errorMessage = res.$2;
isLoading = true;
});
} else {
if (context.mounted) {
Navigator.pop(context);
final res = await ref
.read(
kitsuProvider(
syncId: TrackerProviders.kitsu.syncId,
widgetRef: ref,
).notifier,
)
.login(email, password);
if (!res.$1) {
setState(() {
isLoading = false;
errorMessage = res.$2;
});
} else {
TextInput.finishAutofillContext();
if (context.mounted) {
Navigator.pop(context);
}
}
}
},
child: isLoading
? const CircularProgressIndicator()
: Text(l10n.login),
},
child: isLoading
? const CircularProgressIndicator()
: Text(l10n.login),
),
),
),
),
],
],
),
),
),
);