import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:relationship_saver/app/navigation/app_destination.dart'; import 'package:relationship_saver/core/config/app_theme.dart'; import 'package:relationship_saver/features/ai_digest/presentation/ai_digest_review_view.dart'; import 'package:relationship_saver/features/people/presentation/people_view.dart'; import 'package:relationship_saver/features/settings/presentation/settings_view.dart'; import 'package:relationship_saver/features/share_intake/presentation/share_inbox_view.dart'; /// Responsive shell that hosts the main feature slices. class AppShell extends ConsumerStatefulWidget { const AppShell({super.key}); @override ConsumerState createState() => _AppShellState(); } class _AppShellState extends ConsumerState { AppDestination _destination = AppDestination.shareInbox; static const List _destinations = AppDestination.values; static const List _compactPrimaryDestinations = AppDestination.values; @override Widget build(BuildContext context) { return DecoratedBox( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFFF3F8FB), Color(0xFFEAF1F8), Color(0xFFF8FAFC), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Scaffold( backgroundColor: Colors.transparent, body: SafeArea( child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if (constraints.maxWidth < 1000) { return _buildCompactLayout(context); } return Row( children: [ _Sidebar( selected: _destination, destinations: _destinations, onChange: _selectDestination, ), Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 250), layoutBuilder: _expandedSwitcherLayout, child: KeyedSubtree( key: ValueKey(_destination), child: _screenFor(_destination), ), ), ), ], ); }, ), ), ), ); } Widget _buildCompactLayout(BuildContext context) { final int compactIndex = _compactSelectedIndex(_destination); final AppDestination active = _compactPrimaryDestinations[compactIndex]; return _CompactShell( selected: active, body: _screenFor(active), destinations: _compactPrimaryDestinations, onChange: _selectDestination, ); } void _selectDestination(AppDestination destination) { setState(() { _destination = destination; }); } int _compactSelectedIndex(AppDestination destination) { for (int i = 0; i < _compactPrimaryDestinations.length; i += 1) { if (_compactPrimaryDestinations[i] == destination) { return i; } } return 0; } Widget _screenFor(AppDestination destination) { switch (destination) { case AppDestination.shareInbox: return const ShareInboxView(); case AppDestination.people: return const PeopleView(); case AppDestination.aiReview: return const AiDigestReviewView(); case AppDestination.settings: return const SettingsView(); } } } class _Sidebar extends StatelessWidget { const _Sidebar({ required this.selected, required this.destinations, required this.onChange, }); final AppDestination selected; final List destinations; final ValueChanged onChange; @override Widget build(BuildContext context) { return Container( width: 290, margin: const EdgeInsets.fromLTRB(20, 20, 8, 20), padding: const EdgeInsets.fromLTRB(18, 20, 18, 18), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.78), borderRadius: BorderRadius.circular(28), border: Border.all(color: Colors.white.withValues(alpha: 0.7)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 34, height: 34, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), gradient: const LinearGradient( colors: [Color(0xFF1AB6C8), Color(0xFF286DE0)], ), ), child: const Icon( Icons.favorite_rounded, color: Colors.white, size: 20, ), ), const SizedBox(width: 10), Expanded( child: Text( 'Relationship Saver', style: Theme.of(context).textTheme.titleMedium, overflow: TextOverflow.ellipsis, ), ), ], ), const SizedBox(height: 22), ...destinations.map((AppDestination destination) { final bool isSelected = destination == selected; return Padding( padding: const EdgeInsets.only(bottom: 6), child: InkWell( onTap: () => onChange(destination), borderRadius: BorderRadius.circular(14), child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10, ), decoration: BoxDecoration( color: isSelected ? const Color(0xFFEAF7FB) : Colors.transparent, borderRadius: BorderRadius.circular(14), ), child: Row( children: [ Icon( destination.icon, size: 20, color: isSelected ? AppTheme.primary : AppTheme.textSecondary, ), const SizedBox(width: 10), Text( destination.label, style: Theme.of(context).textTheme.titleMedium ?.copyWith( color: isSelected ? AppTheme.primary : AppTheme.textSecondary, ), ), ], ), ), ), ); }), const Spacer(), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFF2F8FB), borderRadius: BorderRadius.circular(16), ), child: Text( 'Share messages or paste text into Capture. Nothing is assigned until you choose a person.', style: Theme.of( context, ).textTheme.bodyMedium?.copyWith(color: AppTheme.textSecondary), ), ), ], ), ); } } class _CompactShell extends StatelessWidget { const _CompactShell({ required this.selected, required this.body, required this.destinations, required this.onChange, }); final AppDestination selected; final Widget body; final List destinations; final ValueChanged onChange; @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 220), layoutBuilder: _expandedSwitcherLayout, child: KeyedSubtree( key: ValueKey(selected), child: body, ), ), ), NavigationBar( selectedIndex: destinations.indexOf(selected), onDestinationSelected: (int index) => onChange(destinations[index]), destinations: destinations .map( (AppDestination destination) => NavigationDestination( icon: Icon(destination.icon), label: destination.label, ), ) .toList(growable: false), ), ], ); } } Widget _expandedSwitcherLayout( Widget? currentChild, List previousChildren, ) { return Stack( fit: StackFit.expand, children: [...previousChildren, ?currentChild], ); }