125 lines
3.7 KiB
Dart
125 lines
3.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../app/i18n/app_localizations.dart';
|
|
import '../app/theme/app_colors.dart';
|
|
import '../app/theme/app_typography.dart';
|
|
import '../features/coupons/presentation/pages/home_page.dart';
|
|
import '../features/coupons/presentation/pages/market_page.dart';
|
|
import '../features/coupons/presentation/pages/my_coupons_page.dart';
|
|
import '../features/message/presentation/pages/message_page.dart';
|
|
import '../features/profile/presentation/pages/profile_page.dart';
|
|
import '../core/updater/update_service.dart';
|
|
import '../core/providers/notification_badge_manager.dart';
|
|
|
|
/// 消费者App主Shell - Bottom Navigation
|
|
///
|
|
/// Tab: 首页 / 市场 / 我的券 / 消息 / 我的
|
|
class MainShell extends StatefulWidget {
|
|
const MainShell({super.key});
|
|
|
|
@override
|
|
State<MainShell> createState() => _MainShellState();
|
|
}
|
|
|
|
class _MainShellState extends State<MainShell> {
|
|
int _currentIndex = 0;
|
|
bool _updateChecked = false;
|
|
|
|
final _pages = const [
|
|
HomePage(),
|
|
MarketPage(),
|
|
MyCouponsPage(),
|
|
MessagePage(),
|
|
ProfilePage(),
|
|
];
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
if (!_updateChecked) {
|
|
_updateChecked = true;
|
|
Future.delayed(const Duration(seconds: 3), () {
|
|
if (mounted) {
|
|
UpdateService().checkForUpdate(context);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: IndexedStack(
|
|
index: _currentIndex,
|
|
children: _pages,
|
|
),
|
|
bottomNavigationBar: Container(
|
|
decoration: const BoxDecoration(
|
|
color: AppColors.surface,
|
|
border: Border(top: BorderSide(color: AppColors.borderLight, width: 0.5)),
|
|
),
|
|
child: NavigationBar(
|
|
selectedIndex: _currentIndex,
|
|
onDestinationSelected: (index) => setState(() => _currentIndex = index),
|
|
destinations: [
|
|
_buildDestination(Icons.home_rounded, Icons.home_outlined, context.t('nav.home')),
|
|
_buildDestination(Icons.storefront_rounded, Icons.storefront_outlined, context.t('nav.market')),
|
|
_buildDestination(
|
|
Icons.confirmation_number_rounded,
|
|
Icons.confirmation_number_outlined,
|
|
context.t('nav.myCoupons'),
|
|
),
|
|
_buildBadgeDestination(
|
|
Icons.notifications_rounded,
|
|
Icons.notifications_outlined,
|
|
context.t('nav.messages'),
|
|
),
|
|
_buildDestination(Icons.person_rounded, Icons.person_outlined, context.t('nav.profile')),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
NavigationDestination _buildDestination(
|
|
IconData selected,
|
|
IconData unselected,
|
|
String label,
|
|
) {
|
|
return NavigationDestination(
|
|
icon: Icon(unselected),
|
|
selectedIcon: Icon(selected),
|
|
label: label,
|
|
);
|
|
}
|
|
|
|
NavigationDestination _buildBadgeDestination(
|
|
IconData selected,
|
|
IconData unselected,
|
|
String label,
|
|
) {
|
|
return NavigationDestination(
|
|
icon: ValueListenableBuilder<int>(
|
|
valueListenable: NotificationBadgeManager().unreadCount,
|
|
builder: (context, count, _) {
|
|
if (count <= 0) return Icon(unselected);
|
|
return Badge(
|
|
label: Text('$count', style: const TextStyle(fontSize: 10)),
|
|
child: Icon(unselected),
|
|
);
|
|
},
|
|
),
|
|
selectedIcon: ValueListenableBuilder<int>(
|
|
valueListenable: NotificationBadgeManager().unreadCount,
|
|
builder: (context, count, _) {
|
|
if (count <= 0) return Icon(selected);
|
|
return Badge(
|
|
label: Text('$count', style: const TextStyle(fontSize: 10)),
|
|
child: Icon(selected),
|
|
);
|
|
},
|
|
),
|
|
label: label,
|
|
);
|
|
}
|
|
}
|