diff --git a/assets/images/umbrix_logo.png b/assets/images/umbrix_logo.png new file mode 100644 index 00000000..039e94b4 Binary files /dev/null and b/assets/images/umbrix_logo.png differ diff --git a/lib/features/profile/add/add_profile_modal.dart b/lib/features/profile/add/add_profile_modal.dart index 1b45991b..8da28c89 100644 --- a/lib/features/profile/add/add_profile_modal.dart +++ b/lib/features/profile/add/add_profile_modal.dart @@ -98,42 +98,70 @@ class AddProfileModal extends HookConsumerWidget { ), secondChild: Column( children: [ + // Заголовок Padding( - padding: const EdgeInsets.symmetric(horizontal: buttonsPadding), - child: Row( + padding: const EdgeInsets.fromLTRB(24, 16, 24, 8), + child: Text( + t.profile.add.buttonText, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + // Основные кнопки в виде больших карточек + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( children: [ - _Button( + _ModernButton( key: const ValueKey("add_from_clipboard_button"), label: t.profile.add.fromClipboard, - icon: FluentIcons.clipboard_paste_24_regular, - size: buttonWidth, + subtitle: "Paste from clipboard", + icon: FluentIcons.clipboard_paste_24_filled, + gradient: LinearGradient( + colors: [ + theme.colorScheme.primaryContainer, + theme.colorScheme.secondaryContainer, + ], + ), onTap: () async { final captureResult = await Clipboard.getData(Clipboard.kTextPlain).then((value) => value?.text ?? ''); if (addProfileState.isLoading) return; ref.read(addProfileProvider.notifier).add(captureResult); }, ), - const Gap(buttonsGap), + const Gap(12), if (!PlatformUtils.isDesktop) - _Button( + _ModernButton( key: const ValueKey("add_by_qr_code_button"), label: t.profile.add.scanQr, - icon: FluentIcons.qr_code_24_regular, - size: buttonWidth, + subtitle: "Camera scanner", + icon: FluentIcons.qr_code_24_filled, + gradient: LinearGradient( + colors: [ + theme.colorScheme.tertiaryContainer, + theme.colorScheme.primaryContainer.withOpacity(0.7), + ], + ), onTap: () async { final cr = await QRCodeScannerScreen().open(context); - if (cr == null) return; if (addProfileState.isLoading) return; ref.read(addProfileProvider.notifier).add(cr); }, ) else - _Button( + _ModernButton( key: const ValueKey("add_manually_button"), label: t.profile.add.manually, - icon: FluentIcons.add_24_regular, - size: buttonWidth, + subtitle: "Create new config", + icon: FluentIcons.edit_24_filled, + gradient: LinearGradient( + colors: [ + theme.colorScheme.tertiaryContainer, + theme.colorScheme.primaryContainer.withOpacity(0.7), + ], + ), onTap: () async { context.pop(); await const NewProfileRoute().push(context); @@ -142,87 +170,32 @@ class AddProfileModal extends HookConsumerWidget { ], ), ), + const Gap(16), + // Дополнительные опции Padding( - padding: const EdgeInsets.symmetric( - horizontal: buttonsPadding, - vertical: 16, - ), + padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ - Semantics( - button: true, - child: SizedBox( - height: 36, - child: Material( - key: const ValueKey("add_warp_button"), - elevation: 8, - color: theme.colorScheme.surface, - surfaceTintColor: theme.colorScheme.surfaceTint, - shadowColor: Colors.transparent, - borderRadius: BorderRadius.circular(8), - clipBehavior: Clip.antiAlias, - child: InkWell( - onTap: () async { - await addProfileModal(context, ref); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - FluentIcons.add_24_regular, - color: theme.colorScheme.primary, - ), - const SizedBox(width: 8), - Text( - t.profile.add.addWarp, - style: theme.textTheme.labelLarge?.copyWith( - color: theme.colorScheme.primary, - ), - ), - ], - ), - ), - ), - ), + _CompactButton( + key: const ValueKey("add_warp_button"), + label: t.profile.add.addWarp, + icon: FluentIcons.cloud_add_24_regular, + color: theme.colorScheme.primary, + onTap: () async { + await addProfileModal(context, ref); + }, ), - if (!PlatformUtils.isDesktop) const SizedBox(height: 16), // Spacing between the buttons + if (!PlatformUtils.isDesktop) const Gap(12), if (!PlatformUtils.isDesktop) - Semantics( - button: true, - child: SizedBox( - height: 36, - child: Material( - key: const ValueKey("add_manually_button"), - elevation: 8, - color: theme.colorScheme.surface, - surfaceTintColor: theme.colorScheme.surfaceTint, - shadowColor: Colors.transparent, - borderRadius: BorderRadius.circular(8), - clipBehavior: Clip.antiAlias, - child: InkWell( - onTap: () async { - context.pop(); - await const NewProfileRoute().push(context); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - FluentIcons.add_24_regular, - color: theme.colorScheme.primary, - ), - const SizedBox(width: 8), - Text( - t.profile.add.manually, - style: theme.textTheme.labelLarge?.copyWith( - color: theme.colorScheme.primary, - ), - ), - ], - ), - ), - ), - ), + _CompactButton( + key: const ValueKey("add_manually_button"), + label: t.profile.add.manually, + icon: FluentIcons.edit_24_regular, + color: theme.colorScheme.secondary, + onTap: () async { + context.pop(); + await const NewProfileRoute().push(context); + }, ), ], ), @@ -282,6 +255,168 @@ class AddProfileModal extends HookConsumerWidget { } } +// Современная большая кнопка с градиентом +class _ModernButton extends StatelessWidget { + const _ModernButton({ + super.key, + required this.label, + required this.subtitle, + required this.icon, + required this.gradient, + required this.onTap, + }); + + final String label; + final String subtitle; + final IconData icon; + final Gradient gradient; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Semantics( + button: true, + child: Material( + elevation: 4, + shadowColor: theme.colorScheme.primary.withOpacity(0.2), + borderRadius: BorderRadius.circular(20), + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: onTap, + child: Container( + height: 80, + decoration: BoxDecoration( + gradient: gradient, + borderRadius: BorderRadius.circular(20), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Container( + width: 56, + height: 56, + decoration: BoxDecoration( + color: theme.colorScheme.surface.withOpacity(0.9), + borderRadius: BorderRadius.circular(16), + ), + child: Icon( + icon, + size: 28, + color: theme.colorScheme.primary, + ), + ), + const Gap(16), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onPrimaryContainer, + ), + ), + const Gap(2), + Text( + subtitle, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onPrimaryContainer.withOpacity(0.7), + ), + ), + ], + ), + ), + Icon( + FluentIcons.chevron_right_24_regular, + color: theme.colorScheme.onPrimaryContainer.withOpacity(0.5), + ), + ], + ), + ), + ), + ), + ), + ); + } +} + +// Компактная кнопка для дополнительных опций +class _CompactButton extends StatelessWidget { + const _CompactButton({ + super.key, + required this.label, + required this.icon, + required this.color, + required this.onTap, + }); + + final String label; + final IconData icon; + final Color color; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Semantics( + button: true, + child: Material( + elevation: 2, + color: theme.colorScheme.surface, + surfaceTintColor: theme.colorScheme.surfaceTint, + shadowColor: Colors.transparent, + borderRadius: BorderRadius.circular(12), + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: onTap, + child: Container( + height: 56, + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + icon, + size: 20, + color: color, + ), + ), + const Gap(12), + Expanded( + child: Text( + label, + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + color: color, + ), + ), + ), + Icon( + FluentIcons.add_24_regular, + size: 20, + color: color.withOpacity(0.5), + ), + ], + ), + ), + ), + ), + ); + } +} + class _Button extends StatelessWidget { const _Button({ super.key,