diff --git a/Sources/SkipUI/SkipUI/Commands/Toolbar.swift b/Sources/SkipUI/SkipUI/Commands/Toolbar.swift index f108720c..450b4588 100644 --- a/Sources/SkipUI/SkipUI/Commands/Toolbar.swift +++ b/Sources/SkipUI/SkipUI/Commands/Toolbar.swift @@ -298,14 +298,16 @@ struct ToolbarPreferences: Equatable { let titleDisplayMode: ToolbarTitleDisplayMode? let titleMenu: View? let backButtonHidden: Bool? + let isSystemBackground: Bool? let navigationBar: ToolbarBarPreferences? let bottomBar: ToolbarBarPreferences? - init(content: [View]? = nil, titleDisplayMode: ToolbarTitleDisplayMode? = nil, titleMenu: View? = nil, backButtonHidden: Bool? = nil, navigationBar: ToolbarBarPreferences? = nil, bottomBar: ToolbarBarPreferences? = nil) { + init(content: [View]? = nil, titleDisplayMode: ToolbarTitleDisplayMode? = nil, titleMenu: View? = nil, backButtonHidden: Bool? = nil, isSystemBackground: Bool? = nil, navigationBar: ToolbarBarPreferences? = nil, bottomBar: ToolbarBarPreferences? = nil) { self.content = content self.titleDisplayMode = titleDisplayMode self.titleMenu = titleMenu self.backButtonHidden = backButtonHidden + self.isSystemBackground = isSystemBackground self.navigationBar = navigationBar self.bottomBar = bottomBar } @@ -330,6 +332,7 @@ struct ToolbarPreferences: Equatable { self.titleDisplayMode = nil self.titleMenu = nil self.backButtonHidden = nil + self.isSystemBackground = nil } func reduce(_ next: ToolbarPreferences) -> ToolbarPreferences { @@ -339,7 +342,7 @@ struct ToolbarPreferences: Equatable { } else { rcontent = next.content ?? content } - return ToolbarPreferences(content: rcontent, titleDisplayMode: next.titleDisplayMode ?? titleDisplayMode, titleMenu: next.titleMenu ?? titleMenu, backButtonHidden: next.backButtonHidden ?? backButtonHidden, navigationBar: reduceBar(navigationBar, next.navigationBar), bottomBar: reduceBar(bottomBar, next.bottomBar)) + return ToolbarPreferences(content: rcontent, titleDisplayMode: next.titleDisplayMode ?? titleDisplayMode, titleMenu: next.titleMenu ?? titleMenu, backButtonHidden: next.backButtonHidden ?? backButtonHidden, isSystemBackground: next.isSystemBackground ?? isSystemBackground, navigationBar: reduceBar(navigationBar, next.navigationBar), bottomBar: reduceBar(bottomBar, next.bottomBar)) } private func reduceBar(_ bar: ToolbarBarPreferences?, _ next: ToolbarBarPreferences?) -> ToolbarBarPreferences? { @@ -351,7 +354,7 @@ struct ToolbarPreferences: Equatable { } public static func ==(lhs: ToolbarPreferences, rhs: ToolbarPreferences) -> Bool { - guard lhs.titleDisplayMode == rhs.titleDisplayMode, lhs.backButtonHidden == rhs.backButtonHidden, lhs.navigationBar == rhs.navigationBar, lhs.bottomBar == rhs.bottomBar else { + guard lhs.titleDisplayMode == rhs.titleDisplayMode, lhs.backButtonHidden == rhs.backButtonHidden, lhs.isSystemBackground == rhs.isSystemBackground, lhs.navigationBar == rhs.navigationBar, lhs.bottomBar == rhs.bottomBar else { return false } guard (lhs.content?.count ?? 0) == (rhs.content?.count ?? 0), (lhs.titleMenu != nil) == (rhs.titleMenu != nil) else { diff --git a/Sources/SkipUI/SkipUI/Containers/List.swift b/Sources/SkipUI/SkipUI/Containers/List.swift index 9b04f4b9..88920048 100644 --- a/Sources/SkipUI/SkipUI/Containers/List.swift +++ b/Sources/SkipUI/SkipUI/Containers/List.swift @@ -184,6 +184,7 @@ public final class List : View { }) modifier = modifier.reorderable(reorderableState) + PreferenceValues.shared.contribute(context: context, key: ToolbarPreferenceKey.self, value: ToolbarPreferences(isSystemBackground: styling.style != ListStyle.plain && styling.backgroundVisibility != Visibility.hidden)) // Integrate with our scroll-to-top and ScrollViewReader let coroutineScope = rememberCoroutineScope() PreferenceValues.shared.contribute(context: context, key: ScrollToTopPreferenceKey.self, value: { @@ -480,7 +481,7 @@ public final class List : View { // Vertical padding ComposeFooter(styling: styling, safeAreaHeight: 0.dp, hasBottomSection: true) } - let backgroundColor = BackgroundColor(styling: styling.withStyle(ListStyle.automatic), isItem: false) + let backgroundColor = BackgroundColor(styling: styling, isItem: false) let modifier = Modifier .zIndex(Float(0.5)) .background(backgroundColor) diff --git a/Sources/SkipUI/SkipUI/Containers/Navigation.swift b/Sources/SkipUI/SkipUI/Containers/Navigation.swift index 9539793d..ce8e8364 100644 --- a/Sources/SkipUI/SkipUI/Containers/Navigation.swift +++ b/Sources/SkipUI/SkipUI/Containers/Navigation.swift @@ -61,6 +61,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned @@ -69,6 +70,7 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.SoftwareKeyboardController import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex @@ -196,6 +198,7 @@ public struct NavigationStack : View where Root: View { let effectiveTitleDisplayMode = navigator.value.titleDisplayMode(for: arguments.state, preference: arguments.toolbarPreferences.titleDisplayMode) let isInlineTitleDisplayMode = useInlineTitleDisplayMode(for: effectiveTitleDisplayMode, safeArea: arguments.safeArea) let toolbarItems = ToolbarItems(content: arguments.toolbarPreferences.content ?? []) + let isSystemBackground = arguments.toolbarPreferences.isSystemBackground == true let searchFieldPadding = 16.dp let density = LocalDensity.current @@ -230,20 +233,25 @@ public struct NavigationStack : 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 topBarBackgroundBrush: androidx.compose.ui.graphics.Brush? if topBarPreferences?.backgroundVisibility == Visibility.hidden { - topBarBackgroundColor = Color.clear.colorImpl() + topBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent + unscrolledTopBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent topBarBackgroundBrush = nil } else if let background = topBarPreferences?.background { if let color = background.asColor(opacity: 1.0, animationContext: nil) { topBarBackgroundColor = color + unscrolledTopBarBackgroundColor = color topBarBackgroundBrush = nil } else { - topBarBackgroundColor = Color.clear.colorImpl() + topBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent + unscrolledTopBarBackgroundColor = androidx.compose.ui.graphics.Color.Transparent topBarBackgroundBrush = background.asBrush(opacity: 1.0, animationContext: nil) } } else { topBarBackgroundColor = Color.systemBarBackground.colorImpl() + unscrolledTopBarBackgroundColor = isSystemBackground ? topBarBackgroundColor : topBarBackgroundColor.copy(alpha: Float(0.0)) topBarBackgroundBrush = nil } let topBar: @Composable () -> Void = { @@ -287,7 +295,7 @@ public struct NavigationStack : View where Root: View { topBarModifier = topBarModifier.background(topBarBackgroundBrush) } let topBarColors = TopAppBarDefaults.topAppBarColors( - containerColor: topBarBackgroundColor, + containerColor: unscrolledTopBarBackgroundColor, scrolledContainerColor: topBarBackgroundColor, titleContentColor: MaterialTheme.colorScheme.onSurface ) @@ -417,7 +425,15 @@ public struct NavigationStack : View where Root: View { var topPadding = 0.dp let searchableState: SearchableState? = arguments.isRoot ? (EnvironmentValues.shared._searchableState ?? searchableStatePreference.value.reduced) : nil if let searchableState { - let searchFieldModifier = Modifier.height(searchFieldHeight.dp + searchFieldPadding).align(androidx.compose.ui.Alignment.TopCenter).offset({ IntOffset(0, Int(searchFieldOffsetPx.value)) }).background(topBarBackgroundColor).padding(start: searchFieldPadding, bottom: searchFieldPadding, end: searchFieldPadding).fillMaxWidth() + 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) + .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) } + .fillMaxWidth() SearchField(state: searchableState, context: context.content(modifier: searchFieldModifier)) let searchFieldPlaceholderPadding = searchFieldHeight.dp + searchFieldPadding + (with(LocalDensity.current) { searchFieldOffsetPx.value.toDp() }) topPadding = searchFieldPlaceholderPadding diff --git a/Sources/SkipUI/SkipUI/Containers/TabView.swift b/Sources/SkipUI/SkipUI/Containers/TabView.swift index fe6b9ca4..0b60ab12 100644 --- a/Sources/SkipUI/SkipUI/Containers/TabView.swift +++ b/Sources/SkipUI/SkipUI/Containers/TabView.swift @@ -116,7 +116,7 @@ public struct TabView : View { } } let colorScheme = reducedTabBarPreferences.colorScheme ?? ColorScheme.fromMaterialTheme() - let indicatorColor = colorScheme == .dark ? androidx.compose.ui.graphics.Color.White.copy(alpha: Float(0.2)) : androidx.compose.ui.graphics.Color.Black.copy(alpha: Float(0.2)) + let indicatorColor = 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 tabBarItemColors: NavigationBarItemColors if reducedTabBarPreferences.backgroundVisibility == Visibility.hidden { diff --git a/Sources/SkipUI/SkipUI/Controls/Picker.swift b/Sources/SkipUI/SkipUI/Controls/Picker.swift index d1878eed..98cced70 100644 --- a/Sources/SkipUI/SkipUI/Controls/Picker.swift +++ b/Sources/SkipUI/SkipUI/Controls/Picker.swift @@ -247,7 +247,7 @@ extension View { } #if SKIP -@Composable private func processPickerContent(content: ComposeBuilder, selection: Binding, context: ComposeContext, requireTagViews: Bool = false) -> (View, [TagModifierView]?) { +@Composable func processPickerContent(content: ComposeBuilder, selection: Binding, context: ComposeContext, requireTagViews: Bool = false) -> (View, [TagModifierView]?) { let selectedTag = selection.wrappedValue let viewCollectingComposer = PickerViewCollectingComposer(selectedTag: selectedTag, requireTagViews: requireTagViews) let viewCollector = context.content(composer: viewCollectingComposer) diff --git a/Tests/SkipUITests/SkipUITests.swift b/Tests/SkipUITests/SkipUITests.swift index 051709e8..f066cf45 100644 --- a/Tests/SkipUITests/SkipUITests.swift +++ b/Tests/SkipUITests/SkipUITests.swift @@ -268,8 +268,8 @@ final class SkipUITests: SkipUITestCase { rule.onNodeWithTag("label").assertIsDisplayed() rule.onNodeWithTag("label").assert(hasTextExactly("0%")) rule.onNodeWithTag("slider").performGesture { - down(Offset(Float(0.0), Float(0.0))) - moveTo(Offset(Float(1000.0), Float(0.0))) + down(Offset(Float(10.0), Float(20.0))) + moveTo(Offset(Float(1000.0), Float(20.0))) up() } //rule.onNodeWithTag("label").assert(hasTextExactly("100%"))