@@ -5,15 +5,18 @@ package com.thewizrd.simplewear.ui.simplewear
55import android.content.Intent
66import androidx.compose.foundation.ExperimentalFoundationApi
77import androidx.compose.foundation.Image
8+ import androidx.compose.foundation.clickable
89import androidx.compose.foundation.layout.Box
910import androidx.compose.foundation.layout.Column
11+ import androidx.compose.foundation.layout.Row
1012import androidx.compose.foundation.layout.fillMaxSize
1113import androidx.compose.foundation.layout.fillMaxWidth
1214import androidx.compose.foundation.layout.padding
1315import androidx.compose.foundation.layout.size
1416import androidx.compose.foundation.layout.wrapContentHeight
1517import androidx.compose.foundation.pager.rememberPagerState
1618import androidx.compose.foundation.shape.CircleShape
19+ import androidx.compose.material.LinearProgressIndicator
1720import androidx.compose.runtime.Composable
1821import androidx.compose.runtime.CompositionLocalProvider
1922import androidx.compose.runtime.DisposableEffect
@@ -27,15 +30,19 @@ import androidx.compose.ui.draw.clip
2730import androidx.compose.ui.graphics.BlendMode
2831import androidx.compose.ui.graphics.Color
2932import androidx.compose.ui.graphics.ColorFilter
33+ import androidx.compose.ui.graphics.StrokeCap
3034import androidx.compose.ui.graphics.asImageBitmap
3135import androidx.compose.ui.graphics.vector.ImageVector
36+ import androidx.compose.ui.platform.LocalConfiguration
3237import androidx.compose.ui.platform.LocalContext
3338import androidx.compose.ui.platform.LocalLifecycleOwner
39+ import androidx.compose.ui.platform.LocalView
3440import androidx.compose.ui.res.painterResource
3541import androidx.compose.ui.res.stringResource
3642import androidx.compose.ui.res.vectorResource
3743import androidx.compose.ui.text.style.TextAlign
3844import androidx.compose.ui.text.style.TextOverflow
45+ import androidx.compose.ui.unit.Dp
3946import androidx.compose.ui.unit.dp
4047import androidx.core.content.ContextCompat
4148import androidx.core.graphics.drawable.toBitmap
@@ -46,6 +53,7 @@ import androidx.wear.ambient.AmbientLifecycleObserver
4653import androidx.wear.compose.foundation.SwipeToDismissBoxState
4754import androidx.wear.compose.foundation.lazy.items
4855import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
56+ import androidx.wear.compose.material.ButtonDefaults
4957import androidx.wear.compose.material.ChipDefaults
5058import androidx.wear.compose.material.CompactChip
5159import androidx.wear.compose.material.Icon
@@ -57,14 +65,16 @@ import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales
5765import com.google.android.horologist.annotations.ExperimentalHorologistApi
5866import com.google.android.horologist.audio.ui.VolumeUiState
5967import com.google.android.horologist.audio.ui.components.actions.SetVolumeButton
60- import com.google.android.horologist.audio.ui.components.animated.AnimatedSetVolumeButton
68+ import com.google.android.horologist.audio.ui.components.actions.SettingsButton
69+ import com.google.android.horologist.audio.ui.rotaryVolumeControlsWithFocus
6170import com.google.android.horologist.compose.ambient.AmbientAware
6271import com.google.android.horologist.compose.ambient.AmbientState
6372import com.google.android.horologist.compose.layout.ScalingLazyColumn
6473import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
6574import com.google.android.horologist.compose.layout.rememberResponsiveColumnState
6675import com.google.android.horologist.compose.layout.scrollAway
6776import com.google.android.horologist.compose.material.Chip
77+ import com.google.android.horologist.compose.rotaryinput.RotaryDefaults
6878import com.google.android.horologist.media.model.PlaybackStateEvent
6979import com.google.android.horologist.media.model.TimestampProvider
7080import com.google.android.horologist.media.ui.components.ControlButtonLayout
@@ -78,6 +88,7 @@ import com.google.android.horologist.media.ui.state.LocalTimestampProvider
7888import com.google.android.horologist.media.ui.state.mapper.TrackPositionUiModelMapper
7989import com.thewizrd.shared_resources.actions.ActionStatus
8090import com.thewizrd.shared_resources.actions.Actions
91+ import com.thewizrd.shared_resources.actions.AudioStreamState
8192import com.thewizrd.shared_resources.actions.AudioStreamType
8293import com.thewizrd.shared_resources.helpers.MediaHelper
8394import com.thewizrd.shared_resources.helpers.WearConnectionStatus
@@ -100,6 +111,7 @@ import com.thewizrd.simplewear.ui.theme.findActivity
100111import com.thewizrd.simplewear.viewmodels.WearableListenerViewModel
101112import kotlinx.coroutines.delay
102113import kotlinx.coroutines.launch
114+ import kotlin.math.sqrt
103115
104116@Composable
105117fun MediaPlayerUi (
@@ -346,6 +358,15 @@ private fun MediaPlayerControlsPage(
346358 navController.navigate(
347359 Screen .ValueAction .getRoute(Actions .VOLUME , AudioStreamType .MUSIC )
348360 )
361+ },
362+ onVolumeUp = {
363+ mediaPlayerViewModel.requestVolumeUp()
364+ },
365+ onVolumeDown = {
366+ mediaPlayerViewModel.requestVolumeDown()
367+ },
368+ onVolumeChange = {
369+ mediaPlayerViewModel.requestSetVolume(it)
349370 }
350371 )
351372
@@ -366,6 +387,9 @@ private fun MediaPlayerControlsPage(
366387 onSkipBack : () -> Unit = {},
367388 onSkipForward : () -> Unit = {},
368389 onVolume : () -> Unit = {},
390+ onVolumeUp : () -> Unit = {},
391+ onVolumeDown : () -> Unit = {},
392+ onVolumeChange : (Int ) -> Unit = {},
369393) {
370394 val volumeUiState = remember(uiState) {
371395 uiState.audioStreamState?.let {
@@ -413,7 +437,20 @@ private fun MediaPlayerControlsPage(
413437 loading = uiState.isLoading && ! isAmbient
414438 ) {
415439 PlayerScreen (
416- modifier = Modifier .ambientMode(ambientState),
440+ modifier = Modifier
441+ .ambientMode(ambientState)
442+ .run {
443+ if (! isAmbient && volumeUiState != null ) {
444+ this .rotaryVolumeControlsWithFocus(
445+ volumeUiStateProvider = { volumeUiState },
446+ onRotaryVolumeInput = onVolumeChange,
447+ localView = LocalView .current,
448+ isLowRes = RotaryDefaults .isLowResInput()
449+ )
450+ } else {
451+ this
452+ }
453+ },
417454 mediaDisplay = {
418455 if (uiState.isPlaybackLoading && ! isAmbient) {
419456 LoadingMediaDisplay ()
@@ -502,10 +539,48 @@ private fun MediaPlayerControlsPage(
502539 buttons = {
503540 if (! isAmbient) {
504541 if (volumeUiState != null ) {
505- AnimatedSetVolumeButton (
506- onVolumeClick = onVolume,
507- volumeUiState = volumeUiState
508- )
542+ val config = LocalConfiguration .current
543+ val inset = remember(config) {
544+ val isRound = config.isScreenRound
545+ val screenHeightDp = config.screenHeightDp
546+ var bottomInset = Dp (screenHeightDp - (screenHeightDp * 0.8733032f ))
547+
548+ if (isRound) {
549+ val screenWidthDp = config.smallestScreenWidthDp
550+ val maxSquareEdge =
551+ (sqrt(((screenHeightDp * screenWidthDp) / 2 ).toFloat()))
552+ bottomInset =
553+ Dp ((screenHeightDp - (maxSquareEdge * 0.8733032f )) / 2 )
554+ }
555+
556+ bottomInset
557+ }
558+
559+ Row (
560+ modifier = Modifier .padding(horizontal = inset)
561+ ) {
562+ SettingsButton (
563+ onClick = onVolumeDown,
564+ imageVector = ImageVector .vectorResource(id = R .drawable.ic_baseline_volume_down_24),
565+ contentDescription = stringResource(R .string.horologist_volume_screen_volume_down_content_description),
566+ tapTargetSize = ButtonDefaults .ExtraSmallButtonSize
567+ )
568+ LinearProgressIndicator (
569+ modifier = Modifier
570+ .weight(1f )
571+ .align(Alignment .CenterVertically )
572+ .clickable(onClick = onVolume),
573+ progress = volumeUiState.current.toFloat() / volumeUiState.max,
574+ color = MaterialTheme .colors.primary,
575+ strokeCap = StrokeCap .Round
576+ )
577+ SettingsButton (
578+ onClick = onVolumeUp,
579+ imageVector = ImageVector .vectorResource(id = R .drawable.ic_volume_up_white_24dp),
580+ contentDescription = stringResource(R .string.horologist_volume_screen_volume_up_content_description),
581+ tapTargetSize = ButtonDefaults .ExtraSmallButtonSize
582+ )
583+ }
509584 } else {
510585 SetVolumeButton (onVolumeClick = onVolume)
511586 }
@@ -807,7 +882,8 @@ private fun PreviewMediaControls() {
807882 title = " Title" ,
808883 artist = " Artist" ,
809884 artworkBitmap = background
810- )
885+ ),
886+ audioStreamState = AudioStreamState (5 , 0 , 10 , AudioStreamType .MUSIC )
811887 )
812888 }
813889
0 commit comments