import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../data/models/user_setting_model.dart'; import '../../providers/user_setting_provider.dart'; import '../../widgets/toast_helper.dart'; import '../../widgets/desktop_constrained.dart'; /// 文件偏好设置页 class FilePreferencesPage extends StatefulWidget { const FilePreferencesPage({super.key}); @override State createState() => _FilePreferencesPageState(); } class _FilePreferencesPageState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().loadSettings(); }); } @override Widget build(BuildContext context) { final provider = context.watch(); final settings = provider.settings; return Scaffold( appBar: AppBar(title: const Text('文件偏好')), body: DesktopConstrained( child: ListView( children: [ _buildSection( title: '版本保留', children: [ SwitchListTile( secondary: const Icon(Icons.history), title: const Text('启用版本保留'), subtitle: const Text('保留文件的历史版本'), value: settings?.versionRetentionEnabled ?? false, onChanged: (value) async { final success = await context.read().updateVersionRetention(enabled: value); if (!mounted) return; if (!success) ToastHelper.failure('更新失败'); }, ), ListTile( leading: const Icon(Icons.filter_list), title: const Text('保留的文件类型'), subtitle: Text( settings?.versionRetentionExt == null ? '所有文件类型' : (settings!.versionRetentionExt!.isEmpty ? '所有文件类型' : settings.versionRetentionExt!.join(', ')), ), trailing: const Icon(Icons.chevron_right), enabled: settings?.versionRetentionEnabled ?? false, onTap: () => _showExtEditor(context, settings), ), ListTile( leading: const Icon(Icons.numbers), title: const Text('最大保留版本数'), subtitle: Text( (settings?.versionRetentionMax ?? 0) == 0 ? '无限制' : '${settings!.versionRetentionMax} 个版本', ), trailing: const Icon(Icons.chevron_right), enabled: settings?.versionRetentionEnabled ?? false, onTap: () => _showMaxVersionsDialog(context, settings), ), ], ), _buildSection( title: '视图与同步', children: [ SwitchListTile( secondary: const Icon(Icons.sync_disabled), title: const Text('禁用视图同步'), subtitle: const Text('关闭后视图设置不会跨设备同步'), value: settings?.disableViewSync ?? false, onChanged: (value) async { final success = await context.read().updateViewSync(value); if (!mounted) return; if (!success) ToastHelper.failure('更新失败'); }, ), ], ), _buildSection( title: '分享', children: [ ListTile( leading: const Icon(Icons.share_outlined), title: const Text('个人主页分享链接可见性'), subtitle: Text(_shareVisibilityLabel(settings?.shareLinksInProfile ?? '')), trailing: const Icon(Icons.chevron_right), onTap: () => _showShareVisibilityDialog(context, settings), ), ], ), ], ), ), ); } Widget _buildSection({required String title, required List children}) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary, ), ), ), Card( margin: const EdgeInsets.symmetric(horizontal: 16), child: Column(children: children), ), ], ), ); } String _shareVisibilityLabel(String value) { switch (value) { case 'all_share': return '所有分享链接'; case 'hide_share': return '隐藏分享链接'; default: return '仅公开分享'; } } Future _showShareVisibilityDialog(BuildContext context, UserSettingModel? settings) async { final currentValue = settings?.shareLinksInProfile ?? ''; final options = [ ('', '仅公开分享', '仅在个人主页显示公开分享'), ('all_share', '所有分享链接', '在个人主页显示所有分享'), ('hide_share', '隐藏分享链接', '不在个人主页显示任何分享'), ]; final selected = await showDialog( context: context, builder: (ctx) => SimpleDialog( title: const Text('分享链接可见性'), children: options .map((opt) => SimpleDialogOption( onPressed: () => Navigator.of(ctx).pop(opt.$1), child: Row( children: [ Icon( currentValue == opt.$1 ? Icons.radio_button_checked : Icons.radio_button_unchecked, color: Theme.of(ctx).colorScheme.primary, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(opt.$2, style: const TextStyle(fontWeight: FontWeight.w500)), Text(opt.$3, style: Theme.of(ctx).textTheme.bodySmall), ], ), ), ], ), )) .toList(), ), ); if (selected == null || !mounted) return; if (selected == currentValue) return; if (!context.mounted) return; final success = await context.read().updateShareLinksInProfile(selected); if (!mounted) return; if (success) { ToastHelper.success('已更新'); } else { ToastHelper.failure('更新失败'); } } Future _showMaxVersionsDialog(BuildContext context, UserSettingModel? settings) async { final controller = TextEditingController( text: (settings?.versionRetentionMax ?? 0) == 0 ? '' : '${settings!.versionRetentionMax}', ); final isUnlimited = (settings?.versionRetentionMax ?? 0) == 0; final result = await showDialog>( context: context, builder: (ctx) => StatefulBuilder( builder: (ctx, setDialogState) => AlertDialog( title: const Text('最大保留版本数'), content: Column( mainAxisSize: MainAxisSize.min, children: [ SwitchListTile( title: const Text('无限制'), value: isUnlimited, onChanged: (v) => setDialogState(() {}), ), if (!isUnlimited) TextField( controller: controller, keyboardType: TextInputType.number, decoration: const InputDecoration( labelText: '版本数', hintText: '输入最大保留版本数', ), ), ], ), actions: [ TextButton(onPressed: () => Navigator.of(ctx).pop(null), child: const Text('取消')), FilledButton( onPressed: () { final unlimited = isUnlimited; final max = unlimited ? 0 : (int.tryParse(controller.text) ?? 0); Navigator.of(ctx).pop({'unlimited': unlimited, 'max': max}); }, child: const Text('确定'), ), ], ), ), ); if (result == null || !mounted) return; final max = result['max'] as int; if (!context.mounted) return; final success = await context.read().updateVersionRetention(max: max); if (!mounted) return; if (success) { ToastHelper.success('已更新'); } else { ToastHelper.failure('更新失败'); } } Future _showExtEditor(BuildContext context, UserSettingModel? settings) async { final exts = settings?.versionRetentionExt ?? []; final controller = TextEditingController(text: exts.join(', ')); final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('保留的文件类型'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('输入文件扩展名,用逗号分隔。留空表示所有类型。'), const SizedBox(height: 8), TextField( controller: controller, decoration: const InputDecoration( labelText: '扩展名', hintText: '.doc, .pdf, .xlsx', ), ), ], ), actions: [ TextButton(onPressed: () => Navigator.of(ctx).pop(false), child: const Text('取消')), FilledButton( onPressed: () => Navigator.of(ctx).pop(true), child: const Text('确定'), ), ], ), ); if (confirmed != true || !mounted) return; final text = controller.text.trim(); List? newExts; if (text.isEmpty) { newExts = null; // null 表示所有类型 } else { newExts = text.split(',').map((e) => e.trim()).where((e) => e.isNotEmpty).toList(); } if (!context.mounted) return; final success = await context.read().updateVersionRetention(ext: newExts); if (!mounted) return; if (success) { ToastHelper.success('已更新'); } else { ToastHelper.failure('更新失败'); } } }