主要合入内容:

- 文件管理器分页加载、排序偏好、桌面表头排序、移动端排序菜单、Ctrl/Cmd+F搜索、Esc 关闭搜索、鼠标右滑返回上级。
- 移动端同步状态页、同步统计卡片、同步任务/累计统计事件、同步页布局更新。
- Android 相册同步默认路径改为 DCIM/Camera,下载路径改用 external_path。
- Rust sync-core 更新:Android 日志依赖、AlbumUpload/AlbumDownload、MirrorWcf 统计修复、Linux FUSE镜像挂载与读写同步支持。

- 依赖更新:external_path、fl_chart、pdfrx 升级,并修了 pdfrx 新版本的deprecated API。
- 新增文件包括:sort_options.dart、sync_page_android.dart、sync_stats_card.dart、platform/fuse.rs、sync_engine/fuse.rs。
This commit is contained in:
2026-06-04 07:11:43 +08:00
parent 5ee6ba1e28
commit b02daf1448
56 changed files with 7589 additions and 1200 deletions
+81 -10
View File
@@ -1,18 +1,23 @@
import 'package:flutter/material.dart';
/// 文件列表表头(桌面端)
import '../../core/constants/sort_options.dart';
/// 文件列表表头(桌面端),支持点击排序
class FileListHeader extends StatelessWidget {
final bool showCheckbox;
const FileListHeader({super.key, this.showCheckbox = false});
final SortOption? currentSort;
final ValueChanged<SortOption>? onSort;
const FileListHeader({
super.key,
this.showCheckbox = false,
this.currentSort,
this.onSort,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final style = TextStyle(
color: theme.hintColor,
fontSize: 12,
fontWeight: FontWeight.w500,
);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
@@ -26,11 +31,77 @@ class FileListHeader extends StatelessWidget {
if (showCheckbox) const SizedBox(width: 40),
// 图标占位
const SizedBox(width: 36 + 16),
Expanded(flex: 5, child: Text('名称', style: style)),
Expanded(flex: 2, child: Text('修改日期', style: style)),
Expanded(flex: 1, child: Text('大小', style: style)),
Expanded(
flex: 5,
child: _buildSortHeader(context, theme, SortField.name, '名称'),
),
Expanded(
flex: 2,
child: _buildSortHeader(
context,
theme,
SortField.updatedAt,
'修改日期',
),
),
Expanded(
flex: 1,
child: _buildSortHeader(context, theme, SortField.size, '大小'),
),
],
),
);
}
Widget _buildSortHeader(
BuildContext context,
ThemeData theme,
SortField field,
String label,
) {
final isActive = currentSort?.field == field;
final style = TextStyle(
color: isActive ? theme.colorScheme.primary : theme.hintColor,
fontSize: 12,
fontWeight: isActive ? FontWeight.w600 : FontWeight.w500,
);
return InkWell(
onTap: () => _onHeaderTap(field),
borderRadius: BorderRadius.circular(4),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(label, style: style),
if (isActive) ...[
const SizedBox(width: 4),
Icon(
currentSort!.direction == SortDirection.asc
? Icons.arrow_upward
: Icons.arrow_downward,
size: 14,
color: theme.colorScheme.primary,
),
],
],
),
),
);
}
void _onHeaderTap(SortField field) {
if (onSort == null) return;
if (currentSort?.field == field) {
// 同一列:切换方向
final newDir = currentSort!.direction == SortDirection.asc
? SortDirection.desc
: SortDirection.asc;
onSort!(SortOption(field, newDir));
} else {
// 新列:默认升序
onSort!(SortOption(field, SortDirection.asc));
}
}
}