✨ [iOS] Native toolbar#51
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request implements a cross-platform NativeScaffold and Toolbar system, incorporating the haze library for UI effects and refactoring SampleFeature. Feedback identifies a typo in an iOS availability check and behavioral inconsistencies in back button handling. Recommendations include optimizing Android performance by remembering filtered lists, improving accessibility with larger touch targets, and ensuring design consistency by adhering to theme-defined typography and Material 3 Icon standards. Additionally, simplifying the NativeColor model was suggested.
There was a problem hiding this comment.
Pull request overview
Adds a cross-platform Toolbar model and NativeScaffold abstraction so Kotlin view models can drive a native iOS navigation bar (title/buttons/menus + Liquid Glass styling) while keeping Android on a Compose TopAppBar implementation.
Changes:
- Introduces
Toolbar+NativeScaffold(expect/actual) and wiresBaseScopedViewModelto exposetoolbar: StateFlow<Toolbar?>. - Refactors SampleFeature to use a new
SampleFeatureRoutethat binds state/events/toolbar consistently across iOS and Android. - Adds iOS SwiftUI toolbar binding utilities and updates Xcode scripts / build logic dependencies for the new UI stack.
Reviewed changes
Copilot reviewed 32 out of 38 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| shared/samplefeature/src/iosMain/kotlin/kmp/shared/samplefeature/presentation/SampleFeatureMainScreenViewController.kt | Switches iOS entry VC to SampleFeatureRoute and adds onShowMessage hook. |
| shared/samplefeature/src/commonMain/kotlin/kmp/shared/samplefeature/presentation/vm/SampleFeatureViewModel.kt | Adds getToolbar() override to provide title/logo from MR resources. |
| shared/samplefeature/src/commonMain/kotlin/kmp/shared/samplefeature/presentation/ui/SampleFeatureRoute.kt | New route composable wiring state, toolbar, and event-driven message handling. |
| shared/samplefeature/src/commonMain/kotlin/kmp/shared/samplefeature/presentation/ui/SampleFeatureMainScreen.kt | Wraps content in NativeScaffold and threads Toolbar? into UI. |
| shared/base/src/iosMain/kotlin/kmp/shared/base/presentation/vm/BaseScopedViewModel.ios.kt | Exposes toolbar StateFlow via Molecule on iOS. |
| shared/base/src/iosMain/kotlin/kmp/shared/base/presentation/ui/NativeScaffold.kt | iOS NativeScaffold actual: Compose Scaffold + optional blur container. |
| shared/base/src/iosMain/kotlin/kmp/shared/base/presentation/ui/NativeColor.kt | iOS bridge to convert NativeColor to UIColor. |
| shared/base/src/iosMain/kotlin/kmp/shared/base/presentation/ui/Keyboard.ios.kt | iOS implementations for keyboard dismissal/focus behaviors. |
| shared/base/src/iosMain/kotlin/kmp/shared/base/presentation/ui/BlurredContainer.kt | New blurred container using Haze + gradients for iOS styling. |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-light@3x.png | Adds toolbar brand logo asset (light, 3x). |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-light@2x.png | Adds toolbar brand logo asset (light, 2x). |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-light@1x.png | Adds toolbar brand logo asset (light, 1x). |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-dark@3x.png | Adds toolbar brand logo asset (dark, 3x). |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-dark@2x.png | Adds toolbar brand logo asset (dark, 2x). |
| shared/base/src/commonMain/moko-resources/images/toolbar_brand_logo-dark@1x.png | Adds toolbar brand logo asset (dark, 1x). |
| shared/base/src/commonMain/kotlin/kmp/shared/base/presentation/vm/BaseScopedViewModel.kt | Adds toolbar flow to base VM contract and getToolbar() hook. |
| shared/base/src/commonMain/kotlin/kmp/shared/base/presentation/ui/Toolbar.kt | New Toolbar/button/menu model shared across platforms. |
| shared/base/src/commonMain/kotlin/kmp/shared/base/presentation/ui/NativeScaffold.kt | New expect declaration for platform-native scaffold. |
| shared/base/src/commonMain/kotlin/kmp/shared/base/presentation/ui/Keyboard.kt | New expect keyboard-related modifier APIs. |
| shared/base/src/androidMain/res/drawable/ic_back_arrow.xml | Adds Android back arrow vector asset for toolbar back button. |
| shared/base/src/androidMain/kotlin/kmp/shared/base/presentation/vm/BaseScopedViewModel.android.kt | Exposes toolbar StateFlow via Molecule on Android. |
| shared/base/src/androidMain/kotlin/kmp/shared/base/presentation/ui/NativeScaffold.kt | Android NativeScaffold actual with Material3 TopAppBar + buttons/menus + Haze. |
| shared/base/src/androidMain/kotlin/kmp/shared/base/presentation/ui/Keyboard.android.kt | Android implementations for keyboard modifiers (IME scroll/focus). |
| shared/base/src/androidMain/kotlin/kmp/shared/base/presentation/ui/HazeTextButton.kt | Adds Haze-styled text button used in transparent toolbar. |
| shared/base/src/androidMain/kotlin/kmp/shared/base/presentation/ui/HazeIconButton.kt | Adds Haze-styled icon button used in transparent toolbar. |
| ios/scripts/generate-strings.sh | Skips MR generation during Xcode clean. |
| ios/scripts/build-kmp.sh | Runs Gradle clean during Xcode clean; keeps embed/sign for builds. |
| ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/View+Toolbar.swift | New SwiftUI extension to apply KMP Toolbar to native nav bar/toolbars. |
| ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/View+NavigationBarTitleColor.swift | New helper to set nav bar title color via a representable VC. |
| ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/View+Extensions.swift | Changes bindViewModel to bind toolbar updates and clear VM scope on dismiss. |
| ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/Moko+Extensions.swift | Adds SwiftUI Image init for ImageResource and StringDesc localization helper. |
| ios/PresentationLayer/SampleFeature/Sources/SampleFeature/SampleFeatureView.swift | Wires toast handling via onShowMessage, binds VM toolbar, updates DI wrapper usage. |
| ios/DomainLayer/SharedDomain/Sources/SharedDomain/ViewModels+Extensions.swift | Retroactive ObservableObject conformance for SampleFeatureViewModel. |
| ios/Application/AppDelegate.swift | Removes global navigation bar appearance setup (defers to per-screen toolbar). |
| ios/.swiftlint.yml | Excludes SharedDomain build output from SwiftLint scanning. |
| gradle/libs.versions.toml | Adds Haze deps + adjusts Compose version to match Haze support. |
| build-logic/convention/src/main/kotlin/plugin/KmpLibraryComposeConventionPlugin.kt | Adds moko-resources compose + haze deps to the Compose convention plugin. |
| android/samplefeature/src/main/kotlin/kmp/android/samplefeature/ui/SampleFeatureMain.kt | Refactors Android route to use SampleFeatureRoute + toast callback. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
^ Conflicts: ^ android/samplefeature/src/main/kotlin/kmp/android/samplefeature/ui/SampleFeatureMain.kt ^ build-logic/convention/src/main/kotlin/plugin/KmpLibraryComposeConventionPlugin.kt ^ gradle/libs.versions.toml ^ ios/.swiftlint.yml ^ shared/samplefeature/src/iosMain/kotlin/kmp/shared/samplefeature/presentation/SampleFeatureMainScreenViewController.kt
3c34a94 to
3fb41a6
Compare
| ComposeUIViewController { | ||
| SampleFeatureRoute( | ||
| viewModel = viewModel, | ||
| onShowMessage = onShowMessage, | ||
| ) |
There was a problem hiding this comment.
Interesting, we now reuse shared routes even with native navigation? 🤔
Since that onSubscription block of SampleFeatureRoutes vm events handles onAppear, won't it cause that it will only be called on the initial appear?
📝 Description
💡 What’s new?
Toolbardata model which defines the toolbar appearance. TheToolbaris defined and set in view's view model - it cannot be set in Compose as the toolbar needs to be set on iOS before the first composition & directly in SwiftUI not nested inside a controller.😶 What’s missing?
📚 References