Skip to content

Commit

Permalink
Fix bug 190: Brightness & Volume gestures only work when controls are… (
Browse files Browse the repository at this point in the history
#200)

* Fix bug 190: Brightness & Volume gestures only work when controls are displayed
  • Loading branch information
tungnk123 authored Oct 19, 2024
1 parent d3e854a commit ca92e34
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsIgnoringVisibility
Expand Down Expand Up @@ -79,15 +77,14 @@ import com.m3u.feature.channel.MaskCenterState.Play
import com.m3u.feature.channel.MaskCenterState.Replay
import com.m3u.feature.channel.components.MaskTextButton
import com.m3u.feature.channel.components.PlayerMask
import com.m3u.feature.channel.components.VerticalGestureArea
import com.m3u.i18n.R.string
import com.m3u.material.components.mask.MaskButton
import com.m3u.material.components.mask.MaskCircleButton
import com.m3u.material.components.mask.MaskPanel
import com.m3u.material.components.mask.MaskState
import com.m3u.material.effects.currentBackStackEntry
import com.m3u.material.ktx.tv
import com.m3u.material.ktx.thenIf
import com.m3u.material.ktx.tv
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.FontFamilies
import com.m3u.ui.Image
Expand All @@ -105,6 +102,7 @@ import kotlin.time.toDuration
internal fun ChannelMask(
cover: String,
title: String,
gesture: MaskGesture?,
playlistTitle: String,
playerState: PlayerState,
volume: Float,
Expand All @@ -120,8 +118,7 @@ internal fun ChannelMask(
openOrClosePanel: () -> Unit,
onEnterPipMode: () -> Unit,
onVolume: (Float) -> Unit,
onBrightness: (Float) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
) {
val preferences = hiltPreferences()
val helper = LocalHelper.current
Expand All @@ -134,7 +131,6 @@ internal fun ChannelMask(
LocalOnBackPressedDispatcherOwner.current
).onBackPressedDispatcher

var gesture: MaskGesture? by remember { mutableStateOf(null) }

// because they will be updated frequently,
// they must be wrapped with rememberUpdatedState when using them.
Expand All @@ -147,7 +143,6 @@ internal fun ChannelMask(
muted -> stringResource(string.feat_channel_tooltip_unmute)
else -> stringResource(string.feat_channel_tooltip_mute)
}

val brightnessOrVolumeText by remember {
derivedStateOf {
when (gesture) {
Expand Down Expand Up @@ -221,9 +216,12 @@ internal fun ChannelMask(
}
}

Box {
Box(
modifier = modifier.fillMaxSize()
) {
MaskPanel(
state = maskState
state = maskState,
modifier = Modifier.align(Alignment.Center)
)

PlayerMask(
Expand Down Expand Up @@ -324,36 +322,6 @@ internal fun ChannelMask(
.fillMaxSize()
.windowInsetsPadding(WindowInsets.systemBarsIgnoringVisibility)
) {
VerticalGestureArea(
percent = currentBrightness,
onDragStart = {
maskState.lock(MaskGesture.BRIGHTNESS)
gesture = MaskGesture.BRIGHTNESS
},
onDragEnd = {
maskState.unlock(MaskGesture.BRIGHTNESS, 400.milliseconds)
gesture = null
},
onDrag = onBrightness,
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.18f)
)
VerticalGestureArea(
percent = currentVolume,
onDragStart = {
maskState.lock(MaskGesture.VOLUME)
gesture = MaskGesture.VOLUME
},
onDragEnd = {
maskState.unlock(MaskGesture.VOLUME, 400.milliseconds)
gesture = null
},
onDrag = onVolume,
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.18f)
)
}
val maskCenterState = MaskCenterState.of(
playerState.playState,
Expand Down Expand Up @@ -560,8 +528,8 @@ internal fun ChannelMask(
}
}
},
modifier = modifier
)

}
}

Expand All @@ -572,7 +540,7 @@ private fun MaskCenterButton(
modifier: Modifier = Modifier,
onPlay: () -> Unit,
onPause: () -> Unit,
onRetry: () -> Unit
onRetry: () -> Unit,
) {
Box(modifier, contentAlignment = Alignment.Center) {
when (maskCenterState) {
Expand Down Expand Up @@ -610,7 +578,7 @@ private enum class MaskCenterState {
isPlaying: Boolean,
alwaysShowReplay: Boolean,
isPanelExpanded: Boolean,
playerError: Exception?
playerError: Exception?,
): MaskCenterState? = when {
isPanelExpanded -> null
playState == Player.STATE_BUFFERING -> Loading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@ import android.content.Intent
import android.graphics.Rect
import android.net.Uri
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.VolumeDown
import androidx.compose.material.icons.automirrored.rounded.VolumeOff
import androidx.compose.material.icons.automirrored.rounded.VolumeUp
import androidx.compose.material.icons.rounded.DarkMode
import androidx.compose.material.icons.rounded.LightMode
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
Expand All @@ -34,14 +43,17 @@ import com.m3u.data.database.model.Playlist
import com.m3u.feature.channel.components.CoverPlaceholder
import com.m3u.feature.channel.components.DlnaDevicesBottomSheet
import com.m3u.feature.channel.components.FormatsBottomSheet
import com.m3u.feature.channel.components.MaskGestureValuePanel
import com.m3u.feature.channel.components.PlayerPanel
import com.m3u.feature.channel.components.VerticalGestureArea
import com.m3u.i18n.R.string
import com.m3u.material.components.Background
import com.m3u.material.components.PullPanelLayout
import com.m3u.material.components.PullPanelLayoutValue
import com.m3u.material.components.mask.MaskInterceptor
import com.m3u.material.components.mask.MaskState
import com.m3u.material.components.mask.rememberMaskState
import com.m3u.material.components.mask.toggle
import com.m3u.material.components.rememberPullPanelLayoutState
import com.m3u.material.ktx.checkPermissionOrRationale
import com.m3u.ui.Player
Expand Down Expand Up @@ -159,7 +171,8 @@ fun ChannelRoute(

Background(
color = Color.Black,
contentColor = Color.White
contentColor = Color.White,
modifier = modifier
) {
PullPanelLayout(
state = pullPanelLayoutState,
Expand Down Expand Up @@ -192,7 +205,7 @@ fun ChannelRoute(
viewModel.onRemindProgramme(it)
}
},
onCancelRemindProgramme = viewModel::onCancelRemindProgramme
onCancelRemindProgramme = viewModel::onCancelRemindProgramme,
)
},
content = {
Expand Down Expand Up @@ -229,7 +242,6 @@ fun ChannelRoute(
maskState.unlockAll()
pullPanelLayoutState.collapse()
},
modifier = modifier
)
}
)
Expand Down Expand Up @@ -291,8 +303,16 @@ private fun ChannelPlayer(
val cover = channel?.cover.orEmpty()
val playlistTitle = playlist?.title ?: "--"
val favourite = channel?.favourite ?: false

var gesture: MaskGesture? by remember { mutableStateOf(null) }
val currentBrightness by rememberUpdatedState(brightness)
val currentVolume by rememberUpdatedState(volume)
val preferences = hiltPreferences()
var isBrightnessValueChange by remember {
mutableStateOf(false)
}
var isVolumeValueChange by remember {
mutableStateOf(false)
}

Background(
color = Color.Black,
Expand All @@ -308,6 +328,40 @@ private fun ChannelPlayer(
state = state,
modifier = Modifier.fillMaxSize()
)
VerticalGestureArea(
percent = currentBrightness,
onDragStart = {
gesture = MaskGesture.BRIGHTNESS
isBrightnessValueChange = true
},
onDragEnd = {
gesture = null
isBrightnessValueChange = false
},
onDrag = onBrightness,
onClick = maskState::toggle,
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.18f)
)

VerticalGestureArea(
percent = currentVolume,
onDragStart = {
gesture = MaskGesture.VOLUME
isVolumeValueChange = true
},
onDragEnd = {
gesture = null
isVolumeValueChange = false
},
onDrag = onVolume,
onClick = maskState::toggle,
modifier = Modifier
.align(Alignment.TopEnd)
.fillMaxHeight()
.fillMaxWidth(0.18f)
)

val shouldShowPlaceholder =
!preferences.noPictureMode && cover.isNotEmpty() && playerState.videoSize.isEmpty
Expand Down Expand Up @@ -335,15 +389,37 @@ private fun ChannelPlayer(
openChooseFormat = openChooseFormat,
openOrClosePanel = openOrClosePanel,
onVolume = onVolume,
onBrightness = onBrightness,
onEnterPipMode = onEnterPipMode,
gesture = gesture
)

if (gesture != null) {
MaskGestureValuePanel(
value = when (gesture) {
MaskGesture.BRIGHTNESS -> "${currentBrightness.times(100).toInt()}%"
else -> "${currentVolume.times(100).toInt()}"
},
icon = when (gesture) {
MaskGesture.BRIGHTNESS -> when {
brightness < 0.5f -> Icons.Rounded.DarkMode
else -> Icons.Rounded.LightMode
}

else -> when {
volume == 0f -> Icons.AutoMirrored.Rounded.VolumeOff
volume < 0.5f -> Icons.AutoMirrored.Rounded.VolumeDown
else -> Icons.AutoMirrored.Rounded.VolumeUp
}
},
modifier = Modifier.align(Alignment.Center)
)
}

LaunchedEffect(playerState.playerError) {
if (playerState.playerError != null) {
maskState.wake()
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.m3u.feature.channel.components

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.tv.material3.MaterialTheme
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.MonoText

@Composable
internal fun MaskGestureValuePanel(
icon: ImageVector,
value: String,
modifier: Modifier = Modifier,
) {
val spacing = LocalSpacing.current
Surface(
modifier = modifier
.clip(shape = RoundedCornerShape(10.dp)),
color = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface
) {
Row(
modifier = Modifier.padding(vertical = 5.dp, horizontal = 10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = icon,
contentDescription = "icon-gesture",
modifier = Modifier.size(24.dp),
)
Spacer(modifier = Modifier.width(spacing.extraSmall))
MonoText(
text = value, fontSize = 14.sp
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import com.m3u.material.components.IconButton
import com.m3u.material.components.mask.MaskState
import com.m3u.material.ktx.tv
import com.m3u.material.ktx.thenIf
import com.m3u.material.ktx.tv
import com.m3u.ui.FontFamilies

@Composable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.m3u.feature.channel.components

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand Down
Loading

0 comments on commit ca92e34

Please sign in to comment.