Files
xianyan/lib/features/desktop/macos_menu_bar_wrapper.dart
Developer 83720002e6 feat: 新增工作台模式、系统托盘,修复多平台兼容性问题
1. 新增工作台三栏布局模式,适配宽屏设备
2. 添加跨平台系统托盘支持,新增托盘图标资源
3. 修复工作台模式下导航返回异常问题
4. 统一JSON类型安全解析,替换硬类型转换
5. 增加macOS深度链接支持,统一渠道分发信息
6. 优化部分页面生命周期和状态加载逻辑
7. 移除废弃的nearby_connections依赖
2026-06-19 06:43:55 +08:00

446 lines
13 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.
/// ============================================================
/// 闲言APP — macOS 原生菜单栏包装器
/// 创建时间: 2026-06-18
/// 更新时间: 2026-06-18
/// 作用: 使用 PlatformMenuBar 注册 macOS 顶部原生菜单(闲言/文件/编辑/视图/窗口/帮助)
/// 上次更新: 初始创建,实现 6 个顶级菜单 + 业务功能入口
/// ============================================================
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/providers/split_view_provider.dart';
import '../../core/router/app_router.dart' show appRouter;
import '../../core/router/app_routes.dart';
import '../../core/utils/logger.dart';
import '../../core/utils/platform/platform_utils.dart' as pu;
import '../../features/settings/providers/theme_settings_provider.dart';
/// macOS 原生菜单栏包装器
///
/// 在 macOS 上使用 [PlatformMenuBar] 注册原生顶部菜单栏,包含:
/// 1. 闲言菜单:关于/偏好设置/新建笔记/新建灵感/隐藏/退出
/// 2. 文件菜单:新建笔记/打开文件/关闭窗口
/// 3. 编辑菜单:撤销/重做/剪切/复制/粘贴/全选(系统标准)
/// 4. 视图菜单:全屏/切换深色模式/工作台模式/切换侧边栏
/// 5. 窗口菜单:最小化/缩放/关闭窗口(系统标准)
/// 6. 帮助菜单:闲言帮助/检查更新/反馈问题
///
/// 非 macOS 平台直接返回 child不包裹 PlatformMenuBar。
class MacosMenuBarWrapper extends ConsumerWidget {
const MacosMenuBarWrapper({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context, WidgetRef ref) {
// 非 macOS 平台不注册原生菜单栏
if (!pu.isMacOS) return child;
// 监听主题和工作台模式状态(用于菜单勾选)
final isDark = ref.watch(themeSettingsProvider).isDark;
final isWorkbench = ref.watch(splitViewProvider).workbenchEnabled;
return PlatformMenuBar(
menus: _buildMenus(
context: context,
ref: ref,
isDark: isDark,
isWorkbench: isWorkbench,
),
child: child,
);
}
/// 构建所有菜单
List<PlatformMenuItem> _buildMenus({
required BuildContext context,
required WidgetRef ref,
required bool isDark,
required bool isWorkbench,
}) {
return [
_buildAppMenu(context, ref),
_buildFileMenu(context, ref),
_buildEditMenu(),
_buildViewMenu(context, ref, isDark, isWorkbench),
_buildWindowMenu(),
_buildHelpMenu(context, ref),
];
}
// ============================================================
// 闲言菜单application
// ============================================================
PlatformMenu _buildAppMenu(BuildContext context, WidgetRef ref) {
return PlatformMenu(
label: '闲言',
menus: [
const PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.about,
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '偏好设置…',
shortcut: const SingleActivator(
LogicalKeyboardKey.comma,
meta: true,
),
onSelected: () => _navigateTo(AppRoutes.generalSettings),
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '新建笔记',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyN,
meta: true,
),
onSelected: () => _navigateTo(AppRoutes.noteEdit),
),
PlatformMenuItem(
label: '新建灵感',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyI,
meta: true,
),
onSelected: () => _navigateTo(AppRoutes.inspiration),
),
],
),
const PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.hide,
),
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.hideOtherApplications,
),
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.showAllApplications,
),
],
),
const PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.quit,
),
],
),
],
);
}
// ============================================================
// 文件菜单
// ============================================================
PlatformMenu _buildFileMenu(BuildContext context, WidgetRef ref) {
return PlatformMenu(
label: '文件',
menus: [
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '新建笔记',
// 快捷键 Cmd+N 已在"闲言"菜单中注册,此处不重复注册
onSelected: () => _navigateTo(AppRoutes.noteEdit),
),
PlatformMenuItem(
label: '打开稍后阅读…',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyR,
meta: true,
),
onSelected: () => _navigateTo(AppRoutes.readLater),
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '关闭窗口',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyW,
meta: true,
),
onSelected: () => _closeWindow(),
),
],
),
],
);
}
// ============================================================
// 编辑菜单(系统标准)
// ============================================================
PlatformMenu _buildEditMenu() {
return PlatformMenu(
label: '编辑',
menus: [
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '撤销',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyZ,
meta: true,
),
onSelected: () => _undo(),
),
PlatformMenuItem(
label: '重做',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyZ,
meta: true,
shift: true,
),
onSelected: () => _redo(),
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '剪切',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyX,
meta: true,
),
onSelected: () => _cut(),
),
PlatformMenuItem(
label: '复制',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyC,
meta: true,
),
onSelected: () => _copy(),
),
PlatformMenuItem(
label: '粘贴',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyV,
meta: true,
),
onSelected: () => _paste(),
),
PlatformMenuItem(
label: '全选',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyA,
meta: true,
),
onSelected: () => _selectAll(),
),
],
),
],
);
}
// ============================================================
// 视图菜单
// ============================================================
PlatformMenu _buildViewMenu(
BuildContext context,
WidgetRef ref,
bool isDark,
bool isWorkbench,
) {
return PlatformMenu(
label: '视图',
menus: [
const PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.toggleFullScreen,
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '深色模式',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyD,
meta: true,
shift: true,
),
onSelected: () => _toggleDarkMode(ref),
),
PlatformMenuItem(
label: '工作台模式',
shortcut: const SingleActivator(
LogicalKeyboardKey.keyB,
meta: true,
),
onSelected: () => _toggleWorkbench(ref),
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '每日拾句',
onSelected: () => _navigateTo(AppRoutes.home),
),
PlatformMenuItem(
label: '句子广场',
onSelected: () => _navigateTo(AppRoutes.home),
),
],
),
],
);
}
// ============================================================
// 窗口菜单(系统标准)
// ============================================================
PlatformMenu _buildWindowMenu() {
return const PlatformMenu(
label: '窗口',
menus: [
PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.minimizeWindow,
),
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.zoomWindow,
),
],
),
PlatformMenuItemGroup(
members: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.arrangeWindowsInFront,
),
],
),
],
);
}
// ============================================================
// 帮助菜单
// ============================================================
PlatformMenu _buildHelpMenu(BuildContext context, WidgetRef ref) {
return PlatformMenu(
label: '帮助',
menus: [
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '闲言帮助',
onSelected: () => _navigateTo(AppRoutes.about),
),
],
),
PlatformMenuItemGroup(
members: [
PlatformMenuItem(
label: '检查更新',
onSelected: () => _navigateTo(AppRoutes.appInfo),
),
PlatformMenuItem(
label: '反馈问题',
onSelected: () => _navigateTo(AppRoutes.correction),
),
],
),
],
);
}
// ============================================================
// 辅助方法
// ============================================================
/// 导航到指定路由
void _navigateTo(String route) {
try {
appRouter.push(route);
} catch (e) {
Log.e('MacosMenuBarWrapper._navigateTo 失败: $e');
}
}
/// 切换深色/浅色模式
void _toggleDarkMode(WidgetRef ref) {
try {
final settings = ref.read(themeSettingsProvider);
final newMode = settings.isDark ? AppThemeMode.light : AppThemeMode.dark;
ref.read(themeSettingsProvider.notifier).setThemeMode(newMode);
} catch (e) {
Log.e('MacosMenuBarWrapper._toggleDarkMode 失败: $e');
}
}
/// 切换工作台模式
void _toggleWorkbench(WidgetRef ref) {
try {
final current = ref.read(splitViewProvider).workbenchEnabled;
ref.read(splitViewProvider.notifier).setWorkbenchEnabled(!current);
} catch (e) {
Log.e('MacosMenuBarWrapper._toggleWorkbench 失败: $e');
}
}
/// 关闭窗口
///
/// macOS 上快捷键 Cmd+W 由系统自动处理,此方法作为菜单点击的 fallback。
void _closeWindow() {
// 快捷键 Cmd+W 由系统自动处理,此方法仅作为菜单点击的 fallback
Log.d('MacosMenuBarWrapper._closeWindow: 由系统快捷键处理');
}
/// 撤销
///
/// macOS 上快捷键 Cmd+Z 由系统自动处理,此方法作为菜单点击的 fallback。
void _undo() {
Log.d('MacosMenuBarWrapper._undo: 由系统快捷键处理');
}
/// 重做
void _redo() {
Log.d('MacosMenuBarWrapper._redo: 由系统快捷键处理');
}
/// 剪切
void _cut() {
Log.d('MacosMenuBarWrapper._cut: 由系统快捷键处理');
}
/// 复制
void _copy() {
Log.d('MacosMenuBarWrapper._copy: 由系统快捷键处理');
}
/// 粘贴
void _paste() {
Log.d('MacosMenuBarWrapper._paste: 由系统快捷键处理');
}
/// 全选
void _selectAll() {
Log.d('MacosMenuBarWrapper._selectAll: 由系统快捷键处理');
}
}