Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

weicu
liwei1dao 1 year ago
parent
commit
9fcedbe97f
  1. 4
      ios/Runner/Info.plist
  2. 4
      lib/core/bindings/initial_binding.dart
  3. 34
      lib/data/services/novice_guide_service.dart
  4. 3
      lib/modules/agent/controllers/agent_controller.dart
  5. 21
      lib/modules/agent/views/agent_view.dart
  6. 28
      lib/modules/agent/widgets/sound_bar_widget.dart
  7. 124
      lib/modules/home/controllers/home_controller.dart
  8. 41
      lib/modules/home/views/home_view.dart
  9. 207
      lib/modules/splash/controllers/splash_controller.dart

4
ios/Runner/Info.plist

@ -121,6 +121,10 @@
<string>audio</string> <string>audio</string>
<string>location</string> <string>location</string>
</array> </array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>telephony</string>
</array>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<string>1</string> <string>1</string>

4
lib/core/bindings/initial_binding.dart

@ -6,6 +6,7 @@ import '../../../data/services/navigation_manager.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../data/services/meeting/meeting_task_service.dart'; import '../../data/services/meeting/meeting_task_service.dart';
import '../../data/services/meeting/meeting_upload_service.dart'; import '../../data/services/meeting/meeting_upload_service.dart';
import '../../data/services/novice_guide_service.dart';
import '../../data/services/speech_factory.dart'; import '../../data/services/speech_factory.dart';
import '../../data/services/volcano_translation_service.dart'; import '../../data/services/volcano_translation_service.dart';
import '../../data/services/volcano_ai_service.dart'; import '../../data/services/volcano_ai_service.dart';
@ -64,6 +65,9 @@ class InitialBinding extends Bindings {
// 会议助手音频上传 // 会议助手音频上传
Get.lazyPut<UserportraitManager>(() => UserportraitManager(), fenix: true); Get.lazyPut<UserportraitManager>(() => UserportraitManager(), fenix: true);
// 新手引导
Get.lazyPut<NoviceGuideService>(() => NoviceGuideService(), fenix: true);
// 杰理蓝牙服务 // 杰理蓝牙服务
// // 语言管理器(需要最先初始化) // // 语言管理器(需要最先初始化)

34
lib/data/services/novice_guide_service.dart

@ -0,0 +1,34 @@
import 'package:flutter_intro/flutter_intro.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
class NoviceGuideService extends GetxService {
final GetStorage _storage = GetStorage();
bool isHomeGuide = false;
bool isAIGuide = false;
@override
void onInit() {
super.onInit();
// isHomeGuide = _storage.read('home_guide') ?? false;
// isAIGuide = _storage.read('ai_guide') ?? false;
}
void startHomeGuide() {
if (!isHomeGuide) {
isHomeGuide = true;
_storage.write('home_guide', true);
Intro.of(Get.context!).start(group: 'home');
}
}
void startAIGuide() async {
if (!isAIGuide) {
await Future.delayed(const Duration(milliseconds: 100));
isAIGuide = true;
_storage.write('ai_guide', true);
Intro.of(Get.context!).start(group: 'ai');
}
}
}

3
lib/modules/agent/controllers/agent_controller.dart

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:ffi'; import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:amap_service/amap_service.dart'; import 'package:amap_service/amap_service.dart';
import '../../../data/services/novice_guide_service.dart';
import '/core/utils/upload_oss.dart'; import '/core/utils/upload_oss.dart';
import '/data/models/user_Info.dart'; import '/data/models/user_Info.dart';
import '/data/services/music_manager.dart'; import '/data/services/music_manager.dart';
@ -39,6 +40,8 @@ class AgentController extends GetxController {
final TextEditingController textController = TextEditingController(); final TextEditingController textController = TextEditingController();
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
final noviceGuideService = Get.find<NoviceGuideService>();
//音乐播放管理 //音乐播放管理
final _musiceManager = Get.find<MusicManager>(); final _musiceManager = Get.find<MusicManager>();

21
lib/modules/agent/views/agent_view.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_intro/flutter_intro.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../controllers/agent_controller.dart'; import '../controllers/agent_controller.dart';
import '../controllers/message_action_controller.dart'; import '../controllers/message_action_controller.dart';
@ -388,7 +389,18 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
if (controller.isTextInputMode.value) { if (controller.isTextInputMode.value) {
// 文本输入模式 - 限制最大高度并只向上扩展 // 文本输入模式 - 限制最大高度并只向上扩展
return Container( return IntroStepBuilder(
group: 'ai',
order: 1,
text: '对小言说“今天天气怎么样”',
onWidgetLoad: () {
controller.noviceGuideService
.startAIGuide();
},
builder: (BuildContext context,
GlobalKey key) =>
Container(
key: key,
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: 44.h, minHeight: 44.h,
maxHeight: 120.h, maxHeight: 120.h,
@ -424,10 +436,12 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
maxLines: isImageActive maxLines: isImageActive
? 3 ? 3
: 5, // 设置合理的最大行数 : 5, // 设置合理的最大行数
minLines: isImageActive ? 2 : 1, minLines:
isImageActive ? 2 : 1,
keyboardType: TextInputType keyboardType: TextInputType
.multiline, // 启用多行键盘 .multiline, // 启用多行键盘
textInputAction: TextInputAction textInputAction:
TextInputAction
.newline, // 支持回车换行 .newline, // 支持回车换行
onTap: () { onTap: () {
// 当点击输入框时,如果'+'选项已展开,则收缩 // 当点击输入框时,如果'+'选项已展开,则收缩
@ -479,6 +493,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
), ),
], ],
), ),
),
); );
} else { } else {
Timer? _holdTimer; // 增加延迟触发的计时器 Timer? _holdTimer; // 增加延迟触发的计时器

28
lib/modules/agent/widgets/sound_bar_widget.dart

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../controllers/agent_controller.dart'; import '../controllers/agent_controller.dart';
/// 声音柱动画组件 /// 声音柱动画组件 (已优化)
/// 用于显示语音输入时的音频波形效果 /// 用于显示语音输入时的音频波形效果
class SoundBarWidget extends StatefulWidget { class SoundBarWidget extends StatefulWidget {
final double delay; final double delay;
@ -37,9 +37,8 @@ class _SoundBarWidgetState extends State<SoundBarWidget>
parent: _controller, parent: _controller,
curve: Curves.easeInOut, curve: Curves.easeInOut,
), ),
)..addListener(() { );
setState(() {}); // 移除了 .addListener(() { setState(() {}); })
});
_startOrStopAnimation(); _startOrStopAnimation();
} }
@ -54,6 +53,9 @@ class _SoundBarWidgetState extends State<SoundBarWidget>
/// 开始或停止动画 /// 开始或停止动画
void _startOrStopAnimation() { void _startOrStopAnimation() {
// 确保组件仍然挂载在树上
if (!mounted) return;
if (widget.isActive) { if (widget.isActive) {
Future.delayed(Duration(milliseconds: (widget.delay * 1000).toInt()), () { Future.delayed(Duration(milliseconds: (widget.delay * 1000).toInt()), () {
if (mounted && widget.isActive) { if (mounted && widget.isActive) {
@ -61,9 +63,10 @@ class _SoundBarWidgetState extends State<SoundBarWidget>
} }
}); });
} else { } else {
_controller.reset(); // 停止并平滑地过渡到初始状态
// 设置为小高度的静态状态 _controller.stop();
_controller.animateTo(0.1, duration: const Duration(milliseconds: 300)); _controller.animateTo(0.0,
duration: const Duration(milliseconds: 200), curve: Curves.easeOut);
} }
} }
@ -77,8 +80,13 @@ class _SoundBarWidgetState extends State<SoundBarWidget>
Widget build(BuildContext context) { Widget build(BuildContext context) {
final primaryColor = Theme.of(context).primaryColor; final primaryColor = Theme.of(context).primaryColor;
// 使用 AnimatedBuilder 来优化性能
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container( return Container(
width: 2.5, width: 2.5,
// 当动画不活跃时,高度固定为3;活跃时使用动画值
height: widget.isActive ? _animation.value : 3, height: widget.isActive ? _animation.value : 3,
margin: const EdgeInsets.symmetric(horizontal: 1), margin: const EdgeInsets.symmetric(horizontal: 1),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -88,10 +96,12 @@ class _SoundBarWidgetState extends State<SoundBarWidget>
borderRadius: BorderRadius.circular(1.5), borderRadius: BorderRadius.circular(1.5),
), ),
); );
},
);
} }
} }
/// 声音柱组合组件 /// 声音柱组合组件 (无需改动)
/// 包含多个声音柱的组合显示 /// 包含多个声音柱的组合显示
class SoundBarsWidget extends StatelessWidget { class SoundBarsWidget extends StatelessWidget {
final bool isActive; final bool isActive;
@ -120,7 +130,7 @@ class SoundBarsWidget extends StatelessWidget {
} }
} }
/// 带控制器集成的声音柱组件 /// 带控制器集成的声音柱组件 (无需改动)
/// 自动从AgentController获取状态 /// 自动从AgentController获取状态
class AgentSoundBarsWidget extends StatelessWidget { class AgentSoundBarsWidget extends StatelessWidget {
final int barCount; final int barCount;

124
lib/modules/home/controllers/home_controller.dart

@ -1,13 +1,11 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'dart:async'; import 'dart:async';
import '../../../data/services/novice_guide_service.dart';
import '../../../routes/app_routes.dart'; import '../../../routes/app_routes.dart';
import '../../../core/utils/logger.dart'; import '../../../core/utils/logger.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../data/services/bluetooth_manager.dart'; import '../../../data/services/bluetooth_manager.dart';
import '../../../data/services/ble_manager.dart'; import '../../../data/services/ble_manager.dart';
import '../../../data/services/version_update_service.dart';
import '../../common/widgets/version_update_dialog.dart';
import 'package:get_storage/get_storage.dart';
/// 连接状态枚举 /// 连接状态枚举
enum ConnectionStatus { enum ConnectionStatus {
@ -53,14 +51,9 @@ class HomeController extends GetxController {
final _bluetoothManager = Get.find<BluetoothManager>(); final _bluetoothManager = Get.find<BluetoothManager>();
final _bleManager = Get.find<BleManager>(); final _bleManager = Get.find<BleManager>();
final _storage = GetStorage();
// 会话级别的版本检查标记(静态变量,整个应用会话期间保持) final noviceGuideService = Get.find<NoviceGuideService>();
static bool _hasCheckedVersionInSession = false;
// 版本检查相关常量
static const String _lastVersionCheckKey = 'last_version_check_timestamp';
static const int _versionCheckIntervalHours = 24; // 24小时间隔
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -78,12 +71,6 @@ class HomeController extends GetxController {
void _initWithCachedInfo() { void _initWithCachedInfo() {
_setupStateListeners(); _setupStateListeners();
_checkConnectionStatus(); _checkConnectionStatus();
// 延迟检查版本更新,避免影响页面加载
// 混合检查机制:会话检查 + 24小时间隔检查
Future.delayed(const Duration(seconds: 2), () {
_checkVersionUpdateIfNeeded();
});
} }
void _setupStateListeners() { void _setupStateListeners() {
@ -94,7 +81,8 @@ class HomeController extends GetxController {
update(); update();
}); });
_classicBluetoothWorker = ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { _classicBluetoothWorker =
ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) {
if (device != null) { if (device != null) {
_lastConnectedDeviceName = device.name; _lastConnectedDeviceName = device.name;
} }
@ -181,7 +169,9 @@ class HomeController extends GetxController {
return bleDeviceName; return bleDeviceName;
} }
if (!_isFullyConnected.value && _lastConnectedDeviceName != null && _lastConnectedDeviceName!.isNotEmpty) { if (!_isFullyConnected.value &&
_lastConnectedDeviceName != null &&
_lastConnectedDeviceName!.isNotEmpty) {
return _lastConnectedDeviceName!; return _lastConnectedDeviceName!;
} }
@ -270,104 +260,4 @@ class HomeController extends GetxController {
? deviceInfo.value!.firmwareVersion ? deviceInfo.value!.firmwareVersion
: 'unknown'.tr; : 'unknown'.tr;
} }
/// 混合检查机制:判断是否需要进行版本检查
/// 检查条件:1. 会话内未检查过 OR 2. 距离上次检查超过24小时
void _checkVersionUpdateIfNeeded() {
try {
final now = DateTime.now();
final lastCheckTimestamp = _storage.read(_lastVersionCheckKey);
bool shouldCheck = false;
String reason = '';
// 条件1:会话内未检查过
if (!_hasCheckedVersionInSession) {
shouldCheck = true;
reason = '会话内首次检查';
}
// 条件2:距离上次检查超过24小时
else if (lastCheckTimestamp != null) {
final lastCheckTime = DateTime.fromMillisecondsSinceEpoch(lastCheckTimestamp);
final timeDifference = now.difference(lastCheckTime);
if (timeDifference.inHours >= _versionCheckIntervalHours) {
shouldCheck = true;
reason = '距离上次检查已超过${_versionCheckIntervalHours}小时';
}
}
// 条件3:从未检查过(首次使用应用)
else {
shouldCheck = true;
reason = '首次使用应用';
}
if (shouldCheck) {
Logger.i(_tag, '开始版本检查 - 原因: $reason');
_performVersionCheck();
} else {
Logger.i(_tag, '跳过版本检查 - 会话内已检查且未超过时间间隔');
}
} catch (e) {
Logger.e(_tag, '版本检查判断失败: $e');
}
}
/// 执行版本检查(在后台进行,不阻塞启动流程)
Future<void> _performVersionCheck() async {
try {
final versionService = VersionUpdateService.to;
final updateInfo = await versionService.checkForUpdate();
if (updateInfo.hasUpdate) {
Logger.i(_tag, '发现新版本: ${updateInfo.latestVersion}');
// 显示更新对话框
await VersionUpdateDialog.show(updateInfo);
} else {
Logger.i(_tag, '当前已是最新版本: ${updateInfo.currentVersion}');
}
// 更新检查记录
_updateVersionCheckRecord();
} catch (e) {
Logger.e(_tag, '版本检查失败: $e');
// 即使检查失败,也更新记录,避免频繁重试
_updateVersionCheckRecord();
}
}
/// 更新版本检查记录
void _updateVersionCheckRecord() {
try {
// 更新时间戳
final now = DateTime.now();
_storage.write(_lastVersionCheckKey, now.millisecondsSinceEpoch);
// 标记本次会话已检查过版本
_hasCheckedVersionInSession = true;
Logger.i(_tag, '版本检查记录已更新: ${now.toIso8601String()}');
} catch (e) {
Logger.e(_tag, '更新版本检查记录失败: $e');
}
}
/// 重置版本检查标记(可用于强制重新检查)
/// 注意:这会清除会话标记,但不会清除时间戳记录
static void resetVersionCheckFlag() {
_hasCheckedVersionInSession = false;
Logger.i('HomeCtrl', '版本检查会话标记已重置');
}
/// 完全重置版本检查状态(包括时间戳)
/// 用于测试或特殊情况下强制重新检查
void forceResetVersionCheck() {
try {
_hasCheckedVersionInSession = false;
_storage.remove(_lastVersionCheckKey);
Logger.i(_tag, '版本检查状态已完全重置');
} catch (e) {
Logger.e(_tag, '重置版本检查状态失败: $e');
}
}
} }

41
lib/modules/home/views/home_view.dart

@ -84,11 +84,30 @@ class HomeView extends GetView<HomeController> {
_buildAppBar(isDarkMode), _buildAppBar(isDarkMode),
// 顶部图片 // 顶部图片
_buildEarbudsImage(), IntroStepBuilder(
group: 'home',
order: 1,
text: '欢迎使用Voitrans!首先,让我们唤醒你的专属 AI—— 小言',
onWidgetLoad: () {
controller.noviceGuideService.startHomeGuide();
},
builder: (BuildContext context, GlobalKey key) => SizedBox(
key: key,
child: _buildEarbudsImage(),
),
),
SizedBox(height: 20.h), SizedBox(height: 20.h),
// 设备状态卡片 // 设备状态卡片
_buildDeviceStatusCard(isDarkMode), IntroStepBuilder(
group: 'home',
order: 2,
text: '对着麦克风说“小言小言”',
builder: (BuildContext context, GlobalKey key) => SizedBox(
key: key,
child: _buildDeviceStatusCard(isDarkMode),
),
),
SizedBox(height: 20.h), SizedBox(height: 20.h),
// 热门AI体验 // 热门AI体验
@ -624,8 +643,9 @@ class HomeView extends GetView<HomeController> {
Expanded( Expanded(
flex: 1, flex: 1,
child: IntroStepBuilder( child: IntroStepBuilder(
group: 'home',
order: 3, order: 3,
text: 'AI全能助手', text: '太棒了!你已成功唤醒小言,接下来试试让它帮你做件事吧',
onHighlightWidgetTap: () { onHighlightWidgetTap: () {
Intro.of(Get.context!).dispose(); Intro.of(Get.context!).dispose();
controller.exploreAIFeatures(); controller.exploreAIFeatures();
@ -660,15 +680,7 @@ class HomeView extends GetView<HomeController> {
child: Column( child: Column(
children: [ children: [
// 右上卡片 - 同声翻译 // 右上卡片 - 同声翻译
IntroStepBuilder(
order: 1,
text: '同声传译',
// onWidgetLoad: () {
// Intro.of(Get.context!).start();
// },
builder: (BuildContext context, GlobalKey key) =>
_buildFeatureCard( _buildFeatureCard(
key: key,
title: 'simultaneousInterpretation'.tr, // 同声传译 title: 'simultaneousInterpretation'.tr, // 同声传译
description: description:
'simultaneousInterpretationInfo'.tr, // 80+语言实时翻译,出国无忧 'simultaneousInterpretationInfo'.tr, // 80+语言实时翻译,出国无忧
@ -686,18 +698,12 @@ class HomeView extends GetView<HomeController> {
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
iconColor: const Color(0xFF4CAF50), iconColor: const Color(0xFF4CAF50),
), ),
),
SizedBox(height: 5.h), // 减少间距 SizedBox(height: 5.h), // 减少间距
// 右下卡片 - // 右下卡片 -
// 右下卡片 - 会议助手 // 右下卡片 - 会议助手
IntroStepBuilder(
order: 2,
text: '商务会议助手',
builder: (BuildContext context, GlobalKey key) =>
_buildFeatureCard( _buildFeatureCard(
key: key,
title: 'conferenceAssistant'.tr, // 商务会议助手 title: 'conferenceAssistant'.tr, // 商务会议助手
description: 'conferenceAssistantInfo'.tr, // 实时记录会议纪要,多语言翻译 description: 'conferenceAssistantInfo'.tr, // 实时记录会议纪要,多语言翻译
icon: Icons.people, icon: Icons.people,
@ -716,7 +722,6 @@ class HomeView extends GetView<HomeController> {
isDarkMode: isDarkMode, isDarkMode: isDarkMode,
iconColor: const Color(0xFFd81b60), // 品红 iconColor: const Color(0xFFd81b60), // 品红
), ),
),
], ],
), ),
), ),

207
lib/modules/splash/controllers/splash_controller.dart

@ -14,10 +14,12 @@ import '../../../data/services/network/api.dart';
import '../../../data/services/version_update_service.dart'; import '../../../data/services/version_update_service.dart';
import '../../../modules/common/widgets/version_update_dialog.dart'; import '../../../modules/common/widgets/version_update_dialog.dart';
import '../../../modules/common/widgets/privacy_policy_dialog.dart'; import '../../../modules/common/widgets/privacy_policy_dialog.dart';
import '../../common/webview_page.dart'; import '../../../core/utils/logger.dart';
class SplashController extends GetxController { class SplashController extends GetxController {
final GetStorage _storage = GetStorage(); final GetStorage _storage = GetStorage();
static const String _tag = 'SplashCtrl';
// 进度条动画控制 // 进度条动画控制
final _loadingProgress = 0.0.obs; final _loadingProgress = 0.0.obs;
double get loadingProgress => _loadingProgress.value; double get loadingProgress => _loadingProgress.value;
@ -34,6 +36,13 @@ class SplashController extends GetxController {
// 主题服务 // 主题服务
final ThemeService _themeService = ThemeService(); final ThemeService _themeService = ThemeService();
// 会话级别的版本检查标记(静态变量,整个应用会话期间保持)
static bool _hasCheckedVersionInSession = false;
// 版本检查相关常量
static const String _lastVersionCheckKey = 'last_version_check_timestamp';
static const int _versionCheckIntervalHours = 24; // 24小时间隔
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -50,10 +59,19 @@ class SplashController extends GetxController {
} }
}); });
//弹出用户追中问题 // 异步处理用户追踪授权,不阻塞主流程
WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) async { _requestTrackingPermissionAsync();
final status = }
/// 异步请求追踪权限,不阻塞启动流程
void _requestTrackingPermissionAsync() {
Future.delayed(const Duration(milliseconds: 500), () async {
try {
await AppTrackingTransparency.requestTrackingAuthorization(); await AppTrackingTransparency.requestTrackingAuthorization();
Logger.d(_tag, '用户追踪权限请求完成');
} catch (e) {
Logger.e(_tag, '用户追踪权限请求失败: $e');
}
}); });
} }
@ -62,10 +80,23 @@ class SplashController extends GetxController {
_loadAppResources(); _loadAppResources();
} }
/// 智能调度版本检查,在页面跳转后执行,完全不影响启动流程
void _scheduleVersionCheck() {
// 在独立的微任务中执行,避免阻塞主线程
scheduleMicrotask(() async {
try {
Logger.d(_tag, '开始执行版本检查(后台任务)');
_checkVersionUpdateIfNeeded();
} catch (e) {
Logger.e(_tag, '版本检查调度失败: $e');
}
});
}
void _onPrivacyAccepted() { void _onPrivacyAccepted() {
_storage.write('hasAcceptedPrivacy', true); _storage.write('hasAcceptedPrivacy', true);
Get.back(); // 关闭弹窗 Get.back(); // 关闭弹窗
_startNormalFlow(); // 开始正常流程 _startNormalFlow(); // 开始正常流程(已包含版本检查)
} }
void _onPrivacyRejected() { void _onPrivacyRejected() {
@ -84,18 +115,6 @@ class SplashController extends GetxController {
); );
} }
// 初始化地图SDK
// void _initMapSDK() {
// try {
// AmapFlutter().initSdk(
// iosKey: "a4a1394fe817c2f86a424b897b4a9af4",
// androidKey: "78e7946dd602778df82c6ae143a88184",
// );
// } catch (e) {
// print('地图SDK初始化失败: $e');
// }
// }
// 进度条动画(持续2秒) // 进度条动画(持续2秒)
void _startLoadingAnimation() { void _startLoadingAnimation() {
const totalDuration = 1500; // 动画总时长增加到1.5秒 const totalDuration = 1500; // 动画总时长增加到1.5秒
@ -122,22 +141,23 @@ class SplashController extends GetxController {
// await _loadImages(); // await _loadImages();
// await _initDatabase(); // await _initDatabase();
// 检查版本更新(在后台进行,不阻塞启动流程)
//_checkVersionUpdate();
_isResourceLoaded.value = true; _isResourceLoaded.value = true;
_checkNavigateCondition(); _checkNavigateCondition();
} catch (e) { } catch (e) {
Get.snackbar('错误', '资源加载失败,请检查网络连接'); Get.snackbar('错误', '资源加载失败,请检查网络连接');
_isResourceLoaded.value = true; // 允许用户继续使用 _isResourceLoaded.value = true; // 允许用户继续使用
print('资源加载错误: $e'); Logger.e(_tag, '资源加载错误: $e');
} }
} }
// 检查跳转条件 // 检查跳转条件
void _checkNavigateCondition() { void _checkNavigateCondition() async {
if (_loadingProgress.value >= 1.0 && _isResourceLoaded.value) { if (_loadingProgress.value >= 1.0 && _isResourceLoaded.value) {
_navigateToLogin(); // 关键改动:先执行页面跳转,并用 await 等待它完成
await _navigateToLogin();
// 页面跳转完全结束后,再安心地安排版本检查
_scheduleVersionCheck();
} }
} }
@ -145,7 +165,7 @@ class SplashController extends GetxController {
Future<void> _navigateToLogin() async { Future<void> _navigateToLogin() async {
bool isLoggedIn = false; bool isLoggedIn = false;
final token = _storage.read('logintoken'); final token = _storage.read('logintoken');
print('getLoginToken:进来了${token}'); Logger.d(_tag, 'getLoginToken:进来了${token}');
if (token != null && token.isNotEmpty) { if (token != null && token.isNotEmpty) {
isLoggedIn = await getLoginToken(); isLoggedIn = await getLoginToken();
} }
@ -159,14 +179,14 @@ class SplashController extends GetxController {
Future<bool> getLoginToken() async { Future<bool> getLoginToken() async {
try { try {
print('getLoginToken:进来了'); Logger.d(_tag, 'getLoginToken:进来了');
//if (User.getname() != "") { //if (User.getname() != "") {
final response = await Api.tokenlogin(); final response = await Api.tokenlogin();
print('getLoginToken: $response'); Logger.d(_tag, 'getLoginToken: $response');
if (response == null) return false; if (response == null) return false;
if (response['user'] != '') { if (response['user'] != '') {
print('getLoginToken:进来了'); Logger.d(_tag, 'getLoginToken:进来了');
// 根据API设计调整 // 根据API设计调整
final user = User.fromJson(response); final user = User.fromJson(response);
@ -178,21 +198,21 @@ class SplashController extends GetxController {
//} //}
return false; return false;
} catch (e) { } catch (e) {
print('Token获取失败: $e'); Logger.e(_tag, 'Token获取失败: $e');
return false; return false;
} }
} }
Future<bool> getAppConfig() async { Future<bool> getAppConfig() async {
try { try {
print('getAppConfig:进来了'); Logger.d(_tag, 'getAppConfig:进来了');
//if (User.getname() != "") { //if (User.getname() != "") {
final response = await Api.getappconfig(); final response = await Api.getappconfig();
print('getAppConfig: $response'); Logger.d(_tag, 'getAppConfig: $response');
if (response == null) return false; if (response == null) return false;
// 根据API设计调整 // 根据API设计调整
final resp = UserGetAppConfigResp.fromJson(response); final resp = UserGetAppConfigResp.fromJson(response);
print('getAppConfig:进来了'); Logger.d(_tag, 'getAppConfig:进来了');
// 存储用户信息(示例) // 存储用户信息(示例)
// _storage.write('ENV', resp.env); // _storage.write('ENV', resp.env);
// _storage.write('AGENTS', resp.agents); // _storage.write('AGENTS', resp.agents);
@ -200,27 +220,116 @@ class SplashController extends GetxController {
AppConfig.initialize(resp); AppConfig.initialize(resp);
return true; return true;
} catch (e) { } catch (e) {
print('getAppConfig 取失败: $e'); Logger.e(_tag, 'getAppConfig 取失败: $e');
return false; return false;
} }
} }
/// 检查版本更新(后台执行,不阻塞启动流程) /// 混合检查机制:判断是否需要进行版本检查
// void _checkVersionUpdate() { /// 检查条件:1. 会话内未检查过 OR 2. 距离上次检查超过24小时
// // 延迟执行版本检查,避免影响启动速度 void _checkVersionUpdateIfNeeded() {
// Timer(const Duration(seconds: 1), () async { try {
// try { final now = DateTime.now();
// final versionService = VersionUpdateService.to; final lastCheckTimestamp = _storage.read(_lastVersionCheckKey);
// final updateInfo = await versionService.checkForUpdate();
// if (updateInfo.hasUpdate) { bool shouldCheck = false;
// // 显示更新对话框 String reason = '';
// await VersionUpdateDialog.show(updateInfo);
// } // 条件1:会话内未检查过
// } catch (e) { if (!_hasCheckedVersionInSession) {
// print('版本检查失败: $e'); shouldCheck = true;
// // 版本检查失败不影响用户使用,静默处理 reason = '会话内首次检查';
// } }
// }); // 条件2:距离上次检查超过24小时
// } else if (lastCheckTimestamp != null) {
final lastCheckTime =
DateTime.fromMillisecondsSinceEpoch(lastCheckTimestamp);
final timeDifference = now.difference(lastCheckTime);
if (timeDifference.inHours >= _versionCheckIntervalHours) {
shouldCheck = true;
reason = '距离上次检查已超过${_versionCheckIntervalHours}小时';
}
}
// 条件3:从未检查过(首次使用应用)
else {
shouldCheck = true;
reason = '首次使用应用';
}
if (shouldCheck) {
Logger.i(_tag, '开始版本检查 - 原因: $reason');
_performVersionCheck();
} else {
Logger.i(_tag, '跳过版本检查 - 会话内已检查且未超过时间间隔');
}
} catch (e) {
Logger.e(_tag, '版本检查判断失败: $e');
}
}
/// 执行版本检查(在后台进行,不阻塞启动流程)
Future<void> _performVersionCheck() async {
try {
final versionService = VersionUpdateService.to;
// 异步执行,不等待结果
versionService.checkForUpdate().then((updateInfo) {
if (updateInfo.hasUpdate) {
Logger.i(_tag, '发现新版本: ${updateInfo.latestVersion}');
// 在主线程中显示更新对话框
WidgetsBinding.instance.addPostFrameCallback((_) {
VersionUpdateDialog.show(updateInfo);
});
} else {
Logger.i(_tag, '当前已是最新版本: ${updateInfo.currentVersion}');
}
// 更新检查记录
_updateVersionCheckRecord();
}).catchError((e) {
Logger.e(_tag, '版本检查失败: $e');
// 即使检查失败,也更新记录,避免频繁重试
_updateVersionCheckRecord();
});
} catch (e) {
Logger.e(_tag, '版本检查失败: $e');
// 即使检查失败,也更新记录,避免频繁重试
_updateVersionCheckRecord();
}
}
/// 更新版本检查记录
void _updateVersionCheckRecord() {
try {
// 更新时间戳
final now = DateTime.now();
_storage.write(_lastVersionCheckKey, now.millisecondsSinceEpoch);
// 标记本次会话已检查过版本
_hasCheckedVersionInSession = true;
Logger.i(_tag, '版本检查记录已更新: ${now.toIso8601String()}');
} catch (e) {
Logger.e(_tag, '更新版本检查记录失败: $e');
}
}
/// 重置版本检查标记(可用于强制重新检查)
/// 注意:这会清除会话标记,但不会清除时间戳记录
static void resetVersionCheckFlag() {
_hasCheckedVersionInSession = false;
Logger.i('SplashCtrl', '版本检查会话标记已重置');
}
/// 完全重置版本检查状态(包括时间戳)
/// 用于测试或特殊情况下强制重新检查
void forceResetVersionCheck() {
try {
_hasCheckedVersionInSession = false;
_storage.remove(_lastVersionCheckKey);
Logger.i(_tag, '版本检查状态已完全重置');
} catch (e) {
Logger.e(_tag, '重置版本检查状态失败: $e');
}
}
} }

Loading…
Cancel
Save