From 0e6b2194557980dc1d14a16f0f277213514a7e25 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Fri, 20 Mar 2026 08:55:35 +0100 Subject: [PATCH] feat(merge-split): numbered selection instead of checkboxes, user-defined merge order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace checkboxes with numbered selectors (1, 2, 3...) that show the merge order. Click order determines VOD sequence in the merged result. Chronological auto-sort removed — user controls the order. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/main.ts | 6 ++++-- src/renderer-queue.ts | 26 ++++++++++++++------------ src/renderer-shared.ts | 2 +- src/styles.css | 27 ++++++++++++++++++++++----- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/main.ts b/src/main.ts index b0c8294..ad06099 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3870,8 +3870,10 @@ ipcMain.handle('create-merge-group', (_, itemIds: string[]) => { return downloadQueue; } - // Sort chronologically by ISO timestamp (handles same-day different times) - const sorted = [...selectedItems].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); + // Preserve user-defined order from renderer (itemIds array order) + const sorted = itemIds + .map(id => selectedItems.find(item => item.id === id)) + .filter((item): item is QueueItem => item !== undefined); // Calculate total duration const totalDurationSec = sorted.reduce((sum, item) => sum + parseDuration(item.duration_str), 0); diff --git a/src/renderer-queue.ts b/src/renderer-queue.ts index a39cda6..01e9b76 100644 --- a/src/renderer-queue.ts +++ b/src/renderer-queue.ts @@ -140,10 +140,11 @@ function getQueueMetaText(item: QueueItem): string { } function toggleQueueSelection(id: string): void { - if (selectedQueueIds.has(id)) { - selectedQueueIds.delete(id); + const index = selectedQueueIds.indexOf(id); + if (index >= 0) { + selectedQueueIds.splice(index, 1); } else { - selectedQueueIds.add(id); + selectedQueueIds.push(id); } renderQueue(); updateMergeGroupButton(); @@ -157,11 +158,11 @@ function updateMergeGroupButton(): void { const validIds = new Set( queue.filter(item => item.status === 'pending' && !item.mergeGroup).map(item => item.id) ); - selectedQueueIds = new Set([...selectedQueueIds].filter(id => validIds.has(id))); + selectedQueueIds = selectedQueueIds.filter(id => validIds.has(id)); - if (selectedQueueIds.size >= 2) { + if (selectedQueueIds.length >= 2) { btn.style.display = ''; - btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.size})`; + btn.textContent = `${UI_TEXT.mergeGroup.btn} (${selectedQueueIds.length})`; btn.disabled = false; } else { btn.style.display = 'none'; @@ -169,10 +170,10 @@ function updateMergeGroupButton(): void { } async function createMergeGroupFromSelection(): Promise { - if (selectedQueueIds.size < 2) return; + if (selectedQueueIds.length < 2) return; const ids = [...selectedQueueIds]; - selectedQueueIds.clear(); + selectedQueueIds = []; queue = await window.api.createMergeGroup(ids); renderQueue(); updateMergeGroupButton(); @@ -213,8 +214,9 @@ function renderQueue(): void { const progressClass = item.status === 'downloading' && !hasDeterminateProgress ? ' indeterminate' : ''; const isMergeGroup = !!item.mergeGroup; - const showCheckbox = item.status === 'pending' && !isMergeGroup; - const isChecked = selectedQueueIds.has(item.id); + const showSelector = item.status === 'pending' && !isMergeGroup; + const selectionIndex = selectedQueueIds.indexOf(item.id); + const isSelected = selectionIndex >= 0; const mergeIcon = isMergeGroup ? ' ' : ''; @@ -224,8 +226,8 @@ function renderQueue(): void { return `
- ${showCheckbox - ? `` + ${showSelector + ? `
${isSelected ? selectionIndex + 1 : ''}
` : '' }
diff --git a/src/renderer-shared.ts b/src/renderer-shared.ts index a83f87a..8187d3c 100644 --- a/src/renderer-shared.ts +++ b/src/renderer-shared.ts @@ -24,7 +24,7 @@ let currentStreamer: string | null = null; let isConnected = false; let downloading = false; let queue: QueueItem[] = []; -let selectedQueueIds: Set = new Set(); +let selectedQueueIds: string[] = []; let cutterFile: string | null = null; let cutterVideoInfo: VideoInfo | null = null; diff --git a/src/styles.css b/src/styles.css index b5de05a..bfec844 100644 --- a/src/styles.css +++ b/src/styles.css @@ -329,13 +329,30 @@ body { opacity: 1; } -.queue-checkbox { - width: 14px; - height: 14px; - margin-top: 2px; +.queue-selector { + width: 22px; + height: 22px; + border: 2px solid var(--text-secondary); + border-radius: 4px; cursor: pointer; - accent-color: var(--accent); flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + font-weight: 700; + color: var(--bg-primary); + user-select: none; + transition: all 0.15s; +} + +.queue-selector.selected { + background: var(--accent); + border-color: var(--accent); +} + +.queue-selector:hover { + border-color: var(--accent); } .queue-item.merge-group {