[ui] UI theme should match repertory blue #61
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				BlockStorage/repertory/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	BlockStorage/repertory/pipeline/head This commit looks good
				
			This commit is contained in:
		| @@ -1,4 +1,3 @@ | ||||
| import 'dart:ui'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| @@ -79,38 +78,36 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     void navigateHomePostFrame() { | ||||
|       WidgetsBinding.instance.addPostFrameCallback((_) { | ||||
|         final navCtx = constants.navigatorKey.currentContext; | ||||
|         if (navCtx == null) { | ||||
|           return; | ||||
|         } | ||||
|         Navigator.of(navCtx).pushNamedAndRemoveUntil('/', (r) => false); | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: Text(widget.title), | ||||
|         scrolledUnderElevation: 0, | ||||
|         backgroundColor: Theme.of( | ||||
|           context, | ||||
|         ).colorScheme.surface.withValues(alpha: 0.55), | ||||
|         elevation: 0, | ||||
|         flexibleSpace: ClipRRect( | ||||
|           child: BackdropFilter( | ||||
|             filter: ImageFilter.blur(sigmaX: 14, sigmaY: 14), | ||||
|             child: const SizedBox.expand(), | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|       appBar: AppBar(title: Text(widget.title), scrolledUnderElevation: 0), | ||||
|       body: SafeArea( | ||||
|         child: CoolScaffoldBg( | ||||
|           enableAurora: true, | ||||
|         child: Container( | ||||
|           width: double.infinity, | ||||
|           height: double.infinity, | ||||
|           decoration: BoxDecoration( | ||||
|             gradient: LinearGradient( | ||||
|               begin: Alignment.topLeft, | ||||
|               end: Alignment.bottomRight, | ||||
|               colors: [ | ||||
|                 Theme.of(context).colorScheme.surface, | ||||
|                 Theme.of(context).colorScheme.surface.withValues(alpha: 0.9), | ||||
|               ], | ||||
|               stops: const [0.0, 1.0], | ||||
|             ), | ||||
|           ), | ||||
|           child: Consumer<Auth>( | ||||
|             builder: (context, auth, _) { | ||||
|               if (auth.authenticated) { | ||||
|                 navigateHomePostFrame(); | ||||
|                 Future.delayed(const Duration(milliseconds: 1), () { | ||||
|                   if (constants.navigatorKey.currentContext == null) { | ||||
|                     return; | ||||
|                   } | ||||
|  | ||||
|                   Navigator.of( | ||||
|                     constants.navigatorKey.currentContext!, | ||||
|                   ).pushNamedAndRemoveUntil('/', (r) => false); | ||||
|                 }); | ||||
|  | ||||
|                 return const SizedBox.shrink(); | ||||
|               } | ||||
|  | ||||
| @@ -139,134 +136,124 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|                             key: _formKey, | ||||
|                             autovalidateMode: | ||||
|                                 AutovalidateMode.onUserInteraction, | ||||
|                             child: AutofillGroup( | ||||
|                               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: ClipRRect( | ||||
|                                         borderRadius: BorderRadius.circular(28), | ||||
|                                         child: Image.asset( | ||||
|                                           'assets/images/repertory.png', | ||||
|                                           width: 28, | ||||
|                                           height: 28, | ||||
|                                           fit: BoxFit.contain, | ||||
|                                           errorBuilder: (_, _, _) => Icon( | ||||
|                                             Icons.folder, | ||||
|                                             color: scheme.primary, | ||||
|                                             size: 28, | ||||
|                                           ), | ||||
|                             child: Column( | ||||
|                               mainAxisSize: MainAxisSize.min, | ||||
|                               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|                               children: [ | ||||
|                                 Align( | ||||
|                                   alignment: Alignment.center, | ||||
|                                   child: Container( | ||||
|                                     width: 56, | ||||
|                                     height: 56, | ||||
|                                     decoration: BoxDecoration( | ||||
|                                       color: scheme.primary.withValues( | ||||
|                                         alpha: 0.18, | ||||
|                                       ), | ||||
|                                       borderRadius: BorderRadius.circular(8), | ||||
|                                     ), | ||||
|                                     padding: const EdgeInsets.all(8), | ||||
|                                     child: Image.asset( | ||||
|                                       'assets/images/repertory.png', | ||||
|                                       fit: BoxFit.contain, | ||||
|                                       errorBuilder: (_, _, _) { | ||||
|                                         return Icon( | ||||
|                                           Icons.folder, | ||||
|                                           color: scheme.primary, | ||||
|                                           size: 40, | ||||
|                                         ); | ||||
|                                       }, | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                 ), | ||||
|                                 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: 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), | ||||
|                                   TextFormField( | ||||
|                                     autofocus: true, | ||||
|                                     controller: _userController, | ||||
|                                     textInputAction: TextInputAction.next, | ||||
|                                     autofillHints: const [ | ||||
|                                       AutofillHints.username, | ||||
|                                     ], | ||||
|                                     decoration: decoration( | ||||
|                                       'Username', | ||||
|                                       Icons.person, | ||||
|                                     ), | ||||
|                                     validator: (v) => | ||||
|                                         (v == null || v.trim().isEmpty) | ||||
|                                         ? 'Enter your username' | ||||
|                                         : null, | ||||
|                                     onFieldSubmitted: (_) => | ||||
|                                         FocusScope.of(context).nextFocus(), | ||||
|                                   ), | ||||
|                                   const SizedBox(height: constants.padding), | ||||
|                                   TextFormField( | ||||
|                                     controller: _passwordController, | ||||
|                                     obscureText: _obscure, | ||||
|                                     textInputAction: TextInputAction.go, | ||||
|                                     autofillHints: const [ | ||||
|                                       AutofillHints.password, | ||||
|                                     ], | ||||
|                                     decoration: | ||||
|                                         decoration( | ||||
|                                           'Password', | ||||
|                                           Icons.lock, | ||||
|                                         ).copyWith( | ||||
|                                           suffixIcon: IconButton( | ||||
|                                             tooltip: _obscure | ||||
|                                                 ? 'Show password' | ||||
|                                                 : 'Hide password', | ||||
|                                             icon: Icon( | ||||
|                                               _obscure | ||||
|                                                   ? Icons.visibility | ||||
|                                                   : Icons.visibility_off, | ||||
|                                             ), | ||||
|                                             onPressed: () => setState( | ||||
|                                               () => _obscure = !_obscure, | ||||
|                                             ), | ||||
|                                           ), | ||||
|                                         ), | ||||
|                                     validator: (v) => (v == null || v.isEmpty) | ||||
|                                         ? 'Enter your password' | ||||
|                                         : null, | ||||
|                                     onFieldSubmitted: (_) => doLogin(auth), | ||||
|                                   ), | ||||
|                                   const SizedBox(height: constants.padding), | ||||
|                                 ), | ||||
|                                 const SizedBox(height: 20), | ||||
|  | ||||
|                                   SizedBox( | ||||
|                                     height: 44, | ||||
|                                     child: ElevatedButton( | ||||
|                                       onPressed: _enabled | ||||
|                                           ? () => doLogin(auth) | ||||
|                                           : null, | ||||
|                                       style: ElevatedButton.styleFrom( | ||||
|                                         shape: RoundedRectangleBorder( | ||||
|                                           borderRadius: BorderRadius.circular( | ||||
|                                             12, | ||||
|                                 TextFormField( | ||||
|                                   autofocus: true, | ||||
|                                   controller: _userController, | ||||
|                                   textInputAction: TextInputAction.next, | ||||
|                                   decoration: decoration( | ||||
|                                     'Username', | ||||
|                                     Icons.person, | ||||
|                                   ), | ||||
|                                   validator: (v) => | ||||
|                                       (v == null || v.trim().isEmpty) | ||||
|                                       ? 'Enter your username' | ||||
|                                       : null, | ||||
|                                   onFieldSubmitted: (_) => | ||||
|                                       FocusScope.of(context).nextFocus(), | ||||
|                                 ), | ||||
|                                 const SizedBox(height: constants.padding), | ||||
|  | ||||
|                                 TextFormField( | ||||
|                                   controller: _passwordController, | ||||
|                                   obscureText: _obscure, | ||||
|                                   textInputAction: TextInputAction.go, | ||||
|                                   decoration: decoration('Password', Icons.lock) | ||||
|                                       .copyWith( | ||||
|                                         suffixIcon: IconButton( | ||||
|                                           tooltip: _obscure | ||||
|                                               ? 'Show password' | ||||
|                                               : 'Hide password', | ||||
|                                           icon: Icon( | ||||
|                                             _obscure | ||||
|                                                 ? Icons.visibility | ||||
|                                                 : Icons.visibility_off, | ||||
|                                           ), | ||||
|                                           onPressed: () => setState( | ||||
|                                             () => _obscure = !_obscure, | ||||
|                                           ), | ||||
|                                         ), | ||||
|                                       ), | ||||
|                                       child: _enabled | ||||
|                                           ? const Text('Login') | ||||
|                                           : const SizedBox( | ||||
|                                               height: 20, | ||||
|                                               width: 20, | ||||
|                                               child: CircularProgressIndicator( | ||||
|                                                 strokeWidth: 2.4, | ||||
|                                               ), | ||||
|                                             ), | ||||
|                                   validator: (v) => (v == null || v.isEmpty) | ||||
|                                       ? 'Enter your password' | ||||
|                                       : null, | ||||
|                                   onFieldSubmitted: (_) => doLogin(auth), | ||||
|                                 ), | ||||
|                                 const SizedBox(height: constants.padding), | ||||
|  | ||||
|                                 SizedBox( | ||||
|                                   height: 44, | ||||
|                                   child: ElevatedButton( | ||||
|                                     onPressed: _enabled | ||||
|                                         ? () => doLogin(auth) | ||||
|                                         : null, | ||||
|                                     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, | ||||
|                                             ), | ||||
|                                           ), | ||||
|                                   ), | ||||
|                                 ], | ||||
|                               ), | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
| @@ -282,109 +269,3 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class CoolScaffoldBg extends StatelessWidget { | ||||
|   final Widget child; | ||||
|   final bool enableAurora; | ||||
|   const CoolScaffoldBg({ | ||||
|     super.key, | ||||
|     required this.child, | ||||
|     this.enableAurora = true, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     return Stack( | ||||
|       children: [ | ||||
|         Builder( | ||||
|           builder: (context) { | ||||
|             return Container( | ||||
|               decoration: BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: [ | ||||
|                     Theme.of(context).colorScheme.primary, | ||||
|                     Theme.of(context).colorScheme.surface, | ||||
|                   ], | ||||
|                 ), | ||||
|               ), | ||||
|             ); | ||||
|           }, | ||||
|         ), | ||||
|         if (enableAurora) const AuroraSweep(), | ||||
|         Align( | ||||
|           alignment: const Alignment(0, 0.1), | ||||
|           child: IgnorePointer( | ||||
|             child: Container( | ||||
|               width: 740, | ||||
|               height: 740, | ||||
|               decoration: BoxDecoration( | ||||
|                 shape: BoxShape.circle, | ||||
|                 gradient: RadialGradient( | ||||
|                   colors: [ | ||||
|                     scheme.primary.withValues(alpha: 0.22), | ||||
|                     Colors.transparent, | ||||
|                   ], | ||||
|                   stops: const [0.0, 1.0], | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|         child, | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class AuroraSweep extends StatefulWidget { | ||||
|   const AuroraSweep({super.key}); | ||||
|  | ||||
|   @override | ||||
|   State<AuroraSweep> createState() => _AuroraSweepState(); | ||||
| } | ||||
|  | ||||
| class _AuroraSweepState extends State<AuroraSweep> | ||||
|     with SingleTickerProviderStateMixin { | ||||
|   late final AnimationController _c = AnimationController( | ||||
|     vsync: this, | ||||
|     duration: const Duration(seconds: 18), | ||||
|   )..repeat(); | ||||
|  | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _c.dispose(); | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     return AnimatedBuilder( | ||||
|       animation: _c, | ||||
|       builder: (_, _) { | ||||
|         final t = _c.value; | ||||
|         return IgnorePointer( | ||||
|           child: Container( | ||||
|             decoration: BoxDecoration( | ||||
|               gradient: LinearGradient( | ||||
|                 begin: Alignment(-1 + 2 * t, -0.6), | ||||
|                 end: Alignment(0.8 - 2 * t, 0.9), | ||||
|                 colors: [ | ||||
|                   scheme.primary.withValues(alpha: 0.06), | ||||
|                   Colors.transparent, | ||||
|                   scheme.primary.withValues(alpha: 0.04), | ||||
|                 ], | ||||
|                 stops: const [0.0, 0.5, 1.0], | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user