Skip to content

Commit

Permalink
Handle custom background + color scheme case
Browse files Browse the repository at this point in the history
  • Loading branch information
aabewhite committed Sep 19, 2024
1 parent 93fc4a2 commit 91ac6f4
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 87 deletions.
4 changes: 2 additions & 2 deletions Sources/SkipUI/SkipUI/Color/ColorScheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public enum ColorScheme : CaseIterable, Hashable, Sendable {

#if SKIP
/// Return the color scheme for the current material color scheme.
@Composable public static func fromMaterialTheme() -> ColorScheme {
@Composable public static func fromMaterialTheme(colorScheme: androidx.compose.material3.ColorScheme = MaterialTheme.colorScheme) -> ColorScheme {
// Material3 doesn't have a built-in light vs dark property, so use the luminance of the background
return MaterialTheme.colorScheme.background.luminance() > Float(0.5) ? ColorScheme.light : ColorScheme.dark
return colorScheme.background.luminance() > Float(0.5) ? ColorScheme.light : ColorScheme.dark
}

/// Return the material color scheme for this scheme.
Expand Down
119 changes: 66 additions & 53 deletions Sources/SkipUI/SkipUI/Containers/Navigation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,33 +230,7 @@ public struct NavigationStack<Root> : View where Root: View {
mutableStateOf(with(density) { safeAreaTopPx + 112.dp.toPx() })
}

let topBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledTopBarBackgroundColor: androidx.compose.ui.graphics.Color
let topBarBackgroundForBrush: ShapeStyle?
// If there is a custom color scheme, we also always show any custom background even when unscrolled, because we can't
// properly interpolate between the title text colors
let topBarHasColorScheme = topBarPreferences?.colorScheme != nil
let isSystemBackground = topBarPreferences?.isSystemBackground == true
if topBarPreferences?.backgroundVisibility == Visibility.hidden {
topBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledTopBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
topBarBackgroundForBrush = nil
} else if let background = topBarPreferences?.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
topBarBackgroundColor = color
unscrolledTopBarBackgroundColor = topBarHasColorScheme ? color : isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
topBarBackgroundForBrush = nil
} else {
unscrolledTopBarBackgroundColor = !topBarHasColorScheme && isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
topBarBackgroundColor = unscrolledTopBarBackgroundColor.copy(alpha: Float(0.0))
topBarBackgroundForBrush = background
}
} else {
topBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledTopBarBackgroundColor = isSystemBackground ? topBarBackgroundColor : topBarBackgroundColor.copy(alpha: Float(0.0))
topBarBackgroundForBrush = nil
}

let topBar: @Composable () -> Void = {
guard topBarPreferences?.visibility != Visibility.hidden else {
SideEffect {
Expand All @@ -276,8 +250,41 @@ public struct NavigationStack<Root> : View where Root: View {
}
topBarHidden.value = false

let materialColorScheme = topBarPreferences?.colorScheme?.asMaterialTheme() ?? MaterialTheme.colorScheme
let isOverlapped = scrollBehavior.state.overlappedFraction > 0
let materialColorScheme: androidx.compose.material3.ColorScheme
if isOverlapped, let customColorScheme = topBarPreferences?.colorScheme?.asMaterialTheme() {
materialColorScheme = customColorScheme
} else {
materialColorScheme = MaterialTheme.colorScheme
}
MaterialTheme(colorScheme: materialColorScheme) {
let topBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledTopBarBackgroundColor: androidx.compose.ui.graphics.Color
let topBarBackgroundForBrush: ShapeStyle?
// If there is a custom color scheme, we also always show any custom background even when unscrolled, because we can't
// properly interpolate between the title text colors
let topBarHasColorScheme = topBarPreferences?.colorScheme != nil
let isSystemBackground = topBarPreferences?.isSystemBackground == true
if topBarPreferences?.backgroundVisibility == Visibility.hidden {
topBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledTopBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
topBarBackgroundForBrush = nil
} else if let background = topBarPreferences?.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
topBarBackgroundColor = color
unscrolledTopBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
topBarBackgroundForBrush = nil
} else {
unscrolledTopBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
topBarBackgroundColor = !topBarHasColorScheme || isOverlapped ? unscrolledTopBarBackgroundColor.copy(alpha: Float(0.0)) : unscrolledTopBarBackgroundColor
topBarBackgroundForBrush = background
}
} else {
topBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledTopBarBackgroundColor = isSystemBackground ? topBarBackgroundColor : topBarBackgroundColor.copy(alpha: Float(0.0))
topBarBackgroundForBrush = nil
}

let tint = EnvironmentValues.shared._tint ?? Color(colorImpl: { MaterialTheme.colorScheme.onSurface })
let placement = EnvironmentValues.shared._placement
EnvironmentValues.shared.setValues {
Expand All @@ -295,7 +302,7 @@ public struct NavigationStack<Root> : View where Root: View {
topBarBottomPx.value = bottomPx
}
}
if let topBarBackgroundForBrush {
if !topBarHasColorScheme || isOverlapped, let topBarBackgroundForBrush {
let opacity = topBarHasColorScheme ? 1.0 : isInlineTitleDisplayMode ? min(1.0, Double(scrollBehavior.state.overlappedFraction * 5)) : Double(scrollBehavior.state.collapsedFraction)
if let topBarBackgroundBrush = topBarBackgroundForBrush.asBrush(opacity: opacity, animationContext: nil) {
topBarModifier = topBarModifier.background(topBarBackgroundBrush)
Expand Down Expand Up @@ -364,32 +371,38 @@ public struct NavigationStack<Root> : View where Root: View {
return
}

let bottomBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledBottomBarBackgroundColor: androidx.compose.ui.graphics.Color
let bottomBarBackgroundForBrush: ShapeStyle?
let bottomBarHasColorScheme = bottomBarPreferences?.colorScheme != nil
if bottomBarPreferences?.backgroundVisibility == Visibility.hidden {
bottomBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledBottomBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
bottomBarBackgroundForBrush = nil
} else if let background = bottomBarPreferences?.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
bottomBarBackgroundColor = color
unscrolledBottomBarBackgroundColor = bottomBarHasColorScheme ? color : isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
let canScrollForward = bottomBarPreferences?.scrollableState.canScrollForward == true
let materialColorScheme: androidx.compose.material3.ColorScheme
if canScrollForward, let customColorScheme = bottomBarPreferences?.colorScheme?.asMaterialTheme() {
materialColorScheme = customColorScheme
} else {
materialColorScheme = MaterialTheme.colorScheme
}
MaterialTheme(colorScheme: materialColorScheme) {
let bottomBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledBottomBarBackgroundColor: androidx.compose.ui.graphics.Color
let bottomBarBackgroundForBrush: ShapeStyle?
let bottomBarHasColorScheme = bottomBarPreferences?.colorScheme != nil
if bottomBarPreferences?.backgroundVisibility == Visibility.hidden {
bottomBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledBottomBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
bottomBarBackgroundForBrush = nil
} else if let background = bottomBarPreferences?.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
bottomBarBackgroundColor = color
unscrolledBottomBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
bottomBarBackgroundForBrush = nil
} else {
unscrolledBottomBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
bottomBarBackgroundColor = unscrolledBottomBarBackgroundColor.copy(alpha: Float(0.0))
bottomBarBackgroundForBrush = background
}
} else {
unscrolledBottomBarBackgroundColor = !bottomBarHasColorScheme && isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
bottomBarBackgroundColor = unscrolledBottomBarBackgroundColor.copy(alpha: Float(0.0))
bottomBarBackgroundForBrush = background
bottomBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledBottomBarBackgroundColor = isSystemBackground ? bottomBarBackgroundColor : bottomBarBackgroundColor.copy(alpha: Float(0.0))
bottomBarBackgroundForBrush = nil
}
} else {
bottomBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledBottomBarBackgroundColor = isSystemBackground ? bottomBarBackgroundColor : bottomBarBackgroundColor.copy(alpha: Float(0.0))
bottomBarBackgroundForBrush = nil
}

let materialColorScheme = bottomBarPreferences?.colorScheme?.asMaterialTheme() ?? MaterialTheme.colorScheme
MaterialTheme(colorScheme: materialColorScheme) {
let tint = EnvironmentValues.shared._tint ?? Color(colorImpl: { MaterialTheme.colorScheme.onSurface })
let placement = EnvironmentValues.shared._placement
EnvironmentValues.shared.setValues {
Expand All @@ -404,8 +417,7 @@ public struct NavigationStack<Root> : View where Root: View {
bottomBarHeightPx.value = bounds.bottom - bounds.top
}
}
let canScrollForward = bottomBarPreferences?.scrollableState.canScrollForward == true
if let bottomBarBackgroundForBrush, bottomBarHasColorScheme || canScrollForward {
if canScrollForward, let bottomBarBackgroundForBrush {
if let bottomBarBackgroundBrush = bottomBarBackgroundForBrush.asBrush(opacity: 1.0, animationContext: nil) {
bottomBarModifier = bottomBarModifier.background(bottomBarBackgroundBrush)
}
Expand Down Expand Up @@ -449,11 +461,12 @@ public struct NavigationStack<Root> : View where Root: View {
var topPadding = 0.dp
let searchableState: SearchableState? = arguments.isRoot ? (EnvironmentValues.shared._searchableState ?? searchableStatePreference.value.reduced) : nil
if let searchableState {
let searchFieldBackground = isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
let searchFieldFadeOffset = searchFieldHeightPx / 3
let searchFieldModifier = Modifier.height(searchFieldHeight.dp + searchFieldPadding)
.align(androidx.compose.ui.Alignment.TopCenter)
.offset({ IntOffset(0, Int(searchFieldOffsetPx.value)) })
.background(unscrolledTopBarBackgroundColor)
.background(searchFieldBackground)
.padding(start: searchFieldPadding, bottom: searchFieldPadding, end: searchFieldPadding)
// Offset is negative. Fade out quickly as it scrolls in case it is moving up under transparent nav bar
.graphicsLayer { alpha = max(Float(0.0), (searchFieldFadeOffset + searchFieldOffsetPx.value) / searchFieldFadeOffset) }
Expand Down
69 changes: 37 additions & 32 deletions Sources/SkipUI/SkipUI/Containers/TabView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,44 +116,49 @@ public struct TabView : View {
bottomBarHeightPx.value = bounds.bottom - bounds.top
}
}
let barColorScheme = reducedTabBarPreferences.colorScheme ?? ColorScheme.fromMaterialTheme()
let hasColorScheme = reducedTabBarPreferences.colorScheme != nil
let isSystemBackground = reducedTabBarPreferences.isSystemBackground == true
let indicatorColor = barColorScheme == .dark ? androidx.compose.ui.graphics.Color.White.copy(alpha: Float(0.1)) : androidx.compose.ui.graphics.Color.Black.copy(alpha: Float(0.1))
let tabBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledTabBarBackgroundColor: androidx.compose.ui.graphics.Color
let tabBarBackgroundForBrush: ShapeStyle?
let tabBarItemColors: NavigationBarItemColors
if reducedTabBarPreferences.backgroundVisibility == Visibility.hidden {
tabBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledTabBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
tabBarBackgroundForBrush = nil
tabBarItemColors = NavigationBarItemDefaults.colors(indicatorColor: indicatorColor)
} else if let background = reducedTabBarPreferences.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
tabBarBackgroundColor = color
unscrolledTabBarBackgroundColor = hasColorScheme ? color : isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
let canScrollForward = reducedTabBarPreferences.scrollableState?.canScrollForward == true
let materialColorScheme: androidx.compose.material3.ColorScheme
if canScrollForward, let customColorScheme = reducedTabBarPreferences.colorScheme?.asMaterialTheme() {
materialColorScheme = customColorScheme
} else {
materialColorScheme = MaterialTheme.colorScheme
}
MaterialTheme(colorScheme: materialColorScheme) {
let indicatorColor = ColorScheme.fromMaterialTheme(colorScheme: materialColorScheme) == ColorScheme.dark ? androidx.compose.ui.graphics.Color.White.copy(alpha: Float(0.1)) : androidx.compose.ui.graphics.Color.Black.copy(alpha: Float(0.1))
let tabBarBackgroundColor: androidx.compose.ui.graphics.Color
let unscrolledTabBarBackgroundColor: androidx.compose.ui.graphics.Color
let tabBarBackgroundForBrush: ShapeStyle?
let tabBarItemColors: NavigationBarItemColors
if reducedTabBarPreferences.backgroundVisibility == Visibility.hidden {
tabBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
unscrolledTabBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent
tabBarBackgroundForBrush = nil
tabBarItemColors = NavigationBarItemDefaults.colors(indicatorColor: indicatorColor)
} else if let background = reducedTabBarPreferences.background {
if let color = background.asColor(opacity: 1.0, animationContext: nil) {
tabBarBackgroundColor = color
unscrolledTabBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : color.copy(alpha: Float(0.0))
tabBarBackgroundForBrush = nil
} else {
unscrolledTabBarBackgroundColor = isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
tabBarBackgroundColor = unscrolledTabBarBackgroundColor.copy(alpha: Float(0.0))
tabBarBackgroundForBrush = background
}
tabBarItemColors = NavigationBarItemDefaults.colors(indicatorColor: indicatorColor)
} else {
unscrolledTabBarBackgroundColor = !hasColorScheme && isSystemBackground ? Color.systemBarBackground.colorImpl() : androidx.compose.ui.graphics.Color.Transparent
tabBarBackgroundColor = unscrolledTabBarBackgroundColor.copy(alpha: Float(0.0))
tabBarBackgroundForBrush = background
tabBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledTabBarBackgroundColor = isSystemBackground ? tabBarBackgroundColor : tabBarBackgroundColor.copy(alpha: Float(0.0))
tabBarBackgroundForBrush = nil
tabBarItemColors = NavigationBarItemDefaults.colors()
}
tabBarItemColors = NavigationBarItemDefaults.colors(indicatorColor: indicatorColor)
} else {
tabBarBackgroundColor = Color.systemBarBackground.colorImpl()
unscrolledTabBarBackgroundColor = isSystemBackground ? tabBarBackgroundColor : tabBarBackgroundColor.copy(alpha: Float(0.0))
tabBarBackgroundForBrush = nil
tabBarItemColors = NavigationBarItemDefaults.colors()
}
let canScrollForward = reducedTabBarPreferences.scrollableState?.canScrollForward == true
if let tabBarBackgroundForBrush, hasColorScheme || canScrollForward {
if let tabBarBackgroundBrush = tabBarBackgroundForBrush.asBrush(opacity: 1.0, animationContext: nil) {
tabBarModifier = tabBarModifier.background(tabBarBackgroundBrush)
if canScrollForward, let tabBarBackgroundForBrush {
if let tabBarBackgroundBrush = tabBarBackgroundForBrush.asBrush(opacity: 1.0, animationContext: nil) {
tabBarModifier = tabBarModifier.background(tabBarBackgroundBrush)
}
}
}
let materialColorScheme = reducedTabBarPreferences.colorScheme?.asMaterialTheme() ?? MaterialTheme.colorScheme
MaterialTheme(colorScheme: materialColorScheme) {

let currentRoute = currentRoute(for: navController) // Note: forces recompose of this context on tab navigation
// Pull the tab bar below the keyboard
let bottomPadding = with(density) { min(bottomBarHeightPx.value, Float(WindowInsets.ime.getBottom(density))).toDp() }
Expand Down

0 comments on commit 91ac6f4

Please sign in to comment.