Skip to content

feat: add download button for attached videos#5042

Merged
siddseethepalli merged 1 commit into
mainfrom
do/video-download-button
Feb 19, 2026
Merged

feat: add download button for attached videos#5042
siddseethepalli merged 1 commit into
mainfrom
do/video-download-button

Conversation

@siddseethepalli

@siddseethepalli siddseethepalli commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a save/download button (arrow.down.circle.fill) that appears on hover over video attachments
  • Opens NSSavePanel to let the user choose where to save the file
  • Handles both inline base64 and lazy-loaded attachments

🤖 Generated with Claude Code


Open with Devin

Co-Authored-By: Claude <noreply@anthropic.com>
@siddseethepalli siddseethepalli merged commit c45d51e into main Feb 19, 2026
@siddseethepalli siddseethepalli deleted the do/video-download-button branch February 19, 2026 08:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6db247ee90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +202 to +203
guard let data = Data(base64Encoded: attachment.data) else { return }
try? data.write(to: destURL)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid blocking UI while saving inline video data

In the non-lazy attachment path, both Data(base64Encoded:) and data.write(to:) run synchronously in the button action, which executes on the main thread. For larger inline videos, this can freeze the chat UI until decode+disk write finishes, making the app feel hung during save. Moving this branch to a background Task (as done for lazy-load saves) would prevent user-visible stalls.

Useful? React with 👍 / 👎.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review


if attachment.isLazyLoad {
guard let port = daemonHttpPort, let attachmentId = attachment.id.isEmpty ? nil : attachment.id else { return }
isLoading = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 saveVideo() sets isLoading=true which hides the active video player during save

When a user is watching a lazy-loaded video and clicks the save button, saveVideo() sets isLoading = true at line 187. Because the view body uses an if/else if chain (InlineVideoAttachmentView.swift:32-42), the isLoading branch takes priority over the player/isPlaying branch, causing the video player to be replaced by a "Loading video..." spinner while the save is in progress.

Root Cause and Impact

The isLoading state is shared between two different operations: initial video loading for playback and the save/download operation. When saveVideo() sets isLoading = true at line 187, the view body at lines 34-36 shows loadingView instead of the VideoPlayerView:

} else if isLoading {
    loadingView          // <-- replaces the video player
} else if let player, isPlaying {
    VideoPlayerView(player: player)  // <-- hidden during save

This means clicking "Save video" on an already-playing lazy-loaded video will:

  1. Hide the video player and show a loading spinner
  2. Re-fetch the attachment data from the server (even though it was already fetched for playback)
  3. After save completes, the video player reappears but the visual interruption is jarring

Impact: The video playback is visually disrupted every time the user saves a lazy-loaded video. The save operation should use a separate state (e.g. isSaving) or avoid setting isLoading altogether, since the save can happen in the background without affecting the UI.

Prompt for agents
In clients/macos/vellum-assistant/Features/Chat/MediaEmbeds/InlineVideoAttachmentView.swift, the saveVideo() function at line 187 sets isLoading = true, which causes the video player to be replaced by a loading spinner during the save operation. To fix this:

1. Add a new @State private var isSaving = false property (around line 22)
2. In saveVideo() (lines 187-199), replace all occurrences of isLoading with isSaving
3. Optionally show a subtle save progress indicator that doesn't replace the video player (e.g. overlay a small spinner on the save button area)
4. Update the save button visibility condition at line 44 to also check !isSaving if you want to hide the button during save

This ensures the save operation doesn't interfere with video playback state.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@siddseethepalli

Copy link
Copy Markdown
Contributor Author

Addressed in #5058

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.

1 participant