diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index 5344e53..3df9808 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -15,8 +15,8 @@ "title": "MixVideo Desktop", "width": 1200, "height": 900, - "minWidth": 800, - "minHeight": 600, + "minWidth": 1200, + "minHeight": 900, "center": true, "resizable": true, "maximizable": true, diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index fb2155a..0e16695 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -1,4 +1,5 @@ +import { useEffect } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { ProjectList } from './components/ProjectList'; import { ProjectForm } from './components/ProjectForm'; @@ -16,6 +17,7 @@ import DebugPanelTool from './pages/tools/DebugPanelTool'; import ChatTool from './pages/tools/ChatTool'; import ChatTestPage from './pages/tools/ChatTestPage'; import WatermarkTool from './pages/tools/WatermarkTool'; +import Settings from './pages/Settings'; // import BatchThumbnailGenerator from './pages/tools/BatchThumbnailGenerator'; import Navigation from './components/Navigation'; @@ -23,6 +25,7 @@ import { NotificationSystem, useNotifications } from './components/NotificationS import { useProjectStore } from './store/projectStore'; import { useUIStore } from './store/uiStore'; import { CreateProjectRequest, UpdateProjectRequest } from './types/project'; +import { screenAdaptationService } from './services/screenAdaptationService'; import "./App.css"; import './styles/design-system.css'; import './styles/animations.css'; @@ -47,6 +50,20 @@ function App() { // 通知系统 const { notifications, removeNotification, success, error } = useNotifications(); + // 屏幕适配 + useEffect(() => { + const initScreenAdaptation = async () => { + try { + await screenAdaptationService.applySmartAdaptation(); + console.log('屏幕适配初始化完成'); + } catch (error) { + console.error('屏幕适配初始化失败:', error); + } + }; + + initScreenAdaptation(); + }, []); + // 处理创建项目 const handleCreateProject = async (data: CreateProjectRequest) => { try { @@ -82,8 +99,8 @@ function App() { {/* 可滚动的主要内容区域 */} -
-
+
+
} /> } /> @@ -102,6 +119,7 @@ function App() { } /> } /> } /> + } /> {/* } /> */}
diff --git a/apps/desktop/src/components/Navigation.tsx b/apps/desktop/src/components/Navigation.tsx index e30efc9..a6edc3c 100644 --- a/apps/desktop/src/components/Navigation.tsx +++ b/apps/desktop/src/components/Navigation.tsx @@ -7,7 +7,8 @@ import { DocumentDuplicateIcon, LinkIcon, WrenchScrewdriverIcon, - SparklesIcon + SparklesIcon, + CogIcon } from '@heroicons/react/24/outline'; const Navigation: React.FC = () => { @@ -55,6 +56,12 @@ const Navigation: React.FC = () => { href: '/tools', icon: WrenchScrewdriverIcon, description: 'AI检索图片/数据清洗工具' + }, + { + name: '应用设置', + href: '/settings', + icon: CogIcon, + description: '屏幕适配和应用配置' } ]; diff --git a/apps/desktop/src/components/ScreenAdaptationSettings.tsx b/apps/desktop/src/components/ScreenAdaptationSettings.tsx new file mode 100644 index 0000000..b3b5a0d --- /dev/null +++ b/apps/desktop/src/components/ScreenAdaptationSettings.tsx @@ -0,0 +1,239 @@ +import React, { useState, useEffect } from 'react'; +import { screenAdaptationService } from '../services/screenAdaptationService'; +import { getCurrentWindow } from '@tauri-apps/api/window'; + +interface ScreenAdaptationSettingsProps { + onClose?: () => void; +} + +/** + * 屏幕适配设置组件 + * 允许用户自定义窗口适配参数 + */ +export const ScreenAdaptationSettings: React.FC = ({ + onClose +}) => { + const [config, setConfig] = useState(screenAdaptationService.getConfig()); + const [screenInfo, setScreenInfo] = useState<{ + width: number; + height: number; + type: string; + } | null>(null); + const [currentSize, setCurrentSize] = useState<{ + width: number; + height: number; + } | null>(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + loadScreenInfo(); + loadCurrentSize(); + }, []); + + const loadScreenInfo = async () => { + try { + const { type } = await screenAdaptationService.getScreenTypeConfig(); + // 模拟获取屏幕信息 + const info = { + width: (globalThis as any).screen?.availWidth || 1920, + height: (globalThis as any).screen?.availHeight || 1080, + type: type + }; + setScreenInfo(info); + } catch (error) { + console.error('获取屏幕信息失败:', error); + } + }; + + const loadCurrentSize = async () => { + try { + const window = getCurrentWindow(); + const size = await window.innerSize(); + setCurrentSize({ + width: size.width, + height: size.height + }); + } catch (error) { + console.error('获取当前窗口尺寸失败:', error); + } + }; + + const handleConfigChange = (key: string, value: number) => { + const newConfig = { ...config, [key]: value }; + setConfig(newConfig); + screenAdaptationService.updateConfig(newConfig); + }; + + const handleApplyAdaptation = async () => { + setLoading(true); + try { + await screenAdaptationService.applyScreenAdaptation(); + await loadCurrentSize(); + } catch (error) { + console.error('应用屏幕适配失败:', error); + } finally { + setLoading(false); + } + }; + + const handleSmartAdaptation = async () => { + setLoading(true); + try { + await screenAdaptationService.applySmartAdaptation(); + setConfig(screenAdaptationService.getConfig()); + await loadCurrentSize(); + } catch (error) { + console.error('智能适配失败:', error); + } finally { + setLoading(false); + } + }; + + const previewSize = screenInfo ? { + width: Math.floor(screenInfo.width * config.defaultWidthRatio), + height: Math.floor(screenInfo.height * config.defaultHeightRatio) + } : null; + + return ( +
+
+
+
+

屏幕适配设置

+ {onClose && ( + + )} +
+ + {/* 屏幕信息 */} + {screenInfo && ( +
+

屏幕信息

+
+
+ 屏幕尺寸: + {screenInfo.width} × {screenInfo.height} +
+
+ 屏幕类型: + {screenInfo.type} +
+ {currentSize && ( +
+ 当前窗口: + {currentSize.width} × {currentSize.height} +
+ )} + {previewSize && ( +
+ 预览尺寸: + {previewSize.width} × {previewSize.height} +
+ )} +
+
+ )} + + {/* 配置选项 */} +
+
+

窗口尺寸配置

+ +
+
+ + handleConfigChange('defaultWidthRatio', parseFloat(e.target.value))} + className="w-full" + /> +
+ +
+ + handleConfigChange('defaultHeightRatio', parseFloat(e.target.value))} + className="w-full" + /> +
+ +
+ + handleConfigChange('minWidth', parseInt(e.target.value))} + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + /> +
+ +
+ + handleConfigChange('minHeight', parseInt(e.target.value))} + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + /> +
+
+
+ + {/* 操作按钮 */} +
+ + + +
+ +
+

智能适配:根据屏幕类型自动选择最佳配置

+

应用设置:使用当前自定义配置

+

• 设置会在应用重启后保持

+
+
+
+
+
+ ); +}; diff --git a/apps/desktop/src/pages/Settings.tsx b/apps/desktop/src/pages/Settings.tsx new file mode 100644 index 0000000..b105af2 --- /dev/null +++ b/apps/desktop/src/pages/Settings.tsx @@ -0,0 +1,152 @@ +import React, { useState } from 'react'; +import { ScreenAdaptationSettings } from '../components/ScreenAdaptationSettings'; + +/** + * 设置页面 + * 包含各种应用设置选项 + */ +const Settings: React.FC = () => { + const [showScreenSettings, setShowScreenSettings] = useState(false); + + return ( +
+
+
+
+

应用设置

+

配置应用的各项参数和偏好设置

+
+ +
+
+ {/* 显示设置 */} +
+

显示设置

+ +
+
+
+

屏幕适配

+

根据屏幕尺寸自动调整窗口大小

+
+ +
+
+
+ + {/* 性能设置 */} +
+

性能设置

+ +
+
+
+

硬件加速

+

启用GPU加速以提升性能

+
+ +
+ +
+
+

自动保存

+

自动保存项目更改

+
+ +
+
+
+ + {/* 通知设置 */} +
+

通知设置

+ +
+
+
+

桌面通知

+

显示系统桌面通知

+
+ +
+ +
+
+

声音提醒

+

播放通知声音

+
+ +
+
+
+ + {/* 数据设置 */} +
+

数据设置

+ +
+
+
+

数据备份

+

定期备份应用数据

+
+ +
+ +
+
+

清理缓存

+

清理临时文件和缓存

+
+ +
+
+
+ + {/* 关于信息 */} +
+

关于

+ +
+

应用版本: 0.2.1

+

构建时间: {new Date().toLocaleDateString()}

+

技术栈: Tauri + React + TypeScript

+
+
+
+
+
+
+ + {/* 屏幕适配设置弹窗 */} + {showScreenSettings && ( + setShowScreenSettings(false)} + /> + )} +
+ ); +}; + +export default Settings; diff --git a/apps/desktop/src/services/screenAdaptationService.ts b/apps/desktop/src/services/screenAdaptationService.ts new file mode 100644 index 0000000..bbd7024 --- /dev/null +++ b/apps/desktop/src/services/screenAdaptationService.ts @@ -0,0 +1,253 @@ +import { getCurrentWindow } from '@tauri-apps/api/window'; +import { LogicalSize } from '@tauri-apps/api/window'; + +/** + * 屏幕适配配置 + */ +interface ScreenAdaptationConfig { + /** 最小宽度 */ + minWidth: number; + /** 最小高度 */ + minHeight: number; + /** 最大宽度比例(相对于屏幕宽度) */ + maxWidthRatio: number; + /** 最大高度比例(相对于屏幕高度) */ + maxHeightRatio: number; + /** 默认宽度比例 */ + defaultWidthRatio: number; + /** 默认高度比例 */ + defaultHeightRatio: number; +} + +/** + * 屏幕信息 + */ +interface ScreenInfo { + width: number; + height: number; + scaleFactor: number; +} + +/** + * 窗口尺寸 + */ +interface WindowSize { + width: number; + height: number; +} + +/** + * 屏幕适配服务 + * 根据用户屏幕尺寸动态调整窗口大小 + */ +export class ScreenAdaptationService { + private static instance: ScreenAdaptationService; + private config: ScreenAdaptationConfig; + + private constructor() { + this.config = { + minWidth: 800, + minHeight: 600, + maxWidthRatio: 0.9, + maxHeightRatio: 0.9, + defaultWidthRatio: 0.75, + defaultHeightRatio: 0.8, + }; + } + + public static getInstance(): ScreenAdaptationService { + if (!ScreenAdaptationService.instance) { + ScreenAdaptationService.instance = new ScreenAdaptationService(); + } + return ScreenAdaptationService.instance; + } + + /** + * 获取屏幕信息 + */ + private async getScreenInfo(): Promise { + try { + // 获取主显示器信息 + const { availableMonitors } = await import('@tauri-apps/api/window'); + const monitors = await availableMonitors(); + const primaryMonitor = monitors.find(m => m.name === 'primary') || monitors[0]; + + if (primaryMonitor) { + return { + width: primaryMonitor.size.width, + height: primaryMonitor.size.height, + scaleFactor: primaryMonitor.scaleFactor, + }; + } + } catch (error) { + console.warn('无法获取显示器信息,使用默认值:', error); + } + + // 回退到浏览器API(如果可用) + if (typeof globalThis !== 'undefined' && 'screen' in globalThis) { + const screen = (globalThis as any).screen; + return { + width: screen.availWidth || 1920, + height: screen.availHeight || 1080, + scaleFactor: (globalThis as any).devicePixelRatio || 1, + }; + } + + // 默认值 + return { + width: 1920, + height: 1080, + scaleFactor: 1, + }; + } + + /** + * 计算最佳窗口尺寸 + */ + private calculateOptimalSize(screenInfo: ScreenInfo): WindowSize { + const { width: screenWidth, height: screenHeight } = screenInfo; + + // 计算基于比例的尺寸 + let width = Math.floor(screenWidth * this.config.defaultWidthRatio); + let height = Math.floor(screenHeight * this.config.defaultHeightRatio); + + // 应用最小尺寸限制 + width = Math.max(width, this.config.minWidth); + height = Math.max(height, this.config.minHeight); + + // 应用最大尺寸限制 + const maxWidth = Math.floor(screenWidth * this.config.maxWidthRatio); + const maxHeight = Math.floor(screenHeight * this.config.maxHeightRatio); + + width = Math.min(width, maxWidth); + height = Math.min(height, maxHeight); + + return { width, height }; + } + + /** + * 应用屏幕适配 + */ + public async applyScreenAdaptation(): Promise { + try { + const window = getCurrentWindow(); + const screenInfo = await this.getScreenInfo(); + const optimalSize = this.calculateOptimalSize(screenInfo); + + console.log('屏幕信息:', screenInfo); + console.log('计算的最佳窗口尺寸:', optimalSize); + + // 设置窗口尺寸 + await window.setSize(new LogicalSize(optimalSize.width, optimalSize.height)); + + // 居中显示 + await window.center(); + + // 设置最小尺寸 + await window.setMinSize(new LogicalSize(this.config.minWidth, this.config.minHeight)); + + console.log('屏幕适配完成'); + } catch (error) { + console.error('屏幕适配失败:', error); + } + } + + /** + * 根据屏幕类型获取预设配置 + */ + public async getScreenTypeConfig(): Promise<{ + type: 'small' | 'medium' | 'large' | 'ultrawide'; + config: Partial; + }> { + const screenInfo = await this.getScreenInfo(); + const { width, height } = screenInfo; + const aspectRatio = width / height; + + // 小屏幕 (< 1366x768) + if (width < 1366 || height < 768) { + return { + type: 'small', + config: { + defaultWidthRatio: 0.95, + defaultHeightRatio: 0.9, + minWidth: 800, + minHeight: 600, + }, + }; + } + + // 超宽屏 (21:9 或更宽) + if (aspectRatio >= 2.3) { + return { + type: 'ultrawide', + config: { + defaultWidthRatio: 0.7, + defaultHeightRatio: 0.85, + minWidth: 1200, + minHeight: 700, + }, + }; + } + + // 大屏幕 (>= 1920x1080) + if (width >= 1920 && height >= 1080) { + return { + type: 'large', + config: { + defaultWidthRatio: 0.75, + defaultHeightRatio: 0.8, + minWidth: 1000, + minHeight: 700, + }, + }; + } + + // 中等屏幕 + return { + type: 'medium', + config: { + defaultWidthRatio: 0.85, + defaultHeightRatio: 0.85, + minWidth: 900, + minHeight: 650, + }, + }; + } + + /** + * 应用智能适配(根据屏幕类型自动调整) + */ + public async applySmartAdaptation(): Promise { + try { + const { type, config } = await this.getScreenTypeConfig(); + + // 更新配置 + this.config = { ...this.config, ...config }; + + console.log(`检测到屏幕类型: ${type}`); + console.log('应用配置:', config); + + // 应用适配 + await this.applyScreenAdaptation(); + } catch (error) { + console.error('智能适配失败:', error); + } + } + + /** + * 更新配置 + */ + public updateConfig(newConfig: Partial): void { + this.config = { ...this.config, ...newConfig }; + } + + /** + * 获取当前配置 + */ + public getConfig(): ScreenAdaptationConfig { + return { ...this.config }; + } +} + +// 导出单例实例 +export const screenAdaptationService = ScreenAdaptationService.getInstance();