Skip to content

Commit

Permalink
Fix Pager shakes under tv devices. #158
Browse files Browse the repository at this point in the history
  • Loading branch information
oxyroid committed May 29, 2024
1 parent d95ee70 commit a113463
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 215 deletions.
1 change: 0 additions & 1 deletion androidApp/src/main/java/com/m3u/androidApp/ui/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ private fun AppImpl(
.then(modifier),
) { contentPadding ->
AppNavHost(
currentDestination = { rootDestination },
navigateToRoot = navigateToRoot,
contentPadding = contentPadding,
modifier = Modifier.fillMaxSize()
Expand Down
2 changes: 0 additions & 2 deletions androidApp/src/main/java/com/m3u/androidApp/ui/AppNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.m3u.ui.SettingDestination

@Composable
fun AppNavHost(
currentDestination: () -> Destination.Root,
navigateToRoot: (Destination.Root) -> Unit,
contentPadding: PaddingValues,
modifier: Modifier = Modifier,
Expand Down Expand Up @@ -65,7 +64,6 @@ fun AppNavHost(
contentPadding = contentPadding
)
rootGraph(
currentDestination = currentDestination,
contentPadding = contentPadding,
navigateToPlaylist = { playlist ->
navController.navigateToPlaylist(playlist.url, tv)
Expand Down
27 changes: 9 additions & 18 deletions androidApp/src/main/java/com/m3u/androidApp/ui/RootGraph.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.m3u.androidApp.ui

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.navigation.NavController
Expand All @@ -18,7 +19,7 @@ import com.m3u.features.setting.SettingRoute
import com.m3u.material.ktx.Edge
import com.m3u.material.ktx.blurEdge
import com.m3u.ui.Destination
import com.m3u.ui.ExtendedHorizontalPager
import com.m3u.ui.LocalRootDestination

const val ROOT_ROUTE = "root_route"

Expand All @@ -27,7 +28,6 @@ fun NavController.restoreBackStack() {
}

fun NavGraphBuilder.rootGraph(
currentDestination: () -> Destination.Root,
contentPadding: PaddingValues,
navigateToPlaylist: (Playlist) -> Unit,
navigateToStream: () -> Unit,
Expand All @@ -36,7 +36,6 @@ fun NavGraphBuilder.rootGraph(
) {
composable(ROOT_ROUTE) {
RootGraph(
currentDestination = currentDestination,
contentPadding = contentPadding,
navigateToPlaylist = navigateToPlaylist,
navigateToStream = navigateToStream,
Expand All @@ -48,33 +47,25 @@ fun NavGraphBuilder.rootGraph(

@Composable
private fun RootGraph(
currentDestination: () -> Destination.Root,
contentPadding: PaddingValues,
navigateToPlaylist: (Playlist) -> Unit,
navigateToStream: () -> Unit,
navigateToSettingPlaylistManagement: () -> Unit,
navigateToPlaylistConfiguration: (Playlist) -> Unit,
modifier: Modifier = Modifier
) {
val rootDestination = currentDestination()
val initialPage = remember {
Destination.Root.entries.indexOf(rootDestination)
val rootDestination = LocalRootDestination.current
val page by remember(rootDestination) {
derivedStateOf { Destination.Root.entries.indexOf(rootDestination) }
}
val pagerState = rememberPagerState(initialPage) { Destination.Root.entries.size }
LaunchedEffect(rootDestination) {
val page = Destination.Root.entries.indexOf(rootDestination)
pagerState.scrollToPage(page)
}
ExtendedHorizontalPager(
state = pagerState,
userScrollEnabled = false,
Box(
modifier = modifier
.fillMaxSize()
.blurEdge(
edge = Edge.Bottom,
color = MaterialTheme.colorScheme.background
)
) { page ->
) {
when (Destination.Root.entries[page]) {
Destination.Root.Foryou -> {
ForyouRoute(
Expand Down
6 changes: 5 additions & 1 deletion androidApp/src/main/java/com/m3u/androidApp/ui/Scaffold.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import com.m3u.material.model.LocalHazeState
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.Destination
import com.m3u.ui.FontFamilies
import com.m3u.ui.LocalRootDestination
import com.m3u.ui.helper.Fob
import com.m3u.ui.helper.LocalHelper
import com.m3u.ui.helper.Metadata
Expand All @@ -77,7 +78,10 @@ internal fun Scaffold(

val hazeState = remember { HazeState() }

CompositionLocalProvider(LocalHazeState provides hazeState) {
CompositionLocalProvider(
LocalHazeState provides hazeState,
LocalRootDestination provides rootDestination
) {
Background {
when {
tv -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import com.m3u.material.ktx.thenIf
import com.m3u.material.model.LocalHazeState
import com.m3u.ui.Destination
import com.m3u.ui.EpisodesBottomSheet
import com.m3u.ui.LocalVisiblePageInfos
import com.m3u.ui.LocalRootDestination
import com.m3u.ui.MediaSheet
import com.m3u.ui.MediaSheetValue
import com.m3u.ui.Sort
Expand All @@ -65,6 +65,7 @@ fun FavouriteRoute(
val helper = LocalHelper.current
val preferences = hiltPreferences()
val context = LocalContext.current
val root = LocalRootDestination.current

val coroutineScope = rememberCoroutineScope()

Expand All @@ -81,11 +82,7 @@ fun FavouriteRoute(
mutableStateOf(MediaSheetValue.FavouriteScreen())
}

val visiblePageInfos = LocalVisiblePageInfos.current
val pageIndex = remember { Destination.Root.entries.indexOf(Destination.Root.Favourite) }
val isPageInfoVisible = remember(pageIndex, visiblePageInfos) {
visiblePageInfos.find { it.index == pageIndex } != null
}
val isPageInfoVisible = root == Destination.Root.Favourite

val series: Stream? by viewModel.series.collectAsStateWithLifecycle()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import com.m3u.material.ktx.thenIf
import com.m3u.material.model.LocalHazeState
import com.m3u.ui.Destination
import com.m3u.ui.EpisodesBottomSheet
import com.m3u.ui.LocalVisiblePageInfos
import com.m3u.ui.LocalRootDestination
import com.m3u.ui.MediaSheet
import com.m3u.ui.MediaSheetValue
import com.m3u.ui.helper.Action
Expand All @@ -67,17 +67,14 @@ fun ForyouRoute(
viewModel: ForyouViewModel = hiltViewModel()
) {
val helper = LocalHelper.current
val root = LocalRootDestination.current
val preferences = hiltPreferences()
val visiblePageInfos = LocalVisiblePageInfos.current
val coroutineScope = rememberCoroutineScope()

val tv = isTelevision()
val title = stringResource(string.ui_title_foryou)

val pageIndex = remember { Destination.Root.entries.indexOf(Destination.Root.Foryou) }
val isPageInfoVisible = remember(pageIndex, visiblePageInfos) {
visiblePageInfos.find { it.index == pageIndex } != null
}
val isPageInfoVisible = root == Destination.Root.Foryou

val playlistCountsResource by viewModel.playlistCountsResource.collectAsStateWithLifecycle()
val recommend by viewModel.recommend.collectAsStateWithLifecycle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ChangeCircle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
Expand Down Expand Up @@ -47,7 +45,7 @@ import com.m3u.material.model.LocalHazeState
import com.m3u.ui.Destination
import com.m3u.ui.EventHandler
import com.m3u.ui.Events
import com.m3u.ui.LocalVisiblePageInfos
import com.m3u.ui.LocalRootDestination
import com.m3u.ui.SettingDestination
import com.m3u.ui.helper.Fob
import com.m3u.ui.helper.Metadata
Expand Down Expand Up @@ -181,24 +179,21 @@ private fun SettingScreen(
contentPadding: PaddingValues = PaddingValues()
) {
val preferences = hiltPreferences()
val root = LocalRootDestination.current

val defaultTitle = stringResource(string.ui_title_setting)
val playlistTitle = stringResource(string.feat_setting_playlist_management)
val appearanceTitle = stringResource(string.feat_setting_appearance)

val colorArgb = preferences.argb

val visiblePageInfos = LocalVisiblePageInfos.current
val pageIndex = remember { Destination.Root.entries.indexOf(Destination.Root.Setting) }
val isPageInfoVisible = remember(pageIndex, visiblePageInfos) {
visiblePageInfos.find { it.index == pageIndex } != null
}
val isPageInfoVisible = root == Destination.Root.Setting

val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<SettingDestination>()
val destination = scaffoldNavigator.currentDestination?.content ?: SettingDestination.Default
val navigator = rememberListDetailPaneScaffoldNavigator<SettingDestination>()
val destination = navigator.currentDestination?.content ?: SettingDestination.Default

EventHandler(Events.settingDestination) {
scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail, it)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, it)
}

if (isPageInfoVisible) {
Expand All @@ -218,7 +213,7 @@ private fun SettingScreen(
icon = Icons.Rounded.ChangeCircle,
iconTextId = string.feat_setting_back_home
) {
scaffoldNavigator.navigateBack()
navigator.navigateBack()
}
}
Metadata.actions = emptyList()
Expand All @@ -229,78 +224,73 @@ private fun SettingScreen(
}

ListDetailPaneScaffold(
directive = scaffoldNavigator.scaffoldDirective,
value = scaffoldNavigator.scaffoldValue,
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
Crossfade(destination) { destination ->
PreferencesFragment(
fragment = destination,
PreferencesFragment(
fragment = destination,
contentPadding = contentPadding,
versionName = versionName,
versionCode = versionCode,
navigateToPlaylistManagement = {
navigator.navigateTo(
pane = ListDetailPaneScaffoldRole.Detail,
content = SettingDestination.Playlists
)
},
navigateToThemeSelector = {
navigator.navigateTo(
pane = ListDetailPaneScaffoldRole.Detail,
content = SettingDestination.Appearance
)
},
cacheSpace = cacheSpace,
onClearCache = onClearCache,
modifier = Modifier.fillMaxSize()
)
},
detailPane = {
when (destination) {
SettingDestination.Playlists -> {
SubscriptionsFragment(
titleState = titleState,
urlState = urlState,
uriState = uriState,
selectedState = selectedState,
basicUrlState = basicUrlState,
usernameState = usernameState,
passwordState = passwordState,
epgState = epgState,
localStorageState = localStorageState,
forTvState = forTvState,
backingUpOrRestoring = backingUpOrRestoring,
hiddenStreams = hiddenStreams,
hiddenCategoriesWithPlaylists = hiddenCategoriesWithPlaylists,
onUnhideStream = onUnhideStream,
onUnhidePlaylistCategory = onUnhidePlaylistCategory,
onClipboard = onClipboard,
onSubscribe = onSubscribe,
backup = backup,
restore = restore,
epgs = epgs,
onDeleteEpgPlaylist = onDeleteEpgPlaylist,
contentPadding = contentPadding,
versionName = versionName,
versionCode = versionCode,
navigateToPlaylistManagement = {
scaffoldNavigator.navigateTo(
pane = ListDetailPaneScaffoldRole.Detail,
content = SettingDestination.Playlists
)
},
navigateToThemeSelector = {
scaffoldNavigator.navigateTo(
pane = ListDetailPaneScaffoldRole.Detail,
content = SettingDestination.Appearance
)
},
cacheSpace = cacheSpace,
onClearCache = onClearCache,
modifier = Modifier.fillMaxSize()
)
}
}
},
detailPane = {
AnimatedPane(Modifier.fillMaxSize()) {
when (destination) {
SettingDestination.Playlists -> {
SubscriptionsFragment(
titleState = titleState,
urlState = urlState,
uriState = uriState,
selectedState = selectedState,
basicUrlState = basicUrlState,
usernameState = usernameState,
passwordState = passwordState,
epgState = epgState,
localStorageState = localStorageState,
forTvState = forTvState,
backingUpOrRestoring = backingUpOrRestoring,
hiddenStreams = hiddenStreams,
hiddenCategoriesWithPlaylists = hiddenCategoriesWithPlaylists,
onUnhideStream = onUnhideStream,
onUnhidePlaylistCategory = onUnhidePlaylistCategory,
onClipboard = onClipboard,
onSubscribe = onSubscribe,
backup = backup,
restore = restore,
epgs = epgs,
onDeleteEpgPlaylist = onDeleteEpgPlaylist,
contentPadding = contentPadding,
modifier = Modifier.fillMaxSize()
)
}

SettingDestination.Appearance -> {
AppearanceFragment(
colorSchemes = colorSchemes,
colorArgb = colorArgb,
openColorCanvas = openColorCanvas,
restoreSchemes = restoreSchemes,
contentPadding = contentPadding
)
}

else -> {}
SettingDestination.Appearance -> {
AppearanceFragment(
colorSchemes = colorSchemes,
colorArgb = colorArgb,
openColorCanvas = openColorCanvas,
restoreSchemes = restoreSchemes,
contentPadding = contentPadding,
modifier = Modifier.fillMaxSize()
)
}

else -> {}
}
},
modifier = modifier
Expand All @@ -311,7 +301,7 @@ private fun SettingScreen(
)
.testTag("feature:setting")
)
BackHandler(scaffoldNavigator.canNavigateBack()) {
scaffoldNavigator.navigateBack()
BackHandler(navigator.canNavigateBack()) {
navigator.navigateBack()
}
}
Loading

0 comments on commit a113463

Please sign in to comment.