/ app / lib / screens / desktop_shell.dart
desktop_shell.dart
 1  import 'package:flutter/material.dart';
 2  import 'package:flutter_riverpod/flutter_riverpod.dart';
 3  
 4  import '../core/theme/app_theme.dart';
 5  import 'contacts/contacts_screen.dart';
 6  
 7  /// Side-by-side layout for wide screens: contacts sidebar + content area.
 8  class DesktopShell extends ConsumerWidget {
 9    final Widget child;
10    final String location;
11  
12    const DesktopShell({super.key, required this.child, required this.location});
13  
14    @override
15    Widget build(BuildContext context, WidgetRef ref) {
16      final colors = AppColors.of(context);
17  
18      // Right panel shows placeholder when on /contacts (sidebar already shows it)
19      final hasContent = location != '/contacts';
20  
21      final rightPanel = hasContent ? child : _EmptyConversation();
22  
23      return Scaffold(
24        body: SafeArea(
25          child: Row(
26            children: [
27              // Left panel: contacts sidebar
28              SizedBox(
29                width: 300,
30                child: ContactsScreen(sidebarMode: true),
31              ),
32              VerticalDivider(width: 1, thickness: 1, color: colors.outline),
33              // Right panel: animated content area
34              Expanded(
35                child: AnimatedSwitcher(
36                  duration: const Duration(milliseconds: 800),
37                  switchInCurve: Curves.easeOut,
38                  switchOutCurve: Curves.easeIn,
39                  transitionBuilder: (child, animation) {
40                    return FadeTransition(
41                      opacity: animation,
42                      child: SlideTransition(
43                        position: Tween<Offset>(
44                          begin: const Offset(0.02, 0),
45                          end: Offset.zero,
46                        ).animate(animation),
47                        child: child,
48                      ),
49                    );
50                  },
51                  child: KeyedSubtree(
52                    key: ValueKey(location),
53                    child: rightPanel,
54                  ),
55                ),
56              ),
57            ],
58          ),
59        ),
60      );
61    }
62  }
63  
64  class _EmptyConversation extends StatelessWidget {
65    @override
66    Widget build(BuildContext context) {
67      final colors = AppColors.of(context);
68      return Center(
69        child: Column(
70          mainAxisSize: MainAxisSize.min,
71          children: [
72            Icon(
73              Icons.chat_bubble_outline,
74              size: 64,
75              color: colors.onBackgroundSecondary,
76            ),
77            const SizedBox(height: 16),
78            Text(
79              'Select a conversation',
80              style: Theme.of(context).textTheme.titleMedium?.copyWith(
81                    color: colors.onBackgroundSecondary,
82                  ),
83            ),
84          ],
85        ),
86      );
87    }
88  }