Fixes #29 — Delete downloaded video inline on the guide detail view
The middle button in the Stream/Download/Play row now cycles through the full download lifecycle instead of ending at a disabled "Downloaded" checkmark. Once a video is on disk the button becomes a red, destructive "Delete" with a trash icon; tapping presents a confirmation dialog, and confirming removes the file + SwiftData row, flipping the button back to "Download" and disabling Play. Settings → Downloaded Videos retains the swipe-delete and "Delete all" affordances for bulk management. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ struct VideoActionsButtonRow: View {
|
|||||||
@State private var isDownloaded: Bool
|
@State private var isDownloaded: Bool
|
||||||
@State private var playerVideoId: String?
|
@State private var playerVideoId: String?
|
||||||
@State private var downloadError: String?
|
@State private var downloadError: String?
|
||||||
|
@State private var confirmDelete: Bool = false
|
||||||
|
|
||||||
init(video: YouTubeVideoStore.VideoEntry) {
|
init(video: YouTubeVideoStore.VideoEntry) {
|
||||||
self.video = video
|
self.video = video
|
||||||
@@ -64,6 +65,19 @@ struct VideoActionsButtonRow: View {
|
|||||||
} message: {
|
} message: {
|
||||||
Text(downloadError ?? "")
|
Text(downloadError ?? "")
|
||||||
}
|
}
|
||||||
|
.confirmationDialog(
|
||||||
|
"Delete this downloaded video?",
|
||||||
|
isPresented: $confirmDelete,
|
||||||
|
titleVisibility: .visible
|
||||||
|
) {
|
||||||
|
Button("Delete", role: .destructive) {
|
||||||
|
downloadService.delete(videoId: video.videoId, modelContext: modelContext)
|
||||||
|
isDownloaded = false
|
||||||
|
}
|
||||||
|
Button("Cancel", role: .cancel) {}
|
||||||
|
} message: {
|
||||||
|
Text("You can re-download it at any time.")
|
||||||
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Refresh on appear in case the user deleted the file via Settings.
|
// Refresh on appear in case the user deleted the file via Settings.
|
||||||
isDownloaded = VideoDownloadService.isDownloaded(videoId: video.videoId)
|
isDownloaded = VideoDownloadService.isDownloaded(videoId: video.videoId)
|
||||||
@@ -88,29 +102,42 @@ struct VideoActionsButtonRow: View {
|
|||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var downloadButton: some View {
|
private var downloadButton: some View {
|
||||||
Button {
|
// Single slot whose role flips through the download lifecycle:
|
||||||
Task { await startDownload() }
|
// Download → progress (disabled) → Delete.
|
||||||
} label: {
|
if isDownloading, let progress = activeProgress {
|
||||||
Group {
|
Button {} label: {
|
||||||
if let progress = activeProgress {
|
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
ProgressView(value: progress)
|
ProgressView(value: progress).frame(width: 40)
|
||||||
.frame(width: 40)
|
|
||||||
Text("\(Int(progress * 100))%")
|
Text("\(Int(progress * 100))%")
|
||||||
.font(.caption.monospacedDigit())
|
.font(.caption.monospacedDigit())
|
||||||
}
|
}
|
||||||
} else if isDownloaded {
|
|
||||||
Label("Downloaded", systemImage: "checkmark.circle.fill")
|
|
||||||
} else {
|
|
||||||
Label("Download", systemImage: "arrow.down.to.line")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
.buttonStyle(.bordered)
|
.buttonStyle(.bordered)
|
||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.disabled(isDownloaded || isDownloading)
|
.disabled(true)
|
||||||
|
} else if isDownloaded {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
confirmDelete = true
|
||||||
|
} label: {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
.buttonStyle(.bordered)
|
||||||
|
.tint(.red)
|
||||||
|
.controlSize(.large)
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
Task { await startDownload() }
|
||||||
|
} label: {
|
||||||
|
Label("Download", systemImage: "arrow.down.to.line")
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
.buttonStyle(.bordered)
|
||||||
|
.tint(.blue)
|
||||||
|
.controlSize(.large)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var playButton: some View {
|
private var playButton: some View {
|
||||||
|
|||||||
Reference in New Issue
Block a user