feat(settings): surface graphics recommendation banner in the Graphics tab
The detection + decision matrix in autoconfig_graphics.rs already knew
the right combination for every (GPU vendor x display server x desktop)
case, but the only way to consume it was the qbz --autoconfig-graphics
CLI tool which most users never run. The recommendation sat invisible
while users hunted toggles by hand.
Lifts the same logic into the Settings UI as a persistent banner at
the top of the new Graphics tab:
- autoconfig_graphics: Environment and Recommendation structs become
public with Serialize, the three pieces (detect_environment,
compute_recommendation, write_recommendation) become pub so they
can be re-used. The existing apply_recommendation CLI helper now
delegates writes to the shared write_recommendation, keeping the
behaviour identical (and inverting the DMA-BUF mapping so that
rec.disable_dmabuf=false now writes force_dmabuf=true, matching
the 1.2.13 opt-in semantics).
- commands_v2/graphics_recommendation.rs (new): two thin Tauri
commands — v2_get_graphics_recommendation returns the environment
plus the computed recommendation so the frontend can compare it
to persisted settings; v2_apply_graphics_recommendation writes
the whole bundle in one call.
- Settings UI: the Graphics tab loads the recommendation on mount.
A $derived computes whether at least one recommended value
diverges from the four persisted settings (HW accel / force_x11 /
gsk_renderer / force_dmabuf with the inverted DMA-BUF axis).
When it does, a violet-accent banner appears above the profile
grid showing the detected environment, the rationale lines from
the matrix, and an Apply button. Persistent (no dismiss) — vanishes
the moment the persisted state matches the recommendation, no
second copy of state to keep in sync.
- i18n: 4 new keys per locale (title / detected / apply / applied)
across en/es/de/fr/pt. The rationale strings stay in English
because they're hardcoded in autoconfig_graphics.rs and reword
them per scenario would mean a structured i18n key per case —
not worth it for diagnostic copy that's read once and dismissed.
cc
This commit is contained in:
10 files changed
+314
-49
No files matched your search
@@ -3,30 +3,39 @@
|
||||
//! Detects the current GPU, display server, desktop environment, and compositor,
|
||||
//! then recommends and applies optimal graphics settings.
|
||||
//!
|
||||
//! Usage: `qbz --autoconfig-graphics`
|
||||
//! Two entry points:
|
||||
//! - `run()` — CLI prompt invoked via `qbz --autoconfig-graphics`
|
||||
//! - `detect_environment()` / `compute_recommendation()` / `apply_recommendation()`
|
||||
//! — public helpers consumed by V2 commands that surface the recommendation
|
||||
//! inside the Settings UI (issue #315 follow-up)
|
||||
|
||||
use crate::config::graphics_settings::GraphicsSettingsStore;
|
||||
use serde::Serialize;
|
||||
use std::io::{self, BufRead, Write};
|
||||
|
||||
/// Detected environment information
|
||||
struct Environment {
|
||||
display_server: String,
|
||||
gpu_nvidia: bool,
|
||||
gpu_amd: bool,
|
||||
gpu_intel: bool,
|
||||
gpu_name: String,
|
||||
desktop: String,
|
||||
is_vm: bool,
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Environment {
|
||||
pub display_server: String,
|
||||
pub gpu_nvidia: bool,
|
||||
pub gpu_amd: bool,
|
||||
pub gpu_intel: bool,
|
||||
pub gpu_name: String,
|
||||
pub desktop: String,
|
||||
pub is_vm: bool,
|
||||
}
|
||||
|
||||
/// Recommended configuration
|
||||
struct Recommendation {
|
||||
hardware_acceleration: bool,
|
||||
force_x11: bool,
|
||||
gsk_renderer: Option<String>,
|
||||
disable_dmabuf: bool,
|
||||
disable_blur_background: bool,
|
||||
rationale: Vec<String>,
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Recommendation {
|
||||
pub hardware_acceleration: bool,
|
||||
pub force_x11: bool,
|
||||
pub gsk_renderer: Option<String>,
|
||||
pub disable_dmabuf: bool,
|
||||
pub disable_blur_background: bool,
|
||||
pub rationale: Vec<String>,
|
||||
}
|
||||
|
||||
/// Run the autoconfig-graphics CLI tool.
|
||||
@@ -57,7 +66,7 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_environment() -> Environment {
|
||||
pub fn detect_environment() -> Environment {
|
||||
let display_server = detect_display_server();
|
||||
let gpu_nvidia = is_nvidia_gpu();
|
||||
let gpu_amd = is_amd_gpu();
|
||||
@@ -200,7 +209,7 @@ fn print_environment(env: &Environment) {
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
fn compute_recommendation(env: &Environment) -> Recommendation {
|
||||
pub fn compute_recommendation(env: &Environment) -> Recommendation {
|
||||
let mut rationale = Vec::new();
|
||||
|
||||
// VM: software rendering, no blur
|
||||
@@ -361,9 +370,40 @@ fn print_recommendation(rec: &Recommendation) {
|
||||
}
|
||||
|
||||
fn apply_recommendation(rec: &Recommendation) {
|
||||
match write_recommendation(rec) {
|
||||
Ok(()) => {
|
||||
if rec.disable_blur_background {
|
||||
eprintln!(
|
||||
"[QBZ AutoConfig] Note: blur background will be disabled. You can toggle this in Settings > Appearance."
|
||||
);
|
||||
}
|
||||
eprintln!();
|
||||
eprintln!("[QBZ AutoConfig] Configuration applied successfully.");
|
||||
eprintln!("[QBZ AutoConfig] Restart QBZ to take effect.");
|
||||
}
|
||||
Err(errors) => {
|
||||
eprintln!();
|
||||
eprintln!("[QBZ AutoConfig] Some settings could not be applied:");
|
||||
for e in &errors {
|
||||
eprintln!(" - {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the recommendation to the persistence layer. Shared between the CLI
|
||||
/// prompt (`apply_recommendation`) and the V2 command surface. Returns the
|
||||
/// list of write errors so the caller can surface them appropriately (stderr
|
||||
/// for CLI, frontend toast for the Settings UI).
|
||||
///
|
||||
/// DMA-BUF semantics after the 1.2.13 opt-in flip:
|
||||
/// - `rec.disable_dmabuf = true` → force_dmabuf = false (matches default;
|
||||
/// runtime keeps DMA-BUF off).
|
||||
/// - `rec.disable_dmabuf = false` → force_dmabuf = true (user opts in via
|
||||
/// this recommendation; runtime turns DMA-BUF on).
|
||||
pub fn write_recommendation(rec: &Recommendation) -> Result<(), Vec<String>> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// Apply graphics settings to DB
|
||||
match GraphicsSettingsStore::new() {
|
||||
Ok(store) => {
|
||||
if let Err(e) = store.set_hardware_acceleration(rec.hardware_acceleration) {
|
||||
@@ -381,41 +421,21 @@ fn apply_recommendation(rec: &Recommendation) {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply developer settings (force_dmabuf)
|
||||
if rec.disable_dmabuf {
|
||||
// Note: we don't set force_dmabuf=true here because the default behavior
|
||||
// already disables DMA-BUF for NVIDIA+Wayland. We only reset it to ensure
|
||||
// it's not forced ON.
|
||||
match crate::config::developer_settings::DeveloperSettingsStore::new() {
|
||||
Ok(store) => {
|
||||
if let Err(e) = store.set_force_dmabuf(false) {
|
||||
errors.push(format!("force_dmabuf: {}", e));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
errors.push(format!("developer settings store: {}", e));
|
||||
let desired_force_dmabuf = !rec.disable_dmabuf;
|
||||
match crate::config::developer_settings::DeveloperSettingsStore::new() {
|
||||
Ok(store) => {
|
||||
if let Err(e) = store.set_force_dmabuf(desired_force_dmabuf) {
|
||||
errors.push(format!("force_dmabuf: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply blur background setting to localStorage config file
|
||||
// Note: This is stored in localStorage by the frontend, so we write a hint
|
||||
// that the frontend will read on next startup
|
||||
if rec.disable_blur_background {
|
||||
eprintln!(
|
||||
"[QBZ AutoConfig] Note: blur background will be disabled. You can toggle this in Settings > Appearance."
|
||||
);
|
||||
Err(e) => {
|
||||
errors.push(format!("developer settings store: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
eprintln!();
|
||||
eprintln!("[QBZ AutoConfig] Configuration applied successfully.");
|
||||
eprintln!("[QBZ AutoConfig] Restart QBZ to take effect.");
|
||||
Ok(())
|
||||
} else {
|
||||
eprintln!();
|
||||
eprintln!("[QBZ AutoConfig] Some settings could not be applied:");
|
||||
for e in &errors {
|
||||
eprintln!(" - {}", e);
|
||||
}
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//! V2 commands that expose the graphics auto-config recommendation to the
|
||||
//! Settings UI. The detection + decision logic lives in
|
||||
//! `autoconfig_graphics.rs` (shared with the `qbz --autoconfig-graphics` CLI
|
||||
//! tool); this module is just the Tauri surface that the Graphics tab uses
|
||||
//! to render the "Detected / Recommended" banner.
|
||||
|
||||
use crate::autoconfig_graphics::{
|
||||
compute_recommendation, detect_environment, write_recommendation, Environment, Recommendation,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
/// Payload returned to the Settings UI. Splits environment from
|
||||
/// recommendation so the frontend can show a human-readable detection
|
||||
/// line and then compare the recommendation to the user's current
|
||||
/// persisted settings to decide whether to surface the banner at all.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct GraphicsRecommendationPayload {
|
||||
pub environment: Environment,
|
||||
pub recommendation: Recommendation,
|
||||
}
|
||||
|
||||
/// Compute the recommendation for the current host. Cheap — runs the
|
||||
/// same detection that the CLI tool runs and synthesizes the matrix
|
||||
/// decision. The Settings UI calls this on Graphics-tab mount.
|
||||
#[tauri::command]
|
||||
pub fn v2_get_graphics_recommendation() -> GraphicsRecommendationPayload {
|
||||
let environment = detect_environment();
|
||||
let recommendation = compute_recommendation(&environment);
|
||||
GraphicsRecommendationPayload {
|
||||
environment,
|
||||
recommendation,
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the current recommendation to the persistence layer.
|
||||
/// `force_dmabuf` is derived from `disable_dmabuf` per the 1.2.13
|
||||
/// opt-in semantics (see `write_recommendation` in autoconfig_graphics).
|
||||
/// Returns the list of per-field errors so the UI can surface them.
|
||||
/// Empty `Ok(Vec)` means "everything written, restart required".
|
||||
#[tauri::command]
|
||||
pub fn v2_apply_graphics_recommendation() -> Result<Vec<String>, Vec<String>> {
|
||||
let environment = detect_environment();
|
||||
let recommendation = compute_recommendation(&environment);
|
||||
match write_recommendation(&recommendation) {
|
||||
Ok(()) => Ok(Vec::new()),
|
||||
Err(errors) => Err(errors),
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,9 @@ pub struct V2PlaylistSuggestionsInput {
|
||||
pub(crate) mod helpers;
|
||||
pub use helpers::*;
|
||||
|
||||
mod graphics_recommendation;
|
||||
pub use graphics_recommendation::*;
|
||||
|
||||
mod runtime;
|
||||
pub use runtime::*;
|
||||
|
||||
|
||||
@@ -1656,6 +1656,8 @@ pub fn run(qconnect_cli_override: Option<bool>) {
|
||||
commands_v2::v2_set_gdk_scale,
|
||||
commands_v2::v2_set_gdk_dpi_scale,
|
||||
commands_v2::v2_set_gsk_renderer,
|
||||
commands_v2::v2_get_graphics_recommendation,
|
||||
commands_v2::v2_apply_graphics_recommendation,
|
||||
commands_v2::v2_clear_cache,
|
||||
commands_v2::v2_clear_artist_cache,
|
||||
commands_v2::v2_get_vector_store_stats,
|
||||
|
||||
@@ -389,6 +389,34 @@
|
||||
let gdkScale = $state('');
|
||||
let gdkDpiScale = $state('');
|
||||
let gskRenderer = $state('');
|
||||
|
||||
// Graphics recommendation surfaced in the Graphics tab. Populated on
|
||||
// mount via v2_get_graphics_recommendation (matrix lives in
|
||||
// autoconfig_graphics.rs). The banner fires only when at least one
|
||||
// recommended value differs from the currently persisted setting; the
|
||||
// "Apply" button writes the entire recommendation via
|
||||
// v2_apply_graphics_recommendation.
|
||||
type GraphicsRecommendation = {
|
||||
environment: {
|
||||
display_server: string;
|
||||
gpu_nvidia: boolean;
|
||||
gpu_amd: boolean;
|
||||
gpu_intel: boolean;
|
||||
gpu_name: string;
|
||||
desktop: string;
|
||||
is_vm: boolean;
|
||||
};
|
||||
recommendation: {
|
||||
hardware_acceleration: boolean;
|
||||
force_x11: boolean;
|
||||
gsk_renderer: string | null;
|
||||
disable_dmabuf: boolean;
|
||||
disable_blur_background: boolean;
|
||||
rationale: string[];
|
||||
};
|
||||
};
|
||||
let graphicsRecommendation = $state<GraphicsRecommendation | null>(null);
|
||||
|
||||
// Graphics startup status (for showing degraded mode warning)
|
||||
let graphicsUsingFallback = $state(false);
|
||||
let graphicsIsWayland = $state(false);
|
||||
@@ -1809,6 +1837,17 @@
|
||||
graphicsHwAccelEnabled = status.hardware_accel_enabled;
|
||||
}).catch(() => {});
|
||||
|
||||
// Linux-only: recommendation banner in the Graphics tab
|
||||
if (platform === 'linux') {
|
||||
invoke<GraphicsRecommendation>('v2_get_graphics_recommendation')
|
||||
.then((payload) => {
|
||||
graphicsRecommendation = payload;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('[Settings] graphics recommendation unavailable:', err);
|
||||
});
|
||||
}
|
||||
|
||||
// Subscribe to offline state changes
|
||||
const unsubscribeOffline = subscribeOffline(() => {
|
||||
offlineStatus = getOfflineStatus();
|
||||
@@ -4064,6 +4103,53 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the auto-detected recommendation diverges from any of the
|
||||
// four persisted graphics settings. The DMA-BUF axis is inverted:
|
||||
// recommendation `disable_dmabuf=true` maps to `force_dmabuf=false`
|
||||
// (1.2.13 opt-in semantics), so the two booleans differ iff
|
||||
// `disable_dmabuf === force_dmabuf` (same value means mismatch given
|
||||
// the inversion).
|
||||
const recommendationDiffers = $derived.by(() => {
|
||||
if (!graphicsRecommendation) return false;
|
||||
const rec = graphicsRecommendation.recommendation;
|
||||
if (rec.hardware_acceleration !== hardwareAcceleration) return true;
|
||||
if (rec.force_x11 !== forceX11) return true;
|
||||
if (rec.disable_dmabuf === forceDmabuf) return true;
|
||||
if ((rec.gsk_renderer ?? '') !== gskRenderer) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
async function handleApplyGraphicsRecommendation() {
|
||||
try {
|
||||
const errors = await invoke<string[]>('v2_apply_graphics_recommendation');
|
||||
if (errors && errors.length > 0) {
|
||||
console.error('Failed to apply some graphics settings:', errors);
|
||||
showToast(errors.join('; '), 'error');
|
||||
return;
|
||||
}
|
||||
// Refresh local state from DB so the toggles snap to the new values
|
||||
const gs = await invoke<any>('v2_get_graphics_settings');
|
||||
forceX11 = gs.force_x11;
|
||||
gskRenderer = gs.gsk_renderer || '';
|
||||
hardwareAcceleration = gs.hardware_acceleration;
|
||||
const ds = await invoke<any>('v2_get_developer_settings');
|
||||
forceDmabuf = ds.force_dmabuf;
|
||||
showToast($t('settings.graphics.recommendation.applied'), 'success');
|
||||
} catch (err) {
|
||||
console.error('Failed to apply graphics recommendation:', err);
|
||||
showToast(String(err), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function buildEnvironmentSummary(env: GraphicsRecommendation['environment']): string {
|
||||
const parts: string[] = [];
|
||||
if (env.gpu_name) parts.push(env.gpu_name);
|
||||
if (env.display_server) parts.push(env.display_server);
|
||||
if (env.desktop && env.desktop !== 'Unknown') parts.push(env.desktop);
|
||||
if (env.is_vm) parts.push('VM');
|
||||
return parts.join(' / ');
|
||||
}
|
||||
|
||||
const GSK_RENDERER_KEYS = ['', 'gl', 'ngl', 'vulkan', 'cairo'] as const;
|
||||
|
||||
function getGskRendererOptions(): string[] {
|
||||
@@ -5217,6 +5303,29 @@
|
||||
<h3 class="section-title">{$t('settings.graphics.title')}</h3>
|
||||
<p class="section-note">{$t('settings.graphics.helpText')}</p>
|
||||
|
||||
{#if graphicsRecommendation && recommendationDiffers}
|
||||
<div class="recommendation-banner">
|
||||
<div class="recommendation-info">
|
||||
<span class="recommendation-title">{$t('settings.graphics.recommendation.title')}</span>
|
||||
<span class="recommendation-detected">
|
||||
{$t('settings.graphics.recommendation.detected')}: {buildEnvironmentSummary(graphicsRecommendation.environment)}
|
||||
</span>
|
||||
{#if graphicsRecommendation.recommendation.rationale.length > 0}
|
||||
<ul class="recommendation-rationale">
|
||||
{#each graphicsRecommendation.recommendation.rationale as line}
|
||||
<li>{line}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="recommendation-actions">
|
||||
<button class="primary-btn" onclick={handleApplyGraphicsRecommendation}>
|
||||
{$t('settings.graphics.recommendation.apply')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if graphicsUsingFallback}
|
||||
<div class="composition-warning fallback-warning">
|
||||
<TriangleAlert size={14} />
|
||||
@@ -7019,6 +7128,58 @@ flatpak override --user --filesystem=/home/USUARIO/Música com.blitzfc.qbz</pre>
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* Graphics recommendation banner. Shown at the top of the Graphics
|
||||
section when the autoconfig recommendation diverges from the
|
||||
persisted settings. Persistent (no dismiss) so the user knows the
|
||||
option is available; disappears the moment recommendation == state. */
|
||||
.recommendation-banner {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 8px;
|
||||
background: var(--accent-primary-tint, rgba(124, 58, 237, 0.08));
|
||||
border: 1px solid var(--accent-primary, rgba(124, 58, 237, 0.3));
|
||||
}
|
||||
|
||||
.recommendation-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.recommendation-title {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.recommendation-detected {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.recommendation-rationale {
|
||||
margin: 4px 0 0;
|
||||
padding-left: 18px;
|
||||
list-style: disc;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.recommendation-rationale li {
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
.recommendation-actions {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.fallback-desc {
|
||||
display: block;
|
||||
color: var(--text-secondary);
|
||||
|
||||
@@ -2821,6 +2821,12 @@
|
||||
"maxPerformanceLabel": "Maximale Leistung",
|
||||
"maxPerformanceDesc": "Software-Rendering (Cairo) mit deaktiviertem Blur. Maximale Kompatibilitaet, niedrigste GPU-Nutzung. Verwenden bei Ruckeln oder Abstuerzen.",
|
||||
"applied": "Profil angewendet: {profile}. QBZ neu starten, damit es wirksam wird."
|
||||
},
|
||||
"recommendation": {
|
||||
"title": "Empfohlen für dein System",
|
||||
"detected": "Erkannt",
|
||||
"apply": "Übernehmen",
|
||||
"applied": "Konfiguration übernommen. QBZ neu starten, damit es wirksam wird."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2827,6 +2827,12 @@
|
||||
"maxPerformanceLabel": "Max Performance",
|
||||
"maxPerformanceDesc": "Software rendering (Cairo) with blur disabled. Maximum compatibility, lowest GPU usage. Use if experiencing stutter or crashes.",
|
||||
"applied": "Applied profile: {profile}. Restart QBZ to take effect."
|
||||
},
|
||||
"recommendation": {
|
||||
"title": "Recommended for your system",
|
||||
"detected": "Detected",
|
||||
"apply": "Apply",
|
||||
"applied": "Configuration applied. Restart QBZ to take effect."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2827,6 +2827,12 @@
|
||||
"maxPerformanceLabel": "Rendimiento maximo",
|
||||
"maxPerformanceDesc": "Renderizado por software (Cairo) con blur desactivado. Maxima compatibilidad, menor uso de GPU. Usar si hay tartamudeo o crashes.",
|
||||
"applied": "Perfil aplicado: {profile}. Reinicia QBZ para que surta efecto."
|
||||
},
|
||||
"recommendation": {
|
||||
"title": "Recomendado para tu sistema",
|
||||
"detected": "Detectado",
|
||||
"apply": "Aplicar",
|
||||
"applied": "Configuracion aplicada. Reinicia QBZ para que surta efecto."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2821,6 +2821,12 @@
|
||||
"maxPerformanceLabel": "Performance maximale",
|
||||
"maxPerformanceDesc": "Rendu logiciel (Cairo) avec flou désactivé. Compatibilité maximale, utilisation GPU minimale. À utiliser en cas de saccades ou de plantages.",
|
||||
"applied": "Profil appliqué : {profile}. Redémarrez QBZ pour appliquer le changement."
|
||||
},
|
||||
"recommendation": {
|
||||
"title": "Recommandé pour votre système",
|
||||
"detected": "Détecté",
|
||||
"apply": "Appliquer",
|
||||
"applied": "Configuration appliquée. Redémarrez QBZ pour qu'elle prenne effet."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2821,6 +2821,12 @@
|
||||
"maxPerformanceLabel": "Desempenho Máximo",
|
||||
"maxPerformanceDesc": "Renderização por software (Cairo) com desfoque desativado. Máxima compatibilidade, menor uso de GPU. Use se tiver engasgos ou travamentos.",
|
||||
"applied": "Perfil aplicado: {profile}. Reinicie o QBZ para aplicar."
|
||||
},
|
||||
"recommendation": {
|
||||
"title": "Recomendado para o seu sistema",
|
||||
"detected": "Detectado",
|
||||
"apply": "Aplicar",
|
||||
"applied": "Configuracao aplicada. Reinicie o QBZ para que tenha efeito."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user