Files
MookNote/lib/pages/main_content_page.dart
DelLevin-Home d28c5e562e 完善2
2026-03-07 23:20:24 +08:00

495 lines
15 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/app_provider.dart';
import 'movie_tab_page.dart';
import 'book_tab_page.dart';
import 'note_tab_page.dart';
import 'search_page.dart';
import 'webdav_sync_page.dart';
import '../utils/webdav_service.dart';
import '../utils/toast_util.dart';
/// 云备份模式
enum SyncMode {
uploadOnly, // 上传
downloadOnly, // 下载
}
/// 主内容页 - 观影/阅读/笔记标签页
class MainContentPage extends StatelessWidget {
const MainContentPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 顶部 AppBar
_buildAppBar(context),
// 三个标签页的标题栏
_buildTabBar(context),
// 标签页内容
Expanded(
child: _buildTabContent(),
),
],
);
}
/// 构建顶部 AppBar
Widget _buildAppBar(BuildContext context) {
return Consumer<AppProvider>(
builder: (context, provider, child) {
return AppBar(
title: Text(_getAppBarTitle(provider)),
actions: [
// 云备份按钮
IconButton(
icon: const Icon(Icons.cloud_sync_outlined),
onPressed: () => _showCloudSyncDialog(context, provider),
tooltip: '云备份',
),
// 搜索按钮
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SearchPage(),
),
);
},
),
],
);
},
);
}
/// 获取 AppBar 标题
String _getAppBarTitle(AppProvider provider) {
switch (provider.mainTabIndex) {
case 0:
return '观影';
case 1:
return '阅读';
case 2:
return '笔记';
default:
return 'MookNote';
}
}
/// 构建标签栏
Widget _buildTabBar(BuildContext context) {
return Consumer<AppProvider>(
builder: (context, provider, child) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(color: Color(0xFFE5E5E5), width: 0.5),
),
),
child: Row(
children: [
_buildTabItem(
context,
'观影',
0,
provider.mainTabIndex,
() => provider.setMainTabIndex(0),
),
_buildTabItem(
context,
'阅读',
1,
provider.mainTabIndex,
() => provider.setMainTabIndex(1),
),
_buildTabItem(
context,
'笔记',
2,
provider.mainTabIndex,
() => provider.setMainTabIndex(2),
),
],
),
);
},
);
}
/// 构建单个标签项
Widget _buildTabItem(
BuildContext context,
String label,
int index,
int currentIndex,
VoidCallback onTap,
) {
final isSelected = index == currentIndex;
return Expanded(
child: InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
label,
style: TextStyle(
fontSize: 15,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
color: isSelected
? const Color(0xFF1A1A1A)
: const Color(0xFF999999),
),
),
if (isSelected)
Container(
margin: const EdgeInsets.only(top: 8),
width: 20,
height: 2,
color: const Color(0xFF1A1A1A),
),
],
),
),
),
);
}
/// 构建标签页内容
Widget _buildTabContent() {
return Consumer<AppProvider>(
builder: (context, provider, child) {
switch (provider.mainTabIndex) {
case 0:
return const MovieTabPage();
case 1:
return const BookTabPage();
case 2:
return const NoteTabPage();
default:
return const MovieTabPage();
}
},
);
}
/// 显示云同步对话框
Future<void> _showCloudSyncDialog(BuildContext context, AppProvider provider) async {
// 检查是否已配置 WebDAV
final config = await WebDAVService.instance.getConfig();
if (!context.mounted) return;
// 如果没有配置,直接跳转到配置页面
if (config == null || config.isEmpty) {
// 关闭云同步对话框
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
// 等待对话框关闭完成
await Future.delayed(const Duration(milliseconds: 100));
if (!context.mounted) return;
// 跳转到配置页面
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const WebDAVSyncPage()),
);
// 配置页面返回后,重新检查配置
if (!context.mounted) return;
final newConfig = await WebDAVService.instance.getConfig();
if (newConfig != null && newConfig.isNotEmpty) {
// 配置成功,显示同步选项
_showSyncOptionsDialog(context, provider);
}
return;
}
// 已配置,显示同步选项
_showSyncOptionsDialog(context, provider);
}
/// 显示同步选项对话框
void _showSyncOptionsDialog(BuildContext context, AppProvider provider) {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
elevation: 0,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 标题
Container(
padding: const EdgeInsets.all(20),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFE5E5E5), width: 0.5),
),
),
child: const Text(
'云备份',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: Color(0xFF1A1A1A),
),
),
),
// 同步选项
Column(
children: [
_buildSyncOption(
context,
icon: Icons.cloud_upload,
iconColor: const Color(0xFF1A1A1A),
title: '上传',
subtitle: '将本地数据备份到云端',
onTap: () async {
Navigator.pop(context);
// 等待对话框关闭
await Future.delayed(const Duration(milliseconds: 100));
if (context.mounted) {
_navigateToSync(context, SyncMode.uploadOnly);
}
},
),
const Divider(height: 0.5, indent: 56, color: Color(0xFFE5E5E5)),
_buildSyncOption(
context,
icon: Icons.cloud_download,
iconColor: const Color(0xFF1A1A1A),
title: '下载',
subtitle: '从云端恢复数据到本地',
onTap: () async {
Navigator.pop(context);
// 等待对话框关闭
await Future.delayed(const Duration(milliseconds: 100));
if (context.mounted) {
_navigateToSync(context, SyncMode.downloadOnly);
}
},
),
],
),
// 取消按钮
Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(color: Color(0xFFE5E5E5), width: 0.5),
),
),
child: InkWell(
onTap: () => Navigator.pop(context),
borderRadius: const BorderRadius.vertical(bottom: Radius.circular(12)),
child: Container(
padding: const EdgeInsets.all(16),
alignment: Alignment.center,
child: const Text(
'取消',
style: TextStyle(
fontSize: 15,
color: Color(0xFF999999),
),
),
),
),
),
],
),
),
);
},
);
}
/// 构建同步选项
Widget _buildSyncOption(
BuildContext context, {
required IconData icon,
required Color iconColor,
required String title,
required String subtitle,
required VoidCallback onTap,
}) {
return InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// 图标
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: const Color(0xFFF5F5F5),
borderRadius: BorderRadius.circular(8),
),
child: Icon(
icon,
color: const Color(0xFF1A1A1A),
size: 20,
),
),
const SizedBox(width: 16),
// 文字
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Color(0xFF1A1A1A),
),
),
const SizedBox(height: 4),
Text(
subtitle,
style: const TextStyle(
fontSize: 13,
color: Color(0xFF999999),
),
),
],
),
),
// 箭头
const Icon(
Icons.chevron_right,
color: Color(0xFFCCCCCC),
size: 20,
),
],
),
),
);
}
/// 执行云备份操作
Future<void> _navigateToSync(BuildContext context, SyncMode mode) async {
// 执行同步
final direction = mode == SyncMode.uploadOnly
? SyncDirection.upload
: SyncDirection.download;
final result = await WebDAVService.instance.syncData(direction: direction);
if (!context.mounted) return;
if (result.success) {
// 如果需要重新加载数据(下载模式)
if (result.needReload) {
final provider = context.read<AppProvider>();
await provider.loadMovies();
await provider.loadBooks();
await provider.loadNotes();
}
ToastUtil.show(context, '${_getSyncModeText(mode)}成功');
} else {
ToastUtil.show(context, '${_getSyncModeText(mode)}失败: ${result.message}');
}
}
/// 获取同步模式文本
String _getSyncModeText(SyncMode mode) {
switch (mode) {
case SyncMode.uploadOnly:
return '上传';
case SyncMode.downloadOnly:
return '下载';
}
}
/// 显示添加对话框
void _showAddDialog(BuildContext context, AppProvider provider) {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero),
builder: (BuildContext context) {
return SafeArea(
child: Wrap(
children: [
ListTile(
leading: const Icon(Icons.movie, color: Color(0xFF1A1A1A)),
title: const Text('添加观影'),
onTap: () {
Navigator.pop(context);
// 根据当前影视标签页的选中状态设置默认值
final statusMap = {
0: 'watched',
1: 'watching',
2: 'want_to_watch',
};
final currentStatus = statusMap[provider.movieStatusIndex] ?? 'want_to_watch';
Navigator.pushNamed(
context,
'/movie-form',
arguments: {'initialStatus': currentStatus},
);
},
),
const Divider(height: 0.5, indent: 56),
ListTile(
leading: const Icon(Icons.menu_book, color: Color(0xFF1A1A1A)),
title: const Text('添加阅读'),
onTap: () {
Navigator.pop(context);
// 根据当前阅读标签页的选中状态设置默认值
final statusMap = {
0: 'read',
1: 'reading',
2: 'want_to_read',
};
final currentStatus = statusMap[provider.bookStatusIndex] ?? 'want_to_read';
Navigator.pushNamed(
context,
'/book-form',
arguments: {'initialStatus': currentStatus},
);
},
),
const Divider(height: 0.5, indent: 56),
ListTile(
leading: const Icon(Icons.note, color: Color(0xFF1A1A1A)),
title: const Text('添加笔记'),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, '/note-form');
},
),
],
),
);
},
);
}
}