Merge remote-tracking branch 'origin/beta' into feat/fast-agent

This commit is contained in:
吕柏青 committed 2026-06-05 14:22:12 +08:00
commit 4aa293e1e0
4 files changed
+42 -61

No files matched your search

+36 -12
View File
@@ -422,7 +422,7 @@ pub fn start_dictation_signal_listener(
/// 未安装时输出警告,不做任何文件 I/O。
#[cfg(target_os = "linux")]
pub fn ensure_plugin_installed(_app: &tauri::AppHandle) {
// fcitx5 在不同发行版的 lib 路径不同
// fcitx5 在不同发行版的 lib 路径不同,同时支持用户 XDG 安装
let lib_dirs = [
"/usr/lib/x86_64-linux-gnu/fcitx5", // Debian multiarch
"/usr/lib64/fcitx5", // RPM 64-bit
@@ -430,24 +430,48 @@ pub fn ensure_plugin_installed(_app: &tauri::AppHandle) {
];
let system_conf = std::path::Path::new("/usr/share/fcitx5/addon/openless.conf");
if !system_conf.exists() {
// 用户 XDG 安装:~/.local/ 下自编译安装的版本
let (user_so, user_conf) = if let Ok(home) = std::env::var("HOME") {
let home = std::path::PathBuf::from(home);
(
home.join(".local/lib/fcitx5/libopenless.so"),
home.join(".local/share/fcitx5/addon/openless.conf"),
)
} else {
(std::path::PathBuf::new(), std::path::PathBuf::new())
};
let conf_ok = user_conf.exists() || system_conf.exists();
let system_so_found = lib_dirs.iter().find(|dir| {
std::path::Path::new(dir).join("libopenless.so").exists()
});
let so_ok = user_so.exists() || system_so_found.is_some();
// 用户手动安装过 ~/.local/ 版本,同时系统路径也有(deb 注入的)→
// fcitx5 优先加载用户路径的旧版,系统新版被忽略。
// 提醒用户删除 ~/.local/ 的旧插件。
if user_so.exists() && system_so_found.is_some() {
log::warn!(
"[fcitx] fcitx5 addon config not installed at {:?}. \
The OpenLess package may be incomplete.",
system_conf
"[fcitx] fcitx5 plugin found in both ~/.local/ and system paths. \
fcitx5 will load the ~/.local/ version first, which may be outdated. \
Remove it if you want to use the system-installed version: rm -f {}",
user_so.display()
);
}
if !conf_ok {
log::warn!(
"[fcitx] fcitx5 addon config not found. \
The OpenLess package may be incomplete."
);
return;
}
let found = lib_dirs.iter().any(|dir| {
std::path::Path::new(dir).join("libopenless.so").exists()
});
if !found {
if !so_ok {
log::warn!(
"[fcitx] fcitx5 plugin .so not found in any of {:?}. \
"[fcitx] fcitx5 plugin .so not found in {:?} or {:?}. \
The OpenLess package may be incomplete.",
lib_dirs
lib_dirs, user_so
);
}
}
+4 -47
View File
@@ -26,7 +26,7 @@ interface AppProps {
forcedOs?: OS | null;
}
type Gate = 'checking' | 'onboarding' | 'ready';
type Gate = 'onboarding' | 'ready';
export function App({ isCapsule, isQa, forcedOs }: AppProps) {
if (isCapsule) {
@@ -38,11 +38,10 @@ export function App({ isCapsule, isQa, forcedOs }: AppProps) {
const os = forcedOs ?? detectOS();
// Windows 启动不应被权限探测阻塞首屏。
const [gate, setGate] = useState<Gate>(isTauri ? 'checking' : 'ready');
const [gate, setGate] = useState<Gate>('ready');
useEffect(() => {
if (!isTauri) return;
if (os === 'win' && gate === 'checking') return;
let cancelled = false;
requestAnimationFrame(() => {
if (cancelled) return;
@@ -80,7 +79,7 @@ export function App({ isCapsule, isQa, forcedOs }: AppProps) {
return () => {
cancelled = true;
};
}, [gate, os]);
}, [os]);
useEffect(() => {
if (!isTauri) return;
@@ -170,7 +169,7 @@ export function App({ isCapsule, isQa, forcedOs }: AppProps) {
};
}, [os]);
// Linux: 检测 WEBKIT_DISABLE_COMPOSITING_MODE → 禁用 backdrop-filter fallback
// Linux: 检测 WEBKIT_DISABLE_COMPOSITING_MODE → 触发磨砂 fallback(#570, #553)
useEffect(() => {
if (!isTauri) return;
invoke<boolean>('is_no_compositing_mode').then((val) => {
@@ -182,9 +181,6 @@ export function App({ isCapsule, isQa, forcedOs }: AppProps) {
});
}, []);
if (gate === 'checking') {
return <StartupShell />;
}
return (
<HotkeySettingsProvider>
{gate === 'onboarding' ? <Onboarding onComplete={() => setGate('ready')} /> : <FloatingShell os={os} />}
@@ -193,42 +189,3 @@ export function App({ isCapsule, isQa, forcedOs }: AppProps) {
);
}
function StartupShell() {
// 用透明背景:main window 是 transparent + macOSPrivateApi(NSVisualEffectView 磨砂)。
// 之前用 linear-gradient(rgba(245,245,247,0.96)...) 会盖过 macOS vibrancy,启动时
// 长时间在 'checking' phase(凭据迁移 / 权限 probe 慢)会让窗口看起来「左侧白屏 +
// 右侧磨砂」割裂。现在背景全透明,让磨砂统一展开,提示文字 + icon 用一个轻量
// pill 卡片承载,跟 capsule 视觉一致。
return (
<div
style={{
minHeight: '100vh',
display: 'grid',
placeItems: 'center',
background: 'transparent',
color: 'var(--ol-ink-3)',
fontFamily: 'var(--ol-font-sans)',
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 10,
fontSize: 13,
fontWeight: 500,
padding: '10px 16px',
borderRadius: 999,
background: 'rgba(255, 255, 255, 0.55)',
backdropFilter: 'blur(20px) saturate(180%)',
WebkitBackdropFilter: 'blur(20px) saturate(180%)',
border: '0.5px solid rgba(0, 0, 0, 0.06)',
boxShadow: '0 4px 14px -6px rgba(0, 0, 0, 0.18), 0 0 0 0.5px rgba(0,0,0,0.04)',
}}
>
<img src="AppIcon.png" alt="" style={{ width: 18, height: 18, borderRadius: 4 }} />
<span>OpenLess 正在启动</span>
</div>
</div>
);
}
+1 -1
View File
@@ -735,7 +735,7 @@ export const zhCN = {
startStop: '开始 / 停止录音',
cancel: '取消本次录音',
confirm: '胶囊确认插入',
switchStyle: '切换上一次风格',
switchStyle: '切换到上一个风格',
openApp: '打开 OpenLess',
agentPolish: '选中文本润色',
agentPolishDesc: '选中文本 → 按键 → Claude 润色 → 替换选区。',
+1 -1
View File
@@ -737,7 +737,7 @@ export const zhTW: typeof zhCN = {
startStop: '開始 / 停止錄音',
cancel: '取消本次錄音',
confirm: '膠囊確認插入',
switchStyle: '切換上一次風格',
switchStyle: '切換到上一個風格',
openApp: '打開 OpenLess',
agentPolish: '選取文字潤色',
agentPolishDesc: '選取文字 → 按鍵 → Claude 潤色 → 取代選取。',