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
+308
-43
No files matched your search
@@ -3,30 +3,39 @@
|
|||||||
//! Detects the current GPU, display server, desktop environment, and compositor,
|
//! Detects the current GPU, display server, desktop environment, and compositor,
|
||||||
//! then recommends and applies optimal graphics settings.
|
//! 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 crate::config::graphics_settings::GraphicsSettingsStore;
|
||||||
|
use serde::Serialize;
|
||||||
use std::io::{self, BufRead, Write};
|
use std::io::{self, BufRead, Write};
|
||||||
|
|
||||||
/// Detected environment information
|
/// Detected environment information
|
||||||
struct Environment {
|
#[derive(Debug, Clone, Serialize)]
|
||||||
display_server: String,
|
#[serde(rename_all = "snake_case")]
|
||||||
gpu_nvidia: bool,
|
pub struct Environment {
|
||||||
gpu_amd: bool,
|
pub display_server: String,
|
||||||
gpu_intel: bool,
|
pub gpu_nvidia: bool,
|
||||||
gpu_name: String,
|
pub gpu_amd: bool,
|
||||||
desktop: String,
|
pub gpu_intel: bool,
|
||||||
is_vm: bool,
|
pub gpu_name: String,
|
||||||
|
pub desktop: String,
|
||||||
|
pub is_vm: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recommended configuration
|
/// Recommended configuration
|
||||||
struct Recommendation {
|
#[derive(Debug, Clone, Serialize)]
|
||||||
hardware_acceleration: bool,
|
#[serde(rename_all = "snake_case")]
|
||||||
force_x11: bool,
|
pub struct Recommendation {
|
||||||
gsk_renderer: Option<String>,
|
pub hardware_acceleration: bool,
|
||||||
disable_dmabuf: bool,
|
pub force_x11: bool,
|
||||||
disable_blur_background: bool,
|
pub gsk_renderer: Option<String>,
|
||||||
rationale: Vec<String>,
|
pub disable_dmabuf: bool,
|
||||||
|
pub disable_blur_background: bool,
|
||||||
|
pub rationale: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the autoconfig-graphics CLI tool.
|
/// 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 display_server = detect_display_server();
|
||||||
let gpu_nvidia = is_nvidia_gpu();
|
let gpu_nvidia = is_nvidia_gpu();
|
||||||
let gpu_amd = is_amd_gpu();
|
let gpu_amd = is_amd_gpu();
|
||||||
@@ -200,7 +209,7 @@ fn print_environment(env: &Environment) {
|
|||||||
eprintln!();
|
eprintln!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_recommendation(env: &Environment) -> Recommendation {
|
pub fn compute_recommendation(env: &Environment) -> Recommendation {
|
||||||
let mut rationale = Vec::new();
|
let mut rationale = Vec::new();
|
||||||
|
|
||||||
// VM: software rendering, no blur
|
// VM: software rendering, no blur
|
||||||
@@ -361,9 +370,40 @@ fn print_recommendation(rec: &Recommendation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn apply_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();
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
// Apply graphics settings to DB
|
|
||||||
match GraphicsSettingsStore::new() {
|
match GraphicsSettingsStore::new() {
|
||||||
Ok(store) => {
|
Ok(store) => {
|
||||||
if let Err(e) = store.set_hardware_acceleration(rec.hardware_acceleration) {
|
if let Err(e) = store.set_hardware_acceleration(rec.hardware_acceleration) {
|
||||||
@@ -381,14 +421,10 @@ fn apply_recommendation(rec: &Recommendation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply developer settings (force_dmabuf)
|
let desired_force_dmabuf = !rec.disable_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() {
|
match crate::config::developer_settings::DeveloperSettingsStore::new() {
|
||||||
Ok(store) => {
|
Ok(store) => {
|
||||||
if let Err(e) = store.set_force_dmabuf(false) {
|
if let Err(e) = store.set_force_dmabuf(desired_force_dmabuf) {
|
||||||
errors.push(format!("force_dmabuf: {}", e));
|
errors.push(format!("force_dmabuf: {}", e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,26 +432,10 @@ fn apply_recommendation(rec: &Recommendation) {
|
|||||||
errors.push(format!("developer settings store: {}", e));
|
errors.push(format!("developer settings store: {}", 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."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
eprintln!();
|
Ok(())
|
||||||
eprintln!("[QBZ AutoConfig] Configuration applied successfully.");
|
|
||||||
eprintln!("[QBZ AutoConfig] Restart QBZ to take effect.");
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!();
|
Err(errors)
|
||||||
eprintln!("[QBZ AutoConfig] Some settings could not be applied:");
|
|
||||||
for e in &errors {
|
|
||||||
eprintln!(" - {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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(crate) mod helpers;
|
||||||
pub use helpers::*;
|
pub use helpers::*;
|
||||||
|
|
||||||
|
mod graphics_recommendation;
|
||||||
|
pub use graphics_recommendation::*;
|
||||||
|
|
||||||
mod runtime;
|
mod runtime;
|
||||||
pub use 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_scale,
|
||||||
commands_v2::v2_set_gdk_dpi_scale,
|
commands_v2::v2_set_gdk_dpi_scale,
|
||||||
commands_v2::v2_set_gsk_renderer,
|
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_cache,
|
||||||
commands_v2::v2_clear_artist_cache,
|
commands_v2::v2_clear_artist_cache,
|
||||||
commands_v2::v2_get_vector_store_stats,
|
commands_v2::v2_get_vector_store_stats,
|
||||||
|
|||||||
@@ -389,6 +389,34 @@
|
|||||||
let gdkScale = $state('');
|
let gdkScale = $state('');
|
||||||
let gdkDpiScale = $state('');
|
let gdkDpiScale = $state('');
|
||||||
let gskRenderer = $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)
|
// Graphics startup status (for showing degraded mode warning)
|
||||||
let graphicsUsingFallback = $state(false);
|
let graphicsUsingFallback = $state(false);
|
||||||
let graphicsIsWayland = $state(false);
|
let graphicsIsWayland = $state(false);
|
||||||
@@ -1809,6 +1837,17 @@
|
|||||||
graphicsHwAccelEnabled = status.hardware_accel_enabled;
|
graphicsHwAccelEnabled = status.hardware_accel_enabled;
|
||||||
}).catch(() => {});
|
}).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
|
// Subscribe to offline state changes
|
||||||
const unsubscribeOffline = subscribeOffline(() => {
|
const unsubscribeOffline = subscribeOffline(() => {
|
||||||
offlineStatus = getOfflineStatus();
|
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;
|
const GSK_RENDERER_KEYS = ['', 'gl', 'ngl', 'vulkan', 'cairo'] as const;
|
||||||
|
|
||||||
function getGskRendererOptions(): string[] {
|
function getGskRendererOptions(): string[] {
|
||||||
@@ -5217,6 +5303,29 @@
|
|||||||
<h3 class="section-title">{$t('settings.graphics.title')}</h3>
|
<h3 class="section-title">{$t('settings.graphics.title')}</h3>
|
||||||
<p class="section-note">{$t('settings.graphics.helpText')}</p>
|
<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}
|
{#if graphicsUsingFallback}
|
||||||
<div class="composition-warning fallback-warning">
|
<div class="composition-warning fallback-warning">
|
||||||
<TriangleAlert size={14} />
|
<TriangleAlert size={14} />
|
||||||
@@ -7019,6 +7128,58 @@ flatpak override --user --filesystem=/home/USUARIO/Música com.blitzfc.qbz</pre>
|
|||||||
margin-bottom: 2px;
|
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 {
|
.fallback-desc {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
|||||||
@@ -2821,6 +2821,12 @@
|
|||||||
"maxPerformanceLabel": "Maximale Leistung",
|
"maxPerformanceLabel": "Maximale Leistung",
|
||||||
"maxPerformanceDesc": "Software-Rendering (Cairo) mit deaktiviertem Blur. Maximale Kompatibilitaet, niedrigste GPU-Nutzung. Verwenden bei Ruckeln oder Abstuerzen.",
|
"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."
|
"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",
|
"maxPerformanceLabel": "Max Performance",
|
||||||
"maxPerformanceDesc": "Software rendering (Cairo) with blur disabled. Maximum compatibility, lowest GPU usage. Use if experiencing stutter or crashes.",
|
"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."
|
"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",
|
"maxPerformanceLabel": "Rendimiento maximo",
|
||||||
"maxPerformanceDesc": "Renderizado por software (Cairo) con blur desactivado. Maxima compatibilidad, menor uso de GPU. Usar si hay tartamudeo o crashes.",
|
"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."
|
"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",
|
"maxPerformanceLabel": "Performance maximale",
|
||||||
"maxPerformanceDesc": "Rendu logiciel (Cairo) avec flou désactivé. Compatibilité maximale, utilisation GPU minimale. À utiliser en cas de saccades ou de plantages.",
|
"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."
|
"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",
|
"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.",
|
"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."
|
"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