From 80ed81b0e4a4077ecb43a24106bc3e173e926478 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 13 Sep 2026 13:48:25 +0200 Subject: [PATCH] Let the playlist selector accept only one add per presentation The tapped row stays on screen for the half second the checkmark shows - and for a remote add, the whole round-trip - so quick repeated taps each started another add and the video landed in the playlist several times. One gate covers both paths; a failed remote add reopens it, since failing is the one way the sheet stays up to retry from. --- .../Views/Video/PlaylistSelectorSheet.swift | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Yattee/Views/Video/PlaylistSelectorSheet.swift b/Yattee/Views/Video/PlaylistSelectorSheet.swift index d0f1c91c..95415a13 100644 --- a/Yattee/Views/Video/PlaylistSelectorSheet.swift +++ b/Yattee/Views/Video/PlaylistSelectorSheet.swift @@ -295,8 +295,21 @@ struct PlaylistSelectorSheet: View { playlists = dataManager?.playlists() ?? [] } + /// Whether a tap on a playlist may still start an add. + /// + /// One add per presentation: after a tap lands, the sheet is only showing + /// its checkmark until the auto-dismiss — the same row is still on screen + /// and still tappable, so without this a quick double-tap put the video in + /// twice. A remote add holds the gate for the whole round-trip; only a + /// failure reopens it, since failing is the one way the sheet stays up. + private var canStartAdd: Bool { + !remoteAddInFlight && addedToPlaylist == nil && addedRemotePlaylist == nil + } + + @State private var remoteAddInFlight = false + private func addVideoToPlaylist(_ playlist: LocalPlaylist) { - guard let dataManager else { return } + guard let dataManager, canStartAdd else { return } dataManager.addToPlaylist(video, playlist: playlist) addedToPlaylist = playlist @@ -334,7 +347,8 @@ struct PlaylistSelectorSheet: View { } private func addVideo(to playlist: Playlist, on account: Account) async { - guard let appEnvironment else { return } + guard let appEnvironment, canStartAdd else { return } + remoteAddInFlight = true do { try await appEnvironment.remotePlaylistsCache.addVideo( @@ -355,7 +369,8 @@ struct PlaylistSelectorSheet: View { } } catch { // No dismissal on failure — the sheet is where the user retries, or - // picks somewhere else. + // picks somewhere else. Retrying means the gate reopens. + remoteAddInFlight = false appEnvironment.toastManager.showError( String(localized: "playlist.remote.add.error"), subtitle: error.localizedDescription