eneim / toro

Video list auto playback made simple, specially built for RecyclerView
Apache License 2.0
1.42k stars 253 forks source link

Video can only play once #360

Open dokiKit opened 6 years ago

dokiKit commented 6 years ago

Thanks for the great library. I use this library for purpose of the ability to play video in a recyclerview. I disable auto play. But I found that when I play the video manually using the helper.play() and helper.pause() function, the first time the video is played normally. When the video is completed playing, and I try to play it again, the ToroPlayer.EventListener immediate called onComplete. Why is that? Also, when I swipe another item and swipe back, the video can be played again. Below is my implementation.(The VideoViewHolder part).


fullscreenGalleryContainer.apply {
            adapter = galleryAdapter
            layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
            snapHelper.attachToRecyclerView(this)

            addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    handleScroll()

                }
            })
            playerSelector = PlayerSelector.NONE
            cacheManager = CacheManager.DEFAULT

        } 
package com.doki.launcher.adapter.viewholder

import android.net.Uri
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.widget.ToggleButton
import com.doki.launcher.R
import com.doki.launcher.adapter.adaptermodel.GalleryModel
import com.doki.launcher.utils.extension.setAnimatedOnClickListner
import com.google.android.exoplayer2.ui.PlayerView
import im.ene.toro.ToroPlayer
import im.ene.toro.ToroUtil.visibleAreaOffset
import im.ene.toro.exoplayer.ExoPlayerViewHelper
import im.ene.toro.media.PlaybackInfo
import im.ene.toro.widget.Container
import kotlinx.android.synthetic.main.item_fullscreen_video.view.*
import kotlinx.android.synthetic.main.item_gallery_image.view.*
import java.io.File

interface GalleryViewHolder {
    fun bindViews(isFullscreen: Boolean, position: Int, galleryModel: GalleryModel, clickListener: (GalleryModel, View, Int) -> Unit, longClickListener: (GalleryModel) -> Boolean)
}

class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), GalleryViewHolder {
    override fun bindViews(isFullscreen: Boolean, position: Int, galleryModel: GalleryModel, clickListener: (GalleryModel, View, Int) -> Unit, longClickListener: (GalleryModel) -> Boolean) = with(itemView) {
        galleryImageThumbnail.setImageBitmap((galleryModel as GalleryModel.GalleryImageModel).imageThumbnail)
        if (isFullscreen){
            setOnClickListener { clickListener(galleryModel, itemView.findViewById(R.id.galleryImageThumbnail), position)   }
        } else {
            setAnimatedOnClickListner { clickListener(galleryModel, itemView.findViewById(R.id.galleryImageThumbnail), position) }
        }
        setOnLongClickListener { longClickListener(galleryModel) }
    }

}

class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), GalleryViewHolder, ToroPlayer {
    var helper: ExoPlayerViewHelper? = null
    var mediaUri: Uri? = null
    var listener: ToroPlayer.EventListener? = null

    val videoPlayerView = itemView.findViewById<PlayerView>(R.id.videoPlayerView)
    val playPauseToggle = itemView.findViewById<ToggleButton>(R.id.playPauseToggle)
    val thumbnail = itemView.findViewById<ImageView>(R.id.galleryVideoThumbnail)

    override fun getPlayerView() = videoPlayerView

    override fun getCurrentPlaybackInfo() = helper?.latestPlaybackInfo ?: PlaybackInfo()

    override fun initialize(container: Container, playbackInfo: PlaybackInfo) {
        if (helper == null) helper = ExoPlayerViewHelper(this, mediaUri!!, null)
        listener = object: ToroPlayer.EventListener {
            override fun onBuffering() {
                Log.v("VIDEO", "onBuffering")
            }

            override fun onPlaying() {
                Log.v("VIDEO", "onPlaying")
            }

            override fun onPaused() {
                Log.v("VIDEO", "onPaused")
            }

            override fun onCompleted() {
                Log.v("VIDEO", "onCompleted")
                playPauseToggle.isChecked = false
                thumbnail.visibility = View.VISIBLE
            }

        }
        helper!!.addPlayerEventListener(listener!!)
        helper!!.initialize(container, playbackInfo)

    }

    override fun play() {
        helper!!.play()
    }

    override fun pause() {
        helper!!.pause()
    }

    override fun isPlaying() = helper?.isPlaying ?: false

    override fun release() {
        if (listener != null) {
            helper?.removePlayerEventListener(listener)
            listener = null
        }
        helper?.release()
        helper = null
    }

    override fun wantsToPlay() = visibleAreaOffset(this, itemView.parent) >= 0.65

    override fun getPlayerOrder() = adapterPosition

    override fun bindViews(isFullscreen: Boolean, position: Int, galleryModel: GalleryModel, clickListener: (GalleryModel, View, Int) -> Unit, longClickListener: (GalleryModel) -> Boolean) = with(itemView) {
        thumbnail.setImageBitmap((galleryModel as GalleryModel.GalleryVideoModel).videoThumbnail)
        if (isFullscreen){
            mediaUri = Uri.fromFile(File(galleryModel.filePath))
            setOnClickListener { clickListener(galleryModel, thumbnail, position) }

            playPauseToggle.setOnClickListener {
                if (helper?.isPlaying!!){
                    helper?.pause()
                } else {
                    thumbnail.visibility = View.INVISIBLE
                    helper?.play()
                }
            }
//            playPauseToggle.setOnCheckedChangeListener { buttonView, isChecked ->
//                if(isChecked){
//                    thumbnail.visibility = View.INVISIBLE
//                    helper?.play()
//                } else {
//                    if(helper?.isPlaying!!) {
//                        helper?.pause()
//                    } else {
//                        thumbnail.visibility = View.VISIBLE
//                    }
//                }
//            }
        } else {
            setAnimatedOnClickListner { clickListener(galleryModel, itemView.findViewById(R.id.galleryVideoThumbnail), position) }
        }
        setOnLongClickListener { longClickListener(galleryModel) }
    }

}

class CameraViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), GalleryViewHolder {
    override fun bindViews(isFullscreen: Boolean, position: Int, galleryModel: GalleryModel, clickListener: (GalleryModel, View, Int) -> Unit, longClickListener: (GalleryModel) -> Boolean) {
        itemView.setAnimatedOnClickListner { clickListener(galleryModel, itemView, position) }
//        setOnLongClickListener { longClickListener(galleryModel) }
    }

}

Thanks, Kit

dokiKit commented 6 years ago

I found that if I seek the player to 0ms, the video can be played. Seems that oncomplete does not reset the seek progress

eneim commented 6 years ago

@dokiKit From what I remember now, after onComplete is called, the Player state becomes 'IDLE', which requires it to prepare again to be able to start another playback. If you use helper as standalone, try to call prepare/initialize again and see if it helps.

creativecoderbee commented 5 years ago

How you seek ? @dokiKit