Files
xianyan/lib/features/mine/settings/presentation/general/general_settings_page.dart
2026-06-06 06:54:22 +08:00

1027 lines
31 KiB
Dart

/// ============================================================
/// 闲言APP — 通用设置页面
/// 创建时间: 2026-04-28
/// 更新时间: 2026-06-05
/// 作用: 声音/震动/通知/显示/性能/隐私/高级等设置
/// 上次更新: 添加无障碍分组支持(语义调试开关+系统级状态指示)
/// ============================================================
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:xianyan/core/router/app_nav_extension.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../../../../../../core/constants/app_constants.dart';
import '../../../../../../core/router/app_routes.dart';
import '../../../../../../core/services/device/app_lock_service.dart';
import '../../../../../../core/services/device/haptic_service.dart';
import '../../../../../../core/services/feature/feature_flag_service.dart';
import '../../../../../../core/services/search/search_history_service.dart';
import '../../../../../../core/storage/kv_storage.dart';
import '../../../../../../core/theme/app_colors.dart';
import '../../../../../../core/theme/app_theme.dart';
import '../../../../../../core/theme/app_spacing.dart';
import '../../../../../../core/theme/app_typography.dart';
import '../../../../../../core/theme/app_radius.dart';
import '../../../../../../l10n/translations.dart';
import '../../../../../../shared/widgets/adaptive/adaptive_back_button.dart';
import '../../../../../../shared/widgets/containers/glass_container.dart';
import '../../providers/general_settings_provider.dart';
import '../../providers/plugin_provider.dart';
import '../../../../../../core/providers/split_view_provider.dart';
import 'package:xianyan/features/home/providers/offline_provider.dart';
import 'general_settings_sections.dart';
import 'general_settings_pickers.dart';
import 'general_settings_actions.dart';
import 'log_level_settings_page.dart';
import 'setting_models.dart';
class GeneralSettingsPage extends ConsumerStatefulWidget {
const GeneralSettingsPage({super.key});
@override
ConsumerState<GeneralSettingsPage> createState() =>
_GeneralSettingsPageState();
}
class _GeneralSettingsPageState extends ConsumerState<GeneralSettingsPage>
with GeneralSettingsPickers, GeneralSettingsActions {
String _searchQuery = '';
final _searchController = TextEditingController();
final _searchFocusNode = FocusNode();
String _versionText = '';
List<String> _searchHistory = [];
static const _maxHistory = 10;
@override
void initState() {
super.initState();
_searchFocusNode.canRequestFocus = false;
_loadVersion();
_loadSearchHistory();
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(generalSettingsProvider.notifier).calculateCacheSize();
});
}
@override
void dispose() {
_searchController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
void _loadSearchHistory() {
final settings = ref.read(generalSettingsProvider);
if (!settings.searchHistoryEnabled) {
setState(() => _searchHistory = []);
return;
}
final allHistory = SearchHistoryService.instance.getSearchHistory();
setState(() {
_searchHistory = allHistory.take(_maxHistory).toList();
});
}
void _addToHistory(String query) {
if (query.trim().isEmpty) return;
final settings = ref.read(generalSettingsProvider);
if (!settings.searchHistoryEnabled) return;
SearchHistoryService.instance.addSearchRecord(query.trim());
setState(() {
_searchHistory.remove(query.trim());
_searchHistory.insert(0, query.trim());
if (_searchHistory.length > _maxHistory) {
_searchHistory = _searchHistory.sublist(0, _maxHistory);
}
});
}
void _removeHistory(String query) {
SearchHistoryService.instance.removeSearchRecord(query);
setState(() {
_searchHistory.remove(query);
});
}
void _clearHistory() {
SearchHistoryService.instance.clearSearchHistory();
setState(() {
_searchHistory.clear();
});
}
// ── 加载版本号 ──
Future<void> _loadVersion() async {
try {
final info = await PackageInfo.fromPlatform();
if (mounted) {
setState(() {
_versionText = 'v${info.version} (${info.buildNumber})';
});
}
} catch (_) {
_versionText = 'v${AppVersion.version}';
}
}
// ── 过滤后的设置分组 ──
List<SettingSection> get _filteredSections {
final settings = ref.watch(generalSettingsProvider);
final notificationEnabled = ref.watch(notificationEnabledProvider);
final offlineState = ref.watch(offlineProvider);
final pluginState = ref.watch(pluginProvider);
final t = ref.watch(translationsProvider);
final splitState = ref.watch(splitViewProvider);
final allSections = buildGeneralSettingSections(
settings: settings,
notificationEnabled: notificationEnabled,
preloadEnabled: offlineState.config.preloadOnWifi,
appLockMethodLabel: ref.watch(appLockProvider).method.label,
pluginState: pluginState,
t: t,
navBarPositionIndex: splitState.navBarPosition.index,
splitRatio: splitState.splitRatio,
splitViewEnabled: splitState.splitViewEnabled,
);
return filterSettingSections(
allSections,
_searchQuery,
pinyinMatcher: _matchesPinyin,
);
}
static const _pinyinMap = <String, String>{
'shengyin': '声音',
'zhendong': '震动',
'yinjian': '音效',
'tongzhi': '通知',
'xianshi': '显示',
'ziti': '字体',
'yuyan': '语言',
'xingneng': '性能',
'yinsi': '隐私',
'quanxian': '权限',
'gaoji': '高级',
'qita': '其他',
'suoping': '锁屏',
'yingyong': '应用',
'houtai': '后台',
'huancun': '缓存',
'jianpan': '键盘',
'jianqieban': '剪贴板',
'yejian': '夜间',
'shendu': '深度',
'zhineng': '智能',
'moshi': '模式',
'jiaohu': '交互',
'tixing': '提醒',
'meiri': '每日',
'shuaka': '刷新',
'chakan': '查看',
'shezhi': '设置',
'guanyu': '关于',
'banben': '版本',
'gengxin': '更新',
'daochu': '导出',
'daoru': '导入',
'chongzhi': '重置',
'qingli': '清理',
'fuzhu': '辅助',
'secai': '色彩',
'jiacu': '加粗',
'dianchi': '电池',
'cunchu': '存储',
'guanli': '管理',
'changliang': '常亮',
'chidu': '尺寸',
'midu': '密度',
'donghua': '动画',
'texiao': '特效',
'beijing': '背景',
'qiehuan': '切换',
'yidao': '摇到',
'yaoyiyao': '摇一摇',
'changjing': '场景',
'yuedu': '阅读',
'liulan': '浏览',
'sousuo': '搜索',
'shoucang': '收藏',
'lishi': '历史',
'jiance': '检测',
'jiankang': '健康',
'bizhi': '壁纸',
'yuan': '',
'xiaozujian': '小组件',
'zhuomian': '桌面',
'bianji': '编辑',
'muban': '模板',
'tupian': '图片',
'fenlei': '分类',
'biaoqian': '标签',
'shuju': '数据',
'tongbu': '同步',
'beifen': '备份',
'huifu': '恢复',
'anzhuang': '安装',
'xiezai': '卸载',
'zidingyi': '自定义',
'zhuti': '主题',
'peise': '配色',
'yese': '夜色',
'riqi': '日期',
'shijian': '时间',
'daojishi': '倒计时',
'fanqiezhong': '番茄钟',
'jieqi': '节气',
'qiandao': '签到',
'yunshi': '运势',
'juju': '句子',
};
bool _matchesPinyin(String query, String text) {
final q = query.toLowerCase();
if (text.toLowerCase().contains(q)) return true;
for (final entry in _pinyinMap.entries) {
if (entry.key.contains(q) && text.contains(entry.value)) return true;
}
return false;
}
// ── 页面构建 ──
@override
Widget build(BuildContext context) {
final ext = AppTheme.ext(context);
final t = ref.watch(translationsProvider);
return CupertinoPageScaffold(
backgroundColor: ext.bgPrimary,
navigationBar: CupertinoNavigationBar(
leading: const AdaptiveBackButton(),
middle: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(CupertinoIcons.settings, size: 18, color: ext.accent),
const SizedBox(width: 6),
Text(
t.generalSettings,
style: AppTypography.title3.copyWith(color: ext.textPrimary),
),
],
),
backgroundColor: ext.bgElevated.withValues(alpha: 0.85),
border: null,
),
child: SafeArea(
bottom: false,
child: Column(
children: [
_buildSearchBar(ext),
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
children: [
..._filteredSections.expand(
(section) => [
_buildSectionHeader(ext, section),
const SizedBox(height: AppSpacing.xs),
...section.items.map(
(item) => Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.xs),
child: _buildSettingCard(ext, item),
),
),
const SizedBox(height: AppSpacing.sm),
],
),
_buildSuggestions(ext),
const SizedBox(height: AppSpacing.lg),
_buildFooter(ext),
const SizedBox(height: AppSpacing.xl),
],
),
),
],
),
),
);
}
// ── 搜索栏 ──
Widget _buildSearchBar(AppThemeExtension ext) {
final t = ref.watch(translationsProvider);
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
child: GestureDetector(
onTap: () {
_searchFocusNode.canRequestFocus = true;
_searchFocusNode.requestFocus();
},
child: Container(
decoration: BoxDecoration(
color: ext.bgSecondary,
borderRadius: AppRadius.lgBorder,
),
child: CupertinoTextField(
controller: _searchController,
focusNode: _searchFocusNode,
placeholder: t.searchSettings,
prefix: Padding(
padding: const EdgeInsets.only(left: AppSpacing.md),
child: Icon(
CupertinoIcons.search,
size: 16,
color: ext.textHint,
),
),
suffix: _searchQuery.isNotEmpty
? GestureDetector(
onTap: () {
_searchController.clear();
setState(() => _searchQuery = '');
},
child: Padding(
padding: const EdgeInsets.only(right: AppSpacing.sm),
child: Icon(
CupertinoIcons.clear_circled_solid,
size: 18,
color: ext.textHint,
),
),
)
: null,
placeholderStyle: AppTypography.subhead.copyWith(
color: ext.textHint,
),
style: AppTypography.body.copyWith(color: ext.textPrimary),
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.sm,
vertical: AppSpacing.sm,
),
decoration: null,
onChanged: (v) => setState(() => _searchQuery = v),
onSubmitted: (v) {
if (v.trim().isNotEmpty) _addToHistory(v.trim());
},
),
),
),
),
if (_searchQuery.isEmpty && _searchHistory.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'搜索历史',
style: AppTypography.caption1.copyWith(
color: ext.textHint,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
GestureDetector(
onTap: _clearHistory,
child: Text(
'清除',
style: AppTypography.caption1.copyWith(
color: ext.accent,
),
),
),
],
),
const SizedBox(height: AppSpacing.xs),
Wrap(
spacing: 6,
runSpacing: 6,
children: _searchHistory.map((keyword) {
return GestureDetector(
onTap: () {
_searchController.text = keyword;
setState(() => _searchQuery = keyword);
},
onLongPress: () => _removeHistory(keyword),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: ext.bgSecondary,
borderRadius: AppRadius.pillBorder,
),
child: Text(
keyword,
style: AppTypography.caption1.copyWith(
color: ext.textSecondary,
),
),
),
);
}).toList(),
),
],
),
),
],
);
}
// ── 分组标题 ──
Widget _buildSectionHeader(AppThemeExtension ext, SettingSection section) {
return Padding(
padding: const EdgeInsets.only(left: AppSpacing.xs),
child: Row(
children: [
Icon(section.icon, size: 14, color: section.color),
const SizedBox(width: 6),
Text(
section.title,
style: AppTypography.caption1.copyWith(
color: ext.textHint,
fontWeight: FontWeight.w600,
),
),
],
),
);
}
// ── 设置项卡片 ──
Widget _buildSettingCard(AppThemeExtension ext, SettingItem item) {
return GlassContainer(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm + 2,
),
child: _buildItemContent(ext, item),
);
}
Widget _buildPlaceholderContent(
AppThemeExtension ext,
SettingItem item,
FeatureFlag? flag,
) {
final iconWidget = Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: CupertinoColors.systemGrey.withValues(alpha: 0.08),
borderRadius: AppRadius.xsBorder,
),
child: Center(
child: Icon(
CupertinoIcons.lock_fill,
size: 15,
color: CupertinoColors.systemGrey.resolveFrom(context),
),
),
);
final titleColumn = Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.sm),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title,
style: AppTypography.subhead.copyWith(
color: CupertinoColors.secondaryLabel.resolveFrom(context),
fontWeight: FontWeight.w500,
),
),
Text(
item.subtitle,
style: AppTypography.caption1.copyWith(
color: CupertinoColors.tertiaryLabel.resolveFrom(context),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
Widget trailing;
switch (item.type) {
case SettingType.toggle:
trailing = const CupertinoSwitch(
value: false,
activeTrackColor: CupertinoColors.systemGrey,
onChanged: null,
);
case SettingType.selection:
case SettingType.navigation:
trailing = Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'开发中',
style: AppTypography.caption1.copyWith(
color: CupertinoColors.tertiaryLabel.resolveFrom(context),
),
),
const SizedBox(width: 4),
Icon(
CupertinoIcons.chevron_right,
size: 14,
color: CupertinoColors.tertiaryLabel.resolveFrom(context),
),
],
);
case SettingType.action:
trailing = Icon(
CupertinoIcons.chevron_right,
size: 14,
color: CupertinoColors.tertiaryLabel.resolveFrom(context),
);
}
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
HapticService.selection();
final message = flag?.unsupportedMessage ?? '该功能当前设备不支持';
showCupertinoDialog<void>(
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(item.title),
content: Text(message),
actions: [
CupertinoDialogAction(
child: const Text('知道了'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
child: Opacity(
opacity: 0.6,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(children: [iconWidget, titleColumn, trailing]),
),
),
);
}
// ── 设置项内容(根据类型渲染不同控件) ──
Widget _buildItemContent(AppThemeExtension ext, SettingItem item) {
final flag = FeatureFlagService.fromSettingId(item.id);
if (item.isPlaceholder || FeatureFlagService.isPlaceholder(flag)) {
return _buildPlaceholderContent(ext, item, flag);
}
final iconWidget = Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: item.iconColor.withValues(alpha: 0.12),
borderRadius: AppRadius.xsBorder,
),
child: Center(child: Icon(item.icon, size: 17, color: item.iconColor)),
);
final titleColumn = Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.sm),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title,
style: AppTypography.subhead.copyWith(
color: item.isDestructive ? ext.accent : ext.textPrimary,
fontWeight: FontWeight.w500,
),
),
Text(
item.subtitle,
style: AppTypography.caption1.copyWith(color: ext.textHint),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
switch (item.type) {
case SettingType.toggle:
if (item.isLocked) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
HapticService.selection();
showCupertinoDialog<void>(
context: context,
builder: (_) => CupertinoAlertDialog(
content: const Text('该功能暂不可用'),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: const Text('知道了'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
child: Opacity(
opacity: 0.5,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(
children: [
iconWidget,
titleColumn,
const CupertinoSwitch(
value: false,
activeTrackColor: CupertinoColors.systemGrey,
onChanged: null,
),
],
),
),
),
);
}
return Row(
children: [
iconWidget,
titleColumn,
CupertinoSwitch(
value: item.value ?? false,
activeTrackColor: ext.accent,
onChanged: (v) => _onToggle(item.id, v),
),
],
);
case SettingType.selection:
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _onSelection(item.id),
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(
children: [
iconWidget,
titleColumn,
Text(
item.displayValue ?? '',
style: AppTypography.caption1.copyWith(
color: ext.textSecondary,
),
),
const SizedBox(width: 4),
Icon(
CupertinoIcons.chevron_right,
size: 14,
color: ext.textHint,
),
],
),
),
);
case SettingType.navigation:
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _onNavigate(item.id),
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(
children: [
iconWidget,
titleColumn,
Text(
item.displayValue ?? '',
style: AppTypography.caption1.copyWith(
color: ext.textSecondary,
),
),
const SizedBox(width: 4),
Icon(
CupertinoIcons.chevron_right,
size: 14,
color: ext.textHint,
),
],
),
),
);
case SettingType.action:
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _onAction(item.id),
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(
children: [
iconWidget,
titleColumn,
Icon(
CupertinoIcons.chevron_right,
size: 14,
color: ext.textHint,
),
],
),
),
);
}
}
// ── 推荐设置区域 ──
Widget _buildSuggestions(AppThemeExtension ext) {
final t = ref.watch(translationsProvider);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: AppSpacing.xs),
child: Row(
children: [
const Icon(
CupertinoIcons.lightbulb_fill,
size: 14,
color: AppColors.iosYellow,
),
const SizedBox(width: 6),
Text(
t.youMayBeLookingFor,
style: AppTypography.caption1.copyWith(
color: ext.textHint,
fontWeight: FontWeight.w600,
),
),
],
),
),
const SizedBox(height: AppSpacing.xs),
GlassContainer(
padding: const EdgeInsets.all(AppSpacing.md),
child: Column(
children: [
_suggestionRow(
ext,
CupertinoIcons.paintbrush_fill,
AppColors.iosPurple,
t.themeCustomization,
'/settings/theme',
),
const SizedBox(height: AppSpacing.sm),
_suggestionRow(
ext,
CupertinoIcons.textbox,
AppColors.iosLightPurple,
t.fontManagement,
'/settings/fonts',
),
const SizedBox(height: AppSpacing.sm),
_suggestionRow(
ext,
CupertinoIcons.folder_fill,
AppColors.iosOrange,
t.profile.dataManagement,
'/settings/data',
),
],
),
),
],
);
}
// ── 推荐项行 ──
Widget _suggestionRow(
AppThemeExtension ext,
IconData icon,
Color color,
String title,
String route,
) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => context.appPush(route),
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 44),
child: Row(
children: [
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.12),
borderRadius: AppRadius.xsBorder,
),
child: Center(child: Icon(icon, size: 15, color: color)),
),
const SizedBox(width: AppSpacing.sm),
Expanded(
child: Text(
title,
style: AppTypography.subhead.copyWith(color: ext.textPrimary),
),
),
Icon(CupertinoIcons.chevron_right, size: 14, color: ext.textHint),
],
),
),
);
}
// ── 页脚(版本号 + 版权) ──
Widget _buildFooter(AppThemeExtension ext) {
final t = ref.watch(translationsProvider);
return Column(
children: [
Text(
'闲言 $_versionText',
style: AppTypography.caption1.copyWith(
color: ext.textHint,
fontSize: 11,
),
),
const SizedBox(height: 2),
Text(
t.copyright,
style: AppTypography.caption1.copyWith(
color: ext.textHint,
fontSize: 10,
),
),
],
);
}
// ── 开关切换事件 ──
void _onToggle(String id, bool value) {
HapticService.toggleSwitch();
final notifier = ref.read(generalSettingsProvider.notifier);
final lockedIds = {'predictive_back', 'long_press_preview'};
if (lockedIds.contains(id)) {
showCupertinoDialog<void>(
context: context,
builder: (_) => CupertinoAlertDialog(
content: const Text('该功能暂不可用'),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: const Text('知道了'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
return;
}
switch (id) {
case 'sound':
notifier.setSoundEnabled(value);
case 'immersive_status':
notifier.setImmersiveStatusBar(value);
case 'reduce_animations':
notifier.setReduceAnimations(value);
case 'preload':
final config = ref.read(offlineProvider).config;
ref
.read(offlineProvider.notifier)
.updateConfig(config.copyWith(preloadOnWifi: value));
case 'data_saver':
notifier.setDataSaverMode(value);
case 'clipboard_read':
notifier.setClipboardReadEnabled(value);
case 'app_lock':
context.appPush(AppRoutes.appLockSettings);
case 'sfx':
notifier.setSfxEnabled(value);
case 'shake_to_switch':
notifier.setShakeToSwitch(value);
case 'daily_notification':
notifier.setDailyNotification(value);
case 'shader_background':
notifier.setShaderBackground(value);
case 'nearby_discovery':
notifier.setNearbyDiscovery(value);
case 'split_view_enabled':
ref.read(splitViewProvider.notifier).setSplitViewEnabled(value);
}
}
// ── 选择器事件 ──
void _onSelection(String id) {
HapticService.selection();
_searchFocusNode.unfocus();
switch (id) {
case 'vibration':
showVibrationPicker();
case 'sound_effect':
showSoundEffectPicker();
case 'screen_timeout':
showScreenTimeoutPicker();
case 'language':
context.appPush(AppRoutes.languageSettings);
case 'startup_page':
showStartupPagePicker();
case 'page_transition_mode':
showPageTransitionModePicker();
case 'content_density':
showContentDensityPicker();
case 'cache_strategy':
showCacheStrategyPicker();
case 'image_quality':
showImageQualityPicker();
case 'sfx_style':
showSfxStylePicker();
case 'screen_always_on':
showScreenAlwaysOnPicker();
case 'notify_time':
showNotifyTimePicker();
case 'nav_bar_position':
showNavBarPositionPicker();
case 'split_view_ratio':
showSplitRatioPicker();
}
}
// ── 导航事件 ──
void _onNavigate(String id) {
HapticService.selection();
_searchFocusNode.unfocus();
switch (id) {
case 'plugin':
context.appPush(AppRoutes.plugin);
case 'notification':
context.appPush(AppRoutes.notificationSettings);
case 'smart_mode':
context.appPush(AppRoutes.smartModeSettings);
case 'other_settings':
context.appPush(AppRoutes.otherSettings);
case 'permission':
context.appPush(AppRoutes.permissionManagement);
case 'font_scale':
context.appPush(AppRoutes.fontManagement);
case 'app_lock':
context.appPush(AppRoutes.appLockSettings);
case 'log_level':
Navigator.of(context).push<void>(
CupertinoPageRoute<void>(
builder: (_) => const LogLevelSettingsPage(),
),
);
}
}
// ── 操作事件 ──
void _onAction(String id) {
HapticService.impact();
_searchFocusNode.unfocus();
switch (id) {
case 'reopen_onboarding':
// 需要先重置引导页状态,否则路由重定向会阻止跳转
_reopenOnboarding();
}
}
/// 重新打开引导页:先重置存储状态,再导航
Future<void> _reopenOnboarding() async {
await KvStorage.setBool(StorageKeys.onboardingCompleted, false);
await KvStorage.setShowOnboarding(true);
if (mounted) {
context.appGo(AppRoutes.onboarding);
}
}
}