[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,12 +18,46 @@ 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(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: scheme.primary, width: 2),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
);
VoidCallback? createLoginHandler(Auth auth) {
if (!_enabled) return null;
return () async {
setState(() => _enabled = false);
await auth.authenticate(_userController.text, _passwordController.text);
setState(() => _enabled = true);
};
}
return Scaffold(
appBar: AppBar(title: Text(widget.title), scrolledUnderElevation: 0),
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF1050A0), Color(0xFF202124)],
),
),
child: Consumer<Auth>(
builder: (context, auth, _) { builder: (context, auth, _) {
if (auth.authenticated) { if (auth.authenticated) {
Future.delayed(Duration(milliseconds: 1), () { Future.delayed(Duration(milliseconds: 1), () {
@@ -35,82 +69,123 @@ class _AuthScreenState extends State<AuthScreen> {
constants.navigatorKey.currentContext!, constants.navigatorKey.currentContext!,
).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false); ).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false);
}); });
return SizedBox.shrink();
}
createLoginHandler() { return const SizedBox.shrink();
return _enabled
? () async {
setState(() => _enabled = false);
await auth.authenticate(
_userController.text,
_passwordController.text,
);
setState(() => _enabled = true);
}
: null;
} }
return Center( 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( child: Card(
elevation: 12,
color: scheme.surface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Padding( child: Padding(
padding: const EdgeInsets.all(constants.padding), padding: const EdgeInsets.all(constants.padding),
child: SizedBox(
width: constants.logonWidth,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ 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( Text(
constants.appLogonTitle, constants.appLogonTitle,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.w600),
), ),
const SizedBox(height: constants.padding), 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( TextField(
autofocus: true, autofocus: true,
decoration: InputDecoration(labelText: 'Username'),
controller: _userController, controller: _userController,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
decoration: decoration('Username', Icons.person),
), ),
const SizedBox(height: constants.padding), const SizedBox(height: constants.padding),
TextField( TextField(
obscureText: true,
decoration: InputDecoration(labelText: 'Password'),
controller: _passwordController, controller: _passwordController,
obscureText: true,
textInputAction: TextInputAction.go, textInputAction: TextInputAction.go,
onSubmitted: (_) { onSubmitted: (_) {
final handler = createLoginHandler(); final handler = createLoginHandler(auth);
if (handler == null) { handler?.call();
return;
}
handler();
}, },
decoration: decoration('Password', Icons.lock),
), ),
const SizedBox(height: constants.padding), const SizedBox(height: constants.padding),
ElevatedButton( SizedBox(
onPressed: createLoginHandler(), height: 44,
child: const Text('Login'), 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);
} }
} }