Files
mixvideo-v2/apps/desktop/src/components/ScreenAdaptationSettings.tsx
imeepos 78f27983a6 feat: 实现智能屏幕适配功能
新功能:
- 根据用户屏幕尺寸自动调整窗口大小
- 支持小屏幕、中等屏幕、大屏幕、超宽屏的智能适配
- 提供屏幕适配设置页面,用户可自定义配置
- 应用启动时自动应用屏幕适配

技术实现:
- 创建ScreenAdaptationService服务类
- 支持动态获取屏幕信息和显示器配置
- 提供智能适配和手动配置两种模式
- 集成到应用设置页面,提供友好的UI界面

配置选项:
- 默认宽度/高度比例可调节
- 最小窗口尺寸限制
- 最大窗口尺寸比例
- 支持不同屏幕类型的预设配置

用户体验:
- 应用启动时自动适配屏幕
- 设置页面提供实时预览
- 支持一键智能适配和手动微调
- 窗口居中显示,提升视觉体验

适配策略:
- 小屏幕(<1366x768): 95%宽度, 90%高度
- 中等屏幕(1366-1920): 85%宽度, 85%高度
- 大屏幕(>=1920x1080): 75%宽度, 80%高度
- 超宽屏(21:9+): 70%宽度, 85%高度

解决了固定窗口尺寸在不同屏幕上显示不佳的问题
2025-07-23 20:55:51 +08:00

240 lines
8.6 KiB
TypeScript
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.
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<ScreenAdaptationSettingsProps> = ({
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 (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto">
<div className="p-6">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-semibold text-gray-900"></h2>
{onClose && (
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
)}
</div>
{/* 屏幕信息 */}
{screenInfo && (
<div className="mb-6 p-4 bg-blue-50 rounded-lg">
<h3 className="text-sm font-medium text-blue-900 mb-2"></h3>
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<span className="text-blue-700">:</span>
<span className="ml-2 font-mono">{screenInfo.width} × {screenInfo.height}</span>
</div>
<div>
<span className="text-blue-700">:</span>
<span className="ml-2 capitalize">{screenInfo.type}</span>
</div>
{currentSize && (
<div>
<span className="text-blue-700">:</span>
<span className="ml-2 font-mono">{currentSize.width} × {currentSize.height}</span>
</div>
)}
{previewSize && (
<div>
<span className="text-blue-700">:</span>
<span className="ml-2 font-mono">{previewSize.width} × {previewSize.height}</span>
</div>
)}
</div>
</div>
)}
{/* 配置选项 */}
<div className="space-y-6">
<div>
<h3 className="text-lg font-medium text-gray-900 mb-4"></h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
({Math.round(config.defaultWidthRatio * 100)}%)
</label>
<input
type="range"
min="0.5"
max="1"
step="0.05"
value={config.defaultWidthRatio}
onChange={(e) => handleConfigChange('defaultWidthRatio', parseFloat(e.target.value))}
className="w-full"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
({Math.round(config.defaultHeightRatio * 100)}%)
</label>
<input
type="range"
min="0.5"
max="1"
step="0.05"
value={config.defaultHeightRatio}
onChange={(e) => handleConfigChange('defaultHeightRatio', parseFloat(e.target.value))}
className="w-full"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
(px)
</label>
<input
type="number"
min="600"
max="1200"
value={config.minWidth}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
(px)
</label>
<input
type="number"
min="400"
max="900"
value={config.minHeight}
onChange={(e) => 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"
/>
</div>
</div>
</div>
{/* 操作按钮 */}
<div className="flex space-x-4 pt-4 border-t border-gray-200">
<button
onClick={handleSmartAdaptation}
disabled={loading}
className="flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{loading ? '应用中...' : '智能适配'}
</button>
<button
onClick={handleApplyAdaptation}
disabled={loading}
className="flex-1 bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{loading ? '应用中...' : '应用设置'}
</button>
</div>
<div className="text-xs text-gray-500 space-y-1">
<p> <strong></strong></p>
<p> <strong></strong>使</p>
<p> </p>
</div>
</div>
</div>
</div>
</div>
);
};