mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-28 15:23:01 +00:00
fix(ios): stabilize stream navigation and header insets
This commit is contained in:
parent
5789af84aa
commit
070ef29ede
5 changed files with 44 additions and 8 deletions
|
|
@ -1,7 +1,9 @@
|
|||
package com.nuvio.app.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -11,3 +13,7 @@ internal actual val nuvioPlatformExtraBottomPadding: Dp = 0.dp
|
|||
internal actual val nuvioBottomNavigationExtraVerticalPadding: Dp = 6.dp
|
||||
@Composable
|
||||
internal actual fun nuvioBottomNavigationBarInsets(): WindowInsets = WindowInsets.navigationBars
|
||||
|
||||
@Composable
|
||||
internal actual fun platformPhysicalTopInset(): Dp =
|
||||
WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ internal expect val nuvioBottomNavigationExtraVerticalPadding: Dp
|
|||
@Composable
|
||||
internal expect fun nuvioBottomNavigationBarInsets(): WindowInsets
|
||||
|
||||
/** Physical display-safe top inset, excluding any enclosing native toolbar. */
|
||||
@Composable
|
||||
internal expect fun platformPhysicalTopInset(): Dp
|
||||
|
||||
internal val LocalNuvioBottomNavigationOverlayPadding = staticCompositionLocalOf { 0.dp }
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.lerp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.nuvio.app.core.ui.NuvioBackButton
|
||||
import com.nuvio.app.core.ui.platformPhysicalTopInset
|
||||
import com.nuvio.app.features.details.MetaDetails
|
||||
import com.nuvio.app.isIos
|
||||
import com.nuvio.app.navigation.LocalUseNativeNavigation
|
||||
|
|
@ -55,10 +56,14 @@ fun DetailFloatingHeader(
|
|||
onToggleSaved: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val safeAreaTop = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
val useNativeNavigation = LocalUseNativeNavigation.current
|
||||
val safeAreaTop = if (useNativeNavigation) {
|
||||
platformPhysicalTopInset()
|
||||
} else {
|
||||
WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
}
|
||||
val headerTopPadding = (safeAreaTop - 6.dp).coerceAtLeast(safeAreaTop * 0.8f)
|
||||
val interactive = progress > 0.05f
|
||||
val useNativeNavigation = LocalUseNativeNavigation.current
|
||||
val surfaceColor = backgroundColor ?: if (isIos) {
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = 1.0f)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@ package com.nuvio.app.core.ui
|
|||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.uikit.LocalUIViewController
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.useContents
|
||||
|
||||
internal actual val nuvioPlatformExtraTopPadding: Dp = 0.dp
|
||||
internal actual val nuvioPlatformExtraBottomPadding: Dp = 0.dp
|
||||
|
|
@ -15,3 +20,14 @@ internal actual val nuvioBottomNavigationExtraVerticalPadding: Dp = 0.dp
|
|||
@Composable
|
||||
internal actual fun nuvioBottomNavigationBarInsets(): WindowInsets =
|
||||
WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom)
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@Composable
|
||||
internal actual fun platformPhysicalTopInset(): Dp {
|
||||
val physicalTop = LocalUIViewController.current.view.window
|
||||
?.safeAreaInsets
|
||||
?.useContents { top.toFloat() }
|
||||
|
||||
return physicalTop?.dp
|
||||
?: WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -596,6 +596,11 @@ struct TabContentView: View {
|
|||
coordinator: coordinator,
|
||||
appCoordinator: appCoordinator
|
||||
)
|
||||
// A native replace keeps the same NavigationStack depth.
|
||||
// Keying by the wrapper forces SwiftUI to replace the
|
||||
// embedded Compose controller instead of reusing the old
|
||||
// screen with the new route's toolbar preferences.
|
||||
.id(wrapper.id)
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
|
|
@ -642,12 +647,12 @@ private struct DetailDestinationView: View {
|
|||
@ObservedObject var coordinator: TabNavigationCoordinator
|
||||
@ObservedObject var appCoordinator: AppNavigationCoordinator
|
||||
|
||||
private var isMetaDetail: Bool {
|
||||
wrapper.route is DetailRoute
|
||||
private var usesComposeNavigationHeader: Bool {
|
||||
wrapper.route is DetailRoute || wrapper.route is StreamRoute
|
||||
}
|
||||
|
||||
private var showsReadabilityFade: Bool {
|
||||
!wrapper.route.hidesNavigationBar && !isMetaDetail
|
||||
!wrapper.route.hidesNavigationBar && !usesComposeNavigationHeader
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
|
|
@ -663,9 +668,9 @@ private struct DetailDestinationView: View {
|
|||
NativeToolbarReadabilityFade()
|
||||
}
|
||||
}
|
||||
.navigationTitle(isMetaDetail ? "" : wrapper.route.title ?? "")
|
||||
.navigationTitle(usesComposeNavigationHeader ? "" : wrapper.route.title ?? "")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbarRole(isMetaDetail ? .editor : .automatic)
|
||||
.toolbarRole(usesComposeNavigationHeader ? .editor : .automatic)
|
||||
.toolbar(.hidden, for: .tabBar)
|
||||
.toolbar(
|
||||
wrapper.route.hidesNavigationBar ? Visibility.hidden : Visibility.visible,
|
||||
|
|
@ -675,7 +680,7 @@ private struct DetailDestinationView: View {
|
|||
|
||||
@ViewBuilder
|
||||
var body: some View {
|
||||
if #available(iOS 26.0, *), !isMetaDetail {
|
||||
if #available(iOS 26.0, *), !usesComposeNavigationHeader {
|
||||
content.navigationSubtitle(wrapper.route.subtitle ?? "")
|
||||
} else {
|
||||
content
|
||||
|
|
|
|||
Loading…
Reference in a new issue