feat(android,ios): mark watched up to an episode, and undo an episode's tick

A long press on an episode row offers "Mark watched up to here", as a
right click on the desktop's tick does. It is for someone joining a show
partway. Ticking one episode now goes through the same path as a season,
so it gets the same Undo.
This commit is contained in:
nvrl committed 2026-10-13 15:48:59 +02:00
1 parent 5c15f45ace
commit 5c0519a226
4 files changed
+49 -39

No files matched your search

+2 -18
View File
@@ -737,25 +737,9 @@ final class AppModel {
/// Unwatching rewinds, matching the desktop client. Marking one seen puts
/// the position at its duration where one is known, so the progress bar
/// agrees with the tick.
/// One episode's tick, with the same Undo a season's has.
func setWatched(_ episode: EpisodeRecord, _ watched: Bool) {
showWatched([episode], watched)
Task {
do {
try await run { engine in
let duration = try engine.watchState(shareId: episode.shareId, linkId: episode.linkId)?.durationSecs
try engine.saveWatchState(
shareId: episode.shareId,
linkId: episode.linkId,
positionSecs: watched ? duration ?? 0 : 0,
durationSecs: duration,
watched: watched
)
}
} catch {
reportError(error)
}
reload()
}
markEpisodes([episode], watched, episode.label)
}
/// Draw a watched mark the moment it is tapped, before the bridge has
+14 -2
View File
@@ -72,7 +72,11 @@ struct TitleView: View {
position: position,
download: downloads.first { $0.shareId == episode.shareId && $0.linkId == episode.linkId },
onPlay: { onPlay(playlist, playlist.firstIndex { $0.linkId == episode.linkId } ?? 0) },
onSetWatched: { model.setWatched(episode, $0) }
onSetWatched: { model.setWatched(episode, $0) },
onWatchedUpTo: {
let upTo = playlist.firstIndex { $0.linkId == episode.linkId } ?? 0
model.markEpisodes(Array(playlist.prefix(upTo + 1)), true, "\(title.displayName) up to \(episode.label)")
}
)
.padding(.horizontal, side)
}
@@ -393,7 +397,11 @@ private struct EpisodeRow: View {
let download: RetainedDownload?
let onPlay: () -> Void
let onSetWatched: (Bool) -> Void
/// Everything up to and including this one, for someone joining a show
/// partway.
let onWatchedUpTo: () -> Void
@Environment(\.scheme) private var scheme
@State private var holding = false
private var subline: String {
let size: String? = episode.size.map { formatBytes($0) }
@@ -460,7 +468,11 @@ private struct EpisodeRow: View {
.padding(.horizontal, 16)
.padding(.vertical, 6)
.contentShape(Rectangle())
.tapAndHold(onPlay)
.tapAndHold(onPlay) { holding = true }
.confirmationDialog(episode.heading(position), isPresented: $holding) {
Button("Mark watched up to here", action: onWatchedUpTo)
}
.accessibilityAction(named: "Mark watched up to here", onWatchedUpTo)
}
}