mirror of
https://github.com/FossifyOrg/Gallery.git
synced 2024-11-22 12:38:00 +01:00
Remove wildcard imports
This commit is contained in:
parent
1edcd5d161
commit
571866543d
3 changed files with 303 additions and 105 deletions
|
@ -13,11 +13,21 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.Surface
|
||||
import android.view.TextureView
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.VideoSize
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.datasource.ContentDataSource
|
||||
import androidx.media3.datasource.DataSource
|
||||
|
@ -28,17 +38,56 @@ import androidx.media3.exoplayer.SeekParameters
|
|||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import org.fossify.commons.extensions.*
|
||||
import org.fossify.commons.extensions.actionBarHeight
|
||||
import org.fossify.commons.extensions.beGone
|
||||
import org.fossify.commons.extensions.beVisible
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.fadeIn
|
||||
import org.fossify.commons.extensions.getColoredDrawableWithColor
|
||||
import org.fossify.commons.extensions.getFilenameFromUri
|
||||
import org.fossify.commons.extensions.getFormattedDuration
|
||||
import org.fossify.commons.extensions.getProperTextColor
|
||||
import org.fossify.commons.extensions.navigationBarHeight
|
||||
import org.fossify.commons.extensions.navigationBarOnSide
|
||||
import org.fossify.commons.extensions.navigationBarWidth
|
||||
import org.fossify.commons.extensions.onGlobalLayout
|
||||
import org.fossify.commons.extensions.portrait
|
||||
import org.fossify.commons.extensions.setDrawablesRelativeWithIntrinsicBounds
|
||||
import org.fossify.commons.extensions.showErrorToast
|
||||
import org.fossify.commons.extensions.statusBarHeight
|
||||
import org.fossify.commons.extensions.updateTextColors
|
||||
import org.fossify.commons.extensions.viewBinding
|
||||
import org.fossify.gallery.R
|
||||
import org.fossify.gallery.databinding.ActivityVideoPlayerBinding
|
||||
import org.fossify.gallery.extensions.*
|
||||
import org.fossify.gallery.extensions.config
|
||||
import org.fossify.gallery.extensions.getFriendlyMessage
|
||||
import org.fossify.gallery.extensions.hasNavBar
|
||||
import org.fossify.gallery.extensions.hideSystemUI
|
||||
import org.fossify.gallery.extensions.mute
|
||||
import org.fossify.gallery.extensions.openPath
|
||||
import org.fossify.gallery.extensions.shareMediumPath
|
||||
import org.fossify.gallery.extensions.showSystemUI
|
||||
import org.fossify.gallery.extensions.unmute
|
||||
import org.fossify.gallery.fragments.PlaybackSpeedFragment
|
||||
import org.fossify.gallery.helpers.*
|
||||
import org.fossify.gallery.helpers.DRAG_THRESHOLD
|
||||
import org.fossify.gallery.helpers.EXOPLAYER_MAX_BUFFER_MS
|
||||
import org.fossify.gallery.helpers.EXOPLAYER_MIN_BUFFER_MS
|
||||
import org.fossify.gallery.helpers.FAST_FORWARD_VIDEO_MS
|
||||
import org.fossify.gallery.helpers.GO_TO_NEXT_ITEM
|
||||
import org.fossify.gallery.helpers.GO_TO_PREV_ITEM
|
||||
import org.fossify.gallery.helpers.HIDE_SYSTEM_UI_DELAY
|
||||
import org.fossify.gallery.helpers.MAX_CLOSE_DOWN_GESTURE_DURATION
|
||||
import org.fossify.gallery.helpers.ROTATE_BY_ASPECT_RATIO
|
||||
import org.fossify.gallery.helpers.ROTATE_BY_DEVICE_ROTATION
|
||||
import org.fossify.gallery.helpers.ROTATE_BY_SYSTEM_SETTING
|
||||
import org.fossify.gallery.helpers.SHOW_NEXT_ITEM
|
||||
import org.fossify.gallery.helpers.SHOW_PREV_ITEM
|
||||
import org.fossify.gallery.interfaces.PlaybackSpeedListener
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@UnstableApi
|
||||
open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListener, TextureView.SurfaceTextureListener, PlaybackSpeedListener {
|
||||
open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListener,
|
||||
TextureView.SurfaceTextureListener, PlaybackSpeedListener {
|
||||
private val PLAY_WHEN_READY_DRAG_DELAY = 100L
|
||||
|
||||
private var mIsFullscreen = false
|
||||
|
@ -122,11 +171,18 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
}
|
||||
|
||||
private fun setupOptionsMenu() {
|
||||
(binding.videoAppbar.layoutParams as RelativeLayout.LayoutParams).topMargin = statusBarHeight
|
||||
(binding.videoAppbar.layoutParams as RelativeLayout.LayoutParams).topMargin =
|
||||
statusBarHeight
|
||||
binding.videoToolbar.apply {
|
||||
setTitleTextColor(Color.WHITE)
|
||||
overflowIcon = resources.getColoredDrawableWithColor(org.fossify.commons.R.drawable.ic_three_dots_vector, Color.WHITE)
|
||||
navigationIcon = resources.getColoredDrawableWithColor(org.fossify.commons.R.drawable.ic_arrow_left_vector, Color.WHITE)
|
||||
overflowIcon = resources.getColoredDrawableWithColor(
|
||||
org.fossify.commons.R.drawable.ic_three_dots_vector,
|
||||
Color.WHITE
|
||||
)
|
||||
navigationIcon = resources.getColoredDrawableWithColor(
|
||||
org.fossify.commons.R.drawable.ic_arrow_left_vector,
|
||||
Color.WHITE
|
||||
)
|
||||
}
|
||||
|
||||
updateMenuItemColors(binding.videoToolbar.menu, forceWhiteIcons = true)
|
||||
|
@ -154,7 +210,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
}
|
||||
|
||||
binding.topShadow.layoutParams.height = statusBarHeight + actionBarHeight
|
||||
(binding.videoAppbar.layoutParams as RelativeLayout.LayoutParams).topMargin = statusBarHeight
|
||||
(binding.videoAppbar.layoutParams as RelativeLayout.LayoutParams).topMargin =
|
||||
statusBarHeight
|
||||
if (!portrait && navigationBarOnSide && navigationBarWidth > 0) {
|
||||
binding.videoToolbar.setPadding(0, 0, navigationBarWidth, 0)
|
||||
} else {
|
||||
|
@ -195,18 +252,29 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
binding.videoSurfaceFrame.setOnClickListener { toggleFullscreen() }
|
||||
binding.videoSurfaceFrame.controller.settings.swallowDoubleTaps = true
|
||||
|
||||
binding.bottomVideoTimeHolder.videoNextFile.beVisibleIf(intent.getBooleanExtra(SHOW_NEXT_ITEM, false))
|
||||
binding.bottomVideoTimeHolder.videoNextFile.beVisibleIf(
|
||||
intent.getBooleanExtra(
|
||||
SHOW_NEXT_ITEM,
|
||||
false
|
||||
)
|
||||
)
|
||||
binding.bottomVideoTimeHolder.videoNextFile.setOnClickListener { handleNextFile() }
|
||||
|
||||
binding.bottomVideoTimeHolder.videoPrevFile.beVisibleIf(intent.getBooleanExtra(SHOW_PREV_ITEM, false))
|
||||
binding.bottomVideoTimeHolder.videoPrevFile.beVisibleIf(
|
||||
intent.getBooleanExtra(
|
||||
SHOW_PREV_ITEM,
|
||||
false
|
||||
)
|
||||
)
|
||||
binding.bottomVideoTimeHolder.videoPrevFile.setOnClickListener { handlePrevFile() }
|
||||
|
||||
val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
handleDoubleTap(e.rawX)
|
||||
return true
|
||||
}
|
||||
})
|
||||
val gestureDetector =
|
||||
GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
handleDoubleTap(e.rawX)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
binding.videoSurfaceFrame.setOnTouchListener { view, event ->
|
||||
handleEvent(event)
|
||||
|
@ -218,17 +286,29 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
binding.videoSurface.surfaceTextureListener = this
|
||||
|
||||
if (config.allowVideoGestures) {
|
||||
binding.videoBrightnessController.initialize(this, binding.slideInfo, true, binding.videoPlayerHolder, singleTap = { x, y ->
|
||||
toggleFullscreen()
|
||||
}, doubleTap = { x, y ->
|
||||
doSkip(false)
|
||||
})
|
||||
binding.videoBrightnessController.initialize(
|
||||
this,
|
||||
binding.slideInfo,
|
||||
true,
|
||||
binding.videoPlayerHolder,
|
||||
singleTap = { x, y ->
|
||||
toggleFullscreen()
|
||||
},
|
||||
doubleTap = { x, y ->
|
||||
doSkip(false)
|
||||
})
|
||||
|
||||
binding.videoVolumeController.initialize(this, binding.slideInfo, false, binding.videoPlayerHolder, singleTap = { x, y ->
|
||||
toggleFullscreen()
|
||||
}, doubleTap = { x, y ->
|
||||
doSkip(true)
|
||||
})
|
||||
binding.videoVolumeController.initialize(
|
||||
this,
|
||||
binding.slideInfo,
|
||||
false,
|
||||
binding.videoPlayerHolder,
|
||||
singleTap = { x, y ->
|
||||
toggleFullscreen()
|
||||
},
|
||||
doubleTap = { x, y ->
|
||||
doSkip(true)
|
||||
})
|
||||
} else {
|
||||
binding.videoBrightnessController.beGone()
|
||||
binding.videoVolumeController.beGone()
|
||||
|
@ -257,7 +337,12 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
.createMediaSource(MediaItem.fromUri(fileDataSource.uri!!))
|
||||
|
||||
val loadControl = DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(EXOPLAYER_MIN_BUFFER_MS, EXOPLAYER_MAX_BUFFER_MS, EXOPLAYER_MIN_BUFFER_MS, EXOPLAYER_MIN_BUFFER_MS)
|
||||
.setBufferDurationsMs(
|
||||
EXOPLAYER_MIN_BUFFER_MS,
|
||||
EXOPLAYER_MAX_BUFFER_MS,
|
||||
EXOPLAYER_MIN_BUFFER_MS,
|
||||
EXOPLAYER_MIN_BUFFER_MS
|
||||
)
|
||||
.setPrioritizeTimeOverSizeThresholds(true)
|
||||
.build()
|
||||
|
||||
|
@ -287,7 +372,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
|
||||
private fun ExoPlayer.initListeners() {
|
||||
addListener(object : Player.Listener {
|
||||
override fun onPositionDiscontinuity(oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, @Player.DiscontinuityReason reason: Int) {
|
||||
override fun onPositionDiscontinuity(
|
||||
oldPosition: Player.PositionInfo,
|
||||
newPosition: Player.PositionInfo,
|
||||
@Player.DiscontinuityReason reason: Int
|
||||
) {
|
||||
// Reset progress views when video loops.
|
||||
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.progress = 0
|
||||
|
@ -327,7 +416,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
binding.bottomVideoTimeHolder.videoTogglePlayPause.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoToggleMute.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(config.playbackSpeed)}x"
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text =
|
||||
"${DecimalFormat("#.##").format(config.playbackSpeed)}x"
|
||||
mDuration = (mExoPlayer!!.duration / 1000).toInt()
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.max = mDuration
|
||||
binding.bottomVideoTimeHolder.videoDuration.text = mDuration.getFormattedDuration()
|
||||
|
@ -430,7 +520,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
|
||||
clearLastVideoSavedProgress()
|
||||
mCurrTime = (mExoPlayer!!.duration / 1000).toInt()
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.progress = binding.bottomVideoTimeHolder.videoSeekbar.max
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.progress =
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.max
|
||||
binding.bottomVideoTimeHolder.videoCurrTime.text = mDuration.getFormattedDuration()
|
||||
pauseVideo()
|
||||
}
|
||||
|
@ -443,7 +534,10 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
|
||||
private fun saveVideoProgress() {
|
||||
if (!didVideoEnd()) {
|
||||
config.saveLastVideoPosition(mUri.toString(), mExoPlayer!!.currentPosition.toInt() / 1000)
|
||||
config.saveLastVideoPosition(
|
||||
mUri.toString(),
|
||||
mExoPlayer!!.currentPosition.toInt() / 1000
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,11 +583,12 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
|
||||
private fun changeOrientation() {
|
||||
mIsOrientationLocked = true
|
||||
requestedOrientation = if (resources.configuration.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
requestedOrientation =
|
||||
if (resources.configuration.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
} else {
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleFullscreen() {
|
||||
|
@ -553,13 +648,20 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
if (isSlow != binding.bottomVideoTimeHolder.videoPlaybackSpeed.tag as? Boolean) {
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.tag = isSlow
|
||||
|
||||
val drawableId = if (isSlow) R.drawable.ic_playback_speed_slow_vector else R.drawable.ic_playback_speed_vector
|
||||
val drawableId =
|
||||
if (isSlow) R.drawable.ic_playback_speed_slow_vector else R.drawable.ic_playback_speed_vector
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed
|
||||
.setDrawablesRelativeWithIntrinsicBounds(AppCompatResources.getDrawable(this, drawableId))
|
||||
.setDrawablesRelativeWithIntrinsicBounds(
|
||||
AppCompatResources.getDrawable(
|
||||
this,
|
||||
drawableId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(speed)}x"
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text =
|
||||
"${DecimalFormat("#.##").format(speed)}x"
|
||||
mExoPlayer?.setPlaybackSpeed(speed)
|
||||
}
|
||||
|
||||
|
@ -590,7 +692,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
if (mExoPlayer != null && !mIsDragged && mIsPlaying) {
|
||||
mCurrTime = (mExoPlayer!!.currentPosition / 1000).toInt()
|
||||
binding.bottomVideoTimeHolder.videoSeekbar.progress = mCurrTime
|
||||
binding.bottomVideoTimeHolder.videoCurrTime.text = mCurrTime.getFormattedDuration()
|
||||
binding.bottomVideoTimeHolder.videoCurrTime.text =
|
||||
mCurrTime.getFormattedDuration()
|
||||
}
|
||||
|
||||
mTimerHandler.postDelayed(this, 1000)
|
||||
|
@ -604,9 +707,11 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
}
|
||||
|
||||
val curr = mExoPlayer!!.currentPosition
|
||||
val newProgress = if (forward) curr + FAST_FORWARD_VIDEO_MS else curr - FAST_FORWARD_VIDEO_MS
|
||||
val newProgress =
|
||||
if (forward) curr + FAST_FORWARD_VIDEO_MS else curr - FAST_FORWARD_VIDEO_MS
|
||||
val roundProgress = Math.round(newProgress / 1000f)
|
||||
val limitedProgress = Math.max(Math.min(mExoPlayer!!.duration.toInt() / 1000, roundProgress), 0)
|
||||
val limitedProgress =
|
||||
Math.max(Math.min(mExoPlayer!!.duration.toInt() / 1000, roundProgress), 0)
|
||||
setPosition(limitedProgress)
|
||||
if (!mIsPlaying) {
|
||||
togglePlayPause()
|
||||
|
@ -627,7 +732,10 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
val diffX = event.rawX - mTouchDownX
|
||||
val diffY = event.rawY - mTouchDownY
|
||||
|
||||
if (mIsDragged || (Math.abs(diffX) > mDragThreshold && Math.abs(diffX) > Math.abs(diffY)) && binding.videoSurfaceFrame.controller.state.zoom == 1f) {
|
||||
if (mIsDragged || (Math.abs(diffX) > mDragThreshold && Math.abs(diffX) > Math.abs(
|
||||
diffY
|
||||
)) && binding.videoSurfaceFrame.controller.state.zoom == 1f
|
||||
) {
|
||||
if (!mIsDragged) {
|
||||
arrayOf(
|
||||
binding.bottomVideoTimeHolder.videoCurrTime,
|
||||
|
@ -644,7 +752,8 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
|
|||
|
||||
val skipLength = (mDuration * 1000f) * (percent / 100f)
|
||||
var newProgress = mProgressAtDown + skipLength
|
||||
newProgress = Math.max(Math.min(mExoPlayer!!.duration.toFloat(), newProgress), 0f)
|
||||
newProgress =
|
||||
Math.max(Math.min(mExoPlayer!!.duration.toFloat(), newProgress), 0f)
|
||||
val newSeconds = (newProgress / 1000).toInt()
|
||||
setPosition(newSeconds)
|
||||
resetPlayWhenReady()
|
||||
|
|
|
@ -2,7 +2,14 @@ package org.fossify.gallery.extensions
|
|||
|
||||
import android.content.Context
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.PlaybackException.*
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_DECODER_INIT_FAILED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FAILED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED
|
||||
import androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED
|
||||
import androidx.media3.common.Player
|
||||
import org.fossify.gallery.R
|
||||
|
||||
|
@ -14,7 +21,7 @@ fun Player.unmute() {
|
|||
volume = 1f
|
||||
}
|
||||
|
||||
fun PlaybackException.getFriendlyMessage(context: Context): String? {
|
||||
fun PlaybackException.getFriendlyMessage(context: Context): String {
|
||||
val resource = when (errorCode) {
|
||||
ERROR_CODE_PARSING_CONTAINER_MALFORMED,
|
||||
ERROR_CODE_PARSING_MANIFEST_MALFORMED -> R.string.file_is_malformed_or_corrupted
|
||||
|
|
|
@ -9,14 +9,26 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import android.view.GestureDetector
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.Surface
|
||||
import android.view.TextureView
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.SeekBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.view.children
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.VideoSize
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.datasource.ContentDataSource
|
||||
import androidx.media3.datasource.DataSource
|
||||
|
@ -29,13 +41,42 @@ import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
|||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import com.bumptech.glide.Glide
|
||||
import org.fossify.commons.extensions.*
|
||||
import org.fossify.commons.extensions.beGone
|
||||
import org.fossify.commons.extensions.beGoneIf
|
||||
import org.fossify.commons.extensions.beInvisible
|
||||
import org.fossify.commons.extensions.beInvisibleIf
|
||||
import org.fossify.commons.extensions.beVisible
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.fadeIn
|
||||
import org.fossify.commons.extensions.getDuration
|
||||
import org.fossify.commons.extensions.getFormattedDuration
|
||||
import org.fossify.commons.extensions.getProperTextColor
|
||||
import org.fossify.commons.extensions.getVideoResolution
|
||||
import org.fossify.commons.extensions.isGone
|
||||
import org.fossify.commons.extensions.isVisible
|
||||
import org.fossify.commons.extensions.navigationBarHeight
|
||||
import org.fossify.commons.extensions.navigationBarWidth
|
||||
import org.fossify.commons.extensions.onGlobalLayout
|
||||
import org.fossify.commons.extensions.realScreenSize
|
||||
import org.fossify.commons.extensions.setDrawablesRelativeWithIntrinsicBounds
|
||||
import org.fossify.commons.extensions.showErrorToast
|
||||
import org.fossify.commons.extensions.updateTextColors
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.gallery.R
|
||||
import org.fossify.gallery.activities.VideoActivity
|
||||
import org.fossify.gallery.databinding.PagerVideoItemBinding
|
||||
import org.fossify.gallery.extensions.*
|
||||
import org.fossify.gallery.helpers.*
|
||||
import org.fossify.gallery.extensions.config
|
||||
import org.fossify.gallery.extensions.getFriendlyMessage
|
||||
import org.fossify.gallery.extensions.hasNavBar
|
||||
import org.fossify.gallery.extensions.mute
|
||||
import org.fossify.gallery.extensions.parseFileChannel
|
||||
import org.fossify.gallery.extensions.unmute
|
||||
import org.fossify.gallery.helpers.Config
|
||||
import org.fossify.gallery.helpers.EXOPLAYER_MAX_BUFFER_MS
|
||||
import org.fossify.gallery.helpers.EXOPLAYER_MIN_BUFFER_MS
|
||||
import org.fossify.gallery.helpers.FAST_FORWARD_VIDEO_MS
|
||||
import org.fossify.gallery.helpers.MEDIUM
|
||||
import org.fossify.gallery.helpers.SHOULD_INIT_FRAGMENT
|
||||
import org.fossify.gallery.interfaces.PlaybackSpeedListener
|
||||
import org.fossify.gallery.models.Medium
|
||||
import org.fossify.gallery.views.MediaSideScroll
|
||||
|
@ -44,7 +85,8 @@ import java.io.FileInputStream
|
|||
import java.text.DecimalFormat
|
||||
|
||||
@UnstableApi
|
||||
class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, SeekBar.OnSeekBarChangeListener, PlaybackSpeedListener {
|
||||
class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener,
|
||||
SeekBar.OnSeekBarChangeListener, PlaybackSpeedListener {
|
||||
private val PROGRESS = "progress"
|
||||
|
||||
private var mIsFullscreen = false
|
||||
|
@ -85,7 +127,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
private lateinit var mPlayPauseButton: ImageView
|
||||
private lateinit var mSeekBar: SeekBar
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val context = requireContext()
|
||||
val activity = requireActivity()
|
||||
val arguments = requireArguments()
|
||||
|
@ -131,29 +177,30 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mTextureView = videoSurface
|
||||
mTextureView.surfaceTextureListener = this@VideoFragment
|
||||
|
||||
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
if (!mConfig.allowInstantChange) {
|
||||
toggleFullscreen()
|
||||
val gestureDetector =
|
||||
GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
if (!mConfig.allowInstantChange) {
|
||||
toggleFullscreen()
|
||||
return true
|
||||
}
|
||||
|
||||
val viewWidth = root.width
|
||||
val instantWidth = viewWidth / 7
|
||||
val clickedX = e.rawX
|
||||
when {
|
||||
clickedX <= instantWidth -> listener?.goToPrevItem()
|
||||
clickedX >= viewWidth - instantWidth -> listener?.goToNextItem()
|
||||
else -> toggleFullscreen()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val viewWidth = root.width
|
||||
val instantWidth = viewWidth / 7
|
||||
val clickedX = e.rawX
|
||||
when {
|
||||
clickedX <= instantWidth -> listener?.goToPrevItem()
|
||||
clickedX >= viewWidth - instantWidth -> listener?.goToNextItem()
|
||||
else -> toggleFullscreen()
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
handleDoubleTap(e.rawX)
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
handleDoubleTap(e.rawX)
|
||||
return true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
videoPreview.setOnTouchListener { view, event ->
|
||||
handleEvent(event)
|
||||
|
@ -183,7 +230,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mIsFragmentVisible = true
|
||||
}
|
||||
|
||||
mIsFullscreen = activity.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
mIsFullscreen =
|
||||
activity.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
initTimeHolder()
|
||||
// checkIfPanorama() TODO: Implement panorama using a FOSS library
|
||||
|
||||
|
@ -213,25 +261,37 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
setVideoSize()
|
||||
|
||||
binding.apply {
|
||||
mBrightnessSideScroll.initialize(activity, slideInfo, true, container, singleTap = { x, y ->
|
||||
if (mConfig.allowInstantChange) {
|
||||
listener?.goToPrevItem()
|
||||
} else {
|
||||
toggleFullscreen()
|
||||
}
|
||||
}, doubleTap = { x, y ->
|
||||
doSkip(false)
|
||||
})
|
||||
mBrightnessSideScroll.initialize(
|
||||
activity,
|
||||
slideInfo,
|
||||
true,
|
||||
container,
|
||||
singleTap = { x, y ->
|
||||
if (mConfig.allowInstantChange) {
|
||||
listener?.goToPrevItem()
|
||||
} else {
|
||||
toggleFullscreen()
|
||||
}
|
||||
},
|
||||
doubleTap = { x, y ->
|
||||
doSkip(false)
|
||||
})
|
||||
|
||||
mVolumeSideScroll.initialize(activity, slideInfo, false, container, singleTap = { x, y ->
|
||||
if (mConfig.allowInstantChange) {
|
||||
listener?.goToNextItem()
|
||||
} else {
|
||||
toggleFullscreen()
|
||||
}
|
||||
}, doubleTap = { x, y ->
|
||||
doSkip(true)
|
||||
})
|
||||
mVolumeSideScroll.initialize(
|
||||
activity,
|
||||
slideInfo,
|
||||
false,
|
||||
container,
|
||||
singleTap = { x, y ->
|
||||
if (mConfig.allowInstantChange) {
|
||||
listener?.goToNextItem()
|
||||
} else {
|
||||
toggleFullscreen()
|
||||
}
|
||||
},
|
||||
doubleTap = { x, y ->
|
||||
doSkip(true)
|
||||
})
|
||||
|
||||
videoSurface.onGlobalLayout {
|
||||
if (mIsFragmentVisible && mConfig.autoplayVideos && !mConfig.openVideosOnSeparateScreen) {
|
||||
|
@ -251,7 +311,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mConfig = requireContext().config // make sure we get a new config, in case the user changed something in the app settings
|
||||
mConfig =
|
||||
requireContext().config // make sure we get a new config, in case the user changed something in the app settings
|
||||
requireActivity().updateTextColors(binding.videoHolder)
|
||||
val allowVideoGestures = mConfig.allowVideoGestures
|
||||
mTextureView.beGoneIf(mConfig.openVideosOnSeparateScreen || mIsPanorama)
|
||||
|
@ -321,7 +382,10 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
private fun saveVideoProgress() {
|
||||
if (!videoEnded()) {
|
||||
if (mExoPlayer != null) {
|
||||
mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000)
|
||||
mConfig.saveLastVideoPosition(
|
||||
mMedium.path,
|
||||
mExoPlayer!!.currentPosition.toInt() / 1000
|
||||
)
|
||||
} else {
|
||||
mConfig.saveLastVideoPosition(mMedium.path, mPositionAtPause.toInt() / 1000)
|
||||
}
|
||||
|
@ -387,7 +451,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mPlayOnPrepared = true
|
||||
|
||||
val loadControl = DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(EXOPLAYER_MIN_BUFFER_MS, EXOPLAYER_MAX_BUFFER_MS, EXOPLAYER_MIN_BUFFER_MS, EXOPLAYER_MIN_BUFFER_MS)
|
||||
.setBufferDurationsMs(
|
||||
EXOPLAYER_MIN_BUFFER_MS,
|
||||
EXOPLAYER_MAX_BUFFER_MS,
|
||||
EXOPLAYER_MIN_BUFFER_MS,
|
||||
EXOPLAYER_MIN_BUFFER_MS
|
||||
)
|
||||
.setPrioritizeTimeOverSizeThresholds(true)
|
||||
.build()
|
||||
|
||||
|
@ -570,7 +639,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
|
||||
private fun showPlaybackSpeedPicker() {
|
||||
val fragment = PlaybackSpeedFragment()
|
||||
childFragmentManager.beginTransaction().add(fragment, fragment::class.java.simpleName).commit()
|
||||
childFragmentManager.beginTransaction().add(fragment, fragment::class.java.simpleName)
|
||||
.commit()
|
||||
fragment.setListener(this)
|
||||
}
|
||||
|
||||
|
@ -579,19 +649,28 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
if (isSlow != binding.bottomVideoTimeHolder.videoPlaybackSpeed.tag as? Boolean) {
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.tag = isSlow
|
||||
|
||||
val drawableId = if (isSlow) R.drawable.ic_playback_speed_slow_vector else R.drawable.ic_playback_speed_vector
|
||||
val drawableId =
|
||||
if (isSlow) R.drawable.ic_playback_speed_slow_vector else R.drawable.ic_playback_speed_vector
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed
|
||||
.setDrawablesRelativeWithIntrinsicBounds(AppCompatResources.getDrawable(requireContext(), drawableId))
|
||||
.setDrawablesRelativeWithIntrinsicBounds(
|
||||
AppCompatResources.getDrawable(
|
||||
requireContext(),
|
||||
drawableId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(speed)}x"
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text =
|
||||
"${DecimalFormat("#.##").format(speed)}x"
|
||||
mExoPlayer?.setPlaybackSpeed(speed)
|
||||
}
|
||||
|
||||
private fun getExtendedDetailsY(height: Int): Float {
|
||||
val smallMargin = context?.resources?.getDimension(org.fossify.commons.R.dimen.small_margin) ?: return 0f
|
||||
val fullscreenOffset = smallMargin + if (mIsFullscreen) 0 else requireContext().navigationBarHeight
|
||||
val smallMargin =
|
||||
context?.resources?.getDimension(org.fossify.commons.R.dimen.small_margin) ?: return 0f
|
||||
val fullscreenOffset =
|
||||
smallMargin + if (mIsFullscreen) 0 else requireContext().navigationBarHeight
|
||||
var actionsHeight = 0f
|
||||
if (!mIsFullscreen) {
|
||||
if (binding.bottomVideoTimeHolder.root.children.any { isVisible }) {
|
||||
|
@ -623,9 +702,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
val curr = mExoPlayer!!.currentPosition
|
||||
val newProgress = if (forward) curr + FAST_FORWARD_VIDEO_MS else curr - FAST_FORWARD_VIDEO_MS
|
||||
val newProgress =
|
||||
if (forward) curr + FAST_FORWARD_VIDEO_MS else curr - FAST_FORWARD_VIDEO_MS
|
||||
val roundProgress = Math.round(newProgress / 1000f)
|
||||
val limitedProgress = Math.max(Math.min(mExoPlayer!!.duration.toInt() / 1000, roundProgress), 0)
|
||||
val limitedProgress =
|
||||
Math.max(Math.min(mExoPlayer!!.duration.toInt() / 1000, roundProgress), 0)
|
||||
setPosition(limitedProgress)
|
||||
if (!mIsPlaying) {
|
||||
togglePlayPause()
|
||||
|
@ -734,7 +815,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mPlayPauseButton.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoToggleMute.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.beVisible()
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(mConfig.playbackSpeed)}x"
|
||||
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text =
|
||||
"${DecimalFormat("#.##").format(mConfig.playbackSpeed)}x"
|
||||
}
|
||||
|
||||
mWasVideoStarted = true
|
||||
|
|
Loading…
Reference in a new issue