Files
flutterApp/lib/features/v2/my/presentation/pages/system_settings_page.dart
2026-09-14 12:35:20 +08:00

499 lines
16 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 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart';
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
import 'package:maibu_satabot_v2/core/localization/locale_cubit.dart';
import 'package:maibu_satabot_v2/core/router/route_paths.dart';
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
import 'package:maibu_satabot_v2/core/storage/user_storage.dart';
import 'package:maibu_satabot_v2/features/auth/presentation/bloc/auth_cubit.dart';
import 'package:maibu_satabot_v2/features/main_container/presentation/cubit/tab_config_cubit.dart';
import 'package:maibu_satabot_v2/features/main_container/domain/tab_config.dart';
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/cubit/float_bar_setting_cubit.dart';
import 'package:maibu_satabot_v2/core/update/update_cubit.dart';
import 'package:maibu_satabot_v2/core/update/update_state.dart';
/// 系统设置综合页面
class SystemSettingsPage extends StatefulWidget {
const SystemSettingsPage({super.key});
@override
State<SystemSettingsPage> createState() => _SystemSettingsPageState();
}
class _SystemSettingsPageState extends State<SystemSettingsPage> {
String _currentVersion = '';
int _currentVersionCode = 0;
@override
void initState() {
super.initState();
_loadVersion();
}
Future<void> _loadVersion() async {
try {
final String versionString = await rootBundle.loadString('pubspec.yaml');
final versionMatch = RegExp(r'version:\s*(\d+\.\d+\.\d+)\+(\d+)').firstMatch(versionString);
setState(() {
_currentVersion = versionMatch?.group(1) ?? '1.0.0';
_currentVersionCode = int.tryParse(versionMatch?.group(2) ?? '1') ?? 1;
});
} catch (_) {}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: context.appColors.pageBackground,
appBar: AppBar(
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: context.appColors.textPrimary),
onPressed: () => Navigator.pop(context),
),
title: Text(
AppLocalizations.of(context).translate('my.settings'),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: context.appColors.textPrimary,
),
),
centerTitle: true,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// Tab 设置
_buildTabSettingsSection(),
const SizedBox(height: 12),
// 悬浮条设置
_buildFloatBarSection(),
const SizedBox(height: 12),
// 语言设置
_buildLanguageSection(),
const SizedBox(height: 12),
// 版本更新
_buildUpdateSection(),
const SizedBox(height: 12),
// 退出登录(已挪至“我的”页面最下边,此处注释掉)
// _buildLogoutButton(context),
// const SizedBox(height: 20),
],
),
);
}
/// 悬浮条设置
Widget _buildFloatBarSection() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: context.appColors.cardBackground,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: context.appColors.cardShadow,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context).translate('my_v2.suspend_bar'),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: context.appColors.textPrimary,
),
),
const SizedBox(height: 4),
Text(
AppLocalizations.of(
context,
).translate('my_v2.suspend_bar_desc'),
style: TextStyle(
fontSize: 13,
color: context.appColors.textTertiary,
),
),
],
),
),
ValueListenableBuilder<bool>(
valueListenable: FloatBarSettingService.settingNotifier,
builder: (context, isEnabled, child) {
return Switch(
value: isEnabled,
onChanged: (value) {
FloatBarSettingService.setEnabled(value);
},
activeColor: const Color(0xFF165DFF),
);
},
),
],
),
);
}
/// Tab 设置
Widget _buildTabSettingsSection() {
// 🔥 个人角色(roleKey == 'personal'):Tab 设置只列出「设备 + 我的」,且开关常开锁定
final roleKey = context.watch<AppUserCubit>().state.user?.roleKey;
final isPersonal = roleKey == TabConfig.personalRoleKey;
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: context.appColors.cardBackground,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: context.appColors.cardShadow,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context).translate('my_v2.tab_settings'),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: context.appColors.textPrimary,
),
),
const SizedBox(height: 16),
BlocBuilder<TabConfigCubit, dynamic>(
builder: (context, state) {
if (state.runtimeType.toString() != 'TabConfigLoaded') {
return const Center(child: CircularProgressIndicator());
}
final tabs = state.config.settingItemsForRole(roleKey);
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: tabs.length,
itemBuilder: (context, index) {
final tab = tabs[index];
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
children: [
Expanded(
child: Text(
tab.name,
style: TextStyle(
fontSize: 14,
color: context.appColors.textPrimary,
),
),
),
Switch(
// 个人角色:设备/我的 强制常开且不可关闭
value: isPersonal ? true : tab.isEnabled,
onChanged: isPersonal
? null
: (value) {
context.read<TabConfigCubit>().toggleTab(tab.id);
},
activeColor: const Color(0xFF165DFF),
),
],
),
);
},
);
},
),
],
),
);
}
/// 语言设置
Widget _buildLanguageSection() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: context.appColors.cardBackground,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: context.appColors.cardShadow,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context).translate('my.language'),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: context.appColors.textPrimary,
),
),
const SizedBox(height: 16),
BlocBuilder<LocaleCubit, Locale>(
builder: (context, locale) {
return Column(
children: [
_buildLanguageOption(
AppLocalizations.of(context).translate('my.chinese'),
'zh',
locale.languageCode == 'zh',
() => context.read<LocaleCubit>().setLocale(
const Locale('zh', 'CN'),
),
),
const SizedBox(height: 12),
_buildLanguageOption(
AppLocalizations.of(context).translate('my.english'),
'en',
locale.languageCode == 'en',
() => context.read<LocaleCubit>().setLocale(
const Locale('en', 'US'),
),
),
],
);
},
),
],
),
);
}
Widget _buildLanguageOption(
String label,
String code,
bool isSelected,
VoidCallback onTap,
) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF165DFF).withOpacity(0.1)
: Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected
? const Color(0xFF165DFF)
: context.appColors.divider,
width: 1,
),
),
child: Row(
children: [
Expanded(
child: Text(
label,
style: TextStyle(
fontSize: 14,
color: isSelected
? const Color(0xFF165DFF)
: context.appColors.textPrimary,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
),
),
),
if (isSelected)
const Icon(
Icons.check_circle,
color: Color(0xFF165DFF),
size: 20,
),
],
),
),
);
}
/// 版本更新
Widget _buildUpdateSection() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: context.appColors.cardBackground,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: context.appColors.cardShadow,
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: BlocConsumer<UpdateCubit, UpdateState>(
listener: (context, state) {
if (state is UpdateUpToDate) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('当前已是最新版本'),
backgroundColor: context.appColors.success,
duration: const Duration(seconds: 2),
),
);
}
},
builder: (context, state) {
final isChecking = state is UpdateChecking;
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'版本更新',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: context.appColors.textPrimary,
),
),
const SizedBox(height: 4),
Text(
'当前版本: $_currentVersion ($_currentVersionCode)',
style: TextStyle(
fontSize: 13,
color: context.appColors.textTertiary,
),
),
const SizedBox(height: 2),
Text(
isChecking ? '正在检查更新...' : '点击检查是否有新版本',
style: TextStyle(
fontSize: 13,
color: context.appColors.textTertiary,
),
),
],
),
),
if (isChecking)
const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
)
else
GestureDetector(
onTap: () {
context.read<UpdateCubit>().checkUpdate();
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
color: const Color(0xFF165DFF),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'检查更新',
style: TextStyle(
fontSize: 14,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
),
],
);
},
),
);
}
/// 退出登录按钮(已挪至“我的”页面最下边,此处注释掉)
// Widget _buildLogoutButton(BuildContext context) {
// return GestureDetector(
// onTap: () {
// _showLogoutDialog(context);
// },
// child: Container(
// padding: const EdgeInsets.symmetric(vertical: 16),
// decoration: BoxDecoration(
// color: context.appColors.cardBackground,
// borderRadius: BorderRadius.circular(12),
// boxShadow: [
// BoxShadow(
// color: context.appColors.cardShadow,
// blurRadius: 8,
// offset: Offset(0, 2),
// ),
// ],
// ),
// child: Center(
// child: Text(
// AppLocalizations.of(context).translate('login.logout'),
// style: const TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// color: Color(0xFFF53F3F),
// ),
// ),
// ),
// ),
// );
// }
/// 显示退出登录确认对话框(已挪至“我的”页面最下边,此处注释掉)
// void _showLogoutDialog(BuildContext context) {
// showDialog(
// context: context,
// builder: (context) => AlertDialog(
// title: Text(AppLocalizations.of(context).translate('login.logout')),
// content: Text(
// AppLocalizations.of(context).translate('login.confirm_logout'),
// ),
// actions: [
// TextButton(
// onPressed: () => Navigator.pop(context),
// child: Text(AppLocalizations.of(context).translate('my_v2.cancel')),
// ),
// TextButton(
// onPressed: () async {
// Navigator.pop(context);
// // 执行退出登录逻辑
// await GetIt.I<UserStorage>().deleteUser();
// GetIt.I<AuthCubit>().logout();
// context.go(RoutePaths.login);
// },
// style: TextButton.styleFrom(
// foregroundColor: const Color(0xFFF53F3F),
// ),
// child: Text(
// AppLocalizations.of(context).translate('my_v2.confirm'),
// ),
// ),
// ],
// ),
// );
// }
}