From 784248f9842ab9beb9a9c74c26163f8c003b3165 Mon Sep 17 00:00:00 2001 From: Yuri Karamian Date: Thu, 11 Jun 2026 15:50:18 +0200 Subject: [PATCH] Tasks: per-vault persistence for the Flagged filter, Hide done, and sort mode (issue #94) --- src-tauri/src/types.rs | 9 +++++++++ src/lib/components/AppLayout.svelte | 14 +++++++++++++- src/lib/components/TasksView.svelte | 22 +++++++++++----------- src/lib/stores/app.ts | 3 +++ src/lib/types.ts | 3 +++ 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index 6fd7d69..b0860bb 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -270,6 +270,12 @@ pub struct VaultState { pub last_tag: Option, #[serde(default)] pub tasks_layout: String, + #[serde(default = "default_true")] + pub tasks_hide_completed: bool, + #[serde(default)] + pub tasks_only_flagged: bool, + #[serde(default)] + pub tasks_sort: String, } impl Default for VaultState { @@ -287,6 +293,9 @@ impl Default for VaultState { last_notebook: None, last_tag: None, tasks_layout: String::new(), + tasks_hide_completed: true, + tasks_only_flagged: false, + tasks_sort: String::new(), } } } diff --git a/src/lib/components/AppLayout.svelte b/src/lib/components/AppLayout.svelte index 6f34080..0008790 100644 --- a/src/lib/components/AppLayout.svelte +++ b/src/lib/components/AppLayout.svelte @@ -38,6 +38,9 @@ viewMode, sortMode, tasksLayout, + tasksHideCompleted, + tasksOnlyFlagged, + tasksSort, activeTag, updateAvailable as globalUpdateAvailable, settingsTab, @@ -202,7 +205,10 @@ last_view_mode: $viewMode, last_notebook: $activeNotebook?.relative_path ?? null, last_tag: $activeTag, - tasks_layout: $tasksLayout + tasks_layout: $tasksLayout, + tasks_hide_completed: $tasksHideCompleted, + tasks_only_flagged: $tasksOnlyFlagged, + tasks_sort: $tasksSort }; try { await saveVaultState(state); @@ -504,6 +510,9 @@ $effect(() => { $sortMode; $tasksLayout; + $tasksHideCompleted; + $tasksOnlyFlagged; + $tasksSort; persistState(); }); @@ -529,6 +538,9 @@ $notebookOrder = state.notebook_order ?? {}; if (state.sort_mode === 'created' || state.sort_mode === 'title' || state.sort_mode === 'modified') $sortMode = state.sort_mode; if (state.tasks_layout === 'calendar' || state.tasks_layout === 'list') $tasksLayout = state.tasks_layout; + if (typeof state.tasks_hide_completed === 'boolean') $tasksHideCompleted = state.tasks_hide_completed; + if (typeof state.tasks_only_flagged === 'boolean') $tasksOnlyFlagged = state.tasks_only_flagged; + if (state.tasks_sort === 'due' || state.tasks_sort === 'priority' || state.tasks_sort === 'note') $tasksSort = state.tasks_sort; lastNotePath = state.last_open_note ?? null; lastViewMode = state.last_view_mode ?? ''; lastNotebook = state.last_notebook ?? null; diff --git a/src/lib/components/TasksView.svelte b/src/lib/components/TasksView.svelte index 620b537..109535b 100644 --- a/src/lib/components/TasksView.svelte +++ b/src/lib/components/TasksView.svelte @@ -3,7 +3,7 @@ import { listen } from '@tauri-apps/api/event'; import { getTasks } from '$lib/api'; import { debounce } from '$lib/utils/debounce'; - import { tasksLayout, appConfig } from '$lib/stores/app'; + import { tasksLayout, tasksHideCompleted, tasksOnlyFlagged, tasksSort, appConfig } from '$lib/stores/app'; import { isAndroid } from '$lib/platform'; import type { TaskItem, FileEvent } from '$lib/types'; @@ -16,8 +16,6 @@ let tasks = $state([]); let loading = $state(true); - let hideCompleted = $state(true); - let sortBy = $state<'due' | 'priority' | 'note'>('due'); let unlisten: (() => void) | null = null; async function load() { @@ -46,13 +44,14 @@ const filtered = $derived.by(() => { let list = tasks.slice(); - if (hideCompleted) list = list.filter((t) => !t.completed); + if ($tasksHideCompleted) list = list.filter((t) => !t.completed); + if ($tasksOnlyFlagged) list = list.filter((t) => !!t.due || !!t.priority); list.sort((a, b) => { if (a.completed !== b.completed) return a.completed ? 1 : -1; // done last - if (sortBy === 'priority') { + if ($tasksSort === 'priority') { const d = prank(a.priority) - prank(b.priority); if (d) return d; - } else if (sortBy === 'note') { + } else if ($tasksSort === 'note') { const d = a.note_title.localeCompare(b.note_title); if (d) return d; } else { @@ -110,7 +109,7 @@ const calDayNames = $derived([...DOW.slice(weekStartsOn), ...DOW.slice(0, weekStartsOn)]); // Calendar tasks share the list's hide-completed filter (no sort). - const calBase = $derived(tasks.filter((t) => !hideCompleted || !t.completed)); + const calBase = $derived(tasks.filter((t) => (!$tasksHideCompleted || !t.completed) && (!$tasksOnlyFlagged || !!t.due || !!t.priority))); const tasksByDate = $derived.by(() => { const m = new Map(); @@ -186,7 +185,8 @@ {/if}
- + + {#if !isAndroid}
@@ -196,7 +196,7 @@ {#if viewLayout === 'list'}
{#each [['due', 'Due'], ['priority', 'Priority'], ['note', 'Note']] as [v, label]} - + {/each}
{/if} @@ -458,7 +458,7 @@ background: transparent; color: var(--text-tertiary); border: 1px dashed var(--border-color); - opacity: 0; + opacity: 0.4; transition: opacity 0.1s; } .task-row:hover .task-prio.prio-none { opacity: 1; } @@ -529,7 +529,7 @@ background: transparent; border-style: dashed; color: var(--text-tertiary); - opacity: 0; + opacity: 0.4; transition: opacity 0.1s; } .task-row:hover .task-due:not(.set) { opacity: 1; } diff --git a/src/lib/stores/app.ts b/src/lib/stores/app.ts index 373c50f..fa6437e 100644 --- a/src/lib/stores/app.ts +++ b/src/lib/stores/app.ts @@ -17,6 +17,9 @@ export const vaultReady = writable(false); export const viewMode = writable("all"); export const sortMode = writable("modified"); export const tasksLayout = writable<"list" | "calendar">("list"); +export const tasksHideCompleted = writable(true); +export const tasksOnlyFlagged = writable(false); +export const tasksSort = writable<"due" | "priority" | "note">("due"); export const sidebarCollapsed = writable(false); export const sidebarWidth = writable(220); export const notelistWidth = writable(280); diff --git a/src/lib/types.ts b/src/lib/types.ts index c6f0546..0e97547 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -111,6 +111,9 @@ export interface VaultState { last_notebook?: string | null; last_tag?: string | null; tasks_layout?: string; + tasks_hide_completed?: boolean; + tasks_only_flagged?: boolean; + tasks_sort?: string; } export interface SearchResult {