Files
monisuo/flutter_monisuo/lib/main.dart
sion 658f49e280 refactor: 批量替换 shadcn_ui 为 Material Design 组件
## 样式主题重点优化

### 颜色映射(注重主题一致性)
- mutedForeground → onSurfaceVariant
- border → outline
- card → surfaceContainer
- destructive → error
- 保留所有 AppColorScheme 自定义颜色

### 文本样式映射
- theme.textTheme.h1/muted/large → AppTextStyles.xxx(context)
- 统一使用项目定义的文本样式系统

### 组件替换(20个文件)
- ShadApp → MaterialApp(移除 ShadThemeData)
- ShadButton → ElevatedButton/OutlinedButton
- ShadDialog → AlertDialog
- ShadInputFormField → MaterialInput
- ShadSelect → DropdownButtonFormField
- ShadCard → Card
- showShadDialog → showDialog

### 依赖变更
- 移除:shadcn_ui: ^0.52.1
- 添加:lucide_icons_flutter: ^2.0.0

### 业务逻辑保护
 所有 onPressed/onChanged/validator 回调保持不变
 所有 controller/focusNode 数据绑定保持不变
 所有布局结构(Column/Row/Padding)保持不变
 仅替换 UI 组件层,业务逻辑完全保留
2026-04-08 12:24:24 +08:00

168 lines
5.3 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 'dart:ui';
import 'package:flutter/material.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'core/network/dio_client.dart';
import 'core/storage/local_storage.dart';
import 'core/theme/app_theme.dart';
import 'core/event/app_event_bus.dart';
import 'data/services/user_service.dart';
import 'data/services/market_service.dart';
import 'data/services/trade_service.dart';
import 'data/services/asset_service.dart';
import 'data/services/fund_service.dart';
import 'data/services/bonus_service.dart';
import 'providers/auth_provider.dart';
import 'providers/market_provider.dart';
import 'providers/asset_provider.dart';
import 'providers/theme_provider.dart';
import 'ui/pages/auth/login_page.dart';
import 'ui/pages/main/main_page.dart';
import 'ui/pages/onboarding/onboarding_page.dart';
void main() async {
// 確保 Flutter 綁定初始化
WidgetsFlutterBinding.ensureInitialized();
// 全局錯誤處理 - Flutter 框架錯誤
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
debugPrint('Flutter Error: ${details.exception}');
debugPrint('Stack trace: ${details.stack}');
};
// 全局錯誤處理 - 異步未捕獲錯誤
PlatformDispatcher.instance.onError = (error, stack) {
debugPrint('Uncaught error: $error');
debugPrint('Stack: $stack');
return true;
};
Provider.debugCheckInvalidValueType = null;
try {
await SharedPreferences.getInstance();
await LocalStorage.init();
debugPrint('App initialized successfully');
} catch (e, stack) {
debugPrint('Initialization error: $e');
debugPrint('Stack: $stack');
}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: _buildProviders(),
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, _) {
return _buildMaterialApp(context, themeProvider.themeMode);
},
),
);
}
List<SingleChildWidget> _buildProviders() {
final dioClient = DioClient();
return [
// Theme Provider (必須放在最前面)
ChangeNotifierProvider<ThemeProvider>(
create: (_) => ThemeProvider()..init(),
),
// Services
Provider<DioClient>.value(value: dioClient),
Provider<AppEventBus>(create: (_) => AppEventBus()),
Provider<UserService>(create: (_) => UserService(dioClient)),
Provider<MarketService>(create: (_) => MarketService(dioClient)),
Provider<TradeService>(create: (_) => TradeService(dioClient)),
Provider<AssetService>(create: (_) => AssetService(dioClient)),
Provider<FundService>(create: (_) => FundService(dioClient)),
Provider<BonusService>(create: (_) => BonusService(dioClient)),
// State Management
ChangeNotifierProvider<AuthProvider>(
create: (ctx) {
final authProvider = AuthProvider(ctx.read<UserService>());
// token 過期時DioClient 回調 AuthProvider 強制登出
dioClient.onUnauthorized = authProvider.forceLogout;
return authProvider;
},
),
ChangeNotifierProvider<MarketProvider>(
create: (ctx) => MarketProvider(ctx.read<MarketService>()),
),
ChangeNotifierProvider<AssetProvider>(
create: (ctx) => AssetProvider(
ctx.read<AssetService>(),
ctx.read<FundService>(),
ctx.read<AppEventBus>(),
),
),
];
}
Widget _buildMaterialApp(BuildContext context, ThemeMode themeMode) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeMode,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
builder: (context, child) {
// 配置 BotToast 確保顯示在所有內容之上
final botToastBuilder = BotToastInit();
child = botToastBuilder(context, child);
return child;
},
navigatorObservers: [BotToastNavigatorObserver()],
initialRoute: '/',
routes: {
'/': (context) => const RootPage(),
'/login': (context) => const LoginPage(),
'/main': (context) => const MainPage(),
},
);
}
}
/// 根頁面 - 決定顯示引導頁還是主頁面
class RootPage extends StatelessWidget {
const RootPage({super.key});
@override
Widget build(BuildContext context) {
// 檢查是否需要顯示引導頁
if (!LocalStorage.isOnboardingCompleted) {
return OnboardingPage(
onComplete: () {
Navigator.of(context).pushReplacementNamed('/login');
},
);
}
return Consumer<AuthProvider>(
builder: (context, auth, _) {
if (auth.isLoading) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
return auth.isLoggedIn ? const MainPage() : const LoginPage();
},
);
}
}