From 2b658346512fc0e9cda6b0bf3b3ebf9c8a91bd1a Mon Sep 17 00:00:00 2001 From: Ed Chao Date: Mon, 26 Jan 2026 20:06:41 +0900 Subject: [PATCH] Extend HotwireBottomNavigationController to support NavigationRailView. --- demo/src/main/AndroidManifest.xml | 2 +- .../dev/hotwire/demo/main/MainActivity.kt | 18 +++--- .../kotlin/dev/hotwire/demo/main/MainTabs.kt | 10 +-- .../main/res/layout-land/activity_main.xml | 64 +++++++++++++++++++ demo/src/main/res/layout/activity_main.xml | 10 +-- ...ller.kt => HotwireNavigationController.kt} | 36 +++++------ .../{HotwireBottomTab.kt => HotwireTab.kt} | 8 +-- 7 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 demo/src/main/res/layout-land/activity_main.xml rename navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/{HotwireBottomNavigationController.kt => HotwireNavigationController.kt} (87%) rename navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/{HotwireBottomTab.kt => HotwireTab.kt} (67%) diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 8ea19155..d3d6522e 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ (R.id.root).applyDefaultImeWindowInsets() - initializeBottomTabs() + initializeNavigation() WebViewVersionCompatibility.displayUpdateDialogIfOutdated( activity = this, @@ -32,12 +32,12 @@ class MainActivity : HotwireActivity() { ) } - private fun initializeBottomTabs() { - val bottomNavigationView = findViewById(R.id.bottom_nav) + private fun initializeNavigation() { + val navigationView = findViewById(R.id.navigation_bar) - bottomNavigationController = HotwireBottomNavigationController(this, bottomNavigationView) - bottomNavigationController.load(mainTabs, viewModel.selectedTabIndex) - bottomNavigationController.setOnTabSelectedListener { index, _ -> + navigationController = HotwireNavigationController(this, navigationView) + navigationController.load(mainTabs, viewModel.selectedTabIndex) + navigationController.setOnTabSelectedListener { index, _ -> viewModel.selectedTabIndex = index } } diff --git a/demo/src/main/kotlin/dev/hotwire/demo/main/MainTabs.kt b/demo/src/main/kotlin/dev/hotwire/demo/main/MainTabs.kt index 91561278..c9340c19 100644 --- a/demo/src/main/kotlin/dev/hotwire/demo/main/MainTabs.kt +++ b/demo/src/main/kotlin/dev/hotwire/demo/main/MainTabs.kt @@ -3,9 +3,9 @@ package dev.hotwire.demo.main import dev.hotwire.demo.Demo import dev.hotwire.demo.R import dev.hotwire.navigation.navigator.NavigatorConfiguration -import dev.hotwire.navigation.tabs.HotwireBottomTab +import dev.hotwire.navigation.tabs.HotwireTab -private val navigation = HotwireBottomTab( +private val navigation = HotwireTab( title = "Navigation", iconResId = R.drawable.ic_tab_navigation, configuration = NavigatorConfiguration( @@ -15,7 +15,7 @@ private val navigation = HotwireBottomTab( ) ) -private val bridgeComponents = HotwireBottomTab( +private val bridgeComponents = HotwireTab( title = "Bridge Components", iconResId = R.drawable.ic_tab_bridge_components, configuration = NavigatorConfiguration( @@ -25,7 +25,7 @@ private val bridgeComponents = HotwireBottomTab( ) ) -private val resources = HotwireBottomTab( +private val resources = HotwireTab( title = "Resources", iconResId = R.drawable.ic_tab_resources, configuration = NavigatorConfiguration( @@ -35,7 +35,7 @@ private val resources = HotwireBottomTab( ) ) -private val bugsAndFixes = HotwireBottomTab( +private val bugsAndFixes = HotwireTab( title = "Bugs & Fixes", iconResId = R.drawable.ic_tab_bugs_fixes, isVisible = Demo.current == Demo.Environment.Local, diff --git a/demo/src/main/res/layout-land/activity_main.xml b/demo/src/main/res/layout-land/activity_main.xml new file mode 100644 index 00000000..4b78f3a9 --- /dev/null +++ b/demo/src/main/res/layout-land/activity_main.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + diff --git a/demo/src/main/res/layout/activity_main.xml b/demo/src/main/res/layout/activity_main.xml index fd7d9286..3b5bae91 100644 --- a/demo/src/main/res/layout/activity_main.xml +++ b/demo/src/main/res/layout/activity_main.xml @@ -14,7 +14,7 @@ android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/bottom_nav" + app:layout_constraintBottom_toTopOf="@id/navigation_bar" app:defaultNavHost="false" /> Unit)? = null + private var listener: ((Int, HotwireTab) -> Unit)? = null /** - * Set the visibility of the `BottomNavigationView`. + * Set the visibility of the `NavigationBarView`. */ var visibility = initialVisibility set(value) { @@ -70,29 +70,29 @@ class HotwireBottomNavigationController( } /** - * The currently selected tab in the [BottomNavigationView]. + * The currently selected tab in the [NavigationBarView]. */ - val currentTab: HotwireBottomTab + val currentTab: HotwireTab get() { require(tabs.isNotEmpty()) { "No tabs have been loaded." } return tabs[view.selectedItemId] } /** - * The tabs that have been loaded into the [BottomNavigationView]. + * The tabs that have been loaded into the [NavigationBarView]. */ - var tabs = listOf() + var tabs = listOf() private set /** - * Load the tabs and their navigator configurations into the [BottomNavigationView]. + * Load the tabs and their navigator configurations into the [NavigationBarView]. * - * @param tabs The list of [HotwireBottomTab] instances that correspond to the - * [BottomNavigationView] tabs. + * @param tabs The list of [HotwireTab] instances that correspond to the + * [NavigationBarView] tabs. * @param selectedTabIndex The index of the initially selected tab. */ fun load( - tabs: List, + tabs: List, selectedTabIndex: Int = 0 ) { require(tabs.isNotEmpty()) { "Tabs cannot be empty." } @@ -121,7 +121,7 @@ class HotwireBottomNavigationController( /** * Set a listener that will be notified when a navigation tab is selected. */ - fun setOnTabSelectedListener(listener: ((index: Int, tab: HotwireBottomTab) -> Unit)?) { + fun setOnTabSelectedListener(listener: ((index: Int, tab: HotwireTab) -> Unit)?) { this.listener = listener } @@ -219,7 +219,7 @@ class HotwireBottomNavigationController( } } - private fun switchTab(tab: HotwireBottomTab) { + private fun switchTab(tab: HotwireTab) { activity.delegate.setCurrentNavigator(tab.configuration) tabs.forEach { @@ -228,7 +228,7 @@ class HotwireBottomNavigationController( } } - private val HotwireBottomTab.navigatorHost: NavigatorHost + private val HotwireTab.navigatorHost: NavigatorHost get() { val fragment = activity.supportFragmentManager.findFragmentById(configuration.navigatorHostId) return fragment as NavigatorHost diff --git a/navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireBottomTab.kt b/navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireTab.kt similarity index 67% rename from navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireBottomTab.kt rename to navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireTab.kt index ac0fad4d..730afa9f 100644 --- a/navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireBottomTab.kt +++ b/navigation-fragments/src/main/java/dev/hotwire/navigation/tabs/HotwireTab.kt @@ -4,13 +4,13 @@ import androidx.annotation.DrawableRes import dev.hotwire.navigation.navigator.NavigatorConfiguration /** - * Represents a bottom tab used by the [HotwireBottomNavigationController]. + * Represents a tab used by the [HotwireNavigationController]. * - * @param itemId The [com.google.android.material.bottomnavigation.BottomNavigationView]'s + * @param itemId The [com.google.android.material.navigation.NavigationBarView]'s * menu item ID for the corresponding tab. * @param configuration The [NavigatorConfiguration] for the tab. */ -data class HotwireBottomTab( +data class HotwireTab( val title: String, @DrawableRes val iconResId: Int, val isVisible: Boolean = true, @@ -20,5 +20,5 @@ data class HotwireBottomTab( /** * Maps the tabs to a list of their navigator configurations. */ -val List.navigatorConfigurations +val List.navigatorConfigurations get() = map { it.configuration }