SvenTiigi/YouTubePlayerKit

Detect Play event in SwiftUI

Closed this issue · 3 comments

Goule commented

Hello,

I'm trying to detect the play event with SwiftUI

Here is my view :

struct PlayerVideoView: View {
    let videoId: String
    
    var youtubePlayer: YouTubePlayer {
        let player = YouTubePlayer(stringLiteral: "https://youtube.com/watch?v=\(videoId)")
        return player
    }
    
    var body: some View {
        YouTubePlayerView(youtubePlayer) { state in
            switch state {
            case .idle:
                ProgressView()
            case .ready:
                EmptyView()
            case .error:
                Text(verbatim: "YouTube player couldn't be loaded")
            }
        }
        .onAppear {
            youtubePlayer.statePublisher
                .sink { playbackState in
                    Logs.info(playbackState)
                }
        }
    }
}

The Logs.info(playbackState) never pass.

I've also tested :

.onChange(of: youtubePlayer.playbackState) { state in
            Logs.info(state)
        }

Did I miss something about this publisher or is this more related to my SwiftUI lifecycle ?

Thanks

Hi @Goule

Your example contains two issues:

  1. The YouTubePlayer instance never gets retrained as you are using a computed property instead of a stored property
  2. The closure which you are passing to the sink operation on the statePublisher never gets executed as the returned AnyCancellable instance is not retained and therefore automatically cancelled.
Goule commented

Thanks @SvenTiigi !

Look like I need to learn more SwiftUI and Combine :D

struct PlayerVideoView: View {
    private var cancellable: AnyCancellable?
    
    var youtubePlayer: YouTubePlayer
    
    init(videoId: String) {
        self.youtubePlayer = YouTubePlayer(stringLiteral: "https://youtube.com/watch?v=\(videoId)")
        
        self.cancellable = youtubePlayer
            .playbackStatePublisher
            .sink { playbackState in
                Logs.info(playbackState)
            }
    }
    
    var body: some View {
        YouTubePlayerView(youtubePlayer) { state in
            switch state {
            case .idle:
                ProgressView()
            case .ready:
                EmptyView()
            case .error:
                Text(verbatim: "YouTube player couldn't be loaded")
            }
        }
    }
}

👍 A tip I would recommend subscribing to the playbackStatePublisher in your SwiftUI View via the onReceive view modifier which automatically handle the subscription returned by the publisher.