518 lines
17 KiB
Dart
518 lines
17 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:package_info_plus/package_info_plus.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import 'pages/tabs/tabs.dart';
|
||
import 'providers/auth_provider.dart';
|
||
import 'router/index.dart';
|
||
import 'services/online_time_service.dart';
|
||
import 'services/update_dialog_service.dart';
|
||
import 'components/WelcomeDialog.dart';
|
||
import 'package:flutter/services.dart';
|
||
|
||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||
|
||
// 自定义页面转场,禁用Android手势返回
|
||
class NoTransitionPageTransitionsBuilder extends PageTransitionsBuilder {
|
||
const NoTransitionPageTransitionsBuilder();
|
||
|
||
@override
|
||
Widget buildTransitions<T>(
|
||
PageRoute<T> route,
|
||
BuildContext context,
|
||
Animation<double> animation,
|
||
Animation<double> secondaryAnimation,
|
||
Widget child,
|
||
) {
|
||
return child;
|
||
}
|
||
}
|
||
|
||
void main() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
|
||
|
||
// 在APP启动时完全重置版本检查状态
|
||
UpdateDialogService().resetAllCheckStatus();
|
||
|
||
try {
|
||
final packageInfo = await PackageInfo.fromPlatform();
|
||
print('应用启动版本: ${packageInfo.version}');
|
||
} catch (e) {
|
||
print('启动时获取版本信息失败: $e');
|
||
}
|
||
// 获取登录状态
|
||
final prefs = await SharedPreferences.getInstance();
|
||
final token = prefs.getString('token');
|
||
final userId = prefs.getString('userId');
|
||
|
||
runApp(
|
||
MultiProvider(
|
||
providers: [
|
||
ChangeNotifierProvider(create: (_) => AuthProvider()..setToken(token, userId: userId)),
|
||
],
|
||
child: const MyApp(),
|
||
),
|
||
);
|
||
}
|
||
|
||
class MyApp extends StatefulWidget {
|
||
const MyApp({super.key});
|
||
|
||
@override
|
||
State<MyApp> createState() => _MyAppState();
|
||
}
|
||
|
||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||
final OnlineTimeService _onlineTimeService = OnlineTimeService();
|
||
bool _showedWelcomeDialog = false;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
WidgetsBinding.instance.addObserver(this);
|
||
_onlineTimeService.initWebSocket();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
WidgetsBinding.instance.removeObserver(this);
|
||
_onlineTimeService.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||
switch (state) {
|
||
case AppLifecycleState.resumed:
|
||
_onlineTimeService.initWebSocket();
|
||
break;
|
||
case AppLifecycleState.paused:
|
||
_onlineTimeService.dispose();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 显示欢迎弹窗
|
||
void _showWelcomeDialog(BuildContext context) {
|
||
// 如果已显示过或用户已登录,则不再显示
|
||
if (_showedWelcomeDialog) return;
|
||
_showedWelcomeDialog = true;
|
||
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
showGeneralDialog(
|
||
context: context,
|
||
barrierColor: Colors.black.withOpacity(0.5),
|
||
barrierDismissible: false,
|
||
pageBuilder: (_, __, ___) {
|
||
return WelcomeDialog(
|
||
onAgree: () {
|
||
Navigator.of(context).pop();
|
||
Navigator.pushReplacementNamed(context, '/login');
|
||
},
|
||
onBasicMode: () {
|
||
// 先关闭弹窗
|
||
Navigator.of(context).pop();
|
||
|
||
// 直接使用全局导航器进行页面导航
|
||
navigatorKey.currentState?.pushAndRemoveUntil(
|
||
MaterialPageRoute(
|
||
builder: (context) => const StartPageOne(),
|
||
),
|
||
(route) => false,
|
||
);
|
||
},
|
||
onDisagree: () {
|
||
// 退出应用
|
||
SystemNavigator.pop();
|
||
},
|
||
);
|
||
},
|
||
|
||
);
|
||
});
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return MaterialApp(
|
||
navigatorKey: navigatorKey,
|
||
debugShowCheckedModeBanner: false,
|
||
title: '看那',
|
||
theme: ThemeData(
|
||
useMaterial3: false, //Tabbar取消下划线
|
||
primaryColor: const Color.fromRGBO(255, 255, 255, 0.3),
|
||
appBarTheme: AppBarTheme(
|
||
centerTitle: true,
|
||
backgroundColor: const Color(0xff0C0C16),
|
||
titleTextStyle: Typography.dense2014.bodyLarge,
|
||
),
|
||
// 禁用Android手势返回
|
||
pageTransitionsTheme: PageTransitionsTheme(
|
||
builders: {
|
||
TargetPlatform.android: NoTransitionPageTransitionsBuilder(),
|
||
TargetPlatform.iOS: NoTransitionPageTransitionsBuilder(),
|
||
},
|
||
),
|
||
platform: TargetPlatform.android,
|
||
// 定义默认的输入装饰主题
|
||
inputDecorationTheme: const InputDecorationTheme(
|
||
enabledBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Color.fromRGBO(255, 255, 255, 0.3)),
|
||
),
|
||
focusedBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Color.fromRGBO(255, 255, 255, 0.3)),
|
||
),
|
||
labelStyle: TextStyle(color: Color.fromRGBO(255, 255, 255, 0.3)),
|
||
hintStyle: TextStyle(color: Color.fromRGBO(255, 255, 255, 0.3)),
|
||
),
|
||
// 定义默认的文本选择主题
|
||
textSelectionTheme: TextSelectionThemeData(
|
||
cursorColor: const Color.fromRGBO(255, 255, 255, 0.3), // 光标颜色
|
||
selectionColor:
|
||
const Color.fromRGBO(255, 255, 255, 0.3).withOpacity(0.4), // 选择颜色
|
||
selectionHandleColor:
|
||
const Color.fromRGBO(255, 255, 255, 0.3), // 选择句柄颜色
|
||
),
|
||
),
|
||
home: Builder(
|
||
builder: (context) {
|
||
// 只有在未登录时才显示欢迎弹窗
|
||
if (!Provider.of<AuthProvider>(context).isLoggedIn) {
|
||
_showWelcomeDialog(context);
|
||
}
|
||
|
||
return Provider.of<AuthProvider>(context).isLoggedIn
|
||
? const Tabs(initialIndex: 0)
|
||
: const SplashScreen();
|
||
},
|
||
),
|
||
// Initialize your routes and handle routing
|
||
// initialRoute: "/", 没有home的时候直接进入tabs
|
||
onGenerateRoute: onGenerateRoute,
|
||
);
|
||
}
|
||
}
|
||
|
||
// SplashScreen Widget - 修改后不会自动跳转
|
||
class SplashScreen extends StatelessWidget {
|
||
const SplashScreen({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
// 移除自动跳转逻辑
|
||
return GestureDetector(
|
||
// 添加点击事件,允许用户通过点击跳转到下一页
|
||
onTap: () {
|
||
Navigator.pushReplacement(
|
||
context,
|
||
MaterialPageRoute(builder: (context) => const StartPageOne()),
|
||
);
|
||
},
|
||
child: Container(
|
||
width: double.infinity,
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('images/start.png'),
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
const SizedBox(height: 100),
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(5),
|
||
child: const Image(
|
||
image: AssetImage('images/logo.png'),
|
||
width: 36,
|
||
height: 36,
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
const Text(
|
||
'看那,探索MR元宇宙',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
color: Colors.white,
|
||
decoration: TextDecoration.none),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
// StartPageOne Widget
|
||
class StartPageOne extends StatefulWidget {
|
||
const StartPageOne({super.key});
|
||
|
||
@override
|
||
_StartPageOneState createState() => _StartPageOneState();
|
||
}
|
||
|
||
class _StartPageOneState extends State<StartPageOne> {
|
||
int _currentIndex = 0;
|
||
late PageController _pageController;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_pageController = PageController();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_pageController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: const Color(0xff0C0C16),
|
||
body: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: <Widget>[
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(5), // 设置圆角半径
|
||
child: const Image(
|
||
image: AssetImage('images/logo.png'),
|
||
width: 18,
|
||
height: 18,
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
const SizedBox(width: 10),
|
||
const Text(
|
||
'看那',
|
||
style: TextStyle(fontSize: 18, color: Colors.white),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(
|
||
height: 30,
|
||
),
|
||
SizedBox(
|
||
height: MediaQuery.of(context).size.height * 0.5,
|
||
child: PageView(
|
||
controller: _pageController,
|
||
scrollDirection: Axis.horizontal,
|
||
onPageChanged: (index) {
|
||
setState(() {
|
||
_currentIndex = index;
|
||
});
|
||
},
|
||
children: [
|
||
Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
width: double.infinity,
|
||
height: MediaQuery.of(context).size.height * 0.25,
|
||
margin: const EdgeInsets.only(bottom: 10),
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage(
|
||
'images/loading1.png'), // Replace with your start.png path
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
),
|
||
const Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'奇幻MR之旅',
|
||
style: TextStyle(
|
||
fontSize: 32,
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
Image(
|
||
image: AssetImage('images/trip_new.png'),
|
||
width: 18,
|
||
height: 18,
|
||
fit: BoxFit.fill,
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 10),
|
||
const Text(
|
||
'享受到一种全新、沉浸式的MR旅游体验',
|
||
style: TextStyle(fontSize: 12, color: Color(0xff4E515A)),
|
||
),
|
||
const SizedBox(height: 10),
|
||
const Image(
|
||
image: AssetImage('images/decration.png'),
|
||
width: 60,
|
||
height: 20,
|
||
fit: BoxFit.fill,
|
||
),
|
||
],
|
||
),
|
||
Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
width: double.infinity,
|
||
height: MediaQuery.of(context).size.height * 0.25,
|
||
margin: const EdgeInsets.only(bottom: 10),
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('images/loading2.png'),
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
),
|
||
const Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'探秘MR艺术展',
|
||
style: TextStyle(
|
||
fontSize: 32,
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
Image(
|
||
image: AssetImage('images/trip_new.png'),
|
||
width: 20,
|
||
height: 20,
|
||
fit: BoxFit.fill,
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 10),
|
||
const Text(
|
||
'领略一场震撼、交互式的MR视觉盛宴',
|
||
style: TextStyle(fontSize: 12, color: Color(0xff4E515A)),
|
||
),
|
||
const SizedBox(height: 10),
|
||
const Image(
|
||
image: AssetImage('images/decration.png'),
|
||
width: 60,
|
||
height: 20,
|
||
fit: BoxFit.fill,
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: List.generate(2, (index) {
|
||
return Container(
|
||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||
width: 12,
|
||
height: 12,
|
||
decoration: BoxDecoration(
|
||
shape: BoxShape.circle,
|
||
color: _currentIndex == index ? Colors.white : Colors.grey,
|
||
),
|
||
);
|
||
}),
|
||
),
|
||
const SizedBox(height: 32),
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||
children: <Widget>[
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(8),
|
||
gradient: const LinearGradient(colors: [
|
||
Color(0xff80DAA4),
|
||
Color(0xff79DDED),
|
||
]),
|
||
),
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
if (_currentIndex == 0) {
|
||
setState(() {
|
||
_currentIndex = 1;
|
||
});
|
||
_pageController.animateToPage(
|
||
_currentIndex,
|
||
duration: const Duration(milliseconds: 300),
|
||
curve: Curves.easeInOut,
|
||
);
|
||
} else {
|
||
// 跳转主页
|
||
Navigator.pushReplacementNamed(context, '/tabs');
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.transparent,
|
||
elevation: 0, // 阴影
|
||
shape: const RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.all(Radius.circular(8))),
|
||
minimumSize: const Size(double.infinity, 50),
|
||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||
),
|
||
child: Text(
|
||
_currentIndex == 0 ? '继续' : '开始进入',
|
||
style: const TextStyle(fontSize: 16, color: Colors.black),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
ElevatedButton(
|
||
onPressed: () async {
|
||
final authProvider =
|
||
Provider.of<AuthProvider>(context, listen: false);
|
||
// 使用公开方法名
|
||
await authProvider.loadTokenFromPrefs();
|
||
|
||
if (authProvider.isLoggedIn) {
|
||
// 已登录,直接进入主页并切换到我的页面
|
||
if (!mounted) return;
|
||
Navigator.pushReplacementNamed(context, '/tabs',
|
||
arguments: {'initialIndex': 4});
|
||
} else {
|
||
// 未登录,跳转到登录页
|
||
if (!mounted) return;
|
||
Navigator.pushNamed(context, '/login');
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.transparent,
|
||
shape: const RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||
),
|
||
minimumSize: const Size(double.infinity, 50),
|
||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||
side: const BorderSide(
|
||
style: BorderStyle.solid,
|
||
width: 1, // 边框宽度
|
||
color: Color(0xff73cfcf), // 默认边框颜色
|
||
)),
|
||
child: const Text(
|
||
'登录',
|
||
style: TextStyle(
|
||
color: Color(0xff73cfcf),
|
||
fontSize: 16,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|