Rearrange playback controller buttons (#1366)

## Description
- Moves the audio track selection out of the menu as a button
- Combines the settings & more buttons into one dialog

All functionality works the same, this is just UI changes

### Related issues
Related to #528

### Testing
Emulator, it's just UI changes

## Screenshots

### Before
<img width="1280" height="720" alt="controller_before Large"
src="https://github.com/user-attachments/assets/40430408-2108-4eda-9f05-d5f8c22a8b01"
/>

### After
<img width="1280" height="720" alt="controller_update Large"
src="https://github.com/user-attachments/assets/d2623a7c-9c05-4b0f-ae57-fed1c37e6cbc"
/>


## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-05-11 10:22:27 -04:00 committed by GitHub
parent df71baccea
commit cb46aa4159
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 78 deletions

View file

@ -43,7 +43,7 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
import kotlin.time.Duration import kotlin.time.Duration
enum class PlaybackDialogType { enum class PlaybackDialogType {
MORE, DEBUG,
CAPTIONS, CAPTIONS,
SETTINGS, SETTINGS,
AUDIO, AUDIO,
@ -86,28 +86,8 @@ fun PlaybackDialog(
onChangeSubtitleDelay: (Duration) -> Unit, onChangeSubtitleDelay: (Duration) -> Unit,
) { ) {
when (type) { when (type) {
PlaybackDialogType.MORE -> { PlaybackDialogType.DEBUG -> {
val options = throw IllegalStateException("Should not open a dialog with " + PlaybackDialogType.DEBUG)
buildList {
add(
BottomDialogItem(
data = 0,
headline = stringResource(if (settings.showDebugInfo) R.string.hide_debug_info else R.string.show_debug_info),
supporting = null,
),
)
}
BottomDialog(
choices = options,
onDismissRequest = {
onDismissRequest.invoke()
// focusRequester.tryRequestFocus()
},
onSelectChoice = { index, choice ->
onPlaybackActionClick.invoke(PlaybackAction.ShowDebug)
},
gravity = Gravity.START,
)
} }
PlaybackDialogType.CAPTIONS -> { PlaybackDialogType.CAPTIONS -> {
@ -138,17 +118,8 @@ fun PlaybackDialog(
} }
PlaybackDialogType.SETTINGS -> { PlaybackDialogType.SETTINGS -> {
val currentAudio =
remember(settings) { settings.audioStreams.firstOrNull { it.index == settings.audioIndex } }
val options = val options =
buildList { buildList {
add(
BottomDialogItem(
data = PlaybackDialogType.AUDIO,
headline = stringResource(R.string.audio),
supporting = currentAudio?.displayTitle,
),
)
add( add(
BottomDialogItem( BottomDialogItem(
data = PlaybackDialogType.PLAYBACK_SPEED, data = PlaybackDialogType.PLAYBACK_SPEED,
@ -177,15 +148,26 @@ fun PlaybackDialog(
), ),
) )
} }
add(
BottomDialogItem(
data = PlaybackDialogType.DEBUG,
headline = stringResource(if (settings.showDebugInfo) R.string.hide_debug_info else R.string.show_debug_info),
supporting = null,
),
)
} }
BottomDialog( BottomDialog(
choices = options, choices = options,
currentChoice = null, currentChoice = null,
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
onSelectChoice = { _, choice -> onSelectChoice = { _, choice ->
if (choice.data == PlaybackDialogType.DEBUG) {
onPlaybackActionClick.invoke(PlaybackAction.ShowDebug)
} else {
onClickPlaybackDialogType(choice.data) onClickPlaybackDialogType(choice.data)
}
}, },
gravity = Gravity.END, gravity = Gravity.START,
) )
} }
@ -196,10 +178,6 @@ fun PlaybackDialog(
onDismissRequest = { onDismissRequest = {
onControllerInteraction.invoke() onControllerInteraction.invoke()
onDismissRequest.invoke() onDismissRequest.invoke()
// scope.launch {
// delay(250L)
// settingsFocusRequester.tryRequestFocus()
// }
}, },
onSelectChoice = { _, choice -> onSelectChoice = { _, choice ->
onPlaybackActionClick.invoke(PlaybackAction.ToggleAudio(choice.index)) onPlaybackActionClick.invoke(PlaybackAction.ToggleAudio(choice.index))
@ -223,15 +201,11 @@ fun PlaybackDialog(
onDismissRequest = { onDismissRequest = {
onControllerInteraction.invoke() onControllerInteraction.invoke()
onDismissRequest.invoke() onDismissRequest.invoke()
// scope.launch {
// delay(250L)
// settingsFocusRequester.tryRequestFocus()
// }
}, },
onSelectChoice = { _, value -> onSelectChoice = { _, value ->
onPlaybackActionClick.invoke(PlaybackAction.PlaybackSpeed(value.data)) onPlaybackActionClick.invoke(PlaybackAction.PlaybackSpeed(value.data))
}, },
gravity = Gravity.END, gravity = Gravity.START,
) )
} }
@ -250,15 +224,11 @@ fun PlaybackDialog(
onDismissRequest = { onDismissRequest = {
onControllerInteraction.invoke() onControllerInteraction.invoke()
onDismissRequest.invoke() onDismissRequest.invoke()
// scope.launch {
// delay(250L)
// settingsFocusRequester.tryRequestFocus()
// }
}, },
onSelectChoice = { _, choice -> onSelectChoice = { _, choice ->
onPlaybackActionClick.invoke(PlaybackAction.Scale(choice.data)) onPlaybackActionClick.invoke(PlaybackAction.Scale(choice.data))
}, },
gravity = Gravity.END, gravity = Gravity.START,
) )
} }

View file

@ -660,7 +660,15 @@ fun PlaybackPageContent(
playbackSpeedEnabled = playerBackend == PlayerBackend.MPV || currentPlayback?.audioDecoder != null, playbackSpeedEnabled = playerBackend == PlayerBackend.MPV || currentPlayback?.audioDecoder != null,
), ),
onDismissRequest = { onDismissRequest = {
playbackDialog = null playbackDialog =
when (type) {
// Go back to settings dialog
PlaybackDialogType.PLAYBACK_SPEED,
PlaybackDialogType.VIDEO_SCALE,
-> PlaybackDialogType.SETTINGS
else -> null
}
if (controllerViewState.controlsVisible) { if (controllerViewState.controlsVisible) {
controllerViewState.pulseControls() controllerViewState.pulseControls()
} }

View file

@ -23,7 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@ -225,10 +224,6 @@ fun Controller(
) )
} }
} }
// TODO need to move these up a level?
val moreFocusRequester = remember { FocusRequester() }
val captionFocusRequester = remember { FocusRequester() }
val settingsFocusRequester = remember { FocusRequester() }
PlaybackControls( PlaybackControls(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
player = player, player = player,
@ -248,9 +243,6 @@ fun Controller(
skipBackOnResume = skipBackOnResume, skipBackOnResume = skipBackOnResume,
currentSegment = currentSegment, currentSegment = currentSegment,
onClickPlaybackDialogType = onClickPlaybackDialogType, onClickPlaybackDialogType = onClickPlaybackDialogType,
moreFocusRequester = moreFocusRequester,
captionFocusRequester = captionFocusRequester,
settingsFocusRequester = settingsFocusRequester,
) )
} }
} }

View file

@ -129,9 +129,6 @@ fun PlaybackControls(
controllerViewState: ControllerViewState, controllerViewState: ControllerViewState,
onPlaybackActionClick: (PlaybackAction) -> Unit, onPlaybackActionClick: (PlaybackAction) -> Unit,
onClickPlaybackDialogType: (PlaybackDialogType) -> Unit, onClickPlaybackDialogType: (PlaybackDialogType) -> Unit,
moreFocusRequester: FocusRequester,
captionFocusRequester: FocusRequester,
settingsFocusRequester: FocusRequester,
onSeekProgress: (Long) -> Unit, onSeekProgress: (Long) -> Unit,
showPlay: Boolean, showPlay: Boolean,
previousEnabled: Boolean, previousEnabled: Boolean,
@ -186,7 +183,6 @@ fun PlaybackControls(
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
LeftPlaybackButtons( LeftPlaybackButtons(
moreFocusRequester = moreFocusRequester,
onControllerInteraction = onControllerInteraction, onControllerInteraction = onControllerInteraction,
onClickPlaybackDialogType = onClickPlaybackDialogType, onClickPlaybackDialogType = onClickPlaybackDialogType,
modifier = Modifier.align(Alignment.CenterStart), modifier = Modifier.align(Alignment.CenterStart),
@ -220,8 +216,6 @@ fun PlaybackControls(
) )
} }
RightPlaybackButtons( RightPlaybackButtons(
captionFocusRequester = captionFocusRequester,
settingsFocusRequester = settingsFocusRequester,
onControllerInteraction = onControllerInteraction, onControllerInteraction = onControllerInteraction,
onClickPlaybackDialogType = onClickPlaybackDialogType, onClickPlaybackDialogType = onClickPlaybackDialogType,
modifier = Modifier, modifier = Modifier,
@ -303,7 +297,6 @@ val buttonSpacing = 12.dp
@Composable @Composable
fun LeftPlaybackButtons( fun LeftPlaybackButtons(
moreFocusRequester: FocusRequester,
onControllerInteraction: () -> Unit, onControllerInteraction: () -> Unit,
onClickPlaybackDialogType: (PlaybackDialogType) -> Unit, onClickPlaybackDialogType: (PlaybackDialogType) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -312,24 +305,21 @@ fun LeftPlaybackButtons(
modifier = modifier.focusGroup(), modifier = modifier.focusGroup(),
horizontalArrangement = Arrangement.spacedBy(buttonSpacing), horizontalArrangement = Arrangement.spacedBy(buttonSpacing),
) { ) {
// More options
PlaybackButton( PlaybackButton(
iconRes = R.drawable.baseline_more_vert_96, iconRes = R.drawable.vector_settings,
onClick = { onClick = {
onControllerInteraction.invoke() onControllerInteraction.invoke()
onClickPlaybackDialogType.invoke(PlaybackDialogType.MORE) onClickPlaybackDialogType.invoke(PlaybackDialogType.SETTINGS)
}, },
enabled = true, enabled = true,
onControllerInteraction = onControllerInteraction, onControllerInteraction = onControllerInteraction,
modifier = Modifier.focusRequester(moreFocusRequester), modifier = Modifier,
) )
} }
} }
@Composable @Composable
fun RightPlaybackButtons( fun RightPlaybackButtons(
captionFocusRequester: FocusRequester,
settingsFocusRequester: FocusRequester,
onControllerInteraction: () -> Unit, onControllerInteraction: () -> Unit,
onClickPlaybackDialogType: (PlaybackDialogType) -> Unit, onClickPlaybackDialogType: (PlaybackDialogType) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -347,18 +337,18 @@ fun RightPlaybackButtons(
onClickPlaybackDialogType.invoke(PlaybackDialogType.CAPTIONS) onClickPlaybackDialogType.invoke(PlaybackDialogType.CAPTIONS)
}, },
onControllerInteraction = onControllerInteraction, onControllerInteraction = onControllerInteraction,
modifier = Modifier.focusRequester(captionFocusRequester), modifier = Modifier,
) )
// Playback speed, etc // Audio
PlaybackButton( PlaybackFaButton(
iconRes = R.drawable.vector_settings, enabled = true,
iconRes = R.string.fa_volume_high,
onClick = { onClick = {
onControllerInteraction.invoke() onControllerInteraction.invoke()
onClickPlaybackDialogType.invoke(PlaybackDialogType.SETTINGS) onClickPlaybackDialogType.invoke(PlaybackDialogType.AUDIO)
}, },
enabled = true,
onControllerInteraction = onControllerInteraction, onControllerInteraction = onControllerInteraction,
modifier = Modifier.focusRequester(settingsFocusRequester), modifier = Modifier,
) )
} }
} }
@ -625,7 +615,7 @@ private fun ButtonPreview() {
onControllerInteraction = {}, onControllerInteraction = {},
) )
PlaybackFaButton( PlaybackFaButton(
iconRes = R.string.fa_shuffle, iconRes = R.string.fa_volume_high,
onClick = {}, onClick = {},
onControllerInteraction = {}, onControllerInteraction = {},
textColor = Color.Green, textColor = Color.Green,