From 26ece693fc2198dbafb18559154f1b0b53400057 Mon Sep 17 00:00:00 2001 From: Darrell van Swinderen Date: Wed, 23 Sep 2026 10:02:58 +0200 Subject: [PATCH] fix(storage): watching a clip from Storage Saver is not a view Opening a clip records it as opened, and "never opened" is exactly what Storage Saver lists, so looking at a clip there took it off the list the moment it was watched: it could not be deleted from the screen that exists to delete it. `useClipDetail().open` takes `countAsOpen`, and Storage Saver's tiles pass false. The flag is held for as long as the panel is open, so stepping to the next clip inside it does not start counting, and it is put back on close. Every other way of opening a clip counts exactly as before. Driven against a seeded library: a clip opened from Storage Saver stays at openCount 0 and stays on the list; the same clip opened from the library goes to 1. `npm run check` 849. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../components/ClipDetail/ClipDetailModal.vue | 11 +++++++---- .../src/components/Storage/StorageClipTile.vue | 2 +- .../src/composables/clips/useClipDetail.ts | 18 +++++++++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/ClipDetail/ClipDetailModal.vue b/src/renderer/src/components/ClipDetail/ClipDetailModal.vue index a87abdb1..15518021 100644 --- a/src/renderer/src/components/ClipDetail/ClipDetailModal.vue +++ b/src/renderer/src/components/ClipDetail/ClipDetailModal.vue @@ -58,7 +58,7 @@ import { useClipNeighbours } from '@renderer/composables/clips/useClipNeighbours * with the video, which gave real weight to the one thing nobody opens a clip * to find out. Still there, and now they read as a footnote. */ -const { openClipId, view, close, show, back, open } = useClipDetail(); +const { openClipId, view, close, show, back, open, countsAsOpen } = useClipDetail(); const toastStore = useToastStore(); const collectionsStore = useCollectionsStore(); @@ -112,9 +112,12 @@ watch( * Here rather than anywhere finer grained: this watcher fires once per * open, where a Range request fires several times a second. */ - void recordClipOpened(id).catch((error) => { - console.debug('Could not record that this clip was opened:', error); - }); + // Not when Storage Saver opened it: see `countsAsOpen`. + if (countsAsOpen.value) { + void recordClipOpened(id).catch((error) => { + console.debug('Could not record that this clip was opened:', error); + }); + } // A clip opened after another should not inherit the last one's expanded // date or a half-open sheet. diff --git a/src/renderer/src/components/Storage/StorageClipTile.vue b/src/renderer/src/components/Storage/StorageClipTile.vue index 00cee319..a3188c75 100644 --- a/src/renderer/src/components/Storage/StorageClipTile.vue +++ b/src/renderer/src/components/Storage/StorageClipTile.vue @@ -134,7 +134,7 @@ const frame = computed(() => [ type="button" :class="['group/pic relative block w-full aspect-21/9 bg-video-bed cursor-pointer', FOCUS_RING]" :aria-label="`Watch ${title}`" - @click="openClip(clip.id)" + @click="openClip(clip.id, 'details', { countAsOpen: false })" @mousemove="preview" @mouseleave="stopPreview" > diff --git a/src/renderer/src/composables/clips/useClipDetail.ts b/src/renderer/src/composables/clips/useClipDetail.ts index 992aa267..ec1489e4 100644 --- a/src/renderer/src/composables/clips/useClipDetail.ts +++ b/src/renderer/src/composables/clips/useClipDetail.ts @@ -42,14 +42,29 @@ const view = ref('details'); */ const cameFrom = ref<'library' | 'details'>('details'); +/** + * Whether this opening counts as somebody watching the clip. + * + * False only when Storage Saver opens it. That screen lists the clips nobody + * ever opened, and a look is how somebody there decides whether to delete + * one, so counting it would take the clip off the list the moment it was + * watched: it could never be deleted from the screen that exists to delete + * it. Held for as long as the layer is open, so stepping to the next clip + * inside it does not start counting, and put back on close. + */ +const countsAsOpen = ref(true); + export function useClipDetail() { return { openClipId, view, cameFrom, + countsAsOpen, + /** Open the layer from nothing, on whichever panel was asked for. */ - open: (id: number, as: ClipView = 'details') => { + open: (id: number, as: ClipView = 'details', options: { countAsOpen?: boolean } = {}) => { + countsAsOpen.value = options.countAsOpen ?? true; openClipId.value = id; view.value = as; cameFrom.value = 'library'; @@ -81,6 +96,7 @@ export function useClipDetail() { * to reset. */ close: () => { + countsAsOpen.value = true; openClipId.value = null; }, };