// mobile_shell.dart — 移动外壳(底 Tab + 左右滑动),对照 ui_kits/mobile import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../screens/account_page.dart'; import '../screens/connect_page.dart'; import '../screens/nodes_page.dart'; import '../screens/stats_page.dart'; import '../state/navigation_provider.dart'; import '../widgets/bottom_tab_bar.dart'; import '../widgets/tab_swipe.dart'; class MobileShell extends ConsumerStatefulWidget { const MobileShell({super.key}); @override ConsumerState createState() => _MobileShellState(); } class _MobileShellState extends ConsumerState { int _dir = 0; Timer? _dirReset; int _indexOf(NavView v) { final i = kPrimaryNav.indexOf(v); return i < 0 ? 3 : i; // contact/settings/plans/redeem 归到账户 } void _goTo(NavView v) { final cur = _indexOf(ref.read(navViewProvider)); final next = _indexOf(v); if (next == cur) return; setState(() => _dir = next > cur ? 1 : -1); ref.read(navViewProvider.notifier).state = v; _dirReset?.cancel(); _dirReset = Timer(const Duration(milliseconds: 260), () { if (mounted) setState(() => _dir = 0); }); } void _swipe(int delta) { final cur = _indexOf(ref.read(navViewProvider)); _goTo(kPrimaryNav[(cur + delta).clamp(0, kPrimaryNav.length - 1)]); } @override void dispose() { _dirReset?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { final view = ref.watch(navViewProvider); final index = _indexOf(view); final pages = [ ConnectPage(isWide: false, onOpenNodes: () => _goTo(NavView.servers)), NodesPage(isWide: false, onPicked: () => _goTo(NavView.connect)), const StatsPage(isWide: false), const AccountPage(isWide: false), ]; return SafeArea( bottom: false, child: Column(children: [ Expanded( child: HorizontalSwipeArea( onSwipeLeft: () => _swipe(1), onSwipeRight: () => _swipe(-1), child: DirectionalTabSwitcher(index: index, direction: _dir, child: pages[index]), ), ), BottomTabBar(current: kPrimaryNav[index], onTap: _goTo), ]), ); } }