Skip to content

Commit ffc2b5b

Browse files
committed
chore: comment and clean up changes for Android nav rail support
1 parent dfbc97e commit ffc2b5b

File tree

4 files changed

+133
-351
lines changed

4 files changed

+133
-351
lines changed

packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTNavigationRailView.kt

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,43 @@ import com.facebook.react.common.assets.ReactFontManager
1717
import com.facebook.react.views.text.ReactTypefaceUtils
1818
import com.google.android.material.navigationrail.NavigationRailView
1919

20+
/**
21+
* A React Native compatible NavigationRailView that provides Material 3
22+
* sidebar navigation for tablet devices.
23+
*
24+
* This view extends Material's NavigationRailView to support React Native's
25+
* requirements including image loading, theming, and event handling.
26+
*/
2027
class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
2128
override fun getMaxItemCount(): Int {
2229
return 100
2330
}
2431

32+
// Event listeners
2533
var onTabSelectedListener: ((key: String) -> Unit)? = null
2634
var onTabLongPressedListener: ((key: String) -> Unit)? = null
35+
36+
// Data and state
2737
var items: MutableList<TabInfo> = mutableListOf()
28-
private val iconSources: MutableMap<Int, ImageSource> = mutableMapOf()
29-
private val drawableCache: MutableMap<ImageSource, Drawable> = mutableMapOf()
30-
private var pendingRailSelection: String? = null
31-
3238
private var selectedItem: String? = null
39+
40+
// Visual appearance properties
3341
private var activeTintColor: Int? = null
3442
private var inactiveTintColor: Int? = null
35-
private val checkedStateSet = intArrayOf(android.R.attr.state_checked)
36-
private val uncheckedStateSet = intArrayOf(-android.R.attr.state_checked)
37-
private var hapticFeedbackEnabled = false
3843
private var fontSize: Int? = null
3944
private var fontFamily: String? = null
4045
private var fontWeight: Int? = null
4146
private var labeled: Boolean? = null
4247
private var hasCustomAppearance = false
48+
private var hapticFeedbackEnabled = false
49+
50+
// Icon and image management
51+
private val iconSources: MutableMap<Int, ImageSource> = mutableMapOf()
52+
private val drawableCache: MutableMap<ImageSource, Drawable> = mutableMapOf()
53+
54+
// Material state constants
55+
private val checkedStateSet = intArrayOf(android.R.attr.state_checked)
56+
private val uncheckedStateSet = intArrayOf(-android.R.attr.state_checked)
4357

4458
private val imageLoader = ImageLoader.Builder(context)
4559
.components {
@@ -48,29 +62,45 @@ class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
4862
.build()
4963

5064
init {
51-
// Set up navigation rail listeners using Material3's built-in methods
65+
setupNavigationListeners()
66+
}
67+
68+
// MARK: - Initialization
69+
70+
private fun setupNavigationListeners() {
5271
setOnItemSelectedListener { menuItem ->
53-
try {
54-
val selectedTab = items.getOrNull(menuItem.itemId)
55-
selectedTab?.let {
56-
selectedItem = it.key
57-
onTabSelectedListener?.invoke(it.key)
58-
emitHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
59-
}
60-
} catch (e: Exception) {
61-
// Silently handle selection errors
62-
}
63-
true
72+
handleItemSelection(menuItem)
6473
}
6574

6675
setOnItemReselectedListener { menuItem ->
67-
val reselectedTab = items.getOrNull(menuItem.itemId)
68-
reselectedTab?.let {
69-
// Handle reselection if needed
76+
handleItemReselection(menuItem)
77+
}
78+
}
79+
80+
private fun handleItemSelection(menuItem: MenuItem): Boolean {
81+
return try {
82+
val selectedTab = items.getOrNull(menuItem.itemId)
83+
selectedTab?.let { tab ->
84+
selectedItem = tab.key
85+
onTabSelectedListener?.invoke(tab.key)
86+
emitHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
7087
}
88+
true
89+
} catch (e: Exception) {
90+
// Silently handle selection errors
91+
false
92+
}
93+
}
94+
95+
private fun handleItemReselection(menuItem: MenuItem) {
96+
val reselectedTab = items.getOrNull(menuItem.itemId)
97+
reselectedTab?.let {
98+
// Handle reselection if needed in the future
7199
}
72100
}
73101

102+
// MARK: - Image Loading
103+
74104
private fun getDrawable(imageSource: ImageSource, onDrawableReady: (Drawable?) -> Unit) {
75105
drawableCache[imageSource]?.let {
76106
onDrawableReady(it)
@@ -95,6 +125,8 @@ class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
95125
imageLoader.enqueue(request)
96126
}
97127

128+
// MARK: - Tab Management
129+
98130
fun updateItems(items: MutableList<TabInfo>) {
99131
// If an item got removed, let's re-add all items
100132
if (items.size < this.items.size) {
@@ -173,7 +205,11 @@ class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
173205
}
174206
}
175207
}
176-
} fun setLabeled(labeled: Boolean?) {
208+
}
209+
210+
// MARK: - Configuration Methods
211+
212+
fun setLabeled(labeled: Boolean?) {
177213
this.labeled = labeled
178214
labelVisibilityMode = when (labeled) {
179215
false -> com.google.android.material.navigation.NavigationBarView.LABEL_VISIBILITY_UNLABELED
@@ -240,17 +276,23 @@ class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
240276
}
241277

242278
fun setRippleColor(color: Int?) {
243-
itemRippleColor = color?.let { android.content.res.ColorStateList.valueOf(it) }
279+
// NavigationRail doesn't have direct ripple color support like BottomNavigationView
280+
// The ripple effect is handled by the Material theme
281+
// This method exists for API compatibility but doesn't perform any action
244282
}
245283

246284
fun setActiveIndicatorColor(color: Int?) {
247-
activeTintColor = color
285+
// NavigationRail doesn't have an active indicator like BottomNavigationView
286+
// The active state is shown through different styling
287+
// This method exists for API compatibility but doesn't perform any action
248288
}
249289

250290
override fun setHapticFeedbackEnabled(hapticFeedbackEnabled: Boolean) {
251291
this.hapticFeedbackEnabled = hapticFeedbackEnabled
252292
}
253293

294+
// MARK: - Appearance Updates
295+
254296
fun updateTextAppearance() {
255297
// Early return if there is no custom text appearance
256298
if (fontSize == null && fontFamily == null && fontWeight == null) {
@@ -301,12 +343,16 @@ class ReactNavigationRailView(context: Context) : NavigationRailView(context) {
301343
}
302344
}
303345

346+
// MARK: - Utility Methods
347+
304348
private fun emitHapticFeedback(feedbackConstants: Int) {
305349
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && hapticFeedbackEnabled) {
306350
this.performHapticFeedback(feedbackConstants)
307351
}
308352
}
309353

354+
// MARK: - Lifecycle Methods
355+
310356
fun handleConfigurationChanged(newConfig: Configuration?) {
311357
if (hasCustomAppearance) {
312358
return

0 commit comments

Comments
 (0)