From d18385d24bd3f3d3ec57cd28297a0f186c897cb6 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Thu, 3 Sep 2026 14:00:04 +0200 Subject: [PATCH 1/4] fix: keep seekbar visible during fullscreen seeking --- .../player/components/PlayerControls.kt | 25 ++++++++++++++++--- .../player/components/PlayerSurfaceBox.kt | 9 ++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt index 123a7b55..3050aad5 100644 --- a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt +++ b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt @@ -56,6 +56,7 @@ fun PlayerControls( ) BottomScrim( compact = compactControls, + isFullscreen = isFullscreen, modifier = Modifier.align(Alignment.BottomCenter), ) PlayerTopBar( @@ -99,11 +100,17 @@ fun PlayerControls( .align(Alignment.BottomCenter) .fillMaxWidth() .testTag(PLAYER_BOTTOM_CONTROLS_TAG) - .windowInsetsPadding(WindowInsets.navigationBarsIgnoringVisibility) + .then( + if (isFullscreen) { + Modifier + } else { + Modifier.windowInsetsPadding(WindowInsets.navigationBarsIgnoringVisibility) + }, + ) .padding( start = if (isFullscreen) 12.dp else 4.dp, end = if (isFullscreen) 8.dp else 4.dp, - bottom = if (isFullscreen) 12.dp else 0.dp, + bottom = if (isFullscreen) 6.dp else 0.dp, ), ) } @@ -124,11 +131,21 @@ private fun TopScrim(compact: Boolean, modifier: Modifier = Modifier) { } @Composable -private fun BottomScrim(compact: Boolean, modifier: Modifier = Modifier) { +private fun BottomScrim( + compact: Boolean, + isFullscreen: Boolean, + modifier: Modifier = Modifier, +) { Box( modifier = modifier .fillMaxWidth() - .height(if (compact) 88.dp else 152.dp) + .height( + when { + isFullscreen -> 116.dp + compact -> 88.dp + else -> 152.dp + }, + ) .background( Brush.verticalGradient( colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.72f)), diff --git a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerSurfaceBox.kt b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerSurfaceBox.kt index 3811d3bb..bf9e6f79 100644 --- a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerSurfaceBox.kt +++ b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerSurfaceBox.kt @@ -127,8 +127,15 @@ internal fun PlayerSurfaceBox( LaunchedEffect(accessibleControls) { if (accessibleControls) controlsVisible = true } - LaunchedEffect(controlsVisible, playbackStatus.isPlaying, accessibleControls) { + val isSeekDragging = gestureState.dragMode.value == DragMode.Seek + LaunchedEffect( + controlsVisible, + playbackStatus.isPlaying, + accessibleControls, + isSeekDragging, + ) { if (controlsVisible && playbackStatus.isPlaying && !accessibleControls) { + if (isSeekDragging) return@LaunchedEffect delay(AUTO_HIDE_DELAY_MS) controlsVisible = false } From 617adf2b4f787da88e76163e0b05108e8fefae70 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Thu, 3 Sep 2026 14:31:03 +0200 Subject: [PATCH 2/4] fix: sync active tab selection immediately --- .../dev/typetype/android/AppNavigation.kt | 24 +++++-------------- .../java/dev/typetype/android/AppShell.kt | 20 +++++++++------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/dev/typetype/android/AppNavigation.kt b/app/src/main/java/dev/typetype/android/AppNavigation.kt index fa17289a..934de63e 100644 --- a/app/src/main/java/dev/typetype/android/AppNavigation.kt +++ b/app/src/main/java/dev/typetype/android/AppNavigation.kt @@ -142,8 +142,7 @@ internal fun AppTopBar( @Composable internal fun AppBottomBar( - currentDestination: NavDestination?, - fallbackTabRouteQualifiedName: String?, + selectedTabRouteQualifiedName: String?, onTabClick: (TopLevelTab) -> Unit, tabs: List = topLevelTabs, modifier: Modifier = Modifier, @@ -155,10 +154,10 @@ internal fun AppBottomBar( containerColor = MaterialTheme.colorScheme.surface, ) { tabs.forEach { tab: TopLevelTab -> - val selected = tab.isSelected(currentDestination, fallbackTabRouteQualifiedName, tabs) + val selected = tab.route::class.qualifiedName == selectedTabRouteQualifiedName NavigationBarItem( selected = selected, - onClick = { if (!currentDestination.matchesRoute(tab.route)) onTabClick(tab) }, + onClick = { onTabClick(tab) }, icon = { Icon(painterResource(tab.iconRes), contentDescription = null) }, label = { Text(stringResource(tab.labelRes)) }, ) @@ -169,8 +168,7 @@ internal fun AppBottomBar( @Composable internal fun AppNavigationRail( - currentDestination: NavDestination?, - fallbackTabRouteQualifiedName: String?, + selectedTabRouteQualifiedName: String?, onTabClick: (TopLevelTab) -> Unit, tabs: List = topLevelTabs, modifier: Modifier = Modifier, @@ -184,10 +182,10 @@ internal fun AppNavigationRail( ) { Spacer(Modifier.weight(1f)) tabs.forEach { tab: TopLevelTab -> - val selected = tab.isSelected(currentDestination, fallbackTabRouteQualifiedName, tabs) + val selected = tab.route::class.qualifiedName == selectedTabRouteQualifiedName NavigationRailItem( selected = selected, - onClick = { if (!currentDestination.matchesRoute(tab.route)) onTabClick(tab) }, + onClick = { onTabClick(tab) }, icon = { Icon(painterResource(tab.iconRes), contentDescription = null) }, label = { Text(stringResource(tab.labelRes)) }, ) @@ -220,16 +218,6 @@ private fun ProfileAvatarButton( } } -private fun TopLevelTab.isSelected( - destination: NavDestination?, - fallbackRouteName: String?, - tabs: List, -): Boolean { - val direct = destination.matchesRoute(route) - val anyDirect = tabs.any { destination.matchesRoute(it.route) } - return direct || (!anyDirect && route::class.qualifiedName == fallbackRouteName) -} - internal fun NavDestination?.matchesRoute(route: Any): Boolean { val destination = this ?: return false return when (route) { diff --git a/app/src/main/java/dev/typetype/android/AppShell.kt b/app/src/main/java/dev/typetype/android/AppShell.kt index 5c31247a..29e1ce4d 100644 --- a/app/src/main/java/dev/typetype/android/AppShell.kt +++ b/app/src/main/java/dev/typetype/android/AppShell.kt @@ -90,7 +90,7 @@ fun AppShell( currentDestination?.hasRoute() == true || currentDestination?.hasRoute() == true ) - var activeTabRoute by rememberSaveable { mutableStateOf(null) } + var selectedTabRoute by rememberSaveable { mutableStateOf(null) } var isPlayerFullscreen by remember { mutableStateOf(false) } var playerTransitionProgress by remember { mutableFloatStateOf(0f) } val playerHostState by playerHostController.state.collectAsStateWithLifecycle() @@ -103,9 +103,13 @@ fun AppShell( ) LaunchedEffect(currentDestination) { topLevelTabs.firstOrNull { currentDestination.matchesRoute(it.route) }?.let { - activeTabRoute = it.route::class.qualifiedName + selectedTabRoute = it.route::class.qualifiedName } } + val selectedTabRouteQualifiedName = selectedTabRoute + ?: topLevelTabs.firstOrNull { currentDestination.matchesRoute(it.route) } + ?.route + ?.let { it::class.qualifiedName } val mediaController = rememberMediaController().value val snackbarHostState = remember { SnackbarHostState() } @@ -119,10 +123,10 @@ fun AppShell( Row(modifier = Modifier.fillMaxSize()) { if (usesNavigationRail && showsNavigation && appChromeVisible) { AppNavigationRail( - currentDestination = currentDestination, - fallbackTabRouteQualifiedName = activeTabRoute, + selectedTabRouteQualifiedName = selectedTabRouteQualifiedName, onTabClick = { tab: TopLevelTab -> - navController.navigateTopLevel(tab.route, activeTabRoute) + selectedTabRoute = tab.route::class.qualifiedName + navController.navigateTopLevel(tab.route, selectedTabRoute) }, tabs = navigationTabs, ) @@ -163,10 +167,10 @@ fun AppShell( bottomBar = { if (!usesNavigationRail && showsNavigation) { AppBottomBar( - currentDestination = currentDestination, - fallbackTabRouteQualifiedName = activeTabRoute, + selectedTabRouteQualifiedName = selectedTabRouteQualifiedName, onTabClick = { tab: TopLevelTab -> - navController.navigateTopLevel(tab.route, activeTabRoute) + selectedTabRoute = tab.route::class.qualifiedName + navController.navigateTopLevel(tab.route, selectedTabRoute) }, tabs = navigationTabs, modifier = Modifier.playerChrome(phoneChromeAlpha), From a4afd0436e04b1173bbbfd266bc33ff96f910f55 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Thu, 3 Sep 2026 14:31:03 +0200 Subject: [PATCH 3/4] fix: align portrait player seekbar with bottom --- .../android/feature/player/components/PlayerControls.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt index 3050aad5..9ae73da0 100644 --- a/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt +++ b/app/src/main/java/dev/typetype/android/feature/player/components/PlayerControls.kt @@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.navigationBarsIgnoringVisibility +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars @@ -104,7 +104,7 @@ fun PlayerControls( if (isFullscreen) { Modifier } else { - Modifier.windowInsetsPadding(WindowInsets.navigationBarsIgnoringVisibility) + Modifier.windowInsetsPadding(WindowInsets.navigationBars) }, ) .padding( @@ -174,7 +174,7 @@ private fun BottomBar( }, ) .padding(start = if (isFullscreen) 8.dp else 2.dp, end = 2.dp), - verticalAlignment = Alignment.CenterVertically, + verticalAlignment = Alignment.Bottom, ) { PlayerTimeBar( player = player, From d927e041b068d34ca6e29211236a8bba07ea99f8 Mon Sep 17 00:00:00 2001 From: Priveetee Date: Thu, 3 Sep 2026 14:32:07 +0200 Subject: [PATCH 4/4] chore: bump beta to 1.7.0-beta.9 --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2ba0d5df..e3947311 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,8 +26,8 @@ android { applicationId = "dev.typetype.android" minSdk = 23 targetSdk = 37 - versionCode = 10707 - versionName = "1.7.0-beta.8" + versionCode = 10708 + versionName = "1.7.0-beta.9" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" resValue("string", "app_name", "TypeType") }