Skip to content

Support a drop zone to open files - #3

Open
anavarre wants to merge 5 commits into
omacom:masterfrom
anavarre:drop-zone
Open

anavarre wants to merge 5 commits into
omacom:masterfrom
anavarre:drop-zone

Conversation

@anavarre

Copy link
Copy Markdown

In the spirit of Omarchy making things simple and opinionated with good default settings, here's a Grok-powered solution to have a drop zone in addition to being able to manually open a video.

omacut-drop-zone.mp4

@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds drag-and-drop video opening to the main preview while preserving the existing click-to-open workflow.

  • Wraps the preview content in a DropArea with visual drag feedback and modal/busy-state gating.
  • Passes the first dropped URL to the existing backend loader.
  • Adds a QML integration test covering drag entry, movement, drop acceptance, and backend invocation.

Confidence Score: 5/5

The PR appears safe to merge, with invalid or unsupported drops handled by the existing load-error path.

The new drop flow delegates to the established backend loader, preserves existing click behavior in normal states, and includes coverage for drag acceptance and backend invocation without introducing an established blocking failure.

Important Files Changed

Filename Overview
src/Main.qml Adds the drop target, visual feedback, interaction gating, and forwarding of the first dropped URL to the existing loader; no actionable defect was established.
tests/backend_tests.cpp Extends the backend stub and adds an integration test verifying URL drag-and-drop reaches the QML DropArea and invokes the loader once.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[User drags URLs over preview] --> B{DropArea enabled and URLs present?}
    B -- No --> C[Ignore drop]
    B -- Yes --> D[Accept copy action]
    D --> E[Take first dropped URL]
    E --> F[backend.load URL]
    F --> G{Valid local video?}
    G -- Yes --> H[Load video]
    G -- No --> I[Show load error notice]
Loading

Reviews (1): Last reviewed commit: "Support a drop zone to open files" | Re-trigger Greptile

omarchybot and others added 4 commits September 7, 2026 05:57
A drop can fail before anything is open — a directory, a file that is not a video, a URL that is not a file — but the status line only joined the layout once a video was loaded, so the error it carried never reached the screen and the notice timer cleared it five seconds later. Dropping something unloadable on the empty window looked exactly like dropping nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The drag source writes its own uri-list, and a web page can compose one with DataTransfer.setData, so every entry in it is a stranger's text. It went straight to load(), which hands QUrl::toLocalFile() to ffprobe as the input argument — and a file: URL with no absolute path keeps its path verbatim. "file:http://host/clip" arrives as a network URL, which ffprobe fetches; "file:-report" arrives as an option, which ffprobe acts on, writing a log beside the process. Neither is a file, so neither is opened now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
acceptProposedAction() answers the source with whatever the source proposed, and with Shift held a file manager proposes a move — which it completes by deleting the file it just handed over. Opening a video only reads it, so the answer is always a copy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
ffprobe quotes the path it could not open back in its error, and a dropped path is a stranger's text. Label defaults to AutoText and Qt::mightBeRichText matches tags anywhere in the string, so a path holding markup was parsed as markup: the characters in it were never drawn, and the message the user needed to read came out mangled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
@omarchybot

Copy link
Copy Markdown
Collaborator

Reviewed by Claude Opus 5 with an independent second opinion from Codex at xhigh reasoning. The drop zone works — a video dropped on the window loads, gets its filmstrip, and the click-to-open button, Ctrl+O, the portal picker and the omacut <file> argument all still behave as they did on master. Four defects on the new path have fixes pushed to drop-zone; each is a separate commit and each was proved by putting the old line back and watching its test fail.

Everything below was run on a disposable Omarchy VM with a real Hyprland session, never on the machine doing the review. ./bin/test goes from 28 to 32 passing. The suite needs a Qt platform plugin — it aborts under a bare ssh session and passes with QT_QPA_PLATFORM=offscreen — which is true of master too, so it is not something this PR introduced.

A crafted URL reached ffprobe as a network URL or as an option (Main.qml:51). Every entry of the drag's text/uri-list went to backend.load(), which hands QUrl::toLocalFile() to ffprobe as the input argument, and a file: URL with no absolute path keeps its path verbatim. Dropping file:http://127.0.0.1:8099/relative made ffprobe issue a real GET /relative against a listener on the worker, and the status line reported the server's 404 back. Dropping file:-report was parsed by ffprobe as its -report option and wrote ffprobe-20260907-124703.log into the working directory. A web page can put either string in a drag with DataTransfer.setData, so this is reachable without any local malware. df98d4b refuses anything that is not an absolute local path. A direct https:// drop was never the dangerous case — toLocalFile() empties it, so the remote URL itself never reached ffprobe — but it produced Cannot open video: : No such file or directory, which is nobody's idea of an error message.

The drop told the source the file had been moved (Main.qml:504). acceptProposedAction() answers with whatever action the source proposed, and with Shift held a file manager proposes a move — which it completes by deleting the file it just handed over. Confirmed by sending a drop whose proposed action was MoveAction and reading dropAction() back as MoveAction. omacut only reads the file, so df4a0b8 answers Qt.CopyAction always.

Failed drops were completely silent (Main.qml:599 on the old numbering). onLoadError sets the notice, but the status line only joined the layout once a video was loaded, so in the empty state — which is where the drop zone is most used — the text was set and never drawn. Measured on the worker: after dropping a text file, statusText held Cannot open video: /tmp/x.txt: Invalid data found when processing input while the label carrying it reported isVisible=0, and the screen was pixel-identical to the idle state. Five seconds later the timer cleared it. cdd948d puts the status line in the layout whenever there is something to say. Worth knowing: #5 makes the same one-line change to the same line for its own reasons, so the two agree rather than conflict, though you will want to decide which empty-state hint line survives if both land.

Markup in a path was rendered as markup (Main.qml:605 on the old numbering). ffprobe quotes the path back in its error and the status Label defaults to Text.AutoText; Qt::mightBeRichText matches tags anywhere in the string, not just at the start. A dropped path containing <b>b</b> came out with those characters silently dropped — the label measured exactly as wide as the same message without the tags. 81bd405 sets textFormat: Text.PlainText. I tried to make an <img src="http://…"> in a path fetch the URL and could not get Qt 6.11.2 to issue the request, so the exfiltration step is unproven; the mangled error message is not.

Two things left alone deliberately. Only urls[0] is used, so a multi-file drop opens the first and ignores the rest — reasonable for a single-video trimmer, and it is your call whether it deserves a notice. And with a video already loaded, the 3px accent border is painted by the Rectangle underneath its own VideoOutput child, so the drag highlight only survives in the letterbox margins; it was clearly visible in a 16:9-into-2:1 window on the worker, and would vanish entirely in a window matching the video's aspect ratio. Both are judgement calls rather than defects.

On the second opinion: Codex found the move-action, the relative-file:-URL and the AutoText problems, none of which the first pass had reasoned about, and independently reached the invisible-error conclusion the first pass had already written down — its independence there is not guaranteed, since a read-only sandbox still lets it read this session's transcript. Every one of its findings was verified against a running build before anything was pushed. It also reported that disabling the DropArea while backend.busy propagates to the child MouseArea, so clicking the preview during an export no longer opens the picker while Ctrl+O still does; that is real but it is a defensible choice, so it is left as the author wrote it.

Nothing here is merged or approved — that is the maintainer's call, and #5 overlapping this file is the thing worth deciding first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants