feat(settings): add Windows toggle to disable WebView2 hardware acceleration

This commit is contained in:
xintaofei
2026-04-25 11:57:35 +08:00
parent 5ae081e87a
commit f0bd2a28a2
19 changed files with 338 additions and 3 deletions

View File

@@ -8,6 +8,10 @@ use crate::db::service::app_metadata_service;
use crate::db::AppDatabase; use crate::db::AppDatabase;
use crate::models::{SystemLanguageSettings, SystemProxySettings}; use crate::models::{SystemLanguageSettings, SystemProxySettings};
#[cfg(feature = "tauri-runtime")] #[cfg(feature = "tauri-runtime")]
use crate::models::SystemRenderingSettings;
#[cfg(feature = "tauri-runtime")]
use crate::preferences;
#[cfg(feature = "tauri-runtime")]
use crate::network::proxy; use crate::network::proxy;
const SYSTEM_PROXY_SETTINGS_KEY: &str = "system_proxy_settings"; const SYSTEM_PROXY_SETTINGS_KEY: &str = "system_proxy_settings";
@@ -147,3 +151,26 @@ pub async fn update_system_language_settings(
Ok(settings) Ok(settings)
} }
#[cfg(feature = "tauri-runtime")]
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
pub async fn get_system_rendering_settings() -> Result<SystemRenderingSettings, AppCommandError> {
let prefs = preferences::load();
Ok(SystemRenderingSettings {
disable_hardware_acceleration: prefs.disable_hardware_acceleration,
})
}
#[cfg(feature = "tauri-runtime")]
#[cfg_attr(feature = "tauri-runtime", tauri::command)]
pub async fn update_system_rendering_settings(
settings: SystemRenderingSettings,
) -> Result<SystemRenderingSettings, AppCommandError> {
let mut prefs = preferences::load();
prefs.disable_hardware_acceleration = settings.disable_hardware_acceleration;
preferences::save(&prefs).map_err(|err| {
AppCommandError::io_error("Failed to persist rendering settings")
.with_detail(err.to_string())
})?;
Ok(settings)
}

View File

@@ -10,6 +10,8 @@ pub mod keyring_store;
mod models; mod models;
mod network; mod network;
mod parsers; mod parsers;
#[cfg(feature = "tauri-runtime")]
pub mod preferences;
pub mod process; pub mod process;
mod terminal; mod terminal;
pub mod web; pub mod web;
@@ -35,8 +37,45 @@ mod tauri_app {
static APP_QUITTING: AtomicBool = AtomicBool::new(false); static APP_QUITTING: AtomicBool = AtomicBool::new(false);
/// On Windows, opt-out users can disable WebView2 hardware acceleration to
/// work around AMD/Intel GPU driver bugs that produce a black-screen
/// webview. The flag is stored in a tiny sidecar file at
/// `~/.codeg/preferences.json` so it can be read **before** the Tauri
/// builder, plugins, or tokio runtime start — once a tokio worker is alive,
/// `std::env::set_var` would race with concurrent `getenv` calls from
/// libraries like reqwest/rustls that read `HTTP_PROXY` etc.
#[cfg(target_os = "windows")]
fn apply_webview2_rendering_override() {
const DISABLE_GPU_ARGS: [&str; 2] = ["--disable-gpu", "--disable-software-rasterizer"];
const ENV_KEY: &str = "WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS";
let prefs = crate::preferences::load();
if !prefs.disable_hardware_acceleration {
return;
}
let mut tokens: Vec<String> = match std::env::var(ENV_KEY) {
Ok(prev) => prev
.split_whitespace()
.map(str::to_string)
.collect(),
Err(_) => Vec::new(),
};
for arg in DISABLE_GPU_ARGS {
if !tokens.iter().any(|t| t == arg) {
tokens.push(arg.to_string());
}
}
std::env::set_var(ENV_KEY, tokens.join(" "));
}
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
// Apply the WebView2 rendering override before *any* tokio worker
// exists or any plugin reads the env. See doc comment above.
#[cfg(target_os = "windows")]
apply_webview2_rendering_override();
if let Err(err) = fix_path_env::fix() { if let Err(err) = fix_path_env::fix() {
eprintln!("[PATH] fix_path_env failed: {err}"); eprintln!("[PATH] fix_path_env failed: {err}");
} }
@@ -302,6 +341,8 @@ mod tauri_app {
system_settings::update_system_proxy_settings, system_settings::update_system_proxy_settings,
system_settings::get_system_language_settings, system_settings::get_system_language_settings,
system_settings::update_system_language_settings, system_settings::update_system_language_settings,
system_settings::get_system_rendering_settings,
system_settings::update_system_rendering_settings,
version_control::detect_git, version_control::detect_git,
version_control::test_git_path, version_control::test_git_path,
version_control::get_git_settings, version_control::get_git_settings,

View File

@@ -25,3 +25,5 @@ pub use system::{
GitCredentials, GitDetectResult, GitHubAccountsSettings, GitHubTokenValidation, GitSettings, GitCredentials, GitDetectResult, GitHubAccountsSettings, GitHubTokenValidation, GitSettings,
SystemLanguageSettings, SystemProxySettings, SystemLanguageSettings, SystemProxySettings,
}; };
#[cfg(feature = "tauri-runtime")]
pub use system::SystemRenderingSettings;

View File

@@ -37,6 +37,13 @@ pub struct SystemLanguageSettings {
pub language: AppLocale, pub language: AppLocale,
} }
#[cfg(feature = "tauri-runtime")]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SystemRenderingSettings {
pub disable_hardware_acceleration: bool,
}
// --- Version Control --- // --- Version Control ---
/// Explicit credentials for a single git remote operation. /// Explicit credentials for a single git remote operation.

View File

@@ -0,0 +1,56 @@
//! User-scoped preferences stored at `~/.codeg/preferences.json`.
//!
//! These are settings that must be readable **before** the Tauri builder and
//! tokio runtime start (e.g. WebView2 rendering flags applied via
//! `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS`). All access is synchronous I/O so
//! the data must stay tiny.
use std::fs;
use std::io;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
const PREFERENCES_FILE_NAME: &str = "preferences.json";
const CODEG_DIR_NAME: &str = ".codeg";
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AppPreferences {
pub disable_hardware_acceleration: bool,
}
pub fn preferences_file_path() -> Option<PathBuf> {
dirs::home_dir().map(|h| h.join(CODEG_DIR_NAME).join(PREFERENCES_FILE_NAME))
}
/// Read preferences synchronously. Missing / unreadable / malformed file
/// returns `Default::default()`. Errors are intentionally swallowed because
/// this is called on the startup hot-path; callers log if needed.
pub fn load() -> AppPreferences {
let Some(path) = preferences_file_path() else {
return AppPreferences::default();
};
match fs::read_to_string(&path) {
Ok(raw) => serde_json::from_str(&raw).unwrap_or_default(),
Err(err) if err.kind() == io::ErrorKind::NotFound => AppPreferences::default(),
Err(err) => {
eprintln!(
"[Preferences] failed to read {}: {err}",
path.display()
);
AppPreferences::default()
}
}
}
pub fn save(prefs: &AppPreferences) -> io::Result<()> {
let path = preferences_file_path()
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "home directory unavailable"))?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let serialized = serde_json::to_string_pretty(prefs)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
fs::write(&path, serialized)
}

View File

@@ -6,6 +6,7 @@ import {
CheckCircle2, CheckCircle2,
Languages, Languages,
Loader2, Loader2,
MonitorCog,
RefreshCw, RefreshCw,
Wifi, Wifi,
} from "lucide-react" } from "lucide-react"
@@ -29,11 +30,14 @@ import {
} from "@/components/ui/select" } from "@/components/ui/select"
import { import {
getSystemProxySettings, getSystemProxySettings,
getSystemRenderingSettings,
updateSystemLanguageSettings, updateSystemLanguageSettings,
updateSystemProxySettings, updateSystemProxySettings,
updateSystemRenderingSettings,
} from "@/lib/api" } from "@/lib/api"
import { openUrl } from "@/lib/platform" import { isDesktop, openUrl } from "@/lib/platform"
import type { AppLocale } from "@/lib/types" import type { AppLocale } from "@/lib/types"
import { usePlatform } from "@/hooks/use-platform"
import { import {
checkAppUpdate, checkAppUpdate,
closeAppUpdate, closeAppUpdate,
@@ -62,12 +66,21 @@ function isAppLocale(value: string): value is AppLocale {
type UpdateAction = "check" | "install" type UpdateAction = "check" | "install"
// Captured the first time settings page loads: represents the value that the
// running webview process was launched with. Survives settings-shell remounts
// so the "Restart now" banner doesn't vanish if the user navigates away and
// back without restarting.
let processStartDisableHwAccel: boolean | null = null
export function SystemNetworkSettings() { export function SystemNetworkSettings() {
const t = useTranslations("SystemSettings") const t = useTranslations("SystemSettings")
const tLanguage = useTranslations("Language") const tLanguage = useTranslations("Language")
const locale = useLocale() const locale = useLocale()
const { languageSettings, languageSettingsLoaded, setLanguageSettings } = const { languageSettings, languageSettingsLoaded, setLanguageSettings } =
useAppI18n() useAppI18n()
const { isWindows } = usePlatform()
const renderingSettingsLoadable = isDesktop()
const renderingSectionVisible = renderingSettingsLoadable && isWindows
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
@@ -75,6 +88,14 @@ export function SystemNetworkSettings() {
const [enabled, setEnabled] = useState(false) const [enabled, setEnabled] = useState(false)
const [proxyUrl, setProxyUrl] = useState("") const [proxyUrl, setProxyUrl] = useState("")
const [loadError, setLoadError] = useState<string | null>(null) const [loadError, setLoadError] = useState<string | null>(null)
const [disableHwAccel, setDisableHwAccel] = useState(false)
const [savingRendering, setSavingRendering] = useState(false)
const [persistedDisableHwAccel, setPersistedDisableHwAccel] = useState(false)
const [processStartLoaded, setProcessStartLoaded] = useState(
processStartDisableHwAccel !== null
)
const renderingDirty =
processStartLoaded && persistedDisableHwAccel !== processStartDisableHwAccel
const [currentVersion, setCurrentVersion] = useState<string>("") const [currentVersion, setCurrentVersion] = useState<string>("")
const [availableUpdate, setAvailableUpdate] = useState<Update | null>(null) const [availableUpdate, setAvailableUpdate] = useState<Update | null>(null)
const [checkingUpdate, setCheckingUpdate] = useState(false) const [checkingUpdate, setCheckingUpdate] = useState(false)
@@ -150,14 +171,26 @@ export function SystemNetworkSettings() {
setLoadError(null) setLoadError(null)
try { try {
const [proxySettings, version] = await Promise.all([ const [proxySettings, version, renderingSettings] = await Promise.all([
getSystemProxySettings(), getSystemProxySettings(),
getCurrentAppVersion(), getCurrentAppVersion(),
renderingSettingsLoadable
? getSystemRenderingSettings()
: Promise.resolve(null),
]) ])
setEnabled(proxySettings.enabled) setEnabled(proxySettings.enabled)
setProxyUrl(proxySettings.proxy_url ?? "") setProxyUrl(proxySettings.proxy_url ?? "")
setCurrentVersion(version) setCurrentVersion(version)
if (renderingSettings) {
const value = renderingSettings.disable_hardware_acceleration
setDisableHwAccel(value)
setPersistedDisableHwAccel(value)
if (processStartDisableHwAccel === null) {
processStartDisableHwAccel = value
setProcessStartLoaded(true)
}
}
} catch (err) { } catch (err) {
const message = err instanceof Error ? err.message : String(err) const message = err instanceof Error ? err.message : String(err)
setLoadError(message) setLoadError(message)
@@ -165,7 +198,7 @@ export function SystemNetworkSettings() {
} finally { } finally {
setLoading(false) setLoading(false)
} }
}, []) }, [renderingSettingsLoadable])
useEffect(() => { useEffect(() => {
loadSettings().catch((err) => { loadSettings().catch((err) => {
@@ -208,6 +241,35 @@ export function SystemNetworkSettings() {
[t] [t]
) )
const saveRenderingSettings = useCallback(
async (next: boolean, prev: boolean) => {
setSavingRendering(true)
try {
const result = await updateSystemRenderingSettings({
disable_hardware_acceleration: next,
})
setDisableHwAccel(result.disable_hardware_acceleration)
setPersistedDisableHwAccel(result.disable_hardware_acceleration)
} catch (err) {
setDisableHwAccel(prev)
const message = err instanceof Error ? err.message : String(err)
toast.error(t("renderingSaveFailed", { message }))
} finally {
setSavingRendering(false)
}
},
[t]
)
const restartNow = useCallback(async () => {
try {
await relaunchApp()
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
toast.error(t("restartFailed", { message }))
}
}, [t])
const saveLanguage = useCallback( const saveLanguage = useCallback(
async (lang: LanguageSelectValue) => { async (lang: LanguageSelectValue) => {
setSavingLanguage(true) setSavingLanguage(true)
@@ -559,6 +621,50 @@ export function SystemNetworkSettings() {
</div> </div>
</section> </section>
{renderingSectionVisible && (
<section className="rounded-xl border bg-card p-4 space-y-4">
<div className="flex items-center gap-2">
<MonitorCog className="h-4 w-4 text-muted-foreground" />
<h2 className="text-sm font-semibold">{t("renderingTitle")}</h2>
</div>
<p className="text-xs text-muted-foreground leading-5">
{t("renderingDescription")}
</p>
<label className="inline-flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={disableHwAccel}
disabled={savingRendering}
onChange={(event) => {
const next = event.target.checked
const prev = disableHwAccel
setDisableHwAccel(next)
saveRenderingSettings(next, prev)
}}
/>
{t("disableHardwareAcceleration")}
</label>
{renderingDirty && (
<div className="flex items-center justify-between gap-3 rounded-md border bg-muted/20 px-3 py-2 text-xs">
<span className="text-muted-foreground">
{t("restartRequired")}
</span>
<Button
size="sm"
onClick={restartNow}
disabled={savingRendering}
>
<RefreshCw className="h-3.5 w-3.5" />
{t("restartNow")}
</Button>
</div>
)}
</section>
)}
<section className="rounded-xl border bg-card p-4 space-y-4"> <section className="rounded-xl border bg-card p-4 space-y-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Languages className="h-4 w-4 text-muted-foreground" /> <Languages className="h-4 w-4 text-muted-foreground" />

View File

@@ -114,6 +114,13 @@
"appLanguage": "لغة التطبيق", "appLanguage": "لغة التطبيق",
"languageSaveSuccess": "تم حفظ إعدادات اللغة", "languageSaveSuccess": "تم حفظ إعدادات اللغة",
"languageSaveFailed": "فشل حفظ إعدادات اللغة: {message}", "languageSaveFailed": "فشل حفظ إعدادات اللغة: {message}",
"renderingTitle": "العرض",
"renderingDescription": "أوقف تشغيل تسريع الأجهزة إذا ظهرت شاشة سوداء أو أخطاء في العرض (شائع على بعض كروت AMD أو كروت Intel المدمجة). يسري على إصدار سطح المكتب لويندوز فقط.",
"disableHardwareAcceleration": "تعطيل تسريع الأجهزة",
"renderingSaveFailed": "فشل حفظ إعدادات العرض: {message}",
"restartRequired": "تم الحفظ. أعد تشغيل التطبيق ليصبح التغيير نافذًا.",
"restartNow": "إعادة التشغيل الآن",
"restartFailed": "فشل إعادة التشغيل: {message}",
"updateTitle": "تحديث التطبيق", "updateTitle": "تحديث التطبيق",
"versionTitle": "تحديث البرنامج", "versionTitle": "تحديث البرنامج",
"updateDescription": "تحقق من المصدر المهيأ للإصدارات الأحدث وثبّت التحديث مباشرة عند توفره.", "updateDescription": "تحقق من المصدر المهيأ للإصدارات الأحدث وثبّت التحديث مباشرة عند توفره.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "App-Sprache", "appLanguage": "App-Sprache",
"languageSaveSuccess": "Spracheinstellungen wurden gespeichert", "languageSaveSuccess": "Spracheinstellungen wurden gespeichert",
"languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}", "languageSaveFailed": "Spracheinstellungen konnten nicht gespeichert werden: {message}",
"renderingTitle": "Rendering",
"renderingDescription": "Deaktivieren Sie die Hardwarebeschleunigung, wenn die App einen schwarzen Bildschirm oder Render-Fehler zeigt (häufig bei bestimmten AMD-GPUs oder integrierten Intel-GPUs). Wirkt sich nur auf die Windows-Desktop-Version aus.",
"disableHardwareAcceleration": "Hardwarebeschleunigung deaktivieren",
"renderingSaveFailed": "Render-Einstellungen konnten nicht gespeichert werden: {message}",
"restartRequired": "Gespeichert. Starten Sie die App neu, damit die Änderung wirksam wird.",
"restartNow": "Jetzt neu starten",
"restartFailed": "Neustart fehlgeschlagen: {message}",
"updateTitle": "App-Update", "updateTitle": "App-Update",
"versionTitle": "Softwareupdate", "versionTitle": "Softwareupdate",
"updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.", "updateDescription": "Prüft die konfigurierte Release-Quelle auf neue Versionen und installiert sie bei Verfügbarkeit direkt.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "App language", "appLanguage": "App language",
"languageSaveSuccess": "Language settings saved", "languageSaveSuccess": "Language settings saved",
"languageSaveFailed": "Failed to save language settings: {message}", "languageSaveFailed": "Failed to save language settings: {message}",
"renderingTitle": "Rendering",
"renderingDescription": "Disable hardware acceleration if the app shows a black screen or rendering glitches (common on certain AMD GPUs or Intel integrated GPUs). Only takes effect on the Windows desktop build.",
"disableHardwareAcceleration": "Disable hardware acceleration",
"renderingSaveFailed": "Failed to save rendering settings: {message}",
"restartRequired": "Saved. Restart the app for the change to take effect.",
"restartNow": "Restart now",
"restartFailed": "Failed to restart: {message}",
"updateTitle": "App Update", "updateTitle": "App Update",
"versionTitle": "Software Update", "versionTitle": "Software Update",
"updateDescription": "Check the configured release source for newer versions and install directly when available.", "updateDescription": "Check the configured release source for newer versions and install directly when available.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "Idioma de la app", "appLanguage": "Idioma de la app",
"languageSaveSuccess": "La configuración de idioma se guardó", "languageSaveSuccess": "La configuración de idioma se guardó",
"languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}", "languageSaveFailed": "No se pudo guardar la configuración de idioma: {message}",
"renderingTitle": "Renderizado",
"renderingDescription": "Desactiva la aceleración por hardware si la aplicación muestra pantalla negra o fallos de renderizado (común en algunas GPU AMD o Intel integradas). Solo afecta a la versión de escritorio en Windows.",
"disableHardwareAcceleration": "Desactivar aceleración por hardware",
"renderingSaveFailed": "No se pudo guardar la configuración de renderizado: {message}",
"restartRequired": "Guardado. Reinicia la aplicación para aplicar el cambio.",
"restartNow": "Reiniciar ahora",
"restartFailed": "No se pudo reiniciar: {message}",
"updateTitle": "Actualización de la app", "updateTitle": "Actualización de la app",
"versionTitle": "Actualización de software", "versionTitle": "Actualización de software",
"updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.", "updateDescription": "Comprueba versiones más nuevas en la fuente de versiones configurada e instálalas directamente cuando estén disponibles.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "Langue de lapp", "appLanguage": "Langue de lapp",
"languageSaveSuccess": "Les paramètres de langue ont été enregistrés", "languageSaveSuccess": "Les paramètres de langue ont été enregistrés",
"languageSaveFailed": "Échec de lenregistrement des paramètres de langue : {message}", "languageSaveFailed": "Échec de lenregistrement des paramètres de langue : {message}",
"renderingTitle": "Rendu",
"renderingDescription": "Désactivez laccélération matérielle si lapplication affiche un écran noir ou des défauts de rendu (fréquent sur certaines GPU AMD ou GPU Intel intégrées). Na deffet que sur la version Windows de bureau.",
"disableHardwareAcceleration": "Désactiver laccélération matérielle",
"renderingSaveFailed": "Échec de lenregistrement des paramètres de rendu : {message}",
"restartRequired": "Enregistré. Redémarrez lapplication pour appliquer la modification.",
"restartNow": "Redémarrer maintenant",
"restartFailed": "Échec du redémarrage : {message}",
"updateTitle": "Mise à jour de lapp", "updateTitle": "Mise à jour de lapp",
"versionTitle": "Mise à jour logicielle", "versionTitle": "Mise à jour logicielle",
"updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.", "updateDescription": "Vérifiez les nouvelles versions depuis la source de publication configurée et installez-les directement si disponibles.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "アプリ言語", "appLanguage": "アプリ言語",
"languageSaveSuccess": "言語設定を保存しました", "languageSaveSuccess": "言語設定を保存しました",
"languageSaveFailed": "言語設定の保存に失敗しました: {message}", "languageSaveFailed": "言語設定の保存に失敗しました: {message}",
"renderingTitle": "レンダリング",
"renderingDescription": "アプリで黒画面や描画不具合が発生する場合(一部の AMD GPU や Intel 内蔵 GPU で報告あり、ハードウェアアクセラレーションを無効化してください。Windows デスクトップ版のみ有効です。",
"disableHardwareAcceleration": "ハードウェアアクセラレーションを無効化",
"renderingSaveFailed": "レンダリング設定の保存に失敗しました: {message}",
"restartRequired": "保存しました。再起動後に反映されます。",
"restartNow": "今すぐ再起動",
"restartFailed": "再起動に失敗しました: {message}",
"updateTitle": "アプリ更新", "updateTitle": "アプリ更新",
"versionTitle": "ソフトウェアアップデート", "versionTitle": "ソフトウェアアップデート",
"updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。", "updateDescription": "設定されたリリースソースで新しいバージョンを確認し、利用可能なら直接インストールします。",

View File

@@ -114,6 +114,13 @@
"appLanguage": "앱 언어", "appLanguage": "앱 언어",
"languageSaveSuccess": "언어 설정이 저장되었습니다", "languageSaveSuccess": "언어 설정이 저장되었습니다",
"languageSaveFailed": "언어 설정 저장 실패: {message}", "languageSaveFailed": "언어 설정 저장 실패: {message}",
"renderingTitle": "렌더링",
"renderingDescription": "앱이 검은 화면이 되거나 렌더링 문제가 발생하면(일부 AMD GPU 또는 Intel 내장 GPU에서 보고됨) 하드웨어 가속을 끄세요. Windows 데스크톱에서만 적용됩니다.",
"disableHardwareAcceleration": "하드웨어 가속 비활성화",
"renderingSaveFailed": "렌더링 설정 저장 실패: {message}",
"restartRequired": "저장되었습니다. 변경 사항을 적용하려면 앱을 다시 시작하세요.",
"restartNow": "지금 다시 시작",
"restartFailed": "다시 시작 실패: {message}",
"updateTitle": "앱 업데이트", "updateTitle": "앱 업데이트",
"versionTitle": "소프트웨어 업데이트", "versionTitle": "소프트웨어 업데이트",
"updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.", "updateDescription": "설정된 릴리스 소스에서 새 버전을 확인하고 가능하면 바로 설치합니다.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "Idioma do app", "appLanguage": "Idioma do app",
"languageSaveSuccess": "As configurações de idioma foram salvas", "languageSaveSuccess": "As configurações de idioma foram salvas",
"languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}", "languageSaveFailed": "Falha ao salvar as configurações de idioma: {message}",
"renderingTitle": "Renderização",
"renderingDescription": "Desative a aceleração de hardware se o aplicativo apresentar tela preta ou falhas de renderização (comum em certas GPUs AMD ou GPUs Intel integradas). Aplica-se apenas à versão desktop do Windows.",
"disableHardwareAcceleration": "Desativar aceleração de hardware",
"renderingSaveFailed": "Falha ao salvar as configurações de renderização: {message}",
"restartRequired": "Salvo. Reinicie o aplicativo para aplicar a alteração.",
"restartNow": "Reiniciar agora",
"restartFailed": "Falha ao reiniciar: {message}",
"updateTitle": "Atualização do app", "updateTitle": "Atualização do app",
"versionTitle": "Atualização de software", "versionTitle": "Atualização de software",
"updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.", "updateDescription": "Verifique versões mais novas na fonte de releases configurada e instale diretamente quando disponíveis.",

View File

@@ -114,6 +114,13 @@
"appLanguage": "应用语言", "appLanguage": "应用语言",
"languageSaveSuccess": "语言设置已保存", "languageSaveSuccess": "语言设置已保存",
"languageSaveFailed": "语言设置保存失败:{message}", "languageSaveFailed": "语言设置保存失败:{message}",
"renderingTitle": "渲染加速",
"renderingDescription": "如果应用出现黑屏或渲染异常(常见于 AMD 显卡或部分 Intel 集成显卡),可关闭硬件加速。仅 Windows 桌面端生效。",
"disableHardwareAcceleration": "禁用硬件加速",
"renderingSaveFailed": "渲染设置保存失败:{message}",
"restartRequired": "已保存,重启应用后生效。",
"restartNow": "立即重启",
"restartFailed": "重启失败:{message}",
"updateTitle": "应用升级", "updateTitle": "应用升级",
"versionTitle": "软件更新", "versionTitle": "软件更新",
"updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。", "updateDescription": "点击检查后会从配置的发布源拉取最新版本信息,有新版本时可直接下载并安装。",

View File

@@ -114,6 +114,13 @@
"appLanguage": "應用語言", "appLanguage": "應用語言",
"languageSaveSuccess": "語言設定已儲存", "languageSaveSuccess": "語言設定已儲存",
"languageSaveFailed": "語言設定儲存失敗:{message}", "languageSaveFailed": "語言設定儲存失敗:{message}",
"renderingTitle": "渲染加速",
"renderingDescription": "若應用出現黑屏或渲染異常(常見於 AMD 顯示卡或部分 Intel 內顯),可關閉硬體加速。僅 Windows 桌面端生效。",
"disableHardwareAcceleration": "停用硬體加速",
"renderingSaveFailed": "渲染設定儲存失敗:{message}",
"restartRequired": "已儲存,需重新啟動應用程式才會生效。",
"restartNow": "立即重新啟動",
"restartFailed": "重新啟動失敗:{message}",
"updateTitle": "應用升級", "updateTitle": "應用升級",
"versionTitle": "軟體更新", "versionTitle": "軟體更新",
"updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。", "updateDescription": "點擊檢查後會從設定的發佈來源拉取最新版本資訊,有新版本時可直接下載並安裝。",

View File

@@ -47,6 +47,7 @@ import type {
GitLogResult, GitLogResult,
SystemLanguageSettings, SystemLanguageSettings,
SystemProxySettings, SystemProxySettings,
SystemRenderingSettings,
GitCredentials, GitCredentials,
GitDetectResult, GitDetectResult,
PackageManagerInfo, PackageManagerInfo,
@@ -458,6 +459,16 @@ export async function updateSystemLanguageSettings(
return getTransport().call("update_system_language_settings", { settings }) return getTransport().call("update_system_language_settings", { settings })
} }
export async function getSystemRenderingSettings(): Promise<SystemRenderingSettings> {
return getTransport().call("get_system_rendering_settings")
}
export async function updateSystemRenderingSettings(
settings: SystemRenderingSettings
): Promise<SystemRenderingSettings> {
return getTransport().call("update_system_rendering_settings", { settings })
}
// --- Version Control --- // --- Version Control ---
export async function detectGit(): Promise<GitDetectResult> { export async function detectGit(): Promise<GitDetectResult> {

View File

@@ -45,6 +45,7 @@ import type {
GitLogResult, GitLogResult,
SystemLanguageSettings, SystemLanguageSettings,
SystemProxySettings, SystemProxySettings,
SystemRenderingSettings,
GitCredentials, GitCredentials,
GitDetectResult, GitDetectResult,
GitSettings, GitSettings,
@@ -319,6 +320,16 @@ export async function updateSystemLanguageSettings(
return invoke("update_system_language_settings", { settings }) return invoke("update_system_language_settings", { settings })
} }
export async function getSystemRenderingSettings(): Promise<SystemRenderingSettings> {
return invoke("get_system_rendering_settings")
}
export async function updateSystemRenderingSettings(
settings: SystemRenderingSettings
): Promise<SystemRenderingSettings> {
return invoke("update_system_rendering_settings", { settings })
}
// --- Version Control --- // --- Version Control ---
export async function detectGit(): Promise<GitDetectResult> { export async function detectGit(): Promise<GitDetectResult> {

View File

@@ -634,6 +634,10 @@ export interface SystemLanguageSettings {
language: AppLocale language: AppLocale
} }
export interface SystemRenderingSettings {
disable_hardware_acceleration: boolean
}
// --- Version Control --- // --- Version Control ---
export interface GitCredentials { export interface GitCredentials {