Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Home screen and Episodes screen #1301

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import com.example.jetcaster.core.data.repository.EpisodeStore
import com.example.jetcaster.core.data.repository.PodcastStore
import com.example.jetcaster.core.data.repository.PodcastsRepository
import com.example.jetcaster.core.player.EpisodePlayer
import com.example.jetcaster.util.combine
import com.example.jetcaster.core.util.combine
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class PodcastsRepository(
if (refreshingJob?.isActive == true) {
refreshingJob?.join()
} else if (force || podcastStore.isEmpty()) {

refreshingJob = scope.launch {
// Now fetch the podcasts, and add each to each store
podcastsFetcher(SampleFeeds)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,47 @@
* limitations under the License.
*/

package com.example.jetcaster.util
package com.example.jetcaster.core.util

import kotlinx.coroutines.flow.Flow
/**
* Combines 3 flows into a single flow by combining their latest values using the provided transform function.
*
* @param flow The first flow.
* @param flow2 The second flow.
* @param flow3 The third flow.
* @param transform The transform function to combine the latest values of the three flows.
* @return A flow that emits the results of the transform function applied to the latest values of the three flows.
*/
fun <T1, T2, T3, T4, T5, R> combine(
flow: Flow<T1>,
flow2: Flow<T2>,
flow3: Flow<T3>,
flow4: Flow<T4>,
flow5: Flow<T5>,
transform: suspend (T1, T2, T3, T4, T5) -> R
): Flow<R> =
kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5) { args: Array<*> ->
transform(
args[0] as T1,
args[1] as T2,
args[2] as T3,
args[3] as T4,
args[4] as T5,
)
}
fun <T1, T2, R> combine(
flow: Flow<T1>,
flow2: Flow<T2>,

transform: suspend (T1, T2) -> R
): Flow<R> =
kotlinx.coroutines.flow.combine(flow, flow2) { args: Array<*> ->
transform(
args[0] as T1,
args[1] as T2,
)
}

/**
* Combines six flows into a single flow by combining their latest values using the provided transform function.
Expand Down
3 changes: 2 additions & 1 deletion Jetcaster/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ composeMaterial = "1.2.1"
composeFoundation = "1.2.1"
coreSplashscreen = "1.0.1"
horologistComposeTools = "0.4.8"
horologist = "0.5.25"
horologist = "0.6.6"
roborazzi = "1.11.0"
androidx-wear-compose = "1.3.0"
wear-compose-ui-tooling = "1.3.0"
Expand Down Expand Up @@ -165,6 +165,7 @@ horologist-compose-material = { module = "com.google.android.horologist:horologi
horologist-media-ui = { module = "com.google.android.horologist:horologist-media-ui", version.ref = "horologist" }
horologist-audio-ui = { module = "com.google.android.horologist:horologist-audio-ui", version.ref = "horologist" }
horologist-media-data = { module = "com.google.android.horologist:horologist-media-data", version.ref = "horologist" }
horologist-images-coil = { module = "com.google.android.horologist:horologist-images-coil", version.ref = "horologist" }
horologist-roboscreenshots = { module = "com.google.android.horologist:horologist-roboscreenshots", version.ref = "horologist" }
roborazzi = { group = "io.github.takahirom.roborazzi", name = "roborazzi", version.ref = "roborazzi" }
roborazzi-compose = { group = "io.github.takahirom.roborazzi", name = "roborazzi-compose", version.ref = "roborazzi" }
Expand Down
3 changes: 3 additions & 0 deletions Jetcaster/wear/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ dependencies {
// https://issuetracker.google.com/issues/new?component=1077552&template=1598429&pli=1
implementation libs.wear.compose.material

implementation(libs.kotlinx.collections.immutable)

// Foundation is additive, so you can use the mobile version in your Wear OS app.
implementation libs.wear.compose.foundation
implementation(libs.androidx.material.icons.core)
Expand All @@ -101,6 +103,7 @@ dependencies {
implementation libs.horologist.media.ui
implementation libs.horologist.audio.ui
implementation libs.horologist.media.data
implementation libs.horologist.images.coil

// Preview Tooling
implementation libs.compose.ui.tooling.preview
Expand Down
4 changes: 4 additions & 0 deletions Jetcaster/wear/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

##---------------Begin: proguard configuration for Pusher Java Client ----------
-dontwarn org.slf4j.impl.StaticLoggerBinder
##---------------End: proguard configuration for Pusher Java Client ----------
55 changes: 42 additions & 13 deletions Jetcaster/wear/src/main/java/com/example/jetcaster/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,29 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSavedStateRegistryOwner
import androidx.compose.ui.res.stringResource
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
import androidx.wear.compose.material.TimeText
import androidx.wear.compose.navigation.composable
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
import com.example.jetcaster.theme.WearAppTheme
import com.example.jetcaster.ui.JetcasterNavController.navigateToLatestEpisode
import com.example.jetcaster.ui.JetcasterNavController.navigateToUpNext
import com.example.jetcaster.ui.JetcasterNavController.navigateToYourPodcast
import com.example.jetcaster.ui.LatestEpisodes
import com.example.jetcaster.ui.home.HomeScreen
import com.example.jetcaster.ui.home.HomeViewModel
import com.example.jetcaster.ui.library.LatestEpisodeViewModel
import com.example.jetcaster.ui.library.LatestEpisodesScreen
import com.example.jetcaster.ui.player.PlayerScreen
import com.example.jetcaster.ui.player.PlayerViewModel
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.audio.ui.VolumeViewModel
import com.google.android.horologist.compose.layout.ScreenScaffold
import com.google.android.horologist.compose.layout.rememberColumnState
import com.google.android.horologist.media.ui.navigation.MediaNavController.navigateToVolume
import com.google.android.horologist.media.ui.navigation.MediaPlayerScaffold
import com.google.android.horologist.media.ui.snackbar.SnackbarManager
Expand All @@ -51,10 +64,11 @@ class MainActivity : ComponentActivity() {
}
}

@OptIn(ExperimentalHorologistApi::class)
@Composable
fun WearApp() {
val navController = rememberSwipeDismissableNavController()

val navController = rememberSwipeDismissableNavController()
val navHostState = rememberSwipeDismissableNavHostState()
val volumeViewModel: VolumeViewModel = viewModel(factory = VolumeViewModel.Factory)
val snackBarManager: SnackbarManager = SnackbarManager()
Expand All @@ -78,16 +92,13 @@ fun WearApp() {
)
},
libraryScreen = {
// val columnState = rememberColumnState()

// ScreenScaffold(scrollState = columnState) {
// JetcasterBrowseScreen(
// jetcasterBrowseScreenViewModel = JetcasterBrowseScreenViewModel(),
// onPlaylistsClick = { navController.navigateToCollections() },
// onSettingsClick = { navController.navigateToSettings() },
// columnState = columnState,
// )
// }
HomeScreen(
homeViewModel = HomeViewModel(),
onLatestEpisodeClick = { navController.navigateToLatestEpisode() },
onYourPodcastClick = { navController.navigateToYourPodcast() },
onUpNextClick = { navController.navigateToUpNext() },
onErrorDialogCancelClick = { navController.popBackStack() }
)
},
categoryEntityScreen = { _, _ -> },
mediaEntityScreen = {},
Expand All @@ -97,10 +108,28 @@ fun WearApp() {
navHostState = navHostState,
snackbarViewModel = snackbarViewModel,
volumeViewModel = volumeViewModel,
timeText = {},
timeText = {
TimeText()
},
deepLinkPrefix = "",
navController = navController,
additionalNavRoutes = {},
additionalNavRoutes = {
composable(
route = LatestEpisodes.navRoute,
) {
val columnState = rememberColumnState()

ScreenScaffold(scrollState = columnState) {
LatestEpisodesScreen(
columnState = columnState,
playlistName = stringResource(id = R.string.latest_episodes),
latestEpisodeViewModel = LatestEpisodeViewModel(),
onShuffleButtonClick = {},
onPlayButtonClick = {}
)
}
}
},

)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.jetcaster.ui

import androidx.navigation.NavController
import com.google.android.horologist.media.ui.navigation.NavigationScreens

/**
* NavController extensions that links to the screens of the Jetcaster app.
*/
public object JetcasterNavController {

public fun NavController.navigateToYourPodcast() {
navigate(YourPodcasts.destination())
}

public fun NavController.navigateToLatestEpisode() {
navigate(LatestEpisodes.destination())
}

public fun NavController.navigateToUpNext() {
navigate(UpNext.destination())
}
}

public object YourPodcasts : NavigationScreens("yourPodcasts") {
public fun destination(): String = navRoute
}

public object LatestEpisodes : NavigationScreens("latestEpisodes") {
public fun destination(): String = navRoute
}

public object UpNext : NavigationScreens("upNext") {
public fun destination(): String = navRoute
}
Loading