feat: Minimiert starten + kein Fenster-Popup bei .cloud Oeffnung

- .cloud Doppelklick oeffnet Datei im Hintergrund ohne das Client-
  Fenster aufzupoppen (war nervig)
- Neue Einstellung "Minimiert starten (direkt im System-Tray)"
  als Checkbox im Einstellungen-Bereich
- Wird in config.json gespeichert, bleibt bei Updates erhalten
- Bei aktiviertem Haken: Client startet unsichtbar im Tray,
  Sync laeuft im Hintergrund, Fenster nur per Tray-Doppelklick

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-12 01:50:09 +02:00
parent e9638cc6ed
commit 86545ca405
3 changed files with 43 additions and 5 deletions

View File

@ -104,6 +104,19 @@ async fn auto_login(state: State<'_, AppState>) -> Result<serde_json::Value, Str
})) }))
} }
#[tauri::command]
fn set_start_minimized(minimized: bool) -> Result<String, String> {
let mut config = AppConfig::load();
config.start_minimized = minimized;
config.save()?;
Ok(format!("Minimiert starten: {}", minimized))
}
#[tauri::command]
fn get_start_minimized() -> bool {
AppConfig::load().start_minimized
}
// --- Sync Paths --- // --- Sync Paths ---
#[tauri::command] #[tauri::command]
@ -741,11 +754,7 @@ pub fn run() {
let path = path.trim().to_string(); let path = path.trim().to_string();
if !path.is_empty() { if !path.is_empty() {
let _ = app_req.emit("open-cloud-file", path); let _ = app_req.emit("open-cloud-file", path);
// Show the window // Don't show window - user opens it via tray when needed
if let Some(w) = app_req.get_webview_window("main") {
let _ = w.show();
let _ = w.set_focus();
}
} }
} }
std::fs::remove_file(&request_file).ok(); std::fs::remove_file(&request_file).ok();
@ -753,6 +762,14 @@ pub fn run() {
} }
}); });
// Start minimized if configured
let config = AppConfig::load();
if config.start_minimized {
if let Some(w) = app.get_webview_window("main") {
let _ = w.hide();
}
}
// Handle .cloud file opened via file association (double-click) // Handle .cloud file opened via file association (double-click)
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
if args.len() > 1 { if args.len() > 1 {
@ -803,6 +820,8 @@ pub fn run() {
load_saved_config, load_saved_config,
auto_login, auto_login,
login, login,
set_start_minimized,
get_start_minimized,
add_sync_path, add_sync_path,
remove_sync_path, remove_sync_path,
get_sync_paths, get_sync_paths,

View File

@ -11,6 +11,8 @@ pub struct AppConfig {
pub sync_paths: Vec<SyncPath>, pub sync_paths: Vec<SyncPath>,
#[serde(default)] #[serde(default)]
pub auto_start: bool, pub auto_start: bool,
#[serde(default)]
pub start_minimized: bool,
} }
impl AppConfig { impl AppConfig {

View File

@ -19,6 +19,11 @@ const userInfo = ref(null);
const fileTree = ref([]); const fileTree = ref([]);
const fileChanges = ref([]); const fileChanges = ref([]);
const autoSyncActive = ref(false); const autoSyncActive = ref(false);
const startMinimized = ref(false);
async function saveStartMinimized() {
await invoke("set_start_minimized", { minimized: startMinimized.value });
}
// New sync path form // New sync path form
const showAddPath = ref(false); const showAddPath = ref(false);
@ -114,6 +119,7 @@ async function handleLogin() {
userInfo.value = result; userInfo.value = result;
screen.value = "main"; screen.value = "main";
syncStatus.value = `Verbunden als ${result.username}`; syncStatus.value = `Verbunden als ${result.username}`;
startMinimized.value = await invoke("get_start_minimized");
await loadFileTree(); await loadFileTree();
await loadSyncPaths(); await loadSyncPaths();
} catch (err) { } catch (err) {
@ -236,6 +242,7 @@ onMounted(async () => {
screen.value = "main"; screen.value = "main";
syncStatus.value = `Verbunden als ${result.username}`; syncStatus.value = `Verbunden als ${result.username}`;
syncPaths.value = (await invoke("get_sync_paths")); syncPaths.value = (await invoke("get_sync_paths"));
startMinimized.value = await invoke("get_start_minimized");
await loadFileTree(); await loadFileTree();
// Auto-start sync if paths configured // Auto-start sync if paths configured
if (syncPaths.value.length > 0) { if (syncPaths.value.length > 0) {
@ -461,6 +468,15 @@ onUnmounted(() => { unlistenStatus?.(); unlistenLog?.(); unlistenError?.(); unli
<h3>Sync-Protokoll</h3> <h3>Sync-Protokoll</h3>
<div class="log-list"><div v-for="(m,i) in syncLog" :key="i" class="log-item">{{ m }}</div></div> <div class="log-list"><div v-for="(m,i) in syncLog" :key="i" class="log-item">{{ m }}</div></div>
</div> </div>
<!-- Settings -->
<div class="section">
<h3>Einstellungen</h3>
<label class="checkbox-row">
<input type="checkbox" v-model="startMinimized" @change="saveStartMinimized" />
Minimiert starten (direkt im System-Tray)
</label>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -531,6 +547,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;f
.lf-badge.cloud{background:#e3f2fd;color:#1565c0} .lf-badge.cloud{background:#e3f2fd;color:#1565c0}
.lf-badge.offline{background:#e8f5e9;color:#2e7d32} .lf-badge.offline{background:#e8f5e9;color:#2e7d32}
.lf-size{font-size:.75rem;color:#999;flex-shrink:0} .lf-size{font-size:.75rem;color:#999;flex-shrink:0}
.checkbox-row{display:flex;align-items:center;gap:.5rem;font-size:.85rem;cursor:pointer}
.context-menu{position:fixed;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);z-index:9999;min-width:200px;padding:.25rem 0} .context-menu{position:fixed;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);z-index:9999;min-width:200px;padding:.25rem 0}
.cm-item{padding:.5rem .75rem;cursor:pointer;font-size:.85rem} .cm-item{padding:.5rem .75rem;cursor:pointer;font-size:.85rem}
.cm-item:hover{background:#f0f0f0} .cm-item:hover{background:#f0f0f0}