Created
September 20, 2023 16:14
-
-
Save reactormonk/563a13bcb00f16971ce1145907e98553 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @Composable | |
| @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) | |
| fun AutoPlayPlaylist(mediaItems: List<MediaItem>, mediaItemIndex: Int, position: Long, storeState: (PlayerState) -> (Unit)) { | |
| val TAG = "AutoPlayPlaylist" | |
| val context = LocalContext.current | |
| val lifecycleOwner = LocalLifecycleOwner.current | |
| Log.d(TAG, "MediaItems: $mediaItems") | |
| var done by remember(mediaItems) { Log.d(TAG, "Recreating done."); mutableStateOf(false) } | |
| val exoPlayer = remember(context) { | |
| var started = false | |
| val listener = object : Player.Listener { | |
| override fun onEvents(player: Player, events: Player.Events) { | |
| if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)) { | |
| if (player.playbackState == Player.STATE_ENDED && started) { | |
| done = true | |
| Log.d(TAG, "Done.") | |
| } | |
| } | |
| } | |
| override fun onIsPlayingChanged(isPlaying: Boolean) { | |
| if (isPlaying) { | |
| started = true | |
| } | |
| } | |
| } | |
| val mediaSourceFactory = DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy( | |
| DefaultLoadErrorHandlingPolicy() | |
| ) | |
| val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build() | |
| player.addListener(listener) | |
| // player.addAnalyticsListener(EventLogger()) | |
| player.repeatMode = REPEAT_MODE_OFF | |
| player | |
| } | |
| fun state(): PlayerState = PlayerState(exoPlayer.currentMediaItem, exoPlayer.currentPosition, done) | |
| storeState(state()) // passing through here on recomposition | |
| Log.i(TAG, "Exo player: $exoPlayer") | |
| LaunchedEffect(mediaItems) { | |
| if (exoPlayer.availableCommands.contains(Player.COMMAND_CHANGE_MEDIA_ITEMS)) { | |
| exoPlayer.setMediaItems(mediaItems) | |
| exoPlayer.prepare() | |
| exoPlayer.playWhenReady = true | |
| } else { | |
| Log.e(TAG, "Can't change media items!?!") | |
| } | |
| } | |
| LaunchedEffect(mediaItemIndex, position) { | |
| if (mediaItemIndex > -1) { | |
| exoPlayer.seekTo(mediaItemIndex, position) | |
| } | |
| } | |
| Log.d(TAG, "currentMediaItem: ${exoPlayer.currentMediaItem}") | |
| DisposableEffect(exoPlayer, mediaItems) { | |
| val lifecycleObserver = LifecycleEventObserver { _, event -> | |
| // TODO sort out the done logic into a separate method and test it on all relevant timings | |
| when (event) { | |
| Lifecycle.Event.ON_STOP -> { | |
| storeState(state()) | |
| } | |
| else -> {} | |
| } | |
| } | |
| lifecycleOwner.lifecycle.addObserver(lifecycleObserver) | |
| onDispose { | |
| lifecycleOwner.lifecycle.removeObserver(lifecycleObserver) | |
| } | |
| } | |
| DisposableEffect(exoPlayer) { | |
| val lifecycleObserver = LifecycleEventObserver { _, event -> | |
| when (event) { | |
| Lifecycle.Event.ON_START -> exoPlayer.play() | |
| Lifecycle.Event.ON_STOP -> exoPlayer.pause() | |
| Lifecycle.Event.ON_DESTROY -> exoPlayer.release() | |
| else -> {} | |
| } | |
| } | |
| lifecycleOwner.lifecycle.addObserver(lifecycleObserver) | |
| onDispose { | |
| lifecycleOwner.lifecycle.removeObserver(lifecycleObserver) | |
| exoPlayer.release() | |
| } | |
| } | |
| Log.d(TAG, "Done: $done") | |
| Box( | |
| modifier = Modifier.fillMaxWidth(), | |
| contentAlignment = Alignment.Center, | |
| ) { | |
| if (!done) { | |
| VideoPlayer(exoPlayer) | |
| } else { | |
| ErrorTemplate(message = stringResource(R.string.end_of_playlist)) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment