From b7b1789380ec30fb7288172d83722ccdd280588d Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Feb 2026 15:41:38 +0200 Subject: [PATCH] feat: auto-backup UI and window close hook --- src/App.vue | 17 ++++++++++ src/views/Settings.vue | 76 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/App.vue b/src/App.vue index f1e7436..d9c66e9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -188,6 +188,23 @@ onMounted(async () => { registerShortcuts() + // Auto-backup on window close + try { + const { getCurrentWindow } = await import('@tauri-apps/api/window') + const win = getCurrentWindow() + win.onCloseRequested(async () => { + if (settingsStore.settings.auto_backup === 'true' && settingsStore.settings.backup_path) { + try { + await invoke('auto_backup', { backupDir: settingsStore.settings.backup_path }) + } catch (e) { + console.error('Auto-backup failed:', e) + } + } + }) + } catch (e) { + console.error('Failed to register close handler:', e) + } + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { if (settingsStore.settings.theme_mode === 'system') applyTheme() }) diff --git a/src/views/Settings.vue b/src/views/Settings.vue index 19e103e..76bcc00 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -1198,6 +1198,45 @@ + +
+
+

Last exported

+

{{ lastExportedFormatted }}

+
+
+ +
+ + +
+
+

Auto-backup on close

+

Save a backup when the app closes

+
+ +
+ + +
+
+

Backup directory

+

{{ backupPath || 'Not set' }}

+
+ +
+ +
+

Import Data

@@ -1685,6 +1724,34 @@ watch(showClearDataDialog, (val) => { } }) +// Auto-backup state +const autoBackupEnabled = ref(false) +const backupPath = ref('') +const lastExported = ref('') + +const lastExportedFormatted = computed(() => { + if (!lastExported.value) return '' + return new Date(lastExported.value).toLocaleString() +}) + +async function toggleAutoBackup() { + autoBackupEnabled.value = !autoBackupEnabled.value + await settingsStore.updateSetting('auto_backup', autoBackupEnabled.value ? 'true' : 'false') +} + +async function chooseBackupPath() { + try { + const { open } = await import('@tauri-apps/plugin-dialog') + const selected = await open({ directory: true, title: 'Choose backup directory' }) + if (selected && typeof selected === 'string') { + backupPath.value = selected + await settingsStore.updateSetting('backup_path', selected) + } + } catch { + // User cancelled + } +} + // Import state const importFormat = ref('toggl') const importFileContent = ref('') @@ -2103,6 +2170,10 @@ async function exportData() { a.download = `zeroclock-export-${new Date().toISOString().split('T')[0]}.json` a.click() URL.revokeObjectURL(url) + + const now = new Date().toISOString() + await settingsStore.updateSetting('last_exported', now) + lastExported.value = now } catch (error) { console.error('Failed to export data:', error) toastStore.error('Failed to export data') @@ -2158,6 +2229,11 @@ onMounted(async () => { // Notification settings persistentNotifications.value = settingsStore.settings.persistent_notifications === 'true' + // Auto-backup settings + autoBackupEnabled.value = settingsStore.settings.auto_backup === 'true' + backupPath.value = settingsStore.settings.backup_path || '' + lastExported.value = settingsStore.settings.last_exported || '' + // Sound settings soundEnabled.value = settingsStore.settings.sound_enabled === 'true' soundMode.value = settingsStore.settings.sound_mode || 'synthesized'