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 pager to watch app #908

Merged
merged 10 commits into from
Apr 27, 2023
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
@file:OptIn(ExperimentalFoundationApi::class)

package au.com.shiftyjelly.pocketcasts.wear

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavType
import androidx.navigation.navArgument
import androidx.wear.compose.material.rememberSwipeToDismissBoxState
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.wear.theme.WearAppTheme
import au.com.shiftyjelly.pocketcasts.wear.ui.FilesScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.FiltersScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.SettingsScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.UpNextScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.WatchListScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.authenticationGraph
import au.com.shiftyjelly.pocketcasts.wear.ui.authenticationSubGraph
import au.com.shiftyjelly.pocketcasts.wear.ui.component.NowPlayingPager
import au.com.shiftyjelly.pocketcasts.wear.ui.downloads.DownloadsScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.episode.EpisodeScreenFlow
import au.com.shiftyjelly.pocketcasts.wear.ui.episode.EpisodeScreenFlow.episodeGraph
import au.com.shiftyjelly.pocketcasts.wear.ui.player.NowPlayingScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.player.NowPlayingViewModel
import au.com.shiftyjelly.pocketcasts.wear.ui.player.StreamingConfirmationScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.podcast.PodcastScreen
import au.com.shiftyjelly.pocketcasts.wear.ui.podcasts.PodcastsScreen
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
import com.google.android.horologist.compose.navscaffold.NavScaffoldViewModel
import com.google.android.horologist.compose.navscaffold.WearNavScaffold
import com.google.android.horologist.compose.navscaffold.composable
import com.google.android.horologist.compose.navscaffold.scrollable
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
Expand All @@ -45,80 +47,69 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// TODO add lines for radioactive theme
WearApp(theme.activeTheme)
WearAppTheme(theme.activeTheme) {
WearApp()
}
}
}
}

@Composable
fun WearApp(themeType: Theme.ThemeType) {
WearAppTheme(themeType) {
val navController = rememberSwipeDismissableNavController()
private fun WearApp() {

WearNavScaffold(
navController = navController,
startDestination = WatchListScreen.route
) {
val navController = rememberSwipeDismissableNavController()
val swipeToDismissState = rememberSwipeToDismissBoxState()
val navState = rememberSwipeDismissableNavHostState(swipeToDismissState)

scrollable(
route = WatchListScreen.route,
columnStateFactory = ScalingLazyColumnDefaults.belowTimeText()
) {
WatchListScreen(navController::navigate, it.scrollableState)
}
WearNavScaffold(
navController = navController,
startDestination = WatchListScreen.route,
state = navState,
) {

composable(NowPlayingScreen.route) {
it.timeTextMode = NavScaffoldViewModel.TimeTextMode.Off

// Listen for results from streaming confirmation screen
navController.currentBackStackEntry?.savedStateHandle
?.getStateFlow<StreamingConfirmationScreen.Result?>(StreamingConfirmationScreen.resultKey, null)
?.collectAsStateWithLifecycle()?.value?.let { streamingConfirmationResult ->
val viewModel = hiltViewModel<NowPlayingViewModel>()
LaunchedEffect(streamingConfirmationResult) {
viewModel.onStreamingConfirmationResult(streamingConfirmationResult)
// Clear result once consumed
navController.currentBackStackEntry?.savedStateHandle
?.remove<StreamingConfirmationScreen.Result?>(StreamingConfirmationScreen.resultKey)
scrollable(
route = WatchListScreen.route,
) {
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
NowPlayingPager(
navController = navController,
pagerState = pagerState,
swipeToDismissState = swipeToDismissState,
) {
WatchListScreen(
scrollState = it.scrollableState,
navigateToRoute = navController::navigate,
toNowPlaying = {
coroutineScope.launch {
pagerState.animateScrollToPage(1)
}
}

NowPlayingScreen(
navigateToEpisode = { episodeUuid ->
navController.navigate(EpisodeScreenFlow.navigateRoute(episodeUuid))
},
showStreamingConfirmation = { navController.navigate(StreamingConfirmationScreen.route) },
)
}
}

composable(StreamingConfirmationScreen.route) {
it.timeTextMode = NavScaffoldViewModel.TimeTextMode.Off
composable(StreamingConfirmationScreen.route) {
it.timeTextMode = NavScaffoldViewModel.TimeTextMode.Off

StreamingConfirmationScreen(
onFinished = { result ->
navController.previousBackStackEntry?.savedStateHandle?.set(
StreamingConfirmationScreen.resultKey,
result
)
navController.popBackStack()
},
)
}
StreamingConfirmationScreen(
onFinished = { result ->
navController.previousBackStackEntry?.savedStateHandle?.set(
StreamingConfirmationScreen.resultKey,
result
)
navController.popBackStack()
},
)
}

scrollable(
route = UpNextScreen.route,
) {
UpNextScreen(
navigateToEpisode = { episodeUuid ->
navController.navigate(EpisodeScreenFlow.navigateRoute(episodeUuid))
},
listState = it.scrollableState,
)
}
scrollable(
route = PodcastsScreen.route,
) {

scrollable(
route = PodcastsScreen.route,
NowPlayingPager(
navController = navController,
swipeToDismissState = swipeToDismissState,
) {
PodcastsScreen(
listState = it.scrollableState,
Expand All @@ -127,32 +118,52 @@ fun WearApp(themeType: Theme.ThemeType) {
}
)
}
}

composable(
route = PodcastScreen.route,
arguments = listOf(
navArgument(PodcastScreen.argument) {
type = NavType.StringType
}
),
composable(
route = PodcastScreen.route,
arguments = listOf(
navArgument(PodcastScreen.argument) {
type = NavType.StringType
}
),
) {

NowPlayingPager(
navController = navController,
swipeToDismissState = swipeToDismissState,
) {
PodcastScreen(
onEpisodeTap = { episode ->
navController.navigate(EpisodeScreenFlow.navigateRoute(episodeUuid = episode.uuid))
},
)
}
}

episodeGraph(
navigateToPodcast = { podcastUuid ->
navController.navigate(PodcastScreen.navigateRoute(podcastUuid))
},
episodeGraph(
navigateToPodcast = { podcastUuid ->
navController.navigate(PodcastScreen.navigateRoute(podcastUuid))
},
navController = navController,
swipeToDismissState = swipeToDismissState,
)

composable(FiltersScreen.route) {
NowPlayingPager(
navController = navController,
)
swipeToDismissState = swipeToDismissState,
) {
FiltersScreen()
}
}

composable(FiltersScreen.route) { FiltersScreen() }
scrollable(DownloadsScreen.route) {

scrollable(DownloadsScreen.route) {
NowPlayingPager(
navController = navController,
swipeToDismissState = swipeToDismissState,
) {
DownloadsScreen(
columnState = it.columnState,
onItemClick = { episode ->
Expand All @@ -161,23 +172,32 @@ fun WearApp(themeType: Theme.ThemeType) {
}
)
}
}

composable(FilesScreen.route) { FilesScreen() }

scrollable(SettingsScreen.route) {
SettingsScreen(
scrollState = it.columnState,
signInClick = { navController.navigate(authenticationSubGraph) },
)
composable(FilesScreen.route) {
NowPlayingPager(
navController = navController,
swipeToDismissState = swipeToDismissState,
) {
FilesScreen()
}
}

authenticationGraph(navController)
scrollable(SettingsScreen.route) {
SettingsScreen(
scrollState = it.columnState,
signInClick = { navController.navigate(authenticationSubGraph) },
)
}

authenticationGraph(navController)
}
}

@Preview(device = Devices.WEAR_OS_SMALL_ROUND, showSystemUi = true)
@Composable
fun DefaultPreview() {
WearApp(Theme.ThemeType.DARK)
WearAppTheme(Theme.ThemeType.DARK) {
WearApp()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package au.com.shiftyjelly.pocketcasts.wear.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -15,10 +18,21 @@ object FilesScreen {

@Composable
fun FilesScreen() {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary,
text = stringResource(LR.string.profile_navigation_files)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary,
text = stringResource(LR.string.profile_navigation_files)
)
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary.copy(alpha = 0.5f),
text = "placeholder screen"
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package au.com.shiftyjelly.pocketcasts.wear.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -15,10 +18,21 @@ object FiltersScreen {

@Composable
fun FiltersScreen() {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary,
text = stringResource(LR.string.filters)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary,
text = stringResource(LR.string.filters)
)
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary.copy(alpha = 0.5f),
text = "placeholder screen"
)
}
}
Loading