[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,11 +1,16 @@ | ||||
| // helpers.dart | ||||
|  | ||||
| import 'dart:ui'; | ||||
|  | ||||
| import 'package:convert/convert.dart'; | ||||
| import 'package:collection/collection.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
| import 'package:sodium_libs/sodium_libs.dart' show SecureKey, StringX; | ||||
|  | ||||
| Future doShowDialog(BuildContext context, Widget child) => showDialog( | ||||
| @@ -426,3 +431,56 @@ Future<String?> editMountLocation( | ||||
|     ), | ||||
|   ); | ||||
| } | ||||
|  | ||||
| Scaffold createCommonScaffold(Widget child, {Widget? floatingActionButton}) => | ||||
|     Scaffold( | ||||
|       body: SafeArea( | ||||
|         child: Stack( | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: double.infinity, | ||||
|               height: double.infinity, | ||||
|               decoration: const BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: constants.gradientColors, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) => | ||||
|                   AuroraSweep(enabled: settings.enableAnimations), | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
|                 filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | ||||
|                 child: Container(color: Colors.black.withValues(alpha: 0.06)), | ||||
|               ), | ||||
|             ), | ||||
|             child, | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|       floatingActionButton: floatingActionButton, | ||||
|     ); | ||||
|  | ||||
| InputDecoration createCommonDecoration( | ||||
|   ColorScheme colorScheme, | ||||
|   String label, | ||||
|   IconData icon, | ||||
| ) => InputDecoration( | ||||
|   labelText: label, | ||||
|   prefixIcon: Icon(icon), | ||||
|   filled: true, | ||||
|   fillColor: colorScheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|   border: OutlineInputBorder( | ||||
|     borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|     borderSide: BorderSide.none, | ||||
|   ), | ||||
|   focusedBorder: OutlineInputBorder( | ||||
|     borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|     borderSide: BorderSide(color: colorScheme.primary, width: 2), | ||||
|   ), | ||||
|   contentPadding: const EdgeInsets.all(constants.paddingSmall), | ||||
| ); | ||||
|   | ||||
| @@ -9,9 +9,7 @@ import 'package:repertory/helpers.dart'; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/mount.dart'; | ||||
| import 'package:repertory/models/mount_list.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/types/mount_config.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
| import 'package:repertory/widgets/mount_settings.dart'; | ||||
|  | ||||
| class AddMountScreen extends StatefulWidget { | ||||
| @@ -46,367 +44,273 @@ class _AddMountScreenState extends State<AddMountScreen> { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final textTheme = Theme.of(context).textTheme; | ||||
|  | ||||
|     Widget glassTile({required Widget child, EdgeInsets? padding}) { | ||||
|       return Container( | ||||
|         decoration: BoxDecoration( | ||||
|           color: scheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|           borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|           border: Border.all( | ||||
|             color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|             width: 1, | ||||
|           ), | ||||
|           gradient: const LinearGradient( | ||||
|             begin: Alignment.topCenter, | ||||
|             end: Alignment.bottomCenter, | ||||
|             colors: constants.gradientColors2, | ||||
|           ), | ||||
|           boxShadow: [ | ||||
|             BoxShadow( | ||||
|               color: Colors.black.withValues(alpha: 0.22), | ||||
|               blurRadius: constants.borderRadius, | ||||
|               offset: Offset(0, constants.borderRadius), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|         child: ClipRRect( | ||||
|           borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|           child: Padding( | ||||
|             padding: padding ?? const EdgeInsets.all(constants.padding), | ||||
|             child: child, | ||||
|           ), | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return Scaffold( | ||||
|       body: SafeArea( | ||||
|         child: Stack( | ||||
|     return createCommonScaffold( | ||||
|       Padding( | ||||
|         padding: const EdgeInsets.all(constants.padding), | ||||
|         child: Column( | ||||
|           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: double.infinity, | ||||
|               height: double.infinity, | ||||
|               decoration: const BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: constants.gradientColors, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) { | ||||
|                 return AuroraSweep(enabled: settings.enableAnimations); | ||||
|               }, | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
|                 filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | ||||
|                 child: Container(color: Colors.black.withValues(alpha: 0.06)), | ||||
|               ), | ||||
|             ), | ||||
|             Padding( | ||||
|               padding: const EdgeInsets.all(constants.padding), | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|                 children: [ | ||||
|                   Row( | ||||
|                     children: [ | ||||
|                       Material( | ||||
|                         color: Colors.transparent, | ||||
|                         child: InkWell( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           onTap: () { | ||||
|                             Navigator.of(context).pop(); | ||||
|                           }, | ||||
|                           child: Ink( | ||||
|                             width: 40, | ||||
|                             height: 40, | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                               boxShadow: [ | ||||
|                                 BoxShadow( | ||||
|                                   color: Colors.black.withValues(alpha: 0.22), | ||||
|                                   blurRadius: constants.borderRadius, | ||||
|                                   offset: Offset(0, constants.borderRadius), | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                             child: const Icon(Icons.arrow_back), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|  | ||||
|                       Expanded( | ||||
|                         child: Text( | ||||
|                           widget.title, | ||||
|                           maxLines: 1, | ||||
|                           overflow: TextOverflow.ellipsis, | ||||
|                           style: textTheme.headlineSmall?.copyWith( | ||||
|                             fontWeight: FontWeight.w700, | ||||
|                             letterSpacing: 0.2, | ||||
|                             color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       ClipRRect( | ||||
|             // Header | ||||
|             Row( | ||||
|               children: [ | ||||
|                 Material( | ||||
|                   color: Colors.transparent, | ||||
|                   child: InkWell( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     onTap: () => Navigator.of(context).pop(), | ||||
|                     child: Ink( | ||||
|                       width: 40, | ||||
|                       height: 40, | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         child: BackdropFilter( | ||||
|                           filter: ImageFilter.blur( | ||||
|                             sigmaX: constants.borderRadius, | ||||
|                             sigmaY: constants.borderRadius, | ||||
|                           ), | ||||
|                           child: Container( | ||||
|                             height: 40, | ||||
|                             padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                             child: Consumer<Auth>( | ||||
|                               builder: (context, auth, _) { | ||||
|                                 return IconButton( | ||||
|                                   tooltip: 'Log out', | ||||
|                                   icon: const Icon(Icons.logout), | ||||
|                                   onPressed: () { | ||||
|                                     auth.logoff(); | ||||
|                                   }, | ||||
|                                 ); | ||||
|                               }, | ||||
|                             ), | ||||
|                           ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                   const SizedBox(height: constants.padding), | ||||
|                   glassTile( | ||||
|                     child: Row( | ||||
|                       crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                       children: [ | ||||
|                         Text( | ||||
|                           'Provider Type', | ||||
|                           style: textTheme.titleMedium?.copyWith( | ||||
|                             fontWeight: FontWeight.w600, | ||||
|                           ), | ||||
|                         ), | ||||
|                         const SizedBox(width: constants.padding), | ||||
|                         DropdownButton<String>( | ||||
|                           value: _mountType.isEmpty ? null : _mountType, | ||||
|                           autofocus: true, | ||||
|                           underline: const SizedBox.shrink(), | ||||
|                           onChanged: (mountType) { | ||||
|                             _handleChange( | ||||
|                               Provider.of<Auth>(context, listen: false), | ||||
|                               mountType ?? '', | ||||
|                             ); | ||||
|                           }, | ||||
|                           items: constants.providerTypeList | ||||
|                               .map<DropdownMenuItem<String>>((item) { | ||||
|                                 return DropdownMenuItem<String>( | ||||
|                                   value: item, | ||||
|                                   child: Text(item), | ||||
|                                 ); | ||||
|                               }) | ||||
|                               .toList(), | ||||
|                         ), | ||||
|                       ], | ||||
|                     ), | ||||
|                   ), | ||||
|                   if (_mountType.isNotEmpty && _mountType != 'Remote') ...[ | ||||
|                     const SizedBox(height: constants.padding), | ||||
|                     glassTile( | ||||
|                       child: Column( | ||||
|                         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                         children: [ | ||||
|                           Text( | ||||
|                             'Configuration Name', | ||||
|                             style: textTheme.titleMedium?.copyWith( | ||||
|                               fontWeight: FontWeight.w600, | ||||
|                             ), | ||||
|                           ), | ||||
|                           const SizedBox(height: 8), | ||||
|                           TextField( | ||||
|                             autofocus: true, | ||||
|                             controller: _mountNameController, | ||||
|                             keyboardType: TextInputType.text, | ||||
|                             inputFormatters: [ | ||||
|                               FilteringTextInputFormatter.deny(RegExp(r'\s')), | ||||
|                             ], | ||||
|                             onChanged: (_) => _handleChange( | ||||
|                               Provider.of<Auth>(context, listen: false), | ||||
|                               _mountType, | ||||
|                             ), | ||||
|                             decoration: InputDecoration( | ||||
|                               hintText: 'Enter a unique name', | ||||
|                               filled: true, | ||||
|                               fillColor: scheme.surface.withValues(alpha: 0.30), | ||||
|                               border: OutlineInputBorder( | ||||
|                                 borderRadius: BorderRadius.circular( | ||||
|                                   constants.borderRadius, | ||||
|                                 ), | ||||
|                                 borderSide: BorderSide.none, | ||||
|                               ), | ||||
|                               contentPadding: const EdgeInsets.symmetric( | ||||
|                                 horizontal: 12, | ||||
|                                 vertical: 12, | ||||
|                               ), | ||||
|                             ), | ||||
|                         boxShadow: [ | ||||
|                           BoxShadow( | ||||
|                             color: Colors.black.withValues(alpha: 0.22), | ||||
|                             blurRadius: constants.borderRadius, | ||||
|                             offset: Offset(0, constants.borderRadius), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                       child: const Icon(Icons.arrow_back), | ||||
|                     ), | ||||
|                   ], | ||||
|                   if (_mount != null) ...[ | ||||
|                     const SizedBox(height: constants.padding), | ||||
|                     Expanded( | ||||
|                       child: glassTile( | ||||
|                         padding: EdgeInsets.zero, | ||||
|                         child: Padding( | ||||
|                           padding: const EdgeInsets.all(constants.padding), | ||||
|                           child: MountSettingsWidget( | ||||
|                             isAdd: true, | ||||
|                             mount: _mount!, | ||||
|                             settings: _settings[_mountType]!, | ||||
|                             showAdvanced: false, | ||||
|                           ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Text( | ||||
|                     widget.title, | ||||
|                     maxLines: 1, | ||||
|                     overflow: TextOverflow.ellipsis, | ||||
|                     style: textTheme.headlineSmall?.copyWith( | ||||
|                       fontWeight: FontWeight.w700, | ||||
|                       letterSpacing: 0.2, | ||||
|                       color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 ClipRRect( | ||||
|                   borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                   child: BackdropFilter( | ||||
|                     filter: ImageFilter.blur( | ||||
|                       sigmaX: constants.borderRadius, | ||||
|                       sigmaY: constants.borderRadius, | ||||
|                     ), | ||||
|                     child: Container( | ||||
|                       height: 40, | ||||
|                       padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                       child: Consumer<Auth>( | ||||
|                         builder: (context, auth, _) => IconButton( | ||||
|                           tooltip: 'Log out', | ||||
|                           icon: const Icon(Icons.logout), | ||||
|                           onPressed: auth.logoff, | ||||
|                         ), | ||||
|                       ), | ||||
|                     ), | ||||
|                     const SizedBox(height: constants.padding), | ||||
|                     Row( | ||||
|                       children: [ | ||||
|                         IntrinsicWidth( | ||||
|                           child: ElevatedButton.icon( | ||||
|                             label: const Text('Test'), | ||||
|                             icon: const Icon(Icons.check), | ||||
|                             style: ElevatedButton.styleFrom( | ||||
|                               backgroundColor: scheme.primary.withValues( | ||||
|                                 alpha: 0.18, | ||||
|                               ), | ||||
|                               foregroundColor: scheme.primary, | ||||
|                               elevation: 0, | ||||
|                               shape: RoundedRectangleBorder( | ||||
|                                 borderRadius: BorderRadius.circular( | ||||
|                                   constants.borderRadius, | ||||
|                                 ), | ||||
|                                 side: BorderSide( | ||||
|                                   color: scheme.outlineVariant.withValues( | ||||
|                                     alpha: 0.15, | ||||
|                                   ), | ||||
|                                   width: 1, | ||||
|                                 ), | ||||
|                               ), | ||||
|                             ), | ||||
|                             onPressed: _handleProviderTest, | ||||
|                           ), | ||||
|                         ), | ||||
|                         const SizedBox(width: constants.padding), | ||||
|                         IntrinsicWidth( | ||||
|                           child: ElevatedButton.icon( | ||||
|                             label: const Text('Add'), | ||||
|                             icon: const Icon(Icons.add), | ||||
|                             style: ElevatedButton.styleFrom( | ||||
|                               backgroundColor: scheme.primary, | ||||
|                               foregroundColor: scheme.onPrimary, | ||||
|                               elevation: 8, | ||||
|                               shadowColor: scheme.primary.withValues( | ||||
|                                 alpha: 0.45, | ||||
|                               ), | ||||
|                               shape: RoundedRectangleBorder( | ||||
|                                 borderRadius: BorderRadius.circular( | ||||
|                                   constants.borderRadius, | ||||
|                                 ), | ||||
|                               ), | ||||
|                             ), | ||||
|                             onPressed: () async { | ||||
|                               final mountList = Provider.of<MountList>( | ||||
|                                 context, | ||||
|                                 listen: false, | ||||
|                               ); | ||||
|  | ||||
|                               List<String> failed = []; | ||||
|                               if (!validateSettings( | ||||
|                                 _settings[_mountType]!, | ||||
|                                 failed, | ||||
|                               )) { | ||||
|                                 for (var key in failed) { | ||||
|                                   displayErrorMessage( | ||||
|                                     context, | ||||
|                                     "Setting '$key' is not valid", | ||||
|                                   ); | ||||
|                                 } | ||||
|                                 return; | ||||
|                               } | ||||
|  | ||||
|                               if (mountList.hasConfigName( | ||||
|                                 _mountNameController.text, | ||||
|                               )) { | ||||
|                                 return displayErrorMessage( | ||||
|                                   context, | ||||
|                                   "Configuration name '${_mountNameController.text}' already exists", | ||||
|                                 ); | ||||
|                               } | ||||
|  | ||||
|                               if (_mountType == "Sia" || _mountType == "S3") { | ||||
|                                 final bucket = | ||||
|                                     _settings[_mountType]!["${_mountType}Config"]["Bucket"] | ||||
|                                         as String; | ||||
|                                 if (mountList.hasBucketName( | ||||
|                                   _mountType, | ||||
|                                   bucket, | ||||
|                                 )) { | ||||
|                                   return displayErrorMessage( | ||||
|                                     context, | ||||
|                                     "Bucket '$bucket' already exists", | ||||
|                                   ); | ||||
|                                 } | ||||
|                               } | ||||
|  | ||||
|                               final success = await mountList.add( | ||||
|                                 _mountType, | ||||
|                                 _mountType == 'Remote' | ||||
|                                     ? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}' | ||||
|                                     : _mountNameController.text, | ||||
|                                 _settings[_mountType]!, | ||||
|                               ); | ||||
|  | ||||
|                               if (!success || !context.mounted) { | ||||
|                                 return; | ||||
|                               } | ||||
|  | ||||
|                               Navigator.pop(context); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ), | ||||
|                       ], | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|             const SizedBox(height: constants.padding), | ||||
|             DropdownButtonFormField<String>( | ||||
|               initialValue: _mountType.isEmpty ? null : _mountType, | ||||
|               decoration: createCommonDecoration( | ||||
|                 scheme, | ||||
|                 'Provider Type', | ||||
|                 Icons.cloud_outlined, | ||||
|               ), | ||||
|               isExpanded: true, | ||||
|               items: constants.providerTypeList | ||||
|                   .map<DropdownMenuItem<String>>( | ||||
|                     (item) => DropdownMenuItem<String>( | ||||
|                       value: item, | ||||
|                       child: Text(item), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ], | ||||
|                   ) | ||||
|                   .toList(), | ||||
|               onChanged: (mountType) => _handleChange( | ||||
|                 Provider.of<Auth>(context, listen: false), | ||||
|                 mountType ?? '', | ||||
|               ), | ||||
|             ), | ||||
|  | ||||
|             // Configuration name (only when not Remote) | ||||
|             if (_mountType.isNotEmpty && _mountType != 'Remote') ...[ | ||||
|               const SizedBox(height: constants.padding), | ||||
|               TextField( | ||||
|                 autofocus: true, | ||||
|                 controller: _mountNameController, | ||||
|                 keyboardType: TextInputType.text, | ||||
|                 inputFormatters: [ | ||||
|                   FilteringTextInputFormatter.deny(RegExp(r'\s')), | ||||
|                 ], | ||||
|                 onChanged: (_) => _handleChange( | ||||
|                   Provider.of<Auth>(context, listen: false), | ||||
|                   _mountType, | ||||
|                 ), | ||||
|                 decoration: createCommonDecoration( | ||||
|                   scheme, | ||||
|                   'Configuration Name', | ||||
|                   Icons.drive_file_rename_outline, | ||||
|                 ).copyWith(hintText: 'Enter a unique name'), | ||||
|               ), | ||||
|             ], | ||||
|  | ||||
|             // Settings + Actions | ||||
|             if (_mount != null) ...[ | ||||
|               const SizedBox(height: constants.padding), | ||||
|               Expanded( | ||||
|                 child: Container( | ||||
|                   decoration: BoxDecoration( | ||||
|                     color: scheme.primary.withValues( | ||||
|                       alpha: constants.primaryAlpha, | ||||
|                     ), | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     border: Border.all( | ||||
|                       color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|                       width: 1, | ||||
|                     ), | ||||
|                     gradient: const LinearGradient( | ||||
|                       begin: Alignment.topCenter, | ||||
|                       end: Alignment.bottomCenter, | ||||
|                       colors: constants.gradientColors2, | ||||
|                     ), | ||||
|                     boxShadow: [ | ||||
|                       BoxShadow( | ||||
|                         color: Colors.black.withValues(alpha: 0.22), | ||||
|                         blurRadius: constants.borderRadius, | ||||
|                         offset: Offset(0, constants.borderRadius), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                   child: ClipRRect( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     child: Padding( | ||||
|                       padding: const EdgeInsets.all(constants.padding), | ||||
|                       child: MountSettingsWidget( | ||||
|                         isAdd: true, | ||||
|                         mount: _mount!, | ||||
|                         settings: _settings[_mountType]!, | ||||
|                         showAdvanced: false, | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|               ), | ||||
|               const SizedBox(height: constants.padding), | ||||
|               Row( | ||||
|                 children: [ | ||||
|                   IntrinsicWidth( | ||||
|                     child: ElevatedButton.icon( | ||||
|                       label: const Text('Test'), | ||||
|                       icon: const Icon(Icons.check), | ||||
|                       style: ElevatedButton.styleFrom( | ||||
|                         backgroundColor: scheme.primary.withValues(alpha: 0.18), | ||||
|                         foregroundColor: scheme.primary, | ||||
|                         elevation: 0, | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           side: BorderSide( | ||||
|                             color: scheme.outlineVariant.withValues( | ||||
|                               alpha: 0.15, | ||||
|                             ), | ||||
|                             width: 1, | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       onPressed: _handleProviderTest, | ||||
|                     ), | ||||
|                   ), | ||||
|                   const SizedBox(width: constants.padding), | ||||
|                   IntrinsicWidth( | ||||
|                     child: ElevatedButton.icon( | ||||
|                       label: const Text('Add'), | ||||
|                       icon: const Icon(Icons.add), | ||||
|                       style: ElevatedButton.styleFrom( | ||||
|                         backgroundColor: scheme.primary, | ||||
|                         foregroundColor: scheme.onPrimary, | ||||
|                         elevation: 8, | ||||
|                         shadowColor: scheme.primary.withValues(alpha: 0.45), | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       onPressed: () async { | ||||
|                         final mountList = Provider.of<MountList>( | ||||
|                           context, | ||||
|                           listen: false, | ||||
|                         ); | ||||
|  | ||||
|                         List<String> failed = []; | ||||
|                         if (!validateSettings(_settings[_mountType]!, failed)) { | ||||
|                           for (var key in failed) { | ||||
|                             displayErrorMessage( | ||||
|                               context, | ||||
|                               "Setting '$key' is not valid", | ||||
|                             ); | ||||
|                           } | ||||
|                           return; | ||||
|                         } | ||||
|  | ||||
|                         if (mountList.hasConfigName( | ||||
|                           _mountNameController.text, | ||||
|                         )) { | ||||
|                           return displayErrorMessage( | ||||
|                             context, | ||||
|                             "Configuration name '${_mountNameController.text}' already exists", | ||||
|                           ); | ||||
|                         } | ||||
|  | ||||
|                         if (_mountType == "Sia" || _mountType == "S3") { | ||||
|                           final bucket = | ||||
|                               _settings[_mountType]!["${_mountType}Config"]["Bucket"] | ||||
|                                   as String; | ||||
|                           if (mountList.hasBucketName(_mountType, bucket)) { | ||||
|                             return displayErrorMessage( | ||||
|                               context, | ||||
|                               "Bucket '$bucket' already exists", | ||||
|                             ); | ||||
|                           } | ||||
|                         } | ||||
|  | ||||
|                         final success = await mountList.add( | ||||
|                           _mountType, | ||||
|                           _mountType == 'Remote' | ||||
|                               ? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}' | ||||
|                               : _mountNameController.text, | ||||
|                           _settings[_mountType]!, | ||||
|                         ); | ||||
|  | ||||
|                         if (!success || !context.mounted) return; | ||||
|  | ||||
|                         Navigator.pop(context); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ], | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
| @@ -440,14 +344,10 @@ class _AddMountScreenState extends State<AddMountScreen> { | ||||
|   } | ||||
|  | ||||
|   Future<void> _handleProviderTest() async { | ||||
|     if (_mount == null) { | ||||
|       return; | ||||
|     } | ||||
|     if (_mount == null) return; | ||||
|  | ||||
|     final success = await _mount!.test(); | ||||
|     if (!mounted) { | ||||
|       return; | ||||
|     } | ||||
|     if (!mounted) return; | ||||
|  | ||||
|     displayErrorMessage( | ||||
|       context, | ||||
| @@ -457,9 +357,7 @@ class _AddMountScreenState extends State<AddMountScreen> { | ||||
|  | ||||
|   @override | ||||
|   void setState(VoidCallback fn) { | ||||
|     if (!mounted) { | ||||
|       return; | ||||
|     } | ||||
|     if (!mounted) return; | ||||
|     super.setState(fn); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import 'dart:ui'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| import 'package:repertory/helpers.dart'; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
| @@ -35,22 +36,6 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     InputDecoration decoration(String label, IconData icon) => InputDecoration( | ||||
|       labelText: label, | ||||
|       prefixIcon: Icon(icon), | ||||
|       filled: true, | ||||
|       fillColor: scheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|       border: OutlineInputBorder( | ||||
|         borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|         borderSide: BorderSide.none, | ||||
|       ), | ||||
|       focusedBorder: OutlineInputBorder( | ||||
|         borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|         borderSide: BorderSide(color: scheme.primary, width: 2), | ||||
|       ), | ||||
|       contentPadding: const EdgeInsets.all(constants.paddingSmall), | ||||
|     ); | ||||
|  | ||||
|     Future<void> doLogin(Auth auth) async { | ||||
|       if (!_enabled) { | ||||
|         return; | ||||
| @@ -99,9 +84,8 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) { | ||||
|                 return AuroraSweep(enabled: settings.enableAnimations); | ||||
|               }, | ||||
|               builder: (_, settings, _) => | ||||
|                   AuroraSweep(enabled: settings.enableAnimations), | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
| @@ -246,7 +230,8 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|                                     autofocus: true, | ||||
|                                     controller: _userController, | ||||
|                                     textInputAction: TextInputAction.next, | ||||
|                                     decoration: decoration( | ||||
|                                     decoration: createCommonDecoration( | ||||
|                                       scheme, | ||||
|                                       'Username', | ||||
|                                       Icons.person, | ||||
|                                     ), | ||||
| @@ -267,7 +252,8 @@ class _AuthScreenState extends State<AuthScreen> { | ||||
|                                     obscureText: _obscure, | ||||
|                                     textInputAction: TextInputAction.go, | ||||
|                                     decoration: | ||||
|                                         decoration( | ||||
|                                         createCommonDecoration( | ||||
|                                           scheme, | ||||
|                                           'Password', | ||||
|                                           Icons.lock, | ||||
|                                         ).copyWith( | ||||
|   | ||||
| @@ -1,15 +1,13 @@ | ||||
| // edit_mount_screen.dart | ||||
|  | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'dart:ui'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| import 'package:repertory/helpers.dart'; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/mount.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
| import 'package:repertory/widgets/mount_settings.dart'; | ||||
|  | ||||
| class EditMountScreen extends StatefulWidget { | ||||
| @@ -29,258 +27,200 @@ class _EditMountScreenState extends State<EditMountScreen> { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final textTheme = Theme.of(context).textTheme; | ||||
|  | ||||
|     return Scaffold( | ||||
|       body: SafeArea( | ||||
|         child: Stack( | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: double.infinity, | ||||
|               height: double.infinity, | ||||
|               decoration: const BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: constants.gradientColors, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) { | ||||
|                 return AuroraSweep(enabled: settings.enableAnimations); | ||||
|               }, | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
|                 filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | ||||
|                 child: Container(color: Colors.black.withValues(alpha: 0.06)), | ||||
|               ), | ||||
|             ), | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|     return createCommonScaffold( | ||||
|       Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|         children: [ | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Padding( | ||||
|             padding: const EdgeInsets.symmetric(horizontal: constants.padding), | ||||
|             child: Row( | ||||
|               children: [ | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Padding( | ||||
|                   padding: const EdgeInsets.symmetric( | ||||
|                     horizontal: constants.padding, | ||||
|                 Material( | ||||
|                   color: Colors.transparent, | ||||
|                   child: InkWell( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     onTap: () => Navigator.of(context).pop(), | ||||
|                     child: Ink( | ||||
|                       width: 40, | ||||
|                       height: 40, | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                         boxShadow: [ | ||||
|                           BoxShadow( | ||||
|                             color: Colors.black.withValues(alpha: 0.22), | ||||
|                             blurRadius: constants.borderRadius, | ||||
|                             offset: Offset(0, constants.borderRadius), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                       child: const Icon(Icons.arrow_back), | ||||
|                     ), | ||||
|                   ), | ||||
|                   child: Row( | ||||
|                     children: [ | ||||
|                       Material( | ||||
|                         color: Colors.transparent, | ||||
|                         child: InkWell( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           onTap: () { | ||||
|                             Navigator.of(context).pop(); | ||||
|                           }, | ||||
|                           child: Ink( | ||||
|                             width: 40, | ||||
|                             height: 40, | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                               boxShadow: [ | ||||
|                                 BoxShadow( | ||||
|                                   color: Colors.black.withValues(alpha: 0.22), | ||||
|                                   blurRadius: constants.borderRadius, | ||||
|                                   offset: Offset(0, constants.borderRadius), | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                             child: const Icon(Icons.arrow_back), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       Expanded( | ||||
|                         child: Text( | ||||
|                           widget.title, | ||||
|                           maxLines: 1, | ||||
|                           overflow: TextOverflow.ellipsis, | ||||
|                           style: textTheme.headlineSmall?.copyWith( | ||||
|                             fontWeight: FontWeight.w700, | ||||
|                             letterSpacing: 0.2, | ||||
|                             color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       ClipRRect( | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Text( | ||||
|                     widget.title, | ||||
|                     maxLines: 1, | ||||
|                     overflow: TextOverflow.ellipsis, | ||||
|                     style: textTheme.headlineSmall?.copyWith( | ||||
|                       fontWeight: FontWeight.w700, | ||||
|                       letterSpacing: 0.2, | ||||
|                       color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 ClipRRect( | ||||
|                   borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                   child: BackdropFilter( | ||||
|                     filter: ImageFilter.blur( | ||||
|                       sigmaX: constants.borderRadius, | ||||
|                       sigmaY: constants.borderRadius, | ||||
|                     ), | ||||
|                     child: Container( | ||||
|                       height: 40, | ||||
|                       padding: const EdgeInsets.symmetric(horizontal: 10), | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         child: BackdropFilter( | ||||
|                           filter: ImageFilter.blur( | ||||
|                             sigmaX: constants.borderRadius, | ||||
|                             sigmaY: constants.borderRadius, | ||||
|                           ), | ||||
|                           child: Container( | ||||
|                             height: 40, | ||||
|                             padding: const EdgeInsets.symmetric(horizontal: 10), | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                             child: Row( | ||||
|                               mainAxisSize: MainAxisSize.min, | ||||
|                               children: [ | ||||
|                                 Text( | ||||
|                                   "Advanced", | ||||
|                                   style: textTheme.labelLarge?.copyWith( | ||||
|                                     color: scheme.onSurface.withValues( | ||||
|                                       alpha: 0.90, | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                 ), | ||||
|                                 const SizedBox(width: 6), | ||||
|                                 IconButton( | ||||
|                                   tooltip: _showAdvanced | ||||
|                                       ? 'Hide advanced' | ||||
|                                       : 'Show advanced', | ||||
|                                   icon: Icon( | ||||
|                                     _showAdvanced | ||||
|                                         ? Icons.toggle_on | ||||
|                                         : Icons.toggle_off, | ||||
|                                   ), | ||||
|                                   color: _showAdvanced | ||||
|                                       ? scheme.primary | ||||
|                                       : scheme.onSurface.withValues( | ||||
|                                           alpha: 0.70, | ||||
|                                         ), | ||||
|                                   onPressed: () { | ||||
|                                     setState(() { | ||||
|                                       _showAdvanced = !_showAdvanced; | ||||
|                                     }); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                           ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       ClipRRect( | ||||
|                       child: Row( | ||||
|                         mainAxisSize: MainAxisSize.min, | ||||
|                         children: [ | ||||
|                           Text( | ||||
|                             "Advanced", | ||||
|                             style: textTheme.labelLarge?.copyWith( | ||||
|                               color: scheme.onSurface.withValues(alpha: 0.90), | ||||
|                             ), | ||||
|                           ), | ||||
|                           const SizedBox(width: 6), | ||||
|                           IconButton( | ||||
|                             tooltip: _showAdvanced | ||||
|                                 ? 'Hide advanced' | ||||
|                                 : 'Show advanced', | ||||
|                             icon: Icon( | ||||
|                               _showAdvanced | ||||
|                                   ? Icons.toggle_on | ||||
|                                   : Icons.toggle_off, | ||||
|                             ), | ||||
|                             color: _showAdvanced | ||||
|                                 ? scheme.primary | ||||
|                                 : scheme.onSurface.withValues(alpha: 0.70), | ||||
|                             onPressed: () => | ||||
|                                 setState(() => _showAdvanced = !_showAdvanced), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 ClipRRect( | ||||
|                   borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                   child: BackdropFilter( | ||||
|                     filter: ImageFilter.blur( | ||||
|                       sigmaX: constants.borderRadius, | ||||
|                       sigmaY: constants.borderRadius, | ||||
|                     ), | ||||
|                     child: Container( | ||||
|                       height: 40, | ||||
|                       padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         child: BackdropFilter( | ||||
|                           filter: ImageFilter.blur( | ||||
|                             sigmaX: constants.borderRadius, | ||||
|                             sigmaY: constants.borderRadius, | ||||
|                           ), | ||||
|                           child: Container( | ||||
|                             height: 40, | ||||
|                             padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                             child: Consumer<Auth>( | ||||
|                               builder: (context, auth, _) { | ||||
|                                 return IconButton( | ||||
|                                   tooltip: 'Log out', | ||||
|                                   icon: const Icon(Icons.logout), | ||||
|                                   onPressed: () { | ||||
|                                     auth.logoff(); | ||||
|                                   }, | ||||
|                                 ); | ||||
|                               }, | ||||
|                             ), | ||||
|                           ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                       child: Consumer<Auth>( | ||||
|                         builder: (context, auth, _) => IconButton( | ||||
|                           tooltip: 'Log out', | ||||
|                           icon: const Icon(Icons.logout), | ||||
|                           onPressed: auth.logoff, | ||||
|                         ), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Expanded( | ||||
|             child: Padding( | ||||
|               padding: const EdgeInsets.symmetric( | ||||
|                 horizontal: constants.padding, | ||||
|               ), | ||||
|               child: Material( | ||||
|                 color: Colors.transparent, | ||||
|                 child: Container( | ||||
|                   decoration: BoxDecoration( | ||||
|                     color: scheme.primary.withValues( | ||||
|                       alpha: constants.primaryAlpha, | ||||
|                     ), | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     border: Border.all( | ||||
|                       color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|                       width: 1, | ||||
|                     ), | ||||
|                     gradient: const LinearGradient( | ||||
|                       begin: Alignment.topCenter, | ||||
|                       end: Alignment.bottomCenter, | ||||
|                       colors: constants.gradientColors2, | ||||
|                     ), | ||||
|                     boxShadow: [ | ||||
|                       BoxShadow( | ||||
|                         color: Colors.black.withValues(alpha: 0.22), | ||||
|                         blurRadius: constants.borderRadius, | ||||
|                         offset: Offset(0, constants.borderRadius), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Padding( | ||||
|                     padding: const EdgeInsets.symmetric( | ||||
|                       horizontal: constants.padding, | ||||
|                     ), | ||||
|                     child: Material( | ||||
|                       color: Colors.transparent, | ||||
|                       child: Container( | ||||
|                         decoration: BoxDecoration( | ||||
|                           color: scheme.surface.withValues(alpha: 0.40), | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           border: Border.all( | ||||
|                             color: scheme.outlineVariant.withValues( | ||||
|                               alpha: 0.06, | ||||
|                             ), | ||||
|                             width: 1, | ||||
|                           ), | ||||
|                           gradient: const LinearGradient( | ||||
|                             begin: Alignment.topCenter, | ||||
|                             end: Alignment.bottomCenter, | ||||
|                             colors: constants.gradientColors2, | ||||
|                           ), | ||||
|                           boxShadow: [ | ||||
|                             BoxShadow( | ||||
|                               color: Colors.black.withValues(alpha: 0.22), | ||||
|                               blurRadius: constants.borderRadius, | ||||
|                               offset: Offset(0, constants.borderRadius), | ||||
|                             ), | ||||
|                           ], | ||||
|                         ), | ||||
|                         child: ClipRRect( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           child: MountSettingsWidget( | ||||
|                             mount: widget.mount, | ||||
|                             settings: jsonDecode( | ||||
|                               jsonEncode(widget.mount.mountConfig.settings), | ||||
|                             ), | ||||
|                             showAdvanced: _showAdvanced, | ||||
|                           ), | ||||
|                   child: ClipRRect( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     child: Padding( | ||||
|                       padding: const EdgeInsets.all(constants.padding), | ||||
|                       child: MountSettingsWidget( | ||||
|                         mount: widget.mount, | ||||
|                         settings: jsonDecode( | ||||
|                           jsonEncode(widget.mount.mountConfig.settings), | ||||
|                         ), | ||||
|                         showAdvanced: _showAdvanced, | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|  | ||||
|                 const SizedBox(height: constants.padding), | ||||
|               ], | ||||
|               ), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|           ), | ||||
|  | ||||
|           const SizedBox(height: constants.padding), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void setState(VoidCallback fn) { | ||||
|     if (!mounted) { | ||||
|       return; | ||||
|     } | ||||
|     if (!mounted) return; | ||||
|     super.setState(fn); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -9,8 +9,6 @@ import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| import 'package:repertory/helpers.dart'; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
| import 'package:repertory/widgets/ui_settings.dart'; | ||||
|  | ||||
| class EditSettingsScreen extends StatefulWidget { | ||||
| @@ -27,198 +25,154 @@ class _EditSettingsScreenState extends State<EditSettingsScreen> { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final textTheme = Theme.of(context).textTheme; | ||||
|  | ||||
|     return Scaffold( | ||||
|       body: SafeArea( | ||||
|         child: Stack( | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: double.infinity, | ||||
|               height: double.infinity, | ||||
|               decoration: const BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: constants.gradientColors, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) { | ||||
|                 return AuroraSweep(enabled: settings.enableAnimations); | ||||
|               }, | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
|                 filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | ||||
|                 child: Container(color: Colors.black.withValues(alpha: 0.06)), | ||||
|               ), | ||||
|             ), | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|     return createCommonScaffold( | ||||
|       Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|         children: [ | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Padding( | ||||
|             padding: const EdgeInsets.symmetric(horizontal: constants.padding), | ||||
|             child: Row( | ||||
|               children: [ | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Padding( | ||||
|                   padding: const EdgeInsets.symmetric( | ||||
|                     horizontal: constants.padding, | ||||
|                   ), | ||||
|                   child: Row( | ||||
|                     children: [ | ||||
|                       Material( | ||||
|                         color: Colors.transparent, | ||||
|                         child: InkWell( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           onTap: () { | ||||
|                             Navigator.of(context).pop(); | ||||
|                           }, | ||||
|                           child: Ink( | ||||
|                             width: 40, | ||||
|                             height: 40, | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                               boxShadow: [ | ||||
|                                 BoxShadow( | ||||
|                                   color: Colors.black.withValues(alpha: 0.22), | ||||
|                                   blurRadius: constants.borderRadius, | ||||
|                                   offset: Offset(0, constants.borderRadius), | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                             child: const Icon(Icons.arrow_back), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       Expanded( | ||||
|                         child: Text( | ||||
|                           widget.title, | ||||
|                           maxLines: 1, | ||||
|                           overflow: TextOverflow.ellipsis, | ||||
|                           style: textTheme.headlineSmall?.copyWith( | ||||
|                             fontWeight: FontWeight.w700, | ||||
|                             letterSpacing: 0.2, | ||||
|                             color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       ClipRRect( | ||||
|                 Material( | ||||
|                   color: Colors.transparent, | ||||
|                   child: InkWell( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     onTap: () { | ||||
|                       Navigator.of(context).pop(); | ||||
|                     }, | ||||
|                     child: Ink( | ||||
|                       width: 40, | ||||
|                       height: 40, | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         child: BackdropFilter( | ||||
|                           filter: ImageFilter.blur( | ||||
|                             sigmaX: constants.borderRadius, | ||||
|                             sigmaY: constants.borderRadius, | ||||
|                           ), | ||||
|                           child: Container( | ||||
|                             height: 40, | ||||
|                             padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                             child: Consumer<Auth>( | ||||
|                               builder: (context, auth, _) { | ||||
|                                 return IconButton( | ||||
|                                   tooltip: 'Log out', | ||||
|                                   icon: const Icon(Icons.logout), | ||||
|                                   onPressed: () { | ||||
|                                     auth.logoff(); | ||||
|                                   }, | ||||
|                                 ); | ||||
|                               }, | ||||
|                             ), | ||||
|                           ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                         boxShadow: [ | ||||
|                           BoxShadow( | ||||
|                             color: Colors.black.withValues(alpha: 0.22), | ||||
|                             blurRadius: constants.borderRadius, | ||||
|                             offset: Offset(0, constants.borderRadius), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                       child: const Icon(Icons.arrow_back), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Text( | ||||
|                     widget.title, | ||||
|                     maxLines: 1, | ||||
|                     overflow: TextOverflow.ellipsis, | ||||
|                     style: textTheme.headlineSmall?.copyWith( | ||||
|                       fontWeight: FontWeight.w700, | ||||
|                       letterSpacing: 0.2, | ||||
|                       color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 ClipRRect( | ||||
|                   borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                   child: BackdropFilter( | ||||
|                     filter: ImageFilter.blur( | ||||
|                       sigmaX: constants.borderRadius, | ||||
|                       sigmaY: constants.borderRadius, | ||||
|                     ), | ||||
|                     child: Container( | ||||
|                       height: 40, | ||||
|                       padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                       child: Consumer<Auth>( | ||||
|                         builder: (context, auth, _) { | ||||
|                           return IconButton( | ||||
|                             tooltip: 'Log out', | ||||
|                             icon: const Icon(Icons.logout), | ||||
|                             onPressed: () { | ||||
|                               auth.logoff(); | ||||
|                             }, | ||||
|                           ); | ||||
|                         }, | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Expanded( | ||||
|             child: Padding( | ||||
|               padding: const EdgeInsets.symmetric( | ||||
|                 horizontal: constants.padding, | ||||
|               ), | ||||
|               child: Material( | ||||
|                 color: Colors.transparent, | ||||
|                 child: Container( | ||||
|                   decoration: BoxDecoration( | ||||
|                     color: scheme.surface.withValues(alpha: 0.40), | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     border: Border.all( | ||||
|                       color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|                       width: 1, | ||||
|                     ), | ||||
|                     gradient: const LinearGradient( | ||||
|                       begin: Alignment.topCenter, | ||||
|                       end: Alignment.bottomCenter, | ||||
|                       colors: constants.gradientColors2, | ||||
|                     ), | ||||
|                     boxShadow: [ | ||||
|                       BoxShadow( | ||||
|                         color: Colors.black.withValues(alpha: 0.22), | ||||
|                         blurRadius: constants.borderRadius, | ||||
|                         offset: Offset(0, constants.borderRadius), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Padding( | ||||
|                     padding: const EdgeInsets.symmetric( | ||||
|                       horizontal: constants.padding, | ||||
|                     ), | ||||
|                     child: Material( | ||||
|                       color: Colors.transparent, | ||||
|                       child: Container( | ||||
|                         decoration: BoxDecoration( | ||||
|                           color: scheme.surface.withValues(alpha: 0.40), | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           border: Border.all( | ||||
|                             color: scheme.outlineVariant.withValues( | ||||
|                               alpha: 0.06, | ||||
|                             ), | ||||
|                             width: 1, | ||||
|                           ), | ||||
|                           gradient: const LinearGradient( | ||||
|                             begin: Alignment.topCenter, | ||||
|                             end: Alignment.bottomCenter, | ||||
|                             colors: constants.gradientColors2, | ||||
|                           ), | ||||
|                           boxShadow: [ | ||||
|                             BoxShadow( | ||||
|                               color: Colors.black.withValues(alpha: 0.22), | ||||
|                               blurRadius: constants.borderRadius, | ||||
|                               offset: Offset(0, constants.borderRadius), | ||||
|                             ), | ||||
|                           ], | ||||
|                         ), | ||||
|                         child: ClipRRect( | ||||
|                           borderRadius: BorderRadius.circular( | ||||
|                             constants.borderRadius, | ||||
|                           ), | ||||
|                           child: FutureBuilder<Map<String, dynamic>>( | ||||
|                             future: _grabSettings(), | ||||
|                             initialData: const <String, dynamic>{}, | ||||
|                             builder: (context, snapshot) { | ||||
|                               if (!snapshot.hasData) { | ||||
|                                 return const Center( | ||||
|                                   child: CircularProgressIndicator(), | ||||
|                                 ); | ||||
|                               } | ||||
|                   child: ClipRRect( | ||||
|                     borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                     child: FutureBuilder<Map<String, dynamic>>( | ||||
|                       future: _grabSettings(), | ||||
|                       initialData: const <String, dynamic>{}, | ||||
|                       builder: (context, snapshot) { | ||||
|                         if (!snapshot.hasData) { | ||||
|                           return const Center( | ||||
|                             child: CircularProgressIndicator(), | ||||
|                           ); | ||||
|                         } | ||||
|  | ||||
|                               return UISettingsWidget( | ||||
|                                 origSettings: jsonDecode( | ||||
|                                   jsonEncode(snapshot.requireData), | ||||
|                                 ), | ||||
|                                 settings: snapshot.requireData, | ||||
|                                 showAdvanced: false, | ||||
|                               ); | ||||
|                             }, | ||||
|                         return UISettingsWidget( | ||||
|                           origSettings: jsonDecode( | ||||
|                             jsonEncode(snapshot.requireData), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                           settings: snapshot.requireData, | ||||
|                           showAdvanced: false, | ||||
|                         ); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: constants.padding), | ||||
|               ], | ||||
|               ), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|           ), | ||||
|           const SizedBox(height: constants.padding), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -4,10 +4,10 @@ import 'dart:ui'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:repertory/constants.dart' as constants; | ||||
| import 'package:repertory/helpers.dart'; | ||||
| import 'package:repertory/models/auth.dart'; | ||||
| import 'package:repertory/models/settings.dart'; | ||||
| import 'package:repertory/widgets/mount_list_widget.dart'; | ||||
| import 'package:repertory/widgets/aurora_sweep.dart'; | ||||
|  | ||||
| class HomeScreen extends StatefulWidget { | ||||
|   final String title; | ||||
| @@ -23,156 +23,119 @@ class _HomeScreeState extends State<HomeScreen> { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final textTheme = Theme.of(context).textTheme; | ||||
|  | ||||
|     return Scaffold( | ||||
|       body: SafeArea( | ||||
|         child: Stack( | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: double.infinity, | ||||
|               height: double.infinity, | ||||
|               decoration: const BoxDecoration( | ||||
|                 gradient: LinearGradient( | ||||
|                   begin: Alignment.topLeft, | ||||
|                   end: Alignment.bottomRight, | ||||
|                   colors: constants.gradientColors, | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             Consumer<Settings>( | ||||
|               builder: (_, settings, _) { | ||||
|                 return AuroraSweep(enabled: settings.enableAnimations); | ||||
|               }, | ||||
|             ), | ||||
|             Positioned.fill( | ||||
|               child: BackdropFilter( | ||||
|                 filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | ||||
|                 child: Container(color: Colors.black.withValues(alpha: 0.06)), | ||||
|               ), | ||||
|             ), | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|     return createCommonScaffold( | ||||
|       Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|         children: [ | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Padding( | ||||
|             padding: const EdgeInsets.symmetric(horizontal: constants.padding), | ||||
|             child: Row( | ||||
|               children: [ | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Padding( | ||||
|                   padding: const EdgeInsets.symmetric( | ||||
|                     horizontal: constants.padding, | ||||
|                 SizedBox( | ||||
|                   width: 40, | ||||
|                   height: 40, | ||||
|                   child: Image.asset( | ||||
|                     'assets/images/repertory.png', | ||||
|                     fit: BoxFit.contain, | ||||
|                     errorBuilder: (_, _, _) { | ||||
|                       return Icon( | ||||
|                         Icons.folder, | ||||
|                         color: scheme.primary, | ||||
|                         size: 32, | ||||
|                       ); | ||||
|                     }, | ||||
|                   ), | ||||
|                   child: Row( | ||||
|                     children: [ | ||||
|                       SizedBox( | ||||
|                         width: 48, | ||||
|                         height: 48, | ||||
|                         child: Image.asset( | ||||
|                           'assets/images/repertory.png', | ||||
|                           fit: BoxFit.contain, | ||||
|                           errorBuilder: (_, _, _) { | ||||
|                             return Icon( | ||||
|                               Icons.folder, | ||||
|                               color: scheme.primary, | ||||
|                               size: 40, | ||||
|                             ); | ||||
|                           }, | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       Expanded( | ||||
|                         child: Text( | ||||
|                           widget.title, | ||||
|                           maxLines: 1, | ||||
|                           overflow: TextOverflow.ellipsis, | ||||
|                           style: textTheme.headlineSmall?.copyWith( | ||||
|                             fontWeight: FontWeight.w700, | ||||
|                             letterSpacing: 0.2, | ||||
|                             color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox(width: constants.padding), | ||||
|                       ClipRRect( | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Text( | ||||
|                     widget.title, | ||||
|                     maxLines: 1, | ||||
|                     overflow: TextOverflow.ellipsis, | ||||
|                     style: textTheme.headlineSmall?.copyWith( | ||||
|                       fontWeight: FontWeight.w700, | ||||
|                       letterSpacing: 0.2, | ||||
|                       color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(width: constants.padding), | ||||
|                 ClipRRect( | ||||
|                   borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                   child: BackdropFilter( | ||||
|                     filter: ImageFilter.blur( | ||||
|                       sigmaX: constants.borderRadius, | ||||
|                       sigmaY: constants.borderRadius, | ||||
|                     ), | ||||
|                     child: Container( | ||||
|                       height: 40, | ||||
|                       padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                       decoration: BoxDecoration( | ||||
|                         color: scheme.surface.withValues(alpha: 0.40), | ||||
|                         borderRadius: BorderRadius.circular( | ||||
|                           constants.borderRadius, | ||||
|                         ), | ||||
|                         child: BackdropFilter( | ||||
|                           filter: ImageFilter.blur( | ||||
|                             sigmaX: constants.borderRadius, | ||||
|                             sigmaY: constants.borderRadius, | ||||
|                           ), | ||||
|                           child: Container( | ||||
|                             height: 40, | ||||
|                             padding: const EdgeInsets.symmetric(horizontal: 6), | ||||
|                             decoration: BoxDecoration( | ||||
|                               color: scheme.surface.withValues(alpha: 0.40), | ||||
|                               borderRadius: BorderRadius.circular( | ||||
|                                 constants.borderRadius, | ||||
|                               ), | ||||
|                               border: Border.all( | ||||
|                                 color: scheme.outlineVariant.withValues( | ||||
|                                   alpha: 0.08, | ||||
|                                 ), | ||||
|                                 width: 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                             child: Row( | ||||
|                               children: [ | ||||
|                                 const Text("Auto-start"), | ||||
|                                 Consumer<Settings>( | ||||
|                                   builder: (context, settings, _) { | ||||
|                                     return IconButton( | ||||
|                                       icon: Icon( | ||||
|                                         settings.autoStart | ||||
|                                             ? Icons.toggle_on | ||||
|                                             : Icons.toggle_off, | ||||
|                                       ), | ||||
|                                       color: settings.autoStart | ||||
|                                           ? scheme.primary | ||||
|                                           : scheme.onSurface.withValues( | ||||
|                                               alpha: 0.70, | ||||
|                                             ), | ||||
|                                       onPressed: () => settings.setAutoStart( | ||||
|                                         !settings.autoStart, | ||||
|                                       ), | ||||
|                                     ); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                                 IconButton( | ||||
|                                   tooltip: 'Settings', | ||||
|                                   icon: const Icon(Icons.settings), | ||||
|                                   onPressed: () { | ||||
|                                     Navigator.pushNamed(context, '/settings'); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                                 Consumer<Auth>( | ||||
|                                   builder: (context, auth, _) { | ||||
|                                     return IconButton( | ||||
|                                       tooltip: 'Log out', | ||||
|                                       icon: const Icon(Icons.logout), | ||||
|                                       onPressed: () { | ||||
|                                         auth.logoff(); | ||||
|                                       }, | ||||
|                                     ); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                           ), | ||||
|                         border: Border.all( | ||||
|                           color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|                           width: 1, | ||||
|                         ), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: constants.padding), | ||||
|                 Expanded( | ||||
|                   child: Padding( | ||||
|                     padding: const EdgeInsets.symmetric( | ||||
|                       horizontal: constants.padding, | ||||
|                       child: Row( | ||||
|                         children: [ | ||||
|                           const Text("Auto-start"), | ||||
|                           Consumer<Settings>( | ||||
|                             builder: (context, settings, _) { | ||||
|                               return IconButton( | ||||
|                                 icon: Icon( | ||||
|                                   settings.autoStart | ||||
|                                       ? Icons.toggle_on | ||||
|                                       : Icons.toggle_off, | ||||
|                                 ), | ||||
|                                 color: settings.autoStart | ||||
|                                     ? scheme.primary | ||||
|                                     : scheme.onSurface.withValues(alpha: 0.70), | ||||
|                                 onPressed: () => | ||||
|                                     settings.setAutoStart(!settings.autoStart), | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           IconButton( | ||||
|                             tooltip: 'Settings', | ||||
|                             icon: const Icon(Icons.settings), | ||||
|                             onPressed: () { | ||||
|                               Navigator.pushNamed(context, '/settings'); | ||||
|                             }, | ||||
|                           ), | ||||
|                           Consumer<Auth>( | ||||
|                             builder: (context, auth, _) { | ||||
|                               return IconButton( | ||||
|                                 tooltip: 'Log out', | ||||
|                                 icon: const Icon(Icons.logout), | ||||
|                                 onPressed: () { | ||||
|                                   auth.logoff(); | ||||
|                                 }, | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                     child: const MountListWidget(), | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|           ), | ||||
|           const SizedBox(height: constants.padding), | ||||
|           Expanded( | ||||
|             child: Padding( | ||||
|               padding: const EdgeInsets.symmetric( | ||||
|                 horizontal: constants.padding, | ||||
|               ), | ||||
|               child: const MountListWidget(), | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|       floatingActionButton: Padding( | ||||
|         padding: const EdgeInsets.all(constants.padding), | ||||
|   | ||||
| @@ -39,10 +39,11 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> { | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     // Theme SettingsList to your glass aesthetic (consistent with UISettingsWidget) | ||||
|     final theme = SettingsThemeData( | ||||
|       settingsListBackground: Colors.transparent, | ||||
|       settingsSectionBackground: scheme.surface.withValues(alpha: 0.30), | ||||
|       settingsSectionBackground: scheme.primary.withValues( | ||||
|         alpha: constants.primaryAlpha, | ||||
|       ), | ||||
|       titleTextColor: scheme.onSurface.withValues(alpha: 0.96), | ||||
|       trailingTextColor: scheme.onSurface.withValues(alpha: 0.80), | ||||
|       tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68), | ||||
| @@ -394,6 +395,10 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> { | ||||
|       } | ||||
|     }); | ||||
|  | ||||
|     const sectionMargin = EdgeInsetsDirectional.symmetric( | ||||
|       vertical: constants.padding / 2, | ||||
|     ); | ||||
|  | ||||
|     return SettingsList( | ||||
|       shrinkWrap: false, | ||||
|       platform: DevicePlatform.device, | ||||
| @@ -402,38 +407,48 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> { | ||||
|       sections: [ | ||||
|         if (encryptConfigSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Encrypt Config'), | ||||
|             tiles: encryptConfigSettings, | ||||
|           ), | ||||
|         if (hostConfigSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Host Config'), | ||||
|             tiles: hostConfigSettings, | ||||
|           ), | ||||
|         if (remoteConfigSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Remote Config'), | ||||
|             tiles: remoteConfigSettings, | ||||
|           ), | ||||
|         if (s3ConfigSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('S3 Config'), | ||||
|             tiles: s3ConfigSettings, | ||||
|           ), | ||||
|         if (siaConfigSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Sia Config'), | ||||
|             tiles: siaConfigSettings, | ||||
|           ), | ||||
|         if (remoteMountSettings.isNotEmpty) | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Remote Mount'), | ||||
|             tiles: (widget.settings['RemoteMount']['Enable'] as bool) | ||||
|                 ? remoteMountSettings | ||||
|                 : [remoteMountSettings[0]], | ||||
|           ), | ||||
|         if (commonSettings.isNotEmpty) | ||||
|           SettingsSection(title: const Text('Settings'), tiles: commonSettings), | ||||
|           SettingsSection( | ||||
|             margin: sectionMargin, | ||||
|             title: const Text('Settings'), | ||||
|             tiles: commonSettings, | ||||
|           ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| @@ -1017,24 +1032,18 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> { | ||||
|               }); | ||||
|               return; | ||||
|             } | ||||
|  | ||||
|             mount.setValue(key, value); | ||||
|           }); | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void setState(VoidCallback fn) { | ||||
|     if (!mounted) { | ||||
|       return; | ||||
|     } | ||||
|     if (widget.onChanged != null) { | ||||
|       widget.onChanged!(); | ||||
|     } | ||||
|     if (!mounted) return; | ||||
|     if (widget.onChanged != null) widget.onChanged!(); | ||||
|     super.setState(fn); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -272,7 +272,6 @@ class _MountWidgetState extends State<MountWidget> { | ||||
|       return location; | ||||
|     } | ||||
|  | ||||
|     // ignore: use_build_context_synchronously | ||||
|     return editMountLocation(context, await mount.getAvailableLocations()); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -39,18 +39,17 @@ class _UISettingsWidgetState extends State<UISettingsWidget> { | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     // Theme the SettingsList to align with your glass look | ||||
|     final theme = SettingsThemeData( | ||||
|       settingsListBackground: Colors.transparent, | ||||
|       tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68), | ||||
|       settingsSectionBackground: scheme.surface.withValues( | ||||
|         alpha: 0.30, | ||||
|       ), // slight glass base | ||||
|       tileHighlightColor: scheme.primary.withValues(alpha: 0.08), | ||||
|       settingsSectionBackground: scheme.primary.withValues( | ||||
|         alpha: constants.primaryAlpha, | ||||
|       ), | ||||
|       titleTextColor: scheme.onSurface.withValues(alpha: 0.96), | ||||
|       trailingTextColor: scheme.onSurface.withValues(alpha: 0.80), | ||||
|       tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68), | ||||
|       leadingIconsColor: scheme.onSurface.withValues(alpha: 0.90), | ||||
|       dividerColor: scheme.outlineVariant.withValues(alpha: 0.10), | ||||
|       tileHighlightColor: scheme.primary.withValues(alpha: 0.08), | ||||
|     ); | ||||
|  | ||||
|     List<SettingsTile> commonSettings = []; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user