Add mute button to player controls

Closes https://github.com/FossifyOrg/Gallery/issues/171
This commit is contained in:
Naveen Singh 2024-09-08 01:24:43 +05:30
parent c5993234a7
commit dfac193974
No known key found for this signature in database
GPG key ID: 35F7D64346B28ED7
7 changed files with 110 additions and 3 deletions

View file

@ -16,6 +16,7 @@ import android.util.DisplayMetrics
import android.view.*
import android.widget.RelativeLayout
import android.widget.SeekBar
import androidx.appcompat.content.res.AppCompatResources
import androidx.media3.common.*
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.ContentDataSource
@ -60,6 +61,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
private var mVideoSize = Point(0, 0)
private var mTimerHandler = Handler()
private var mPlayWhenReadyHandler = Handler()
private var mVolumeController: VolumeController? = null
private var mIgnoreCloseDown = false
@ -117,6 +119,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
binding.bottomVideoTimeHolder.videoSeekbar.progress = 0
mTimerHandler.removeCallbacksAndMessages(null)
mPlayWhenReadyHandler.removeCallbacksAndMessages(null)
mVolumeController?.destroy()
}
}
@ -186,6 +189,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
binding.bottomVideoTimeHolder.videoDuration.setOnClickListener { doSkip(true) }
binding.bottomVideoTimeHolder.videoTogglePlayPause.setOnClickListener { togglePlayPause() }
binding.bottomVideoTimeHolder.videoPlaybackSpeed.setOnClickListener { showPlaybackSpeedPicker() }
binding.bottomVideoTimeHolder.videoToggleMute.setOnClickListener { mVolumeController?.toggleMute() }
binding.videoSurfaceFrame.setOnClickListener { toggleFullscreen() }
binding.videoSurfaceFrame.controller.settings.swallowDoubleTaps = true
@ -235,6 +239,12 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
}
mDragThreshold = DRAG_THRESHOLD * resources.displayMetrics.density
mVolumeController = VolumeController(this) { isMuted ->
val icon = if (isMuted) R.drawable.ic_vector_speaker_off else R.drawable.ic_vector_speaker_on
binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable(
AppCompatResources.getDrawable(this, icon)
)
}
}
private fun initExoPlayer() {
@ -306,6 +316,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
if (!mWasVideoStarted) {
binding.bottomVideoTimeHolder.videoTogglePlayPause.beVisible()
binding.bottomVideoTimeHolder.videoPlaybackSpeed.beVisible()
binding.bottomVideoTimeHolder.videoToggleMute.beVisible()
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(config.playbackSpeed)}x"
mDuration = (mExoPlayer!!.duration / 1000).toInt()
binding.bottomVideoTimeHolder.videoSeekbar.max = mDuration
@ -478,6 +489,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
binding.bottomVideoTimeHolder.videoTogglePlayPause,
binding.bottomVideoTimeHolder.videoNextFile,
binding.bottomVideoTimeHolder.videoPlaybackSpeed,
binding.bottomVideoTimeHolder.videoToggleMute,
binding.bottomVideoTimeHolder.videoCurrTime,
binding.bottomVideoTimeHolder.videoSeekbar,
binding.bottomVideoTimeHolder.videoDuration,
@ -491,6 +503,7 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
binding.bottomVideoTimeHolder.videoPrevFile,
binding.bottomVideoTimeHolder.videoNextFile,
binding.bottomVideoTimeHolder.videoPlaybackSpeed,
binding.bottomVideoTimeHolder.videoToggleMute,
binding.bottomVideoTimeHolder.videoCurrTime,
binding.bottomVideoTimeHolder.videoDuration,
).forEach {

View file

@ -13,6 +13,7 @@ import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.SeekBar
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.media3.common.*
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.ContentDataSource
@ -84,6 +85,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private lateinit var mPlayPauseButton: ImageView
private lateinit var mSeekBar: SeekBar
private var mVolumeController: VolumeController? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val context = requireContext()
val activity = requireActivity()
@ -98,6 +101,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
videoHolder.setOnClickListener { toggleFullscreen() }
videoPreview.setOnClickListener { toggleFullscreen() }
bottomVideoTimeHolder.videoPlaybackSpeed.setOnClickListener { showPlaybackSpeedPicker() }
bottomVideoTimeHolder.videoToggleMute.setOnClickListener { mVolumeController?.toggleMute() }
videoSurfaceFrame.controller.settings.swallowDoubleTaps = true
videoPlayOutline.setOnClickListener {
@ -240,6 +244,13 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
restoreLastVideoSavedPosition()
}
mVolumeController = VolumeController(context) { isMuted ->
val icon = if (isMuted) R.drawable.ic_vector_speaker_off else R.drawable.ic_vector_speaker_on
binding.bottomVideoTimeHolder.videoToggleMute.setImageDrawable(
AppCompatResources.getDrawable(context, icon)
)
}
return mView
}
@ -527,7 +538,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
binding.bottomVideoTimeHolder.videoCurrTime,
binding.bottomVideoTimeHolder.videoDuration,
binding.bottomVideoTimeHolder.videoTogglePlayPause,
binding.bottomVideoTimeHolder.videoPlaybackSpeed
binding.bottomVideoTimeHolder.videoPlaybackSpeed,
binding.bottomVideoTimeHolder.videoToggleMute
).forEach {
it.isClickable = !mIsFullscreen
}
@ -689,6 +701,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
if (!mWasVideoStarted) {
binding.videoPlayOutline.beGone()
mPlayPauseButton.beVisible()
binding.bottomVideoTimeHolder.videoToggleMute.beVisible()
binding.bottomVideoTimeHolder.videoPlaybackSpeed.beVisible()
binding.bottomVideoTimeHolder.videoPlaybackSpeed.text = "${DecimalFormat("#.##").format(mConfig.playbackSpeed)}x"
}
@ -790,6 +803,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private fun cleanup() {
pauseVideo()
releaseExoPlayer()
mVolumeController?.destroy()
if (mWasFragmentInit) {
mCurrTimeView.text = 0.getFormattedDuration()

View file

@ -0,0 +1,58 @@
package org.fossify.gallery.helpers
import android.content.Context
import android.database.ContentObserver
import android.media.AudioManager
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import org.fossify.gallery.extensions.audioManager
class VolumeController(
private val context: Context,
private val streamType: Int = AudioManager.STREAM_MUSIC,
private val onVolumeChanged: (isMuted: Boolean) -> Unit
) {
private var audioManager = context.audioManager
private var savedVolume = audioManager.getStreamMaxVolume(streamType) / 2
private val currentVolume: Int
get() = audioManager.getStreamVolume(streamType)
private val volumeObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
onVolumeChanged(isMuted())
}
}
init {
context.contentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, volumeObserver)
onVolumeChanged(isMuted())
}
private fun isMuted() = currentVolume == 0
private fun mute() {
savedVolume = audioManager.getStreamVolume(streamType)
audioManager.setStreamVolume(streamType, 0, 0)
}
private fun unmute() {
audioManager.setStreamVolume(streamType, savedVolume, 0)
}
fun toggleMute() {
if (isMuted()) {
unmute()
onVolumeChanged(false)
} else {
mute()
onVolumeChanged(true)
}
}
fun destroy() {
context.contentResolver.unregisterContentObserver(volumeObserver)
}
}

View file

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:autoMirrored="true" android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="@android:color/white" android:pathData="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c0.03-0.2 0.05-0.41 0.05-0.63zm2.5 0c0 0.94-0.2 1.82-0.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89 0.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-0.67 0.52-1.42 0.93-2.25 1.18v2.06c1.38-0.31 2.63-0.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>
</vector>

View file

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:autoMirrored="true" android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="@android:color/white" android:pathData="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-0.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89 0.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-0.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
</vector>

View file

@ -9,7 +9,7 @@
<TextView
android:id="@+id/video_playback_speed"
android:layout_width="wrap_content"
android:layout_width="@dimen/video_player_button_width"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/big_margin"
android:background="@drawable/darkened_automatic_circle_background"
@ -17,7 +17,6 @@
android:gravity="center"
android:paddingHorizontal="@dimen/normal_margin"
android:paddingVertical="@dimen/medium_margin"
android:shadowColor="@color/default_background_color"
android:textColor="@android:color/white"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_playback_speed_vector"
@ -113,4 +112,20 @@
app:layout_constraintTop_toTopOf="@+id/video_seekbar"
tools:text="00:00" />
<ImageView
android:id="@+id/video_toggle_mute"
android:layout_width="@dimen/video_player_button_width"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/big_margin"
android:background="@drawable/darkened_automatic_circle_background"
android:gravity="center"
android:paddingHorizontal="@dimen/normal_margin"
android:paddingVertical="@dimen/medium_margin"
android:src="@drawable/ic_vector_speaker_on"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/video_toggle_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/video_toggle_play_pause"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -11,6 +11,7 @@
<dimen name="tmb_shadow_height">70dp</dimen>
<dimen name="media_side_slider_width">60dp</dimen>
<dimen name="video_player_play_pause_size">60dp</dimen>
<dimen name="video_player_button_width">68dp</dimen>
<dimen name="list_view_folder_thumbnail_size">72dp</dimen>
<dimen name="bottom_actions_height">64dp</dimen>
<dimen name="bottom_actions_height_double">128dp</dimen>