Skip to content

Commit 0974143

Browse files
committed
Update to latest Horologist
Change-Id: Ie939e3538220769a76941b69c3c2253cb908e3fb
1 parent 122457f commit 0974143

File tree

13 files changed

+351
-148
lines changed

13 files changed

+351
-148
lines changed

Jetcaster/gradle/libs.versions.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ androidx-test-ext-junit = "1.2.1"
2424
androidx-test-ext-truth = "1.6.0"
2525
androidx-tv-foundation = "1.0.0-alpha12"
2626
androidx-tv-material = "1.0.0"
27-
androidx-wear-compose-material3 = "1.0.0-alpha35"
28-
androidx-wear-compose = "1.5.0-alpha12"
27+
androidx-wear-compose-material3 = "1.5.0-beta01"
28+
androidx-wear-compose = "1.5.0-beta01"
2929
androidx-window = "1.3.0"
3030
androidxHiltNavigationCompose = "1.2.0"
3131
androix-test-uiautomator = "2.3.0"
@@ -37,7 +37,8 @@ google-maps = "19.2.0"
3737
gradle-versions = "0.52.0"
3838
hilt = "2.56.2"
3939
hiltExt = "1.2.0"
40-
horologist = "0.7.11-alpha"
40+
horologist = "0.7.14-beta"
41+
# @pin When updating to AGP 7.4.0-alpha10 and up we can update this https://developer.android.com/studio/write/java8-support#library-desugaring-versions
4142
jdkDesugar = "2.1.5"
4243
junit = "4.13.2"
4344
kotlin = "2.1.20"
@@ -60,6 +61,7 @@ spotless = "7.0.3"
6061
targetSdk = "33"
6162
version-catalog-update = "1.0.0"
6263
material3Android = "1.3.1"
64+
media3CommonKtx = "1.7.1"
6365

6466
[libraries]
6567
accompanist-adaptive = { module = "com.google.accompanist:accompanist-adaptive", version.ref = "accompanist" }
@@ -139,6 +141,7 @@ hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", vers
139141
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
140142
hilt-ext-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hiltExt" }
141143
horologist-audio-ui = { module = "com.google.android.horologist:horologist-audio-ui", version.ref = "horologist" }
144+
horologist-audio-uimaterial3 = { module = "com.google.android.horologist:horologist-audio-ui-material3", version.ref = "horologist" }
142145
horologist-audio-ui-model = { module = "com.google.android.horologist:horologist-audio-ui-model", version.ref = "horologist" }
143146
horologist-composables = { module = "com.google.android.horologist:horologist-composables", version.ref = "horologist" }
144147
horologist-compose-layout = { module = "com.google.android.horologist:horologist-compose-layout", version.ref = "horologist" }
@@ -147,6 +150,7 @@ horologist-compose-tools = { module = "com.google.android.horologist:horologist-
147150
horologist-images-coil = { module = "com.google.android.horologist:horologist-images-coil", version.ref = "horologist" }
148151
horologist-media-data = { module = "com.google.android.horologist:horologist-media-data", version.ref = "horologist" }
149152
horologist-media-ui = { module = "com.google.android.horologist:horologist-media-ui", version.ref = "horologist" }
153+
horologist-media-uimaterial3 = { module = "com.google.android.horologist:horologist-media-ui-material3", version.ref = "horologist" }
150154
horologist-media-ui-model = { module = "com.google.android.horologist:horologist-media-ui-model", version.ref = "horologist" }
151155
horologist-roboscreenshots = { module = "com.google.android.horologist:horologist-roboscreenshots", version.ref = "horologist" }
152156
junit = { module = "junit:junit", version.ref = "junit" }
@@ -167,6 +171,7 @@ rometools-rome = { module = "com.rometools:rome", version.ref = "rome" }
167171
androidx-media3-session = {module = "androidx.media3:media3-session",version.ref = "media3"}
168172
androidx-media3-exoplayer = {module = "androidx.media3:media3-exoplayer", version.ref = "media3"}
169173
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
174+
androidx-media3-common-ktx = { group = "androidx.media3", name = "media3-common-ktx", version.ref = "media3CommonKtx" }
170175

171176
[plugins]
172177
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }

Jetcaster/wear/build.gradle

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ android {
7575

7676
dependencies {
7777

78+
implementation libs.androidx.media3.common.ktx
7879
def composeBom = platform(libs.androidx.compose.bom)
7980

8081
// General compose dependencies
@@ -100,15 +101,19 @@ dependencies {
100101
implementation(libs.androidx.material.icons.core)
101102
implementation(libs.androidx.compose.material.iconsExtended)
102103

104+
implementation(libs.androidx.media3.exoplayer)
105+
implementation(libs.androidx.media3.ui.compose)
106+
implementation(libs.androidx.media3.session)
107+
103108
// Horologist for correct Compose layout
104-
implementation libs.horologist.composables
105109
implementation libs.horologist.compose.layout
106-
implementation libs.horologist.compose.material
107110

108111
//Horologist Media toolkit
109112
implementation libs.horologist.media.ui
113+
implementation libs.horologist.media.uimaterial3
110114
implementation libs.horologist.media.ui.model
111115
implementation libs.horologist.audio.ui
116+
implementation libs.horologist.audio.uimaterial3
112117
implementation libs.horologist.audio.ui.model
113118
implementation libs.horologist.media.data
114119
implementation libs.horologist.images.coil

Jetcaster/wear/src/main/java/com/example/jetcaster/WearApp.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import androidx.wear.compose.navigation.composable
3030
import androidx.wear.compose.foundation.pager.rememberPagerState
3131
import androidx.wear.compose.material3.AppScaffold
3232
import androidx.wear.compose.material3.ScreenScaffold
33-
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
3433
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
3534
import com.example.jetcaster.theme.WearAppTheme
3635
import com.example.jetcaster.ui.Episode
@@ -50,12 +49,12 @@ import com.example.jetcaster.ui.player.PlayerScreen
5049
import com.example.jetcaster.ui.podcast.PodcastDetailsScreen
5150
import com.example.jetcaster.ui.podcasts.PodcastsScreen
5251
import com.example.jetcaster.ui.queue.QueueScreen
53-
import com.google.android.horologist.audio.ui.VolumeScreen
52+
import com.google.android.horologist.audio.ui.material3.VolumeScreen
5453
import com.google.android.horologist.audio.ui.VolumeViewModel
55-
import com.google.android.horologist.media.ui.navigation.MediaNavController.navigateToPlayer
56-
import com.google.android.horologist.media.ui.navigation.MediaNavController.navigateToVolume
57-
import com.google.android.horologist.media.ui.navigation.NavigationScreens
58-
import com.google.android.horologist.media.ui.screens.playerlibrarypager.PlayerLibraryPagerScreen
54+
import com.google.android.horologist.media.ui.material3.navigation.MediaNavController.navigateToPlayer
55+
import com.google.android.horologist.media.ui.material3.navigation.MediaNavController.navigateToVolume
56+
import com.google.android.horologist.media.ui.material3.navigation.NavigationScreens
57+
import com.google.android.horologist.media.ui.material3.screens.playerlibrarypager.PlayerLibraryPagerScreen
5958

6059
@Composable
6160
fun WearApp(navController: NavHostController) {

Jetcaster/wear/src/main/java/com/example/jetcaster/theme/ColorScheme.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ import com.example.jetcaster.designsystem.theme.tertiaryDark
4444

4545
internal val wearColorPalette: ColorScheme = ColorScheme(
4646
primary = primaryDark,
47+
primaryDim= primaryDark,
4748
onPrimary = Color(0xFF542104),
4849
primaryContainer = primaryContainerDark,
4950
onPrimaryContainer = onPrimaryContainerDark,
5051
secondary = secondaryDark,
52+
secondaryDim = secondaryDark,
5153
onSecondary = onSecondaryDark,
5254
secondaryContainer = secondaryContainerDark,
5355
onSecondaryContainer = onSecondaryContainerDark,

Jetcaster/wear/src/main/java/com/example/jetcaster/ui/JetcasterNavController.kt

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,80 @@
1616

1717
package com.example.jetcaster.ui
1818

19-
import com.google.android.horologist.media.ui.navigation.NavigationScreen
20-
import kotlinx.serialization.Serializable
19+
import android.net.Uri
20+
import androidx.navigation.NamedNavArgument
21+
import androidx.navigation.NavController
22+
import androidx.navigation.NavType
23+
import androidx.navigation.navArgument
24+
import com.google.android.horologist.media.ui.material3.navigation.MediaNavController.navigateToPlayer
25+
import com.google.android.horologist.media.ui.material3.navigation.MediaNavController.navigateToVolume
26+
import com.google.android.horologist.media.ui.material3.navigation.NavigationScreens
27+
import com.google.android.horologist.media.ui.material3.screens.playerlibrarypager.PlayerLibraryPagerScreen
2128

22-
@Serializable
23-
data object YourPodcasts : NavigationScreen
29+
/**
30+
* NavController extensions that links to the screens of the Jetcaster app.
31+
*/
32+
public object JetcasterNavController {
33+
34+
public fun NavController.navigateToYourPodcast() {
35+
navigate(YourPodcasts.destination())
36+
}
37+
38+
public fun NavController.navigateToLatestEpisode() {
39+
navigate(LatestEpisodes.destination())
40+
}
41+
42+
public fun NavController.navigateToPodcastDetails(podcastUri: String) {
43+
navigate(PodcastDetails.destination(podcastUri))
44+
}
45+
46+
public fun NavController.navigateToUpNext() {
47+
navigate(UpNext.destination())
48+
}
49+
50+
public fun NavController.navigateToEpisode(episodeUri: String) {
51+
navigate(Episode.destination(episodeUri))
52+
}
53+
}
54+
55+
public object YourPodcasts : NavigationScreens("yourPodcasts") {
56+
public fun destination(): String = navRoute
57+
}
58+
59+
public object LatestEpisodes : NavigationScreens("latestEpisodes") {
60+
public fun destination(): String = navRoute
61+
}
62+
63+
public object PodcastDetails : NavigationScreens("podcast?podcastUri={podcastUri}") {
64+
public const val PODCAST_URI: String = "podcastUri"
65+
public fun destination(podcastUri: String): String {
66+
val encodedUri = Uri.encode(podcastUri)
67+
return "podcast?$PODCAST_URI=$encodedUri"
68+
}
2469

25-
@Serializable
26-
data object LatestEpisodes : NavigationScreen
70+
override val arguments: List<NamedNavArgument>
71+
get() = listOf(
72+
navArgument(PODCAST_URI) {
73+
type = NavType.StringType
74+
},
75+
)
76+
}
2777

28-
@Serializable
29-
data class PodcastDetails(val podcastUri: String) : NavigationScreen
78+
public object Episode : NavigationScreens("episode?episodeUri={episodeUri}") {
79+
public const val EPISODE_URI: String = "episodeUri"
80+
public fun destination(episodeUri: String): String {
81+
val encodedUri = Uri.encode(episodeUri)
82+
return "episode?$EPISODE_URI=$encodedUri"
83+
}
3084

31-
@Serializable
32-
data class Episode(val episodeUri: String) : NavigationScreen
85+
override val arguments: List<NamedNavArgument>
86+
get() = listOf(
87+
navArgument(EPISODE_URI) {
88+
type = NavType.StringType
89+
},
90+
)
91+
}
3392

34-
@Serializable
35-
data object UpNext : NavigationScreen
93+
public object UpNext : NavigationScreens("upNext") {
94+
public fun destination(): String = navRoute
95+
}

Jetcaster/wear/src/main/java/com/example/jetcaster/ui/components/PlaceholderButton.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier
3333
import androidx.compose.ui.draw.clip
3434
import androidx.compose.ui.graphics.vector.ImageVector
3535
import androidx.compose.ui.unit.dp
36+
import androidx.wear.compose.material.ExperimentalWearMaterialApi
3637
import androidx.wear.compose.material3.Button
3738
import androidx.wear.compose.material3.ButtonDefaults
3839
import androidx.wear.compose.material3.FilledTonalButton
@@ -46,20 +47,21 @@ import com.google.android.horologist.annotations.ExperimentalHorologistApi
4647
/**
4748
* A placeholder chip to be displayed while the contents of the [Button] is being loaded.
4849
*/
50+
@OptIn(ExperimentalWearMaterialApi::class)
4951
@ExperimentalHorologistApi
5052
@Composable
5153
fun PlaceholderButton(
5254
modifier: Modifier = Modifier,
5355
onClick: () -> Unit = {},
54-
placeholderState: PlaceholderState = rememberPlaceholderState { false },
56+
placeholderState: PlaceholderState = rememberPlaceholderState(false),
5557
secondaryLabel: Boolean = true,
5658
icon: Boolean = true
5759
) {
5860
var labelText by remember { mutableStateOf("") }
5961
var imageVector: ImageVector? by remember { mutableStateOf(null) }
60-
val buttonPlaceholderState = rememberPlaceholderState {
62+
val buttonPlaceholderState = rememberPlaceholderState (
6163
labelText.isNotEmpty() && imageVector != null
62-
}
64+
)
6365
FilledTonalButton(
6466
onClick = { onClick },
6567
enabled = true,
@@ -100,11 +102,6 @@ fun PlaceholderButton(
100102
} else {
101103
null
102104
},
103-
colors =
104-
PlaceholderDefaults.placeholderButtonColors(
105-
originalButtonColors = ButtonDefaults.buttonColors(),
106-
placeholderState = buttonPlaceholderState
107-
),
108105
modifier = modifier.fillMaxWidth()
109106
.placeholderShimmer(buttonPlaceholderState)
110107
)

Jetcaster/wear/src/main/java/com/example/jetcaster/ui/components/SettingsButtons.kt

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package com.example.jetcaster.ui.components
1818

1919
import androidx.compose.foundation.layout.Arrangement
20+
import androidx.compose.foundation.layout.Box
2021
import androidx.compose.foundation.layout.Row
22+
import androidx.compose.foundation.layout.fillMaxHeight
2123
import androidx.compose.foundation.layout.fillMaxWidth
2224
import androidx.compose.runtime.Composable
2325
import androidx.compose.ui.Alignment
@@ -27,10 +29,12 @@ import androidx.compose.ui.res.stringResource
2729
import androidx.compose.ui.res.vectorResource
2830
import com.example.jetcaster.R
2931
import com.example.jetcaster.ui.player.PlayerUiState
32+
import com.google.android.horologist.audio.AudioOutput
3033
import com.google.android.horologist.audio.ui.VolumeUiState
31-
import com.google.android.horologist.audio.ui.components.SettingsButtonsDefaults
32-
import com.google.android.horologist.audio.ui.components.actions.SetVolumeButton
33-
import com.google.android.horologist.audio.ui.components.actions.SettingsButton
34+
import com.google.android.horologist.audio.ui.material3.components.actions.SettingsButton
35+
import com.google.android.horologist.audio.ui.material3.components.actions.VolumeButtonWithBadge
36+
import com.google.android.horologist.audio.ui.material3.components.toAudioOutputUi
37+
3438

3539
/**
3640
* Settings buttons for the Jetcaster media app.
@@ -50,23 +54,24 @@ fun SettingsButtons(
5054
verticalAlignment = Alignment.CenterVertically,
5155
horizontalArrangement = Arrangement.SpaceEvenly,
5256
) {
53-
PlaybackSpeedButton(
54-
currentPlayerSpeed = playerUiState.episodePlayerState
55-
.playbackSpeed.toMillis().toFloat() / 1000,
56-
onPlaybackSpeedChange = onPlaybackSpeedChange,
57-
enabled = enabled,
58-
)
57+
Box(modifier = Modifier.weight(1f).fillMaxHeight()) {
58+
VolumeButtonWithBadge(
59+
onOutputClick = onVolumeClick,
60+
audioOutputUi = AudioOutput.BluetoothHeadset(id = "id", name = "name")
61+
.toAudioOutputUi(),
62+
volumeUiState = volumeUiState
63+
)
64+
}
5965

60-
SettingsButtonsDefaults.BrandIcon(
61-
iconId = R.drawable.ic_logo,
62-
enabled = enabled,
63-
)
66+
Box(modifier = Modifier.weight(1f).fillMaxHeight()) {
67+
PlaybackSpeedButton(
68+
currentPlayerSpeed = playerUiState.episodePlayerState
69+
.playbackSpeed.toMillis().toFloat() / 1000,
70+
onPlaybackSpeedChange = onPlaybackSpeedChange,
71+
enabled = enabled
72+
)
73+
}
6474

65-
SetVolumeButton(
66-
onVolumeClick = onVolumeClick,
67-
volumeUiState = volumeUiState,
68-
enabled = enabled,
69-
)
7075
}
7176
}
7277

0 commit comments

Comments
 (0)