- 引入 dio,封装统一 ApiClient(BaseUrl/Token 注入/401 自动刷新/{code,message,data} 解包)
- TokenStorage 令牌持久化,AuthController 登录状态管理
- AuthRepository 封装 otp/login/logout 接口
- 登录页对接手机号/邮箱验证码登录(Google 登录待 OAuth client 配置)
89 lines
3.2 KiB
Dart
89 lines
3.2 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'core/config/locale_controller.dart';
|
|
import 'core/data/repositories/auth_repository.dart';
|
|
import 'core/data/repositories/catalog_repository.dart';
|
|
import 'core/data/repositories/engagement_repository.dart';
|
|
import 'core/data/services/api_client.dart';
|
|
import 'core/data/services/auth_controller.dart';
|
|
import 'core/data/services/catalog_controller.dart';
|
|
import 'core/data/services/engagement_controller.dart';
|
|
import 'core/data/services/playback_session.dart';
|
|
import 'core/data/services/token_storage.dart';
|
|
import 'core/data/services/video_player_port.dart';
|
|
import 'l10n/app_localizations.dart';
|
|
import 'pages/login/login_view.dart';
|
|
|
|
class LumaDramaApp extends StatelessWidget {
|
|
const LumaDramaApp({super.key, this.playerFactory = VideoPlayerPort.new});
|
|
|
|
final PlayerFactory playerFactory;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MultiProvider(
|
|
providers: [
|
|
Provider(create: (_) => PlaybackCoordinator()),
|
|
Provider<PlayerFactory>(create: (_) => playerFactory),
|
|
Provider(create: (_) => ApiClient()),
|
|
Provider(create: (_) => TokenStorage()),
|
|
Provider(
|
|
create: (ctx) => AuthRepository(
|
|
ctx.read<ApiClient>(),
|
|
ctx.read<TokenStorage>(),
|
|
),
|
|
),
|
|
ChangeNotifierProvider(
|
|
create: (ctx) => AuthController(ctx.read<AuthRepository>()),
|
|
),
|
|
ChangeNotifierProvider(
|
|
create: (_) => CatalogController(DemoCatalogRepository())..load(),
|
|
),
|
|
ChangeNotifierProvider(create: (_) => LocaleController()..load()),
|
|
ChangeNotifierProvider(
|
|
create: (_) =>
|
|
EngagementController(SharedPreferencesEngagementRepository())
|
|
..load(),
|
|
),
|
|
],
|
|
child: Consumer<LocaleController>(
|
|
builder: (context, locale, _) => MaterialApp(
|
|
onGenerateTitle: (context) => AppLocalizations.of(context)!.appName,
|
|
locale: locale.locale,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
localeResolutionCallback: (deviceLocale, supported) {
|
|
final resolved = locale.locale ?? deviceLocale;
|
|
if (resolved == null) return supported.first;
|
|
for (final item in supported) {
|
|
if (item.languageCode == resolved.languageCode) return item;
|
|
}
|
|
return supported.first;
|
|
},
|
|
debugShowCheckedModeBanner: false,
|
|
themeMode: ThemeMode.dark,
|
|
theme: ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: ColorScheme.fromSeed(
|
|
seedColor: const Color(0xFFFF5B3D),
|
|
),
|
|
scaffoldBackgroundColor: const Color(0xFF0B0C10),
|
|
),
|
|
darkTheme: ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: ColorScheme.fromSeed(
|
|
seedColor: const Color(0xFFFF5B3D),
|
|
brightness: Brightness.dark,
|
|
),
|
|
scaffoldBackgroundColor: const Color(0xFF0B0C10),
|
|
),
|
|
home: const LoginPage(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|