gcx/frontend/genex-mobile/lib/main.dart

247 lines
11 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:fluwx/fluwx.dart';
import 'app/theme/app_theme.dart';
import 'app/main_shell.dart';
import 'app/i18n/app_localizations.dart';
import 'app/i18n/locale_manager.dart';
import 'core/services/auth_service.dart';
import 'core/updater/update_service.dart';
import 'core/updater/models/update_config.dart';
import 'core/push/push_service.dart';
import 'core/providers/notification_badge_manager.dart';
import 'features/auth/presentation/pages/login_page.dart';
import 'features/auth/presentation/pages/welcome_page.dart';
import 'features/auth/presentation/pages/register_page.dart';
import 'features/auth/presentation/pages/forgot_password_page.dart';
import 'features/coupons/presentation/pages/coupon_detail_page.dart';
import 'features/coupons/presentation/pages/order_confirm_page.dart';
import 'features/coupons/presentation/pages/payment_page.dart';
import 'features/coupons/presentation/pages/payment_success_page.dart';
import 'features/coupons/presentation/pages/search_page.dart';
import 'features/coupons/presentation/pages/my_coupon_detail_page.dart';
import 'features/coupons/presentation/pages/redeem_qr_page.dart';
import 'features/trading/presentation/pages/trading_page.dart';
import 'features/trading/presentation/pages/transfer_page.dart';
import 'features/trading/presentation/pages/sell_order_page.dart';
import 'features/wallet/presentation/pages/wallet_page.dart';
import 'features/wallet/presentation/pages/deposit_page.dart';
import 'features/wallet/presentation/pages/withdraw_page.dart';
import 'features/wallet/presentation/pages/transaction_records_page.dart';
import 'features/profile/presentation/pages/kyc_page.dart';
import 'features/profile/presentation/pages/settings_page.dart';
import 'features/profile/presentation/pages/payment_management_page.dart';
import 'features/profile/presentation/pages/pro_mode_page.dart';
import 'features/ai_agent/presentation/pages/agent_chat_page.dart';
import 'features/message/presentation/pages/message_detail_page.dart';
import 'features/issuer/presentation/pages/issuer_main_page.dart';
import 'features/merchant/presentation/pages/merchant_home_page.dart';
import 'features/trading/presentation/pages/trading_detail_page.dart';
import 'features/coupons/presentation/pages/wallet_coupons_page.dart';
import 'features/profile/presentation/pages/share_page.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// ── 微信 SDK 初始化 (fluwx 5.x) ──────────────────────────────────────
// WECHAT_APP_ID 在构建时通过 --dart-define 注入,例如:
// flutter build apk --dart-define=WECHAT_APP_ID=wx0000000000000000
// flutter build ipa --dart-define=WECHAT_APP_ID=wx0000000000000000
//
// 未传入 WECHAT_APP_ID 时(本地开发 / CI 未配置),跳过初始化,
// WelcomePage 中点击微信按钮会提示「微信未安装」isWeChatInstalled=false
//
// universalLink: iOS Universal Links 地址,需在微信开放平台填写并配置
// apple-app-site-association 文件(路径: https://www.gogenex.com/wechat/apple-app-site-association
// 详见: https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Universal_Links/Universal_Links.html
//
// fluwx 5.x 迁移说明:
// 旧版 (3.x): 顶层函数 registerWxApi(appId: ..., universalLink: ...)
// 新版 (5.x): 实例方法 Fluwx().registerApi(appId: ..., universalLink: ...)
// 注册只需执行一次app 启动时Fluwx 底层 MethodChannel 为单例,
// 后续在 WelcomePage 中新建 Fluwx() 实例可共享同一注册状态。
const wechatAppId = String.fromEnvironment('WECHAT_APP_ID', defaultValue: '');
if (wechatAppId.isNotEmpty) {
await Fluwx().registerApi(appId: wechatAppId, universalLink: 'https://www.gogenex.com/wechat/');
}
// ─────────────────────────────────────────────────────────────────────
// 初始化升级服务(走 Nginx 反向代理 → Kong 网关)
UpdateService().initialize(UpdateConfig.selfHosted(
apiBaseUrl: 'https://api.gogenex.com',
enabled: true,
));
// 初始化推送服务(无 Firebase 配置时静默失败)
await PushService().initialize();
// 初始化通知徽章管理器
NotificationBadgeManager().initialize();
// 恢复用户语言偏好(无选择时跟随系统语言)
await LocaleManager.init();
// 从安全存储恢复上次登录的 Token若存在则自动进入 /main
await AuthService.instance.restoreSession();
runApp(const GenexConsumerApp());
}
/// Genex Mobile - 券的生命周期管理平台
///
/// 持仓/交易所/消息/个人中心
/// 持有/接收/转赠/交易/核销数字券
///
/// 国际化:首次启动跟随系统语言,用户可在设置中切换
class GenexConsumerApp extends StatefulWidget {
const GenexConsumerApp({super.key});
@override
State<GenexConsumerApp> createState() => _GenexConsumerAppState();
}
class _GenexConsumerAppState extends State<GenexConsumerApp> {
// Navigator Key — 用于在无 BuildContext 时执行命令式导航(如 Session 过期后跳 /
final _navigatorKey = GlobalKey<NavigatorState>();
// 上一帧的登录状态,用于检测 Session 过期(已登录 → 未登录)
bool _wasLoggedIn = false;
@override
void initState() {
super.initState();
LocaleManager.userLocale.addListener(_onLocaleChanged);
_wasLoggedIn = AuthService.instance.isLoggedIn;
AuthService.instance.authState.addListener(_onAuthStateChanged);
}
@override
void dispose() {
LocaleManager.userLocale.removeListener(_onLocaleChanged);
AuthService.instance.authState.removeListener(_onAuthStateChanged);
super.dispose();
}
void _onLocaleChanged() {
setState(() {});
}
/// Token 过期时由 ApiClient 拦截器触发 AuthService._clearAuth()
/// 进而将 authState 置 null此监听器感知变化后导航回欢迎页。
void _onAuthStateChanged() {
final isLoggedIn = AuthService.instance.isLoggedIn;
if (_wasLoggedIn && !isLoggedIn) {
// Session 过期(非主动登出):清空路由栈,回到欢迎页
_navigatorKey.currentState?.pushNamedAndRemoveUntil('/', (_) => false);
}
_wasLoggedIn = isLoggedIn;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Genex',
theme: AppTheme.light,
debugShowCheckedModeBanner: false,
navigatorKey: _navigatorKey,
// i18n
locale: LocaleManager.userLocale.value,
supportedLocales: LocaleManager.supportedLocales,
localizationsDelegates: const [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
localeResolutionCallback: (systemLocale, supportedLocales) {
if (LocaleManager.userLocale.value == null) {
return LocaleManager.resolve(
systemLocale != null ? [systemLocale] : null,
supportedLocales,
);
}
return LocaleManager.userLocale.value;
},
// 启动路由:已有保存的 Token → 直接进主界面;否则显示欢迎页
initialRoute: AuthService.instance.isLoggedIn ? '/main' : '/',
onGenerateRoute: _generateRoute,
);
}
Route<dynamic> _generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) => const WelcomePage());
case '/login':
return MaterialPageRoute(builder: (_) => const LoginPage());
case '/register':
final regArgs = settings.arguments as Map?;
return MaterialPageRoute(
builder: (_) => RegisterPage(isEmail: regArgs?['isEmail'] == true),
);
case '/forgot-password':
return MaterialPageRoute(builder: (_) => const ForgotPasswordPage());
case '/main':
return MaterialPageRoute(builder: (_) => const MainShell());
case '/coupon/detail':
return MaterialPageRoute(builder: (_) => const CouponDetailPage());
case '/order/confirm':
return MaterialPageRoute(builder: (_) => const OrderConfirmPage());
case '/payment':
return MaterialPageRoute(builder: (_) => const PaymentPage());
case '/payment/success':
return MaterialPageRoute(builder: (_) => const PaymentSuccessPage());
case '/search':
return MaterialPageRoute(builder: (_) => const SearchPage());
case '/coupon/mine/detail':
return MaterialPageRoute(builder: (_) => const MyCouponDetailPage());
case '/redeem':
return MaterialPageRoute(builder: (_) => const RedeemQrPage());
case '/trading':
return MaterialPageRoute(builder: (_) => const TradingPage());
case '/transfer':
return MaterialPageRoute(builder: (_) => const TransferPage());
case '/sell':
return MaterialPageRoute(builder: (_) => const SellOrderPage());
case '/wallet':
return MaterialPageRoute(builder: (_) => const WalletPage());
case '/wallet/deposit':
return MaterialPageRoute(builder: (_) => const DepositPage());
case '/wallet/withdraw':
return MaterialPageRoute(builder: (_) => const WithdrawPage());
case '/wallet/records':
return MaterialPageRoute(builder: (_) => const TransactionRecordsPage());
case '/kyc':
return MaterialPageRoute(builder: (_) => const KycPage());
case '/settings':
return MaterialPageRoute(builder: (_) => const SettingsPage());
case '/payment/manage':
return MaterialPageRoute(builder: (_) => const PaymentManagementPage());
case '/pro-mode':
return MaterialPageRoute(builder: (_) => const ProModePage());
case '/ai-chat':
return MaterialPageRoute(builder: (_) => const AgentChatPage());
case '/message/detail':
return MaterialPageRoute(builder: (_) => const MessageDetailPage());
case '/issuer':
return MaterialPageRoute(builder: (_) => const IssuerMainPage());
case '/merchant':
return MaterialPageRoute(builder: (_) => const MerchantHomePage());
case '/trading/detail':
return MaterialPageRoute(builder: (_) => const TradingDetailPage());
case '/wallet/coupons':
return MaterialPageRoute(builder: (_) => const WalletCouponsPage());
case '/share':
return MaterialPageRoute(builder: (_) => const SharePage());
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(child: Text('Route not found: ${settings.name}')),
),
);
}
}
}