[ui] UI theme should match repertory blue #61
This commit is contained in:
		| @@ -22,6 +22,7 @@ const protocolTypeList = ['http', 'https']; | ||||
| const providerTypeList = ['Encrypt', 'Remote', 'S3', 'Sia']; | ||||
| const ringBufferSizeList = ['128', '256', '512', '1024', '2048']; | ||||
| const primaryAlpha = 0.15; | ||||
| const secondaryAlpha = 0.50; | ||||
| const surfaceContainerLowDark = Color(0xFF292A2D); | ||||
| const surfaceDark = Color(0xFF202124); | ||||
|  | ||||
|   | ||||
| @@ -16,7 +16,9 @@ Future doShowDialog(BuildContext context, Widget child) => showDialog( | ||||
|     return Theme( | ||||
|       data: theme.copyWith( | ||||
|         dialogTheme: DialogThemeData( | ||||
|           backgroundColor: scheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|           backgroundColor: scheme.primary.withValues( | ||||
|             alpha: constants.primaryAlpha, | ||||
|           ), | ||||
|           surfaceTintColor: Colors.transparent, | ||||
|           shape: RoundedRectangleBorder( | ||||
|             borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
| @@ -364,11 +366,15 @@ Map<String, dynamic> getChanged( | ||||
| } | ||||
|  | ||||
| Future<String?> editMountLocation( | ||||
|   context, | ||||
|   BuildContext context, | ||||
|   List<String> available, { | ||||
|   bool allowEmpty = false, | ||||
|   String? location, | ||||
| }) async { | ||||
|   if (!context.mounted) { | ||||
|     return location; | ||||
|   } | ||||
|  | ||||
|   String? currentLocation = location; | ||||
|   final controller = TextEditingController(text: currentLocation); | ||||
|   return await doShowDialog( | ||||
|   | ||||
| @@ -179,17 +179,16 @@ class _HomeScreeState extends State<HomeScreen> { | ||||
|         child: Hero( | ||||
|           tag: 'add_mount_fab', | ||||
|           child: Material( | ||||
|             color: Colors.transparent, | ||||
|             color: scheme.primary.withValues(alpha: constants.secondaryAlpha), | ||||
|             elevation: 12, | ||||
|             shape: RoundedRectangleBorder( | ||||
|               borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|             ), | ||||
|             child: Ink( | ||||
|               decoration: BoxDecoration( | ||||
|                 color: scheme.primary.withValues(alpha: 0.10), | ||||
|                 borderRadius: BorderRadius.circular(constants.borderRadius), | ||||
|                 border: Border.all( | ||||
|                   color: scheme.outlineVariant.withValues(alpha: 0.15), | ||||
|                   color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|                   width: 1, | ||||
|                 ), | ||||
|                 gradient: const LinearGradient( | ||||
|   | ||||
| @@ -24,231 +24,255 @@ class _MountWidgetState extends State<MountWidget> { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final textTheme = Theme.of(context).textTheme; | ||||
|  | ||||
|     return Card( | ||||
|       margin: const EdgeInsets.all(0.0), | ||||
|       elevation: 12, | ||||
|       color: scheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|       shape: RoundedRectangleBorder( | ||||
|         borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|         side: BorderSide( | ||||
|           color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|           width: 1, | ||||
|         ), | ||||
|       ), | ||||
|       child: Container( | ||||
|         decoration: BoxDecoration( | ||||
|     final titleStyle = textTheme.titleMedium?.copyWith( | ||||
|       fontWeight: FontWeight.w700, | ||||
|       letterSpacing: 0.15, | ||||
|       color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|     ); | ||||
|     final subStyle = textTheme.bodyMedium?.copyWith( | ||||
|       color: scheme.onSurface.withValues(alpha: 0.78), | ||||
|     ); | ||||
|     final pathStyle = textTheme.bodyMedium?.copyWith( | ||||
|       color: scheme.onSurface.withValues(alpha: 0.68), | ||||
|     ); | ||||
|  | ||||
|     return ConstrainedBox( | ||||
|       constraints: const BoxConstraints(minHeight: 120), | ||||
|       child: Card( | ||||
|         margin: const EdgeInsets.all(0.0), | ||||
|         elevation: 12, | ||||
|         color: scheme.primary.withValues(alpha: constants.primaryAlpha), | ||||
|         shape: RoundedRectangleBorder( | ||||
|           borderRadius: BorderRadius.circular(constants.borderRadiusSmall), | ||||
|           gradient: const LinearGradient( | ||||
|             begin: Alignment.topCenter, | ||||
|             end: Alignment.bottomCenter, | ||||
|             colors: constants.gradientColors2, | ||||
|           side: BorderSide( | ||||
|             color: scheme.outlineVariant.withValues(alpha: 0.06), | ||||
|             width: 1, | ||||
|           ), | ||||
|           boxShadow: [ | ||||
|             BoxShadow( | ||||
|               color: Colors.black.withValues(alpha: 0.22), | ||||
|               blurRadius: constants.borderRadiusSmall, | ||||
|               offset: const Offset(0, constants.borderRadiusSmall), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|         child: Consumer<Mount>( | ||||
|           builder: (context, Mount mount, _) { | ||||
|             final titleStyle = textTheme.titleMedium?.copyWith( | ||||
|               fontWeight: FontWeight.w700, | ||||
|               letterSpacing: 0.15, | ||||
|               color: scheme.onSurface.withValues(alpha: 0.96), | ||||
|             ); | ||||
|             final subStyle = textTheme.bodyMedium?.copyWith( | ||||
|               color: scheme.onSurface.withValues(alpha: 0.78), | ||||
|             ); | ||||
|             final pathStyle = textTheme.bodySmall?.copyWith( | ||||
|               color: scheme.onSurface.withValues(alpha: 0.68), | ||||
|             ); | ||||
|  | ||||
|             final nameText = SelectableText( | ||||
|               formatMountName(mount.type, mount.name), | ||||
|               style: subStyle, | ||||
|             ); | ||||
|  | ||||
|             return ListTile( | ||||
|               isThreeLine: true, | ||||
|               contentPadding: const EdgeInsets.all(constants.paddingSmall), | ||||
|               leading: Container( | ||||
|                 width: 46, | ||||
|                 height: 46, | ||||
|         child: Stack( | ||||
|           children: [ | ||||
|             Positioned.fill( | ||||
|               child: Container( | ||||
|                 decoration: BoxDecoration( | ||||
|                   color: scheme.primary.withValues(alpha: 0.12), | ||||
|                   borderRadius: BorderRadius.circular( | ||||
|                     constants.borderRadiusSmall, | ||||
|                   ), | ||||
|                   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.24), | ||||
|                       color: Colors.black.withValues(alpha: 0.22), | ||||
|                       blurRadius: constants.borderRadiusSmall, | ||||
|                       offset: const Offset(0, 5), | ||||
|                       offset: const Offset(0, constants.borderRadiusSmall), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|                 child: IconButton( | ||||
|                   tooltip: 'Edit settings', | ||||
|                   icon: Icon( | ||||
|                     Icons.settings, | ||||
|                     color: scheme.onSurface.withValues(alpha: 0.92), | ||||
|                     size: 22, | ||||
|                   ), | ||||
|                   onPressed: () { | ||||
|                     Navigator.pushNamed(context, '/edit', arguments: mount); | ||||
|                   }, | ||||
|               ), | ||||
|             ), | ||||
|             Padding( | ||||
|               padding: const EdgeInsets.all(constants.padding), | ||||
|               child: Consumer<Mount>( | ||||
|                 builder: (context, Mount mount, _) { | ||||
|                   return Column( | ||||
|                     mainAxisSize: MainAxisSize.min, | ||||
|                     crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                     children: [ | ||||
|                       Row( | ||||
|                         crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                         children: [ | ||||
|                           _GearBadge( | ||||
|                             onTap: () { | ||||
|                               Navigator.pushNamed( | ||||
|                                 context, | ||||
|                                 '/edit', | ||||
|                                 arguments: mount, | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           const SizedBox(width: constants.padding), | ||||
|                           Expanded( | ||||
|                             child: Column( | ||||
|                               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                               children: [ | ||||
|                                 SelectableText( | ||||
|                                   mount.provider, | ||||
|                                   style: titleStyle, | ||||
|                                 ), | ||||
|                                 SelectableText( | ||||
|                                   '${_formatType(mount.type)} • ${formatMountName(mount.type, mount.name)}', | ||||
|                                   style: subStyle, | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                           ), | ||||
|                           _ToggleFramed( | ||||
|                             mounted: mount.mounted, | ||||
|                             onPressed: _createMountHandler(context, mount), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                       const SizedBox(height: constants.padding), | ||||
|                       Row( | ||||
|                         children: [ | ||||
|                           Expanded( | ||||
|                             child: SelectableText( | ||||
|                               _prettyPath(mount), | ||||
|                               style: pathStyle, | ||||
|                             ), | ||||
|                           ), | ||||
|                           const SizedBox(width: constants.padding), | ||||
|                           _EditPathButton( | ||||
|                             enabled: mount.mounted == false, | ||||
|                             onPressed: () async { | ||||
|                               if (!_editEnabled) { | ||||
|                                 return; | ||||
|                               } | ||||
|                               setState(() { | ||||
|                                 _editEnabled = false; | ||||
|                               }); | ||||
|  | ||||
|                               final available = await mount | ||||
|                                   .getAvailableLocations(); | ||||
|  | ||||
|                               if (!mounted) { | ||||
|                                 setState(() { | ||||
|                                   _editEnabled = true; | ||||
|                                 }); | ||||
|                                 return; | ||||
|                               } | ||||
|  | ||||
|                               if (!context.mounted) { | ||||
|                                 return; | ||||
|                               } | ||||
|  | ||||
|                               final location = await editMountLocation( | ||||
|                                 context, | ||||
|                                 available, | ||||
|                                 location: mount.path, | ||||
|                               ); | ||||
|                               if (location != null) { | ||||
|                                 await mount.setMountLocation(location); | ||||
|                               } | ||||
|  | ||||
|                               if (mounted) { | ||||
|                                 setState(() { | ||||
|                                   _editEnabled = true; | ||||
|                                 }); | ||||
|                               } | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ], | ||||
|                   ); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|             Positioned( | ||||
|               left: constants.padding, | ||||
|               right: constants.padding, | ||||
|               bottom: constants.padding - 1, | ||||
|               child: Container( | ||||
|                 height: 1, | ||||
|                 decoration: BoxDecoration( | ||||
|                   color: Theme.of( | ||||
|                     context, | ||||
|                   ).colorScheme.outlineVariant.withValues(alpha: 0.15), | ||||
|                   borderRadius: BorderRadius.circular(1), | ||||
|                 ), | ||||
|               ), | ||||
|               title: SelectableText(mount.provider, style: titleStyle), | ||||
|               subtitle: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: [ | ||||
|                   nameText, | ||||
|                   const SizedBox(height: 3), | ||||
|                   SelectableText( | ||||
|                     mount.path.isEmpty && mount.mounted == null | ||||
|                         ? 'loading...' | ||||
|                         : mount.path.isEmpty | ||||
|                         ? '<mount location not set>' | ||||
|                         : mount.path, | ||||
|                     style: pathStyle, | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|               trailing: Row( | ||||
|                 mainAxisAlignment: MainAxisAlignment.end, | ||||
|                 mainAxisSize: MainAxisSize.min, | ||||
|                 children: [ | ||||
|                   if (mount.mounted != null && !mount.mounted!) | ||||
|                     IconButton( | ||||
|                       icon: const Icon(Icons.edit), | ||||
|                       color: scheme.onSurface.withValues(alpha: 0.70), | ||||
|                       tooltip: 'Edit mount location', | ||||
|                       onPressed: () async { | ||||
|                         setState(() { | ||||
|                           _editEnabled = false; | ||||
|                         }); | ||||
|                         final available = await mount.getAvailableLocations(); | ||||
|                         if (context.mounted) { | ||||
|                           final location = await editMountLocation( | ||||
|                             context, | ||||
|                             available, | ||||
|                             location: mount.path, | ||||
|                           ); | ||||
|                           if (location != null) { | ||||
|                             await mount.setMountLocation(location); | ||||
|                           } | ||||
|                         } | ||||
|                         setState(() { | ||||
|                           _editEnabled = true; | ||||
|                         }); | ||||
|                       }, | ||||
|                     ), | ||||
|                   IconButton( | ||||
|                     iconSize: 32, | ||||
|                     splashRadius: 26, | ||||
|                     icon: Icon( | ||||
|                       mount.mounted == null | ||||
|                           ? Icons.hourglass_top | ||||
|                           : mount.mounted! | ||||
|                           ? Icons.toggle_on | ||||
|                           : Icons.toggle_off, | ||||
|                     ), | ||||
|                     color: mount.mounted ?? false | ||||
|                         ? scheme.primary | ||||
|                         : scheme.outline.withValues(alpha: 0.70), | ||||
|                     tooltip: mount.mounted == null | ||||
|                         ? '' | ||||
|                         : mount.mounted! | ||||
|                         ? 'Unmount' | ||||
|                         : 'Mount', | ||||
|                     onPressed: _createMountHandler(context, mount), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ); | ||||
|           }, | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   VoidCallback? _createMountHandler(BuildContext context, Mount mount) { | ||||
|     return _enabled && mount.mounted != null | ||||
|         ? () async { | ||||
|             if (mount.mounted == null) { | ||||
|               return; | ||||
|             } | ||||
|  | ||||
|             final mounted = mount.mounted!; | ||||
|  | ||||
|             setState(() { | ||||
|               _enabled = false; | ||||
|             }); | ||||
|  | ||||
|             final location = await _getMountLocation(context, mount); | ||||
|  | ||||
|             void cleanup() { | ||||
|               setState(() { | ||||
|                 _enabled = true; | ||||
|               }); | ||||
|             } | ||||
|  | ||||
|             if (!context.mounted && location == null) { | ||||
|               displayErrorMessage(context, "Mount location is not set"); | ||||
|               cleanup(); | ||||
|               return; | ||||
|             } | ||||
|  | ||||
|             final success = await mount.mount(mounted, location: location); | ||||
|             if (success || | ||||
|                 mounted || | ||||
|                 constants.navigatorKey.currentContext == null || | ||||
|                 !constants.navigatorKey.currentContext!.mounted) { | ||||
|               cleanup(); | ||||
|               return; | ||||
|             } | ||||
|  | ||||
|             displayErrorMessage( | ||||
|               context, | ||||
|               "Mount location is not available: $location", | ||||
|             ); | ||||
|             cleanup(); | ||||
|           } | ||||
|         : null; | ||||
|   String _formatType(String type) { | ||||
|     if (type.toUpperCase() == 'S3') { | ||||
|       return 'S3'; | ||||
|     } | ||||
|     if (type.isEmpty) { | ||||
|       return type; | ||||
|     } | ||||
|     return type[0].toUpperCase() + type.substring(1).toLowerCase(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _timer?.cancel(); | ||||
|     _timer = null; | ||||
|     super.dispose(); | ||||
|   String _prettyPath(Mount mount) { | ||||
|     if (mount.path.isEmpty && mount.mounted == null) { | ||||
|       return 'loading...'; | ||||
|     } | ||||
|     if (mount.path.isEmpty) { | ||||
|       return '<mount location not set>'; | ||||
|     } | ||||
|     return mount.path; | ||||
|   } | ||||
|  | ||||
|   VoidCallback? _createMountHandler(BuildContext context, Mount mount) { | ||||
|     if (!(_enabled && mount.mounted != null)) { | ||||
|       return null; | ||||
|     } | ||||
|  | ||||
|     return () async { | ||||
|       if (mount.mounted == null) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       final mounted = mount.mounted!; | ||||
|       setState(() { | ||||
|         _enabled = false; | ||||
|       }); | ||||
|  | ||||
|       final location = await _getMountLocation(context, mount); | ||||
|  | ||||
|       void cleanup() { | ||||
|         setState(() { | ||||
|           _enabled = true; | ||||
|         }); | ||||
|       } | ||||
|  | ||||
|       if (!mounted && location == null) { | ||||
|         if (!context.mounted) { | ||||
|           return; | ||||
|         } | ||||
|         displayErrorMessage(context, 'Mount location is not set'); | ||||
|         cleanup(); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       final success = await mount.mount(mounted, location: location); | ||||
|       if (success || | ||||
|           mounted || | ||||
|           constants.navigatorKey.currentContext == null || | ||||
|           !constants.navigatorKey.currentContext!.mounted) { | ||||
|         cleanup(); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       displayErrorMessage( | ||||
|         context, | ||||
|         'Mount location is not available: $location', | ||||
|       ); | ||||
|       cleanup(); | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   Future<String?> _getMountLocation(BuildContext context, Mount mount) async { | ||||
|     if (mount.mounted ?? false) { | ||||
|       return null; | ||||
|     } | ||||
|  | ||||
|     if (mount.path.isNotEmpty) { | ||||
|       return mount.path; | ||||
|     } | ||||
|  | ||||
|     String? location = await mount.getMountLocation(); | ||||
|     if (location != null) { | ||||
|       return location; | ||||
|     } | ||||
|  | ||||
|     if (!context.mounted) { | ||||
|       return location; | ||||
|     } | ||||
|  | ||||
|     // ignore: use_build_context_synchronously | ||||
|     return editMountLocation(context, await mount.getAvailableLocations()); | ||||
|   } | ||||
|  | ||||
| @@ -260,6 +284,13 @@ class _MountWidgetState extends State<MountWidget> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _timer?.cancel(); | ||||
|     _timer = null; | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void setState(VoidCallback fn) { | ||||
|     if (!mounted) { | ||||
| @@ -268,3 +299,135 @@ class _MountWidgetState extends State<MountWidget> { | ||||
|     super.setState(fn); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _FramedBox extends StatelessWidget { | ||||
|   final IconData icon; | ||||
|   final VoidCallback? onTap; | ||||
|   final Color? iconColor; | ||||
|   final double iconSize; | ||||
|  | ||||
|   const _FramedBox({ | ||||
|     required this.icon, | ||||
|     this.onTap, | ||||
|     this.iconColor, | ||||
|     this.iconSize = 22, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final radius = BorderRadius.circular(constants.borderRadiusSmall); | ||||
|  | ||||
|     return Material( | ||||
|       color: Colors.transparent, | ||||
|       child: InkWell( | ||||
|         onTap: onTap, | ||||
|         borderRadius: radius, | ||||
|         child: Ink( | ||||
|           width: 46, | ||||
|           height: 46, | ||||
|           decoration: BoxDecoration( | ||||
|             color: scheme.primary.withValues(alpha: 0.12), | ||||
|             borderRadius: radius, | ||||
|             border: Border.all( | ||||
|               color: scheme.outlineVariant.withValues(alpha: 0.08), | ||||
|               width: 1, | ||||
|             ), | ||||
|             boxShadow: [ | ||||
|               BoxShadow( | ||||
|                 color: Colors.black.withValues(alpha: 0.24), | ||||
|                 blurRadius: constants.borderRadiusSmall / 2.0, | ||||
|                 offset: const Offset(0, 5), | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|           child: Center( | ||||
|             child: Transform.scale( | ||||
|               scale: 0.90, | ||||
|               child: Icon( | ||||
|                 icon, | ||||
|                 color: iconColor ?? scheme.onSurface.withValues(alpha: 0.92), | ||||
|                 size: iconSize, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _GearBadge extends StatelessWidget { | ||||
|   final VoidCallback onTap; | ||||
|   const _GearBadge({required this.onTap}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return _FramedBox(icon: Icons.settings, onTap: onTap, iconSize: 22); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _ToggleFramed extends StatelessWidget { | ||||
|   final bool? mounted; | ||||
|   final VoidCallback? onPressed; | ||||
|  | ||||
|   const _ToggleFramed({required this.mounted, required this.onPressed}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|     final bool isOn = mounted ?? false; | ||||
|  | ||||
|     IconData icon = Icons.hourglass_top; | ||||
|     Color iconColor = scheme.onSurface.withValues(alpha: 0.60); | ||||
|  | ||||
|     if (mounted != null) { | ||||
|       icon = isOn ? Icons.toggle_on : Icons.toggle_off; | ||||
|       iconColor = isOn | ||||
|           ? scheme.primary | ||||
|           : scheme.onSurface.withValues(alpha: 0.55); | ||||
|     } | ||||
|  | ||||
|     return _FramedBox( | ||||
|       icon: icon, | ||||
|       iconColor: iconColor, | ||||
|       onTap: mounted == null ? null : onPressed, | ||||
|       iconSize: 22, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _EditPathButton extends StatelessWidget { | ||||
|   final bool enabled; | ||||
|   final VoidCallback onPressed; | ||||
|  | ||||
|   const _EditPathButton({required this.enabled, required this.onPressed}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final scheme = Theme.of(context).colorScheme; | ||||
|  | ||||
|     return Opacity( | ||||
|       opacity: enabled ? 1.0 : 0.45, | ||||
|       child: OutlinedButton.icon( | ||||
|         onPressed: enabled ? onPressed : null, | ||||
|         icon: const Icon(Icons.edit, size: 18), | ||||
|         label: const Text('Edit path'), | ||||
|         style: OutlinedButton.styleFrom( | ||||
|           foregroundColor: scheme.primary, | ||||
|           side: BorderSide( | ||||
|             color: scheme.primary.withValues(alpha: 0.55), | ||||
|             width: 1.2, | ||||
|           ), | ||||
|           shape: RoundedRectangleBorder( | ||||
|             borderRadius: BorderRadius.circular( | ||||
|               constants.borderRadiusSmall * 1.6, | ||||
|             ), | ||||
|           ), | ||||
|           padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), | ||||
|           backgroundColor: scheme.primary.withValues(alpha: 0.10), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -31,6 +31,11 @@ | ||||
|   <link rel="manifest" href="manifest.json"> | ||||
| <script type="text/javascript" src="sodium.js" async="true"></script></head> | ||||
| <body> | ||||
|   <script> | ||||
|       window.flutterConfiguration = { | ||||
|           canvasKitBaseUrl: "/canvaskit/" | ||||
|       }; | ||||
|   </script> | ||||
|   <script src="flutter_bootstrap.js" async=""></script> | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user