139 lines
4.0 KiB
Dart
Raw Normal View History

2026-09-17 14:45:23 +08:00
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'app/bindings/initial_binding.dart';
import 'app/routes/app_pages.dart';
import 'app/routes/app_routes.dart';
import 'app/theme/app_theme.dart';
import 'core/network/auth_session_store.dart';
import 'core/storage/local_storage_service.dart';
import 'core/storage/scoring_storage_keys.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setSystemUIOverlayStyle(_systemUiStyle);
await Future.wait([
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge),
LocalStorageService.initialize(),
]);
await AuthSessionStore.instance.restore();
final hasValidSession = AuthSessionStore.instance.isAuthenticated;
final settings = LocalStorageService.instance.settings;
final shouldResumeScoring =
hasValidSession &&
settings.get(ScoringStorageKeys.apiResumeScoringSetting) == true &&
(settings.get(ScoringStorageKeys.apiActiveSheetSetting) as String?)
?.isNotEmpty ==
true;
runApp(
PatternScoringApp(
initialRoute: shouldResumeScoring
? AppRoutes.scoring
: hasValidSession
? AppRoutes.home
: AppRoutes.login,
),
);
}
const _systemUiStyle = SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
systemStatusBarContrastEnforced: false,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
systemNavigationBarDividerColor: Colors.transparent,
systemNavigationBarContrastEnforced: false,
);
class PatternScoringApp extends StatelessWidget {
const PatternScoringApp({super.key, required this.initialRoute});
final String initialRoute;
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: '花样跳绳裁判评分系统',
debugShowCheckedModeBanner: false,
theme: AppTheme.light,
initialBinding: InitialBinding(),
initialRoute: initialRoute,
getPages: AppPages.pages,
defaultTransition: Transition.rightToLeft,
transitionDuration: const Duration(milliseconds: 360),
opaqueRoute: true,
builder: (context, child) => AnnotatedRegion<SystemUiOverlayStyle>(
value: _systemUiStyle,
child: _StartupPageReveal(
child: MediaQuery(
data: MediaQuery.of(
context,
).copyWith(textScaler: TextScaler.noScaling),
child: child ?? const SizedBox.shrink(),
),
),
),
);
}
}
class _StartupPageReveal extends StatefulWidget {
const _StartupPageReveal({required this.child});
final Widget child;
@override
State<_StartupPageReveal> createState() => _StartupPageRevealState();
}
class _StartupPageRevealState extends State<_StartupPageReveal>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _opacity;
late final Animation<double> _scale;
late final Animation<Offset> _position;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 520),
);
final curved = CurvedAnimation(
parent: _controller,
curve: Curves.easeOutCubic,
);
_opacity = Tween<double>(begin: 0, end: 1).animate(curved);
_scale = Tween<double>(begin: .992, end: 1).animate(curved);
_position = Tween<Offset>(
begin: const Offset(0, .012),
end: Offset.zero,
).animate(curved);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ColoredBox(
color: const Color(0xFFF4F8FE),
child: FadeTransition(
opacity: _opacity,
child: ScaleTransition(
scale: _scale,
child: SlideTransition(position: _position, child: widget.child),
),
),
);
}
}