[ui] UI theme should match repertory blue #61
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good

This commit is contained in:
2025-08-15 10:31:47 -05:00
parent 60c098a5af
commit fec755dc25

View File

@@ -18,99 +18,174 @@ class _AuthScreenState extends State<AuthScreen> {
@override @override
Widget build(context) { Widget build(context) {
return Scaffold( final scheme = Theme.of(context).colorScheme;
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary, InputDecoration decoration(String label, IconData icon) => InputDecoration(
title: Text(widget.title), labelText: label,
prefixIcon: Icon(icon),
filled: true,
fillColor: scheme.surfaceContainerLow.withValues(alpha: 0.65),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
), ),
body: Consumer<Auth>( focusedBorder: OutlineInputBorder(
builder: (context, auth, _) { borderRadius: BorderRadius.circular(12),
if (auth.authenticated) { borderSide: BorderSide(color: scheme.primary, width: 2),
Future.delayed(Duration(milliseconds: 1), () { ),
if (constants.navigatorKey.currentContext == null) { contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
return; );
}
Navigator.of( VoidCallback? createLoginHandler(Auth auth) {
constants.navigatorKey.currentContext!, if (!_enabled) return null;
).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false); return () async {
}); setState(() => _enabled = false);
return SizedBox.shrink(); await auth.authenticate(_userController.text, _passwordController.text);
} setState(() => _enabled = true);
};
}
createLoginHandler() { return Scaffold(
return _enabled appBar: AppBar(title: Text(widget.title), scrolledUnderElevation: 0),
? () async { body: Container(
setState(() => _enabled = false); width: double.infinity,
await auth.authenticate( height: double.infinity,
_userController.text, decoration: const BoxDecoration(
_passwordController.text, gradient: LinearGradient(
); begin: Alignment.topLeft,
setState(() => _enabled = true); end: Alignment.bottomRight,
colors: [Color(0xFF1050A0), Color(0xFF202124)],
),
),
child: Consumer<Auth>(
builder: (context, auth, _) {
if (auth.authenticated) {
Future.delayed(Duration(milliseconds: 1), () {
if (constants.navigatorKey.currentContext == null) {
return;
} }
: null;
}
return Center( Navigator.of(
child: Card( constants.navigatorKey.currentContext!,
child: Padding( ).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false);
padding: const EdgeInsets.all(constants.padding), });
child: SizedBox(
width: constants.logonWidth,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
constants.appLogonTitle,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: constants.padding),
TextField(
autofocus: true,
decoration: InputDecoration(labelText: 'Username'),
controller: _userController,
textInputAction: TextInputAction.next,
),
const SizedBox(height: constants.padding),
TextField(
obscureText: true,
decoration: InputDecoration(labelText: 'Password'),
controller: _passwordController,
textInputAction: TextInputAction.go,
onSubmitted: (_) {
final handler = createLoginHandler();
if (handler == null) {
return;
}
handler(); return const SizedBox.shrink();
}, }
return Center(
child: AnimatedScale(
scale: 1.0,
duration: const Duration(milliseconds: 250),
curve: Curves.easeOutCubic,
child: AnimatedOpacity(
opacity: 1.0,
duration: const Duration(milliseconds: 250),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 420,
minWidth: 300,
),
child: Card(
elevation: 12,
color: scheme.surface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
), ),
const SizedBox(height: constants.padding), child: Padding(
ElevatedButton( padding: const EdgeInsets.all(constants.padding),
onPressed: createLoginHandler(), child: Column(
child: const Text('Login'), mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.center,
child: CircleAvatar(
radius: 28,
backgroundColor: scheme.primary.withValues(
alpha: 0.18,
),
child: Icon(
Icons.folder,
color: scheme.primary,
size: 28,
),
),
),
const SizedBox(height: 14),
Text(
constants.appLogonTitle,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 6),
Text(
"Secure access to your mounts",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(
color: scheme.onSurface.withValues(
alpha: 0.7,
),
),
),
const SizedBox(height: 20),
TextField(
autofocus: true,
controller: _userController,
textInputAction: TextInputAction.next,
decoration: decoration('Username', Icons.person),
),
const SizedBox(height: constants.padding),
TextField(
controller: _passwordController,
obscureText: true,
textInputAction: TextInputAction.go,
onSubmitted: (_) {
final handler = createLoginHandler(auth);
handler?.call();
},
decoration: decoration('Password', Icons.lock),
),
const SizedBox(height: constants.padding),
SizedBox(
height: 44,
child: ElevatedButton(
onPressed: createLoginHandler(auth),
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: _enabled
? const Text('Login')
: const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2.4,
),
),
),
),
],
),
), ),
], ),
), ),
), ),
), ),
), );
); },
}, ),
), ),
); );
} }
@override @override
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
if (!mounted) { if (!mounted) return;
return;
}
super.setState(fn); super.setState(fn);
} }
} }