From fec755dc251edbeeb14de9ab22141a62b6103c8b Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Fri, 15 Aug 2025 10:31:47 -0500 Subject: [PATCH] [ui] UI theme should match repertory blue #61 --- web/repertory/lib/screens/auth_screen.dart | 227 ++++++++++++++------- 1 file changed, 151 insertions(+), 76 deletions(-) diff --git a/web/repertory/lib/screens/auth_screen.dart b/web/repertory/lib/screens/auth_screen.dart index 986ebf04..64c6eb3e 100644 --- a/web/repertory/lib/screens/auth_screen.dart +++ b/web/repertory/lib/screens/auth_screen.dart @@ -18,99 +18,174 @@ class _AuthScreenState extends State { @override Widget build(context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), + final scheme = Theme.of(context).colorScheme; + + InputDecoration decoration(String label, IconData icon) => InputDecoration( + 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( - builder: (context, auth, _) { - if (auth.authenticated) { - Future.delayed(Duration(milliseconds: 1), () { - if (constants.navigatorKey.currentContext == null) { - return; - } + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: scheme.primary, width: 2), + ), + contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), + ); - Navigator.of( - constants.navigatorKey.currentContext!, - ).pushNamedAndRemoveUntil('/', (Route route) => false); - }); - return SizedBox.shrink(); - } + VoidCallback? createLoginHandler(Auth auth) { + if (!_enabled) return null; + return () async { + setState(() => _enabled = false); + await auth.authenticate(_userController.text, _passwordController.text); + setState(() => _enabled = true); + }; + } - createLoginHandler() { - return _enabled - ? () 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( + builder: (context, auth, _) { + if (auth.authenticated) { + Future.delayed(Duration(milliseconds: 1), () { + if (constants.navigatorKey.currentContext == null) { + return; } - : null; - } - return Center( - child: Card( - child: Padding( - 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; - } + Navigator.of( + constants.navigatorKey.currentContext!, + ).pushNamedAndRemoveUntil('/', (Route route) => false); + }); - 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), - ElevatedButton( - onPressed: createLoginHandler(), - child: const Text('Login'), + child: Padding( + padding: const EdgeInsets.all(constants.padding), + child: Column( + 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 void setState(VoidCallback fn) { - if (!mounted) { - return; - } - + if (!mounted) return; super.setState(fn); } }