import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:macos_ui/macos_ui.dart'; import '../rust/api/packages.dart'; import '../rust/frb_generated.dart'; import '../services/app_badge_controller.dart'; import '../services/app_settings_service.dart'; import 'theme/window_theme_style.dart'; import 'screens/cleaner_screen.dart'; import 'screens/discover_screen.dart'; import 'screens/doctor_screen.dart'; import 'screens/history_screen.dart'; import 'screens/installed_screen.dart'; import 'screens/settings_screen.dart'; import 'screens/starter_packs_screen.dart'; import 'screens/updates_screen.dart'; import 'widgets/keyboard_shortcuts_dialog.dart'; import 'widgets/package_inspector.dart'; import 'widgets/setup_wizard_dialog.dart'; import 'widgets/spotlight_search_dialog.dart'; class MainLayout extends StatefulWidget { const MainLayout({super.key}); @override State createState() => _MainLayoutState(); } class _MainLayoutState extends State { int _pageIndex = 0; @override void initState() { super.initState(); _performInitialBadgeScan(); WidgetsBinding.instance.addPostFrameCallback((_) { if (!AppSettingsService.instance.hasCompletedSetupWizard && mounted) { SetupWizardDialog.show(context); } }); } Future _performInitialBadgeScan() async { try { final updates = await RustBridgeApi.checkUpdates(); AppBadgeController.instance.setUpdatesCount(updates.length); } catch (_) {} try { final scan = await RustBridgeApi.scanCleaner(); AppBadgeController.instance.setCleanerBytes(scan.totalReclaimableBytes); } catch (_) {} } void _onInspectPackage(String name, BackendType backend) { PackageInspectorSheet.show( context, packageName: name, backend: backend, ); } void _openSpotlight() { SpotlightSearchDialog.show( context, onSelectPackage: (name, backend) { _onInspectPackage(name, backend); }, ); } @override Widget build(BuildContext context) { final macosTheme = MacosTheme.of(context); return CallbackShortcuts( bindings: { const SingleActivator(LogicalKeyboardKey.keyK, control: true): _openSpotlight, const SingleActivator(LogicalKeyboardKey.keyK, meta: true): _openSpotlight, const SingleActivator(LogicalKeyboardKey.slash, control: true): () => KeyboardShortcutsDialog.show(context), const SingleActivator(LogicalKeyboardKey.f1): () => KeyboardShortcutsDialog.show(context), const SingleActivator(LogicalKeyboardKey.keyR, control: true): _performInitialBadgeScan, const SingleActivator(LogicalKeyboardKey.f5): _performInitialBadgeScan, const SingleActivator(LogicalKeyboardKey.digit1, control: true): () => setState(() => _pageIndex = 0), const SingleActivator(LogicalKeyboardKey.digit2, control: true): () => setState(() => _pageIndex = 1), const SingleActivator(LogicalKeyboardKey.digit3, control: true): () => setState(() => _pageIndex = 2), const SingleActivator(LogicalKeyboardKey.digit4, control: true): () => setState(() => _pageIndex = 3), const SingleActivator(LogicalKeyboardKey.digit5, control: true): () => setState(() => _pageIndex = 4), const SingleActivator(LogicalKeyboardKey.digit6, control: true): () => setState(() => _pageIndex = 5), const SingleActivator(LogicalKeyboardKey.digit7, control: true): () => setState(() => _pageIndex = 6), }, child: Focus( autofocus: true, child: MacosWindow( sidebar: Sidebar( topOffset: 0.0, // Убираем пустой отступ macOS traffic lights на Linux minWidth: 200, startWidth: 220, maxWidth: 260, top: Padding( padding: const EdgeInsets.fromLTRB(16, 14, 16, 10), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Container( width: 30, height: 30, decoration: BoxDecoration( color: macosTheme.primaryColor, borderRadius: BorderRadius.circular( AppSettingsService.instance.effectiveWindowThemeStyle == WindowThemeStyle.kde ? 4 : 8, ), boxShadow: [ BoxShadow( color: macosTheme.primaryColor.withValues(alpha: 0.35), blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Center( child: MacosIcon( AppSettingsService.instance.effectiveWindowThemeStyle == WindowThemeStyle.kde ? CupertinoIcons.gear_alt_fill : AppSettingsService.instance.effectiveWindowThemeStyle == WindowThemeStyle.gnome ? CupertinoIcons.app_badge_fill : CupertinoIcons.cube_box_fill, color: CupertinoColors.white, size: 17, ), ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ const Text( 'Forge', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, letterSpacing: -0.2, ), overflow: TextOverflow.ellipsis, ), Text( AppSettingsService.instance.effectiveWindowThemeStyle == WindowThemeStyle.kde ? 'KDE Breeze Edition' : AppSettingsService.instance.effectiveWindowThemeStyle == WindowThemeStyle.gnome ? 'GNOME Adwaita' : 'macOS Cupertino', style: const TextStyle( fontSize: 10.5, color: CupertinoColors.systemGrey, ), overflow: TextOverflow.ellipsis, ), ], ), ), MacosTooltip( message: 'Горячие клавиши (F1 / Ctrl+/)', child: MacosIconButton( icon: const MacosIcon(CupertinoIcons.keyboard, size: 14), onPressed: () => KeyboardShortcutsDialog.show(context), ), ), ], ), const SizedBox(height: 12), // Spotlight Search Trigger Button CupertinoButton( padding: EdgeInsets.zero, minimumSize: Size.zero, onPressed: _openSpotlight, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6.5), decoration: BoxDecoration( color: CupertinoColors.white.withValues(alpha: 0.05), borderRadius: BorderRadius.circular(7), border: Border.all( color: CupertinoColors.white.withValues(alpha: 0.07), ), ), child: const Row( children: [ MacosIcon( CupertinoIcons.search, size: 13, color: CupertinoColors.systemGrey, ), SizedBox(width: 8), Expanded( child: Text( 'Поиск пакетов...', style: TextStyle( fontSize: 12, color: CupertinoColors.systemGrey, ), ), ), Text( '⌘K', style: TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: CupertinoColors.systemGrey, ), ), ], ), ), ), ], ), ), builder: (context, scrollController) { return ListenableBuilder( listenable: AppBadgeController.instance, builder: (context, _) { final badge = AppBadgeController.instance; return SidebarItems( currentIndex: _pageIndex, onChanged: (index) { setState(() { _pageIndex = index; }); }, scrollController: scrollController, itemSize: SidebarItemSize.large, items: [ const SidebarItem( label: Text('УПРАВЛЕНИЕ'), section: true, ), SidebarItem( leading: const MacosIcon(CupertinoIcons.arrow_down_circle_fill), label: const Text('Обновления'), trailing: badge.updatesCount > 0 ? Container( padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 1.5), decoration: BoxDecoration( color: const Color(0xFF0A84FF), borderRadius: BorderRadius.circular(10), ), child: Text( '${badge.updatesCount}', style: const TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: CupertinoColors.white, ), ), ) : null, ), const SidebarItem( leading: MacosIcon(CupertinoIcons.square_stack_3d_up_fill), label: Text('Установленные'), ), const SidebarItem( leading: MacosIcon(CupertinoIcons.compass_fill), label: Text('Каталог'), ), const SidebarItem( leading: MacosIcon(CupertinoIcons.square_grid_2x2_fill), label: Text('Наборы ПО'), ), const SidebarItem( label: Text('СИСТЕМА И ОПТИМИЗАЦИЯ'), section: true, ), SidebarItem( leading: const MacosIcon(CupertinoIcons.sparkles), label: const Text('Очистка'), trailing: badge.cleanerBytes > 0 ? Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1.5), decoration: BoxDecoration( color: CupertinoColors.systemOrange.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(10), ), child: Text( AppBadgeController.formatBytes(badge.cleanerBytes), style: const TextStyle( fontSize: 9.5, fontWeight: FontWeight.bold, color: CupertinoColors.systemOrange, ), ), ) : null, ), const SidebarItem( leading: MacosIcon(CupertinoIcons.bandage_fill), label: Text('Диагностика'), ), const SidebarItem( leading: MacosIcon(CupertinoIcons.clock_fill), label: Text('История'), ), const SidebarItem( leading: MacosIcon(CupertinoIcons.gear_alt_fill), label: Text('Настройки'), ), ], ); }, ); }, bottom: MacosListTile( leading: const MacosIcon( CupertinoIcons.command, color: CupertinoColors.systemGrey, ), title: const Text( 'Arch / Flatpak / AUR', style: TextStyle(fontSize: 12, color: CupertinoColors.systemGrey), ), ), ), child: IndexedStack( index: _pageIndex.clamp(0, 7), children: [ UpdatesScreen(onInspectPackage: _onInspectPackage), InstalledScreen(onInspectPackage: _onInspectPackage), DiscoverScreen(onInspectPackage: _onInspectPackage), const StarterPacksScreen(), const CleanerScreen(), const DoctorScreen(), const HistoryScreen(), const SettingsScreen(), ], ), ), ), ); } }