Add some previews.
This commit is contained in:
parent
6e624cc198
commit
6e5d7f8f51
5 changed files with 367 additions and 40 deletions
|
|
@ -29,16 +29,20 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize
|
||||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
|
||||
|
||||
@Composable
|
||||
fun MediaFileView(
|
||||
|
|
@ -101,3 +105,16 @@ fun MediaFileView(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MediaFileViewPreview(
|
||||
@PreviewParameter(MediaInfoFileProvider::class) info: MediaInfo
|
||||
) = ElementPreview {
|
||||
MediaFileView(
|
||||
localMediaViewState = rememberLocalMediaViewState(),
|
||||
uri = null,
|
||||
info = info,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.local.file
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo
|
||||
|
||||
open class MediaInfoFileProvider : PreviewParameterProvider<MediaInfo> {
|
||||
override val values: Sequence<MediaInfo>
|
||||
get() = sequenceOf(
|
||||
aPdfMediaInfo(),
|
||||
anAudioMediaInfo(),
|
||||
)
|
||||
}
|
||||
|
|
@ -14,9 +14,12 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage
|
||||
import me.saket.telephoto.zoomable.rememberZoomableImageState
|
||||
|
|
@ -47,3 +50,13 @@ fun MediaImageView(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MediaImageViewPreview() = ElementPreview {
|
||||
MediaImageView(
|
||||
localMediaViewState = rememberLocalMediaViewState(),
|
||||
localMedia = null,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"OVERRIDE_DEPRECATION",
|
||||
"RedundantNullableReturnType",
|
||||
"DEPRECATION",
|
||||
)
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.local.video
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.os.Looper
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
import android.view.TextureView
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.AuxEffectInfo
|
||||
import androidx.media3.common.DeviceInfo
|
||||
import androidx.media3.common.Effect
|
||||
import androidx.media3.common.Format
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.common.PlaybackParameters
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.PriorityTaskManager
|
||||
import androidx.media3.common.Timeline
|
||||
import androidx.media3.common.TrackSelectionParameters
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.VideoSize
|
||||
import androidx.media3.common.text.CueGroup
|
||||
import androidx.media3.common.util.Clock
|
||||
import androidx.media3.common.util.Size
|
||||
import androidx.media3.exoplayer.DecoderCounters
|
||||
import androidx.media3.exoplayer.ExoPlaybackException
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.PlayerMessage
|
||||
import androidx.media3.exoplayer.Renderer
|
||||
import androidx.media3.exoplayer.SeekParameters
|
||||
import androidx.media3.exoplayer.analytics.AnalyticsCollector
|
||||
import androidx.media3.exoplayer.analytics.AnalyticsListener
|
||||
import androidx.media3.exoplayer.image.ImageOutput
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ShuffleOrder
|
||||
import androidx.media3.exoplayer.source.TrackGroupArray
|
||||
import androidx.media3.exoplayer.trackselection.TrackSelectionArray
|
||||
import androidx.media3.exoplayer.trackselection.TrackSelector
|
||||
import androidx.media3.exoplayer.video.VideoFrameMetadataListener
|
||||
import androidx.media3.exoplayer.video.spherical.CameraMotionListener
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class ExoPlayerForPreview(
|
||||
private val isPlaying: Boolean = false,
|
||||
) : ExoPlayer {
|
||||
override fun getApplicationLooper(): Looper = throw NotImplementedError()
|
||||
override fun addListener(listener: Player.Listener) {}
|
||||
override fun removeListener(listener: Player.Listener) {}
|
||||
override fun setMediaItems(mediaItems: MutableList<MediaItem>) {}
|
||||
override fun setMediaItems(mediaItems: MutableList<MediaItem>, resetPosition: Boolean) {}
|
||||
override fun setMediaItems(mediaItems: MutableList<MediaItem>, startIndex: Int, startPositionMs: Long) {}
|
||||
override fun setMediaItem(mediaItem: MediaItem) {}
|
||||
override fun setMediaItem(mediaItem: MediaItem, startPositionMs: Long) {}
|
||||
override fun setMediaItem(mediaItem: MediaItem, resetPosition: Boolean) {}
|
||||
override fun addMediaItem(mediaItem: MediaItem) {}
|
||||
override fun addMediaItem(index: Int, mediaItem: MediaItem) {}
|
||||
override fun addMediaItems(mediaItems: MutableList<MediaItem>) {}
|
||||
override fun addMediaItems(index: Int, mediaItems: MutableList<MediaItem>) {}
|
||||
override fun moveMediaItem(currentIndex: Int, newIndex: Int) {}
|
||||
override fun moveMediaItems(fromIndex: Int, toIndex: Int, newIndex: Int) {}
|
||||
override fun replaceMediaItem(index: Int, mediaItem: MediaItem) {}
|
||||
override fun replaceMediaItems(fromIndex: Int, toIndex: Int, mediaItems: MutableList<MediaItem>) {}
|
||||
override fun removeMediaItem(index: Int) {}
|
||||
override fun removeMediaItems(fromIndex: Int, toIndex: Int) {}
|
||||
override fun clearMediaItems() {}
|
||||
override fun isCommandAvailable(command: Int): Boolean = throw NotImplementedError()
|
||||
override fun canAdvertiseSession(): Boolean = throw NotImplementedError()
|
||||
override fun getAvailableCommands(): Player.Commands = throw NotImplementedError()
|
||||
override fun prepare(mediaSource: MediaSource) {}
|
||||
override fun prepare(mediaSource: MediaSource, resetPosition: Boolean, resetState: Boolean) {}
|
||||
override fun prepare() {}
|
||||
override fun getPlaybackState(): Int = throw NotImplementedError()
|
||||
override fun getPlaybackSuppressionReason(): Int = throw NotImplementedError()
|
||||
override fun isPlaying() = isPlaying
|
||||
override fun getPlayerError(): ExoPlaybackException? = null
|
||||
override fun play() {}
|
||||
override fun pause() {}
|
||||
override fun setPlayWhenReady(playWhenReady: Boolean) {}
|
||||
override fun getPlayWhenReady(): Boolean = throw NotImplementedError()
|
||||
override fun setRepeatMode(repeatMode: Int) {}
|
||||
override fun getRepeatMode(): Int = throw NotImplementedError()
|
||||
override fun setShuffleModeEnabled(shuffleModeEnabled: Boolean) {}
|
||||
override fun getShuffleModeEnabled(): Boolean = throw NotImplementedError()
|
||||
override fun isLoading(): Boolean = throw NotImplementedError()
|
||||
override fun seekToDefaultPosition() {}
|
||||
override fun seekToDefaultPosition(mediaItemIndex: Int) {}
|
||||
override fun seekTo(positionMs: Long) {}
|
||||
override fun seekTo(mediaItemIndex: Int, positionMs: Long) {}
|
||||
override fun getSeekBackIncrement(): Long = throw NotImplementedError()
|
||||
override fun seekBack() {}
|
||||
override fun getSeekForwardIncrement(): Long = throw NotImplementedError()
|
||||
override fun seekForward() {}
|
||||
override fun hasPreviousMediaItem(): Boolean = throw NotImplementedError()
|
||||
override fun seekToPreviousWindow() {}
|
||||
override fun seekToPreviousMediaItem() {}
|
||||
override fun getMaxSeekToPreviousPosition(): Long = throw NotImplementedError()
|
||||
override fun seekToPrevious() {}
|
||||
override fun hasNext(): Boolean = throw NotImplementedError()
|
||||
override fun hasNextWindow(): Boolean = throw NotImplementedError()
|
||||
override fun hasNextMediaItem(): Boolean = throw NotImplementedError()
|
||||
override fun next() {}
|
||||
override fun seekToNextWindow() {}
|
||||
override fun seekToNextMediaItem() {}
|
||||
override fun seekToNext() {}
|
||||
override fun setPlaybackParameters(playbackParameters: PlaybackParameters) {}
|
||||
override fun setPlaybackSpeed(speed: Float) {}
|
||||
override fun getPlaybackParameters(): PlaybackParameters = throw NotImplementedError()
|
||||
override fun stop() {}
|
||||
override fun release() {}
|
||||
override fun getCurrentTracks(): Tracks = throw NotImplementedError()
|
||||
override fun getTrackSelectionParameters(): TrackSelectionParameters = throw NotImplementedError()
|
||||
override fun setTrackSelectionParameters(parameters: TrackSelectionParameters) {}
|
||||
override fun getMediaMetadata(): MediaMetadata = throw NotImplementedError()
|
||||
override fun getPlaylistMetadata(): MediaMetadata = throw NotImplementedError()
|
||||
override fun setPlaylistMetadata(mediaMetadata: MediaMetadata) {}
|
||||
override fun getCurrentManifest(): Any? = throw NotImplementedError()
|
||||
override fun getCurrentTimeline(): Timeline = throw NotImplementedError()
|
||||
override fun getCurrentPeriodIndex(): Int = throw NotImplementedError()
|
||||
override fun getCurrentWindowIndex(): Int = throw NotImplementedError()
|
||||
override fun getCurrentMediaItemIndex(): Int = throw NotImplementedError()
|
||||
override fun getNextWindowIndex(): Int = throw NotImplementedError()
|
||||
override fun getNextMediaItemIndex(): Int = throw NotImplementedError()
|
||||
override fun getPreviousWindowIndex(): Int = throw NotImplementedError()
|
||||
override fun getPreviousMediaItemIndex(): Int = throw NotImplementedError()
|
||||
override fun getCurrentMediaItem(): MediaItem? = throw NotImplementedError()
|
||||
override fun getMediaItemCount(): Int = throw NotImplementedError()
|
||||
override fun getMediaItemAt(index: Int): MediaItem = throw NotImplementedError()
|
||||
override fun getDuration(): Long = throw NotImplementedError()
|
||||
override fun getCurrentPosition(): Long = throw NotImplementedError()
|
||||
override fun getBufferedPosition(): Long = throw NotImplementedError()
|
||||
override fun getBufferedPercentage(): Int = throw NotImplementedError()
|
||||
override fun getTotalBufferedDuration(): Long = throw NotImplementedError()
|
||||
override fun isCurrentWindowDynamic(): Boolean = throw NotImplementedError()
|
||||
override fun isCurrentMediaItemDynamic(): Boolean = throw NotImplementedError()
|
||||
override fun isCurrentWindowLive(): Boolean = throw NotImplementedError()
|
||||
override fun isCurrentMediaItemLive(): Boolean = throw NotImplementedError()
|
||||
override fun getCurrentLiveOffset(): Long = throw NotImplementedError()
|
||||
override fun isCurrentWindowSeekable(): Boolean = throw NotImplementedError()
|
||||
override fun isCurrentMediaItemSeekable(): Boolean = throw NotImplementedError()
|
||||
override fun isPlayingAd(): Boolean = throw NotImplementedError()
|
||||
override fun getCurrentAdGroupIndex(): Int = throw NotImplementedError()
|
||||
override fun getCurrentAdIndexInAdGroup(): Int = throw NotImplementedError()
|
||||
override fun getContentDuration(): Long = throw NotImplementedError()
|
||||
override fun getContentPosition(): Long = throw NotImplementedError()
|
||||
override fun getContentBufferedPosition(): Long = throw NotImplementedError()
|
||||
override fun getAudioAttributes(): AudioAttributes = throw NotImplementedError()
|
||||
override fun setVolume(volume: Float) = throw NotImplementedError()
|
||||
override fun getVolume(): Float = throw NotImplementedError()
|
||||
override fun clearVideoSurface() {}
|
||||
override fun clearVideoSurface(surface: Surface?) {}
|
||||
override fun setVideoSurface(surface: Surface?) {}
|
||||
override fun setVideoSurfaceHolder(surfaceHolder: SurfaceHolder?) {}
|
||||
override fun clearVideoSurfaceHolder(surfaceHolder: SurfaceHolder?) {}
|
||||
override fun setVideoSurfaceView(surfaceView: SurfaceView?) {}
|
||||
override fun clearVideoSurfaceView(surfaceView: SurfaceView?) {}
|
||||
override fun setVideoTextureView(textureView: TextureView?) {}
|
||||
override fun clearVideoTextureView(textureView: TextureView?) {}
|
||||
override fun getVideoSize(): VideoSize = throw NotImplementedError()
|
||||
override fun getSurfaceSize(): Size = throw NotImplementedError()
|
||||
override fun getCurrentCues(): CueGroup = throw NotImplementedError()
|
||||
override fun getDeviceInfo(): DeviceInfo = throw NotImplementedError()
|
||||
override fun getDeviceVolume(): Int = throw NotImplementedError()
|
||||
override fun isDeviceMuted(): Boolean = throw NotImplementedError()
|
||||
override fun setDeviceVolume(volume: Int) {}
|
||||
override fun setDeviceVolume(volume: Int, flags: Int) {}
|
||||
override fun increaseDeviceVolume() {}
|
||||
override fun increaseDeviceVolume(flags: Int) {}
|
||||
override fun decreaseDeviceVolume() {}
|
||||
override fun decreaseDeviceVolume(flags: Int) {}
|
||||
override fun setDeviceMuted(muted: Boolean) {}
|
||||
override fun setDeviceMuted(muted: Boolean, flags: Int) {}
|
||||
override fun setAudioAttributes(audioAttributes: AudioAttributes, handleAudioFocus: Boolean) {}
|
||||
override fun getAudioComponent(): ExoPlayer.AudioComponent? = throw NotImplementedError()
|
||||
override fun getVideoComponent(): ExoPlayer.VideoComponent? = throw NotImplementedError()
|
||||
override fun getTextComponent(): ExoPlayer.TextComponent? = throw NotImplementedError()
|
||||
override fun getDeviceComponent(): ExoPlayer.DeviceComponent? = throw NotImplementedError()
|
||||
override fun addAudioOffloadListener(listener: ExoPlayer.AudioOffloadListener) {}
|
||||
override fun removeAudioOffloadListener(listener: ExoPlayer.AudioOffloadListener) {}
|
||||
override fun getAnalyticsCollector(): AnalyticsCollector = throw NotImplementedError()
|
||||
override fun addAnalyticsListener(listener: AnalyticsListener) {}
|
||||
override fun removeAnalyticsListener(listener: AnalyticsListener) {}
|
||||
override fun getRendererCount(): Int = throw NotImplementedError()
|
||||
override fun getRendererType(index: Int): Int = throw NotImplementedError()
|
||||
override fun getRenderer(index: Int): Renderer = throw NotImplementedError()
|
||||
override fun getTrackSelector(): TrackSelector? = throw NotImplementedError()
|
||||
override fun getCurrentTrackGroups(): TrackGroupArray = throw NotImplementedError()
|
||||
override fun getCurrentTrackSelections(): TrackSelectionArray = throw NotImplementedError()
|
||||
override fun getPlaybackLooper(): Looper = throw NotImplementedError()
|
||||
override fun getClock(): Clock = throw NotImplementedError()
|
||||
override fun setMediaSources(mediaSources: MutableList<MediaSource>) {}
|
||||
override fun setMediaSources(mediaSources: MutableList<MediaSource>, resetPosition: Boolean) {}
|
||||
override fun setMediaSources(mediaSources: MutableList<MediaSource>, startMediaItemIndex: Int, startPositionMs: Long) {}
|
||||
override fun setMediaSource(mediaSource: MediaSource) {}
|
||||
override fun setMediaSource(mediaSource: MediaSource, startPositionMs: Long) {}
|
||||
override fun setMediaSource(mediaSource: MediaSource, resetPosition: Boolean) {}
|
||||
override fun addMediaSource(mediaSource: MediaSource) {}
|
||||
override fun addMediaSource(index: Int, mediaSource: MediaSource) {}
|
||||
override fun addMediaSources(mediaSources: MutableList<MediaSource>) {}
|
||||
override fun addMediaSources(index: Int, mediaSources: MutableList<MediaSource>) {}
|
||||
override fun setShuffleOrder(shuffleOrder: ShuffleOrder) {}
|
||||
override fun setPreloadConfiguration(preloadConfiguration: ExoPlayer.PreloadConfiguration) {}
|
||||
override fun getPreloadConfiguration(): ExoPlayer.PreloadConfiguration = throw NotImplementedError()
|
||||
override fun setAudioSessionId(audioSessionId: Int) {}
|
||||
override fun getAudioSessionId(): Int = throw NotImplementedError()
|
||||
override fun setAuxEffectInfo(auxEffectInfo: AuxEffectInfo) {}
|
||||
override fun clearAuxEffectInfo() {}
|
||||
override fun setPreferredAudioDevice(audioDeviceInfo: AudioDeviceInfo?) {}
|
||||
override fun setSkipSilenceEnabled(skipSilenceEnabled: Boolean) {}
|
||||
override fun getSkipSilenceEnabled(): Boolean = throw NotImplementedError()
|
||||
override fun setVideoEffects(videoEffects: MutableList<Effect>) {}
|
||||
override fun setVideoScalingMode(videoScalingMode: Int) {}
|
||||
override fun getVideoScalingMode(): Int = throw NotImplementedError()
|
||||
override fun setVideoChangeFrameRateStrategy(videoChangeFrameRateStrategy: Int) {}
|
||||
override fun getVideoChangeFrameRateStrategy(): Int = throw NotImplementedError()
|
||||
override fun setVideoFrameMetadataListener(listener: VideoFrameMetadataListener) {}
|
||||
override fun clearVideoFrameMetadataListener(listener: VideoFrameMetadataListener) {}
|
||||
override fun setCameraMotionListener(listener: CameraMotionListener) {}
|
||||
override fun clearCameraMotionListener(listener: CameraMotionListener) {}
|
||||
override fun createMessage(target: PlayerMessage.Target): PlayerMessage = throw NotImplementedError()
|
||||
override fun setSeekParameters(seekParameters: SeekParameters?) {}
|
||||
override fun getSeekParameters(): SeekParameters = throw NotImplementedError()
|
||||
override fun setForegroundMode(foregroundMode: Boolean) {}
|
||||
override fun setPauseAtEndOfMediaItems(pauseAtEndOfMediaItems: Boolean) {}
|
||||
override fun getPauseAtEndOfMediaItems(): Boolean = throw NotImplementedError()
|
||||
override fun getAudioFormat(): Format? = throw NotImplementedError()
|
||||
override fun getVideoFormat(): Format? = throw NotImplementedError()
|
||||
override fun getAudioDecoderCounters(): DecoderCounters? = throw NotImplementedError()
|
||||
override fun getVideoDecoderCounters(): DecoderCounters? = throw NotImplementedError()
|
||||
override fun setHandleAudioBecomingNoisy(handleAudioBecomingNoisy: Boolean) {}
|
||||
override fun setWakeMode(wakeMode: Int) {}
|
||||
override fun setPriority(priority: Int) {}
|
||||
override fun setPriorityTaskManager(priorityTaskManager: PriorityTaskManager?) {}
|
||||
override fun isSleepingForOffload(): Boolean = throw NotImplementedError()
|
||||
override fun isTunnelingEnabled(): Boolean = throw NotImplementedError()
|
||||
override fun isReleased(): Boolean = throw NotImplementedError()
|
||||
override fun setImageOutput(imageOutput: ImageOutput?) {}
|
||||
}
|
||||
|
|
@ -32,51 +32,60 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Timeline
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.ui.AspectRatioFrameLayout
|
||||
import androidx.media3.ui.PlayerView
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.KeepScreenOn
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.PlayableState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
@Composable
|
||||
fun MediaVideoView(
|
||||
localMediaViewState: LocalMediaViewState,
|
||||
localMedia: LocalMedia?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (LocalInspectionMode.current) {
|
||||
Text(
|
||||
modifier = modifier
|
||||
.background(ElementTheme.colors.bgSubtlePrimary)
|
||||
.wrapContentSize(),
|
||||
text = "A Video Player will render here",
|
||||
)
|
||||
val exoPlayer = if (LocalInspectionMode.current) {
|
||||
remember {
|
||||
ExoPlayerForPreview()
|
||||
}
|
||||
} else {
|
||||
ExoPlayerMediaVideoView(
|
||||
localMediaViewState = localMediaViewState,
|
||||
localMedia = localMedia,
|
||||
modifier = modifier,
|
||||
)
|
||||
val context = LocalContext.current
|
||||
remember {
|
||||
ExoPlayerWrapper.create(context)
|
||||
}
|
||||
}
|
||||
ExoPlayerMediaVideoView(
|
||||
localMediaViewState = localMediaViewState,
|
||||
exoPlayer = exoPlayer,
|
||||
localMedia = localMedia,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
@Composable
|
||||
private fun ExoPlayerMediaVideoView(
|
||||
localMediaViewState: LocalMediaViewState,
|
||||
exoPlayer: ExoPlayer,
|
||||
localMedia: LocalMedia?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isControllerVisibleByDefault = LocalInspectionMode.current
|
||||
var mediaPlayerControllerState: MediaPlayerControllerState by remember {
|
||||
mutableStateOf(
|
||||
MediaPlayerControllerState(
|
||||
isVisible = false,
|
||||
isVisible = isControllerVisibleByDefault,
|
||||
isPlaying = false,
|
||||
progressInMillis = 0,
|
||||
durationInMillis = 0,
|
||||
|
|
@ -95,10 +104,6 @@ private fun ExoPlayerMediaVideoView(
|
|||
|
||||
localMediaViewState.playableState = playableState
|
||||
|
||||
val context = LocalContext.current
|
||||
val exoPlayer = remember {
|
||||
ExoPlayerWrapper.create(context)
|
||||
}
|
||||
val playerListener = object : Player.Listener {
|
||||
override fun onRenderedFirstFrame() {
|
||||
localMediaViewState.isReady = true
|
||||
|
|
@ -167,31 +172,40 @@ private fun ExoPlayerMediaVideoView(
|
|||
KeepScreenOn(mediaPlayerControllerState.isPlaying)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(ElementTheme.colors.bgSubtlePrimary)
|
||||
.wrapContentSize(),
|
||||
.background(ElementTheme.colors.bgSubtlePrimary),
|
||||
) {
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
factory = {
|
||||
PlayerView(context).apply {
|
||||
player = exoPlayer
|
||||
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||
setOnClickListener {
|
||||
autoHideController++
|
||||
mediaPlayerControllerState = mediaPlayerControllerState.copy(
|
||||
isVisible = !mediaPlayerControllerState.isVisible,
|
||||
)
|
||||
val context = LocalContext.current
|
||||
if (LocalInspectionMode.current) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.background(ElementTheme.colors.bgSubtlePrimary)
|
||||
.wrapContentSize(),
|
||||
text = "A Video Player will render here",
|
||||
)
|
||||
} else {
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
factory = {
|
||||
PlayerView(context).apply {
|
||||
player = exoPlayer
|
||||
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||
setOnClickListener {
|
||||
autoHideController++
|
||||
mediaPlayerControllerState = mediaPlayerControllerState.copy(
|
||||
isVisible = !mediaPlayerControllerState.isVisible,
|
||||
)
|
||||
}
|
||||
useController = false
|
||||
}
|
||||
useController = false
|
||||
}
|
||||
},
|
||||
onRelease = { playerView ->
|
||||
playerView.setOnClickListener(null)
|
||||
playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?)
|
||||
playerView.player = null
|
||||
},
|
||||
)
|
||||
},
|
||||
onRelease = { playerView ->
|
||||
playerView.setOnClickListener(null)
|
||||
playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?)
|
||||
playerView.player = null
|
||||
},
|
||||
)
|
||||
}
|
||||
MediaPlayerControllerView(
|
||||
state = mediaPlayerControllerState,
|
||||
onTogglePlay = {
|
||||
|
|
@ -235,3 +249,13 @@ private fun ExoPlayerMediaVideoView(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MediaVideoViewPreview() = ElementPreview {
|
||||
MediaVideoView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
localMediaViewState = rememberLocalMediaViewState(),
|
||||
localMedia = null,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue