@onekeyfe/react-native-bottom-tabs 0.0.0-stage → 6.7.0-alpha.339
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +46 -0
- package/README.md +86 -2
- package/android/build.gradle +119 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsPackage.kt +16 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsView.kt +1419 -0
- package/android/src/main/java/com/onekey/bottomtabs/BottomTabsViewManager.kt +216 -0
- package/android/src/main/java/com/onekey/bottomtabs/FloatingTabBarStyle.kt +50 -0
- package/android/src/main/java/com/onekey/bottomtabs/ImageSource.kt +86 -0
- package/android/src/main/java/com/onekey/bottomtabs/TabInfo.kt +13 -0
- package/android/src/main/java/com/onekey/bottomtabs/Utils.kt +31 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/OnNativeLayoutEvent.kt +20 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/OnTabBarMeasuredEvent.kt +19 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/PageSelectedEvent.kt +21 -0
- package/android/src/main/java/com/onekey/bottomtabs/events/TabDoublePressEvent.kt +19 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewComponentDescriptor.h +32 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.cpp +18 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.h +35 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewState.cpp +15 -0
- package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewState.h +25 -0
- package/docs/SPEC.md +101 -0
- package/ios/Extensions.swift +46 -0
- package/ios/RCTBottomAccessoryComponentView.h +12 -0
- package/ios/RCTBottomAccessoryComponentView.mm +67 -0
- package/ios/RCTBottomAccessoryContainerView.swift +51 -0
- package/ios/RCTBottomTabsComponentView.h +12 -0
- package/ios/RCTBottomTabsComponentView.mm +338 -0
- package/ios/RCTBottomTabsContainerView.swift +777 -0
- package/ios/RCTBottomTabsLog.h +7 -0
- package/ios/RCTBottomTabsLog.m +32 -0
- package/ios/SVG/CoreSVG.h +13 -0
- package/ios/SVG/CoreSVG.mm +177 -0
- package/ios/SVG/SvgDecoder.h +10 -0
- package/ios/SVG/SvgDecoder.mm +32 -0
- package/ios/TabBarFontSize.swift +55 -0
- package/lib/module/BottomAccessoryView.js +45 -0
- package/lib/module/BottomAccessoryViewNativeComponent.ts +27 -0
- package/lib/module/BottomTabs.js +323 -0
- package/lib/module/BottomTabsNativeComponent.ts +69 -0
- package/lib/module/DelayedFreeze.js +31 -0
- package/lib/module/NativeSVGDecoder.js +5 -0
- package/lib/module/SceneMap.js +28 -0
- package/lib/module/codegen-types.d.js +2 -0
- package/lib/module/index.js +20 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/utils/BottomTabBarHeightContext.js +5 -0
- package/lib/module/utils/useBottomTabBarHeight.js +12 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/BottomAccessoryView.d.ts +8 -0
- package/lib/typescript/src/BottomAccessoryViewNativeComponent.d.ts +16 -0
- package/lib/typescript/src/BottomTabs.d.ts +202 -0
- package/lib/typescript/src/BottomTabsNativeComponent.d.ts +58 -0
- package/lib/typescript/src/DelayedFreeze.d.ts +9 -0
- package/lib/typescript/src/NativeSVGDecoder.d.ts +6 -0
- package/lib/typescript/src/SceneMap.d.ts +10 -0
- package/lib/typescript/src/index.d.ts +16 -0
- package/lib/typescript/src/types.d.ts +29 -0
- package/lib/typescript/src/utils/BottomTabBarHeightContext.d.ts +3 -0
- package/lib/typescript/src/utils/useBottomTabBarHeight.d.ts +2 -0
- package/package.json +117 -4
- package/react-native-bottom-tabs.podspec +36 -0
- package/react-native.config.js +13 -0
- package/src/BottomAccessoryView.tsx +58 -0
- package/src/BottomAccessoryViewNativeComponent.ts +27 -0
- package/src/BottomTabs.tsx +545 -0
- package/src/BottomTabsNativeComponent.ts +69 -0
- package/src/DelayedFreeze.tsx +33 -0
- package/src/NativeSVGDecoder.ts +5 -0
- package/src/SceneMap.tsx +34 -0
- package/src/codegen-types.d.ts +28 -0
- package/src/index.tsx +18 -0
- package/src/types.ts +31 -0
- package/src/utils/BottomTabBarHeightContext.ts +5 -0
- package/src/utils/useBottomTabBarHeight.ts +15 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
package com.onekey.bottomtabs
|
|
2
|
+
|
|
3
|
+
import android.content.res.ColorStateList
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.bridge.ReadableArray
|
|
8
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
9
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
10
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
11
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
12
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
13
|
+
import com.facebook.react.viewmanagers.RNBottomTabsViewManagerDelegate
|
|
14
|
+
import com.facebook.react.viewmanagers.RNBottomTabsViewManagerInterface
|
|
15
|
+
import com.onekey.bottomtabs.events.OnNativeLayoutEvent
|
|
16
|
+
import com.onekey.bottomtabs.events.OnTabBarMeasuredEvent
|
|
17
|
+
import com.onekey.bottomtabs.events.PageSelectedEvent
|
|
18
|
+
import com.onekey.bottomtabs.events.TabDoublePressEvent
|
|
19
|
+
|
|
20
|
+
@ReactModule(name = BottomTabsViewManager.NAME)
|
|
21
|
+
class BottomTabsViewManager(context: ReactApplicationContext) :
|
|
22
|
+
ViewGroupManager<BottomTabsView>(),
|
|
23
|
+
RNBottomTabsViewManagerInterface<BottomTabsView> {
|
|
24
|
+
|
|
25
|
+
private val delegate: RNBottomTabsViewManagerDelegate<BottomTabsView, BottomTabsViewManager> =
|
|
26
|
+
RNBottomTabsViewManagerDelegate(this)
|
|
27
|
+
|
|
28
|
+
override fun createViewInstance(context: ThemedReactContext): BottomTabsView {
|
|
29
|
+
val view = BottomTabsView(context)
|
|
30
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
31
|
+
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
32
|
+
|
|
33
|
+
view.onTabSelectedListener = { key ->
|
|
34
|
+
eventDispatcher?.dispatchEvent(PageSelectedEvent(surfaceId, view.id, key))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
view.onTabDoublePressedListener = { key ->
|
|
38
|
+
eventDispatcher?.dispatchEvent(TabDoublePressEvent(surfaceId, view.id, key))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
view.onNativeLayoutListener = { width, height ->
|
|
42
|
+
eventDispatcher?.dispatchEvent(OnNativeLayoutEvent(surfaceId, view.id, width, height))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
view.onTabBarMeasuredListener = { height ->
|
|
46
|
+
eventDispatcher?.dispatchEvent(OnTabBarMeasuredEvent(surfaceId, view.id, height))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return view
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override fun onDropViewInstance(view: BottomTabsView) {
|
|
53
|
+
super.onDropViewInstance(view)
|
|
54
|
+
view.onDropViewInstance()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override fun getName(): String = NAME
|
|
58
|
+
|
|
59
|
+
override fun getDelegate(): ViewManagerDelegate<BottomTabsView> = delegate
|
|
60
|
+
|
|
61
|
+
// MARK: - Child view management
|
|
62
|
+
|
|
63
|
+
override fun addView(parent: BottomTabsView, child: View, index: Int) {
|
|
64
|
+
parent.addView(child, index)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override fun getChildCount(parent: BottomTabsView): Int {
|
|
68
|
+
return parent.layoutHolder.childCount
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun getChildAt(parent: BottomTabsView, index: Int): View? {
|
|
72
|
+
val container = parent.layoutHolder.getChildAt(index) as? ViewGroup
|
|
73
|
+
return container?.getChildAt(0) ?: parent.layoutHolder.getChildAt(index)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
override fun removeView(parent: BottomTabsView, view: View) {
|
|
77
|
+
for (i in 0 until parent.layoutHolder.childCount) {
|
|
78
|
+
val container = parent.layoutHolder.getChildAt(i) as? ViewGroup
|
|
79
|
+
if (container != null && container.childCount > 0 && container.getChildAt(0) === view) {
|
|
80
|
+
parent.layoutHolder.removeViewAt(i)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
parent.layoutHolder.removeView(view)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override fun removeAllViews(parent: BottomTabsView) {
|
|
88
|
+
parent.layoutHolder.removeAllViews()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
override fun removeViewAt(parent: BottomTabsView, index: Int) {
|
|
92
|
+
parent.layoutHolder.removeViewAt(index)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override fun needsCustomLayoutForChildren(): Boolean = true
|
|
96
|
+
|
|
97
|
+
// MARK: - Props (RNBottomTabsViewManagerInterface)
|
|
98
|
+
|
|
99
|
+
override fun setItems(view: BottomTabsView?, value: ReadableArray?) {
|
|
100
|
+
if (view != null && value != null) {
|
|
101
|
+
val itemsArray = mutableListOf<TabInfo>()
|
|
102
|
+
for (i in 0 until value.size()) {
|
|
103
|
+
value.getMap(i)?.let { item ->
|
|
104
|
+
itemsArray.add(
|
|
105
|
+
TabInfo(
|
|
106
|
+
key = item.getString("key") ?: "",
|
|
107
|
+
title = item.getString("title") ?: "",
|
|
108
|
+
badge = if (item.hasKey("badge")) item.getString("badge") else null,
|
|
109
|
+
badgeBackgroundColor = if (item.hasKey("badgeBackgroundColor")) item.getInt("badgeBackgroundColor") else null,
|
|
110
|
+
badgeTextColor = if (item.hasKey("badgeTextColor")) item.getInt("badgeTextColor") else null,
|
|
111
|
+
activeTintColor = if (item.hasKey("activeTintColor")) item.getInt("activeTintColor") else null,
|
|
112
|
+
hidden = if (item.hasKey("hidden")) item.getBoolean("hidden") else false,
|
|
113
|
+
testID = item.getString("testID"),
|
|
114
|
+
preventsDefault = if (item.hasKey("preventsDefault")) item.getBoolean("preventsDefault") else false
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
view.updateItems(itemsArray)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun setSelectedPage(view: BottomTabsView?, value: String?) {
|
|
124
|
+
if (view != null && value != null)
|
|
125
|
+
view.setSelectedItem(value)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
override fun setIcons(view: BottomTabsView?, value: ReadableArray?) {
|
|
129
|
+
if (view != null)
|
|
130
|
+
view.setIcons(value)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override fun setLabeled(view: BottomTabsView?, value: Boolean) {
|
|
134
|
+
if (view != null)
|
|
135
|
+
view.setLabeled(value)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override fun setRippleColor(view: BottomTabsView?, value: Int?) {
|
|
139
|
+
if (view != null && value != null) {
|
|
140
|
+
val color = ColorStateList.valueOf(value)
|
|
141
|
+
view.setRippleColor(color)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override fun setBarTintColor(view: BottomTabsView?, value: Int?) {
|
|
146
|
+
if (view != null && value != null)
|
|
147
|
+
view.setBarTintColor(value)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
override fun setActiveTintColor(view: BottomTabsView?, value: Int?) {
|
|
151
|
+
if (view != null && value != null)
|
|
152
|
+
view.setActiveTintColor(value)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override fun setInactiveTintColor(view: BottomTabsView?, value: Int?) {
|
|
156
|
+
if (view != null && value != null)
|
|
157
|
+
view.setInactiveTintColor(value)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
override fun setActiveIndicatorColor(view: BottomTabsView?, value: Int?) {
|
|
161
|
+
if (view != null && value != null) {
|
|
162
|
+
val color = ColorStateList.valueOf(value)
|
|
163
|
+
view.setActiveIndicatorColor(color)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
override fun setHapticFeedbackEnabled(view: BottomTabsView?, value: Boolean) {
|
|
168
|
+
if (view != null)
|
|
169
|
+
view.isHapticFeedbackEnabled = value
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
override fun setFontFamily(view: BottomTabsView?, value: String?) {
|
|
173
|
+
view?.setFontFamily(value)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
override fun setFontWeight(view: BottomTabsView?, value: String?) {
|
|
177
|
+
view?.setFontWeight(value)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override fun setFontSize(view: BottomTabsView?, value: Int) {
|
|
181
|
+
view?.setFontSize(value)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
override fun setDisablePageAnimations(view: BottomTabsView?, value: Boolean) {
|
|
185
|
+
view?.disablePageAnimations = value
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
override fun setTabBarHidden(view: BottomTabsView?, value: Boolean) {
|
|
189
|
+
view?.setTabBarHidden(value)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
override fun setIgnoreBottomInsets(view: BottomTabsView?, value: Boolean) {
|
|
193
|
+
view?.setIgnoreBottomInsets(value)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
override fun setAndroidTabBarStyle(view: BottomTabsView?, value: String?) {
|
|
197
|
+
view?.setAndroidTabBarStyle(value)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
override fun setIgnoreKeyboardInsets(view: BottomTabsView?, value: Boolean) {
|
|
201
|
+
view?.setIgnoreKeyboardInsets(value)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// iOS-only props (no-ops on Android)
|
|
205
|
+
// selectedIcons feeds UITabBarItem.selectedImage on iOS; Android keeps
|
|
206
|
+
// swapping the icon in JS via the focusedKey-driven `icons` array.
|
|
207
|
+
override fun setSelectedIcons(view: BottomTabsView?, value: ReadableArray?) {}
|
|
208
|
+
override fun setTranslucent(view: BottomTabsView?, value: Boolean) {}
|
|
209
|
+
override fun setSidebarAdaptable(view: BottomTabsView?, value: Boolean) {}
|
|
210
|
+
override fun setScrollEdgeAppearance(view: BottomTabsView?, value: String?) {}
|
|
211
|
+
override fun setMinimizeBehavior(view: BottomTabsView?, value: String?) {}
|
|
212
|
+
|
|
213
|
+
companion object {
|
|
214
|
+
const val NAME = "RNBottomTabsView"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.onekey.bottomtabs
|
|
2
|
+
|
|
3
|
+
import android.view.animation.Interpolator
|
|
4
|
+
import kotlin.math.cos
|
|
5
|
+
import kotlin.math.exp
|
|
6
|
+
import kotlin.math.sin
|
|
7
|
+
import kotlin.math.sqrt
|
|
8
|
+
|
|
9
|
+
// Geometry of the floating tab bar, modeled on the iOS 26 Liquid Glass tab bar (dp).
|
|
10
|
+
internal object FloatingTabBarMetrics {
|
|
11
|
+
const val BAR_HEIGHT = 62f
|
|
12
|
+
const val BAR_SIDE_MARGIN = 20f
|
|
13
|
+
const val BAR_MIN_BOTTOM_GAP = 20f
|
|
14
|
+
const val BAR_BOTTOM_EXTRA = 4f
|
|
15
|
+
const val BAR_CONTENT_PADDING = 4f
|
|
16
|
+
const val INDICATOR_INSET = 4f
|
|
17
|
+
const val ICON_SIZE = 26f
|
|
18
|
+
const val LABEL_SIZE_SP = 10f
|
|
19
|
+
const val SHADOW_ELEVATION = 14f
|
|
20
|
+
|
|
21
|
+
// Lens growth while a tab is pressed or dragged.
|
|
22
|
+
const val LENS_SCALE_X = 1.14f
|
|
23
|
+
const val LENS_SCALE_Y = 1.24f
|
|
24
|
+
const val LENS_MAX_STRETCH = 0.16f
|
|
25
|
+
const val ITEM_PRESSED_SCALE = 1.1f
|
|
26
|
+
const val DRAG_EDGE_RESISTANCE = 0.22f
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Damped spring response normalized to [0, 1] input time. A damping ratio
|
|
31
|
+
* below 1 overshoots slightly before settling, matching UIKit spring motion.
|
|
32
|
+
*/
|
|
33
|
+
internal class SpringInterpolator(
|
|
34
|
+
private val dampingRatio: Float = 0.72f,
|
|
35
|
+
private val angularFrequency: Float = 10f,
|
|
36
|
+
) : Interpolator {
|
|
37
|
+
private val dampedFrequency =
|
|
38
|
+
angularFrequency * sqrt(1f - dampingRatio * dampingRatio)
|
|
39
|
+
|
|
40
|
+
override fun getInterpolation(input: Float): Float {
|
|
41
|
+
if (input >= 1f) {
|
|
42
|
+
return 1f
|
|
43
|
+
}
|
|
44
|
+
val decay = exp(-dampingRatio * angularFrequency * input)
|
|
45
|
+
val phase = dampedFrequency * input
|
|
46
|
+
return 1f - decay * (
|
|
47
|
+
cos(phase) + (dampingRatio * angularFrequency / dampedFrequency) * sin(phase)
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
package com.onekey.bottomtabs
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper
|
|
7
|
+
import java.util.Locale
|
|
8
|
+
|
|
9
|
+
data class ImageSource(
|
|
10
|
+
val context: Context,
|
|
11
|
+
val uri: String? = null,
|
|
12
|
+
) {
|
|
13
|
+
private fun isLocalResourceUri(uri: Uri?) = uri?.scheme?.startsWith("res") ?: false
|
|
14
|
+
|
|
15
|
+
fun getUri(context: Context): Uri? {
|
|
16
|
+
val uri = computeUri(context)
|
|
17
|
+
|
|
18
|
+
if (isLocalResourceUri(uri)) {
|
|
19
|
+
return Uri.parse(
|
|
20
|
+
uri!!.toString().replace("res:/", "android.resource://" + context.packageName + "/")
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return uri
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private fun computeUri(context: Context): Uri? {
|
|
28
|
+
val stringUri = uri ?: return null
|
|
29
|
+
return try {
|
|
30
|
+
val uri: Uri = Uri.parse(stringUri)
|
|
31
|
+
// Verify scheme is set, so that relative uri (used by static resources) are not handled.
|
|
32
|
+
if (uri.scheme == null) {
|
|
33
|
+
computeLocalUri(stringUri, context)
|
|
34
|
+
} else {
|
|
35
|
+
uri
|
|
36
|
+
}
|
|
37
|
+
} catch (e: Exception) {
|
|
38
|
+
computeLocalUri(stringUri, context)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun computeLocalUri(stringUri: String, context: Context): Uri? {
|
|
43
|
+
return ResourceIdHelper.getResourceUri(context, stringUri)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Taken from https://github.com/expo/expo/blob/sdk-52/packages/expo-image/android/src/main/java/expo/modules/image/ResourceIdHelper.kt
|
|
48
|
+
object ResourceIdHelper {
|
|
49
|
+
private val idMap = mutableMapOf<String, Int>()
|
|
50
|
+
|
|
51
|
+
@SuppressLint("DiscouragedApi")
|
|
52
|
+
private fun getResourceRawId(context: Context, name: String): Int {
|
|
53
|
+
if (name.isEmpty()) {
|
|
54
|
+
return -1
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
val normalizedName = name.lowercase(Locale.ROOT).replace("-", "_")
|
|
58
|
+
synchronized(this) {
|
|
59
|
+
val id = idMap[normalizedName]
|
|
60
|
+
if (id != null) {
|
|
61
|
+
return id
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return context
|
|
65
|
+
.resources
|
|
66
|
+
.getIdentifier(normalizedName, "raw", context.packageName)
|
|
67
|
+
.also {
|
|
68
|
+
idMap[normalizedName] = it
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fun getResourceUri(context: Context, name: String): Uri? {
|
|
74
|
+
val drawableUri = ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(context, name)
|
|
75
|
+
if (drawableUri != Uri.EMPTY) {
|
|
76
|
+
return drawableUri
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
val resId = getResourceRawId(context, name)
|
|
80
|
+
return if (resId > 0) {
|
|
81
|
+
Uri.Builder().scheme("res").path(resId.toString()).build()
|
|
82
|
+
} else {
|
|
83
|
+
null
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package com.onekey.bottomtabs
|
|
2
|
+
|
|
3
|
+
data class TabInfo(
|
|
4
|
+
val key: String,
|
|
5
|
+
val title: String,
|
|
6
|
+
val badge: String? = null,
|
|
7
|
+
val badgeBackgroundColor: Int? = null,
|
|
8
|
+
val badgeTextColor: Int? = null,
|
|
9
|
+
val activeTintColor: Int? = null,
|
|
10
|
+
val hidden: Boolean = false,
|
|
11
|
+
val testID: String? = null,
|
|
12
|
+
val preventsDefault: Boolean = false
|
|
13
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.onekey.bottomtabs
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
import android.util.TypedValue
|
|
6
|
+
import androidx.appcompat.content.res.AppCompatResources
|
|
7
|
+
|
|
8
|
+
class Utils {
|
|
9
|
+
companion object {
|
|
10
|
+
fun convertPixelsToDp(context: Context, value: Int): Double {
|
|
11
|
+
val displayDensity = context.resources.displayMetrics.density
|
|
12
|
+
return (value / displayDensity).toDouble()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fun getTypefaceStyle(weight: Int?) = when (weight) {
|
|
16
|
+
700 -> Typeface.BOLD
|
|
17
|
+
else -> Typeface.NORMAL
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fun getDefaultColorFor(context: Context, baseColorThemeAttr: Int): Int? {
|
|
21
|
+
val value = TypedValue()
|
|
22
|
+
if (!context.theme.resolveAttribute(baseColorThemeAttr, value, true)) {
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
val baseColor = AppCompatResources.getColorStateList(
|
|
26
|
+
context, value.resourceId
|
|
27
|
+
)
|
|
28
|
+
return baseColor.defaultColor
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package com.onekey.bottomtabs.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class OnNativeLayoutEvent(surfaceId: Int, viewTag: Int, private val width: Double, private val height: Double) : Event<OnNativeLayoutEvent>(surfaceId, viewTag) {
|
|
8
|
+
override fun getEventName(): String = EVENT_NAME
|
|
9
|
+
|
|
10
|
+
override fun getEventData(): WritableMap {
|
|
11
|
+
return Arguments.createMap().apply {
|
|
12
|
+
putDouble("width", width)
|
|
13
|
+
putDouble("height", height)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
const val EVENT_NAME = "onNativeLayout"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package com.onekey.bottomtabs.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class OnTabBarMeasuredEvent(surfaceId: Int, viewTag: Int, private val height: Int) : Event<OnTabBarMeasuredEvent>(surfaceId, viewTag) {
|
|
8
|
+
override fun getEventName(): String = EVENT_NAME
|
|
9
|
+
|
|
10
|
+
override fun getEventData(): WritableMap {
|
|
11
|
+
return Arguments.createMap().apply {
|
|
12
|
+
putInt("height", height)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
companion object {
|
|
17
|
+
const val EVENT_NAME = "onTabBarMeasured"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
package com.onekey.bottomtabs.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class PageSelectedEvent(surfaceId: Int, viewTag: Int, private val key: String) : Event<PageSelectedEvent>(surfaceId, viewTag) {
|
|
8
|
+
override fun getEventName(): String = EVENT_NAME
|
|
9
|
+
|
|
10
|
+
override fun canCoalesce(): Boolean = false
|
|
11
|
+
|
|
12
|
+
override fun getEventData(): WritableMap {
|
|
13
|
+
return Arguments.createMap().apply {
|
|
14
|
+
putString("key", key)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
companion object {
|
|
19
|
+
const val EVENT_NAME = "topPageSelected"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package com.onekey.bottomtabs.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class TabDoublePressEvent(surfaceId: Int, viewTag: Int, private val key: String) : Event<TabDoublePressEvent>(surfaceId, viewTag) {
|
|
8
|
+
override fun getEventName(): String = EVENT_NAME
|
|
9
|
+
|
|
10
|
+
override fun getEventData(): WritableMap {
|
|
11
|
+
return Arguments.createMap().apply {
|
|
12
|
+
putString("key", key)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
companion object {
|
|
17
|
+
const val EVENT_NAME = "onTabDoublePress"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/common/cpp/react/renderer/components/RNBottomTabs/RNBottomTabsViewComponentDescriptor.h
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#ifdef __cplusplus
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.h>
|
|
6
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
7
|
+
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
8
|
+
|
|
9
|
+
namespace facebook::react {
|
|
10
|
+
|
|
11
|
+
class RNBottomTabsViewComponentDescriptor final
|
|
12
|
+
: public ConcreteComponentDescriptor<RNBottomTabsViewShadowNode> {
|
|
13
|
+
public:
|
|
14
|
+
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
15
|
+
|
|
16
|
+
void adopt(ShadowNode& shadowNode) const override {
|
|
17
|
+
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
18
|
+
|
|
19
|
+
#if !defined(ANDROID)
|
|
20
|
+
auto &bottomTabsShadowNode =
|
|
21
|
+
static_cast<RNBottomTabsViewShadowNode&>(shadowNode);
|
|
22
|
+
|
|
23
|
+
std::weak_ptr<void> imageLoader =
|
|
24
|
+
contextContainer_->at<std::shared_ptr<void>>("RCTImageLoader");
|
|
25
|
+
bottomTabsShadowNode.setImageLoader(imageLoader);
|
|
26
|
+
#endif
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
} // namespace facebook::react
|
|
31
|
+
|
|
32
|
+
#endif
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#include <react/renderer/components/RNBottomTabs/RNBottomTabsViewShadowNode.h>
|
|
2
|
+
|
|
3
|
+
namespace facebook::react {
|
|
4
|
+
|
|
5
|
+
extern const char RNBottomTabsViewComponentName[] = "RNBottomTabsView";
|
|
6
|
+
|
|
7
|
+
void RNBottomTabsViewShadowNode::setImageLoader(
|
|
8
|
+
std::weak_ptr<void> imageLoader) {
|
|
9
|
+
getStateDataMutable().setImageLoader(imageLoader);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
RNBottomTabsViewShadowNode::StateData &
|
|
13
|
+
RNBottomTabsViewShadowNode::getStateDataMutable() {
|
|
14
|
+
ensureUnsealed();
|
|
15
|
+
return const_cast<RNBottomTabsViewShadowNode::StateData &>(getStateData());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#ifdef __cplusplus
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/components/RNBottomTabs/EventEmitters.h>
|
|
6
|
+
#include <react/renderer/components/RNBottomTabs/Props.h>
|
|
7
|
+
#include <react/renderer/components/RNBottomTabs/RNBottomTabsViewState.h>
|
|
8
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
9
|
+
#include <jsi/jsi.h>
|
|
10
|
+
|
|
11
|
+
namespace facebook::react {
|
|
12
|
+
|
|
13
|
+
JSI_EXPORT extern const char RNBottomTabsViewComponentName[];
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* `ShadowNode` for <RNBottomTabsView> component.
|
|
17
|
+
*/
|
|
18
|
+
class JSI_EXPORT RNBottomTabsViewShadowNode final: public ConcreteViewShadowNode<
|
|
19
|
+
RNBottomTabsViewComponentName,
|
|
20
|
+
RNBottomTabsViewProps,
|
|
21
|
+
RNBottomTabsViewEventEmitter,
|
|
22
|
+
RNBottomTabsViewState> {
|
|
23
|
+
|
|
24
|
+
public:
|
|
25
|
+
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
26
|
+
using StateData = ConcreteViewShadowNode::ConcreteStateData;
|
|
27
|
+
|
|
28
|
+
void setImageLoader(std::weak_ptr<void> imageLoader);
|
|
29
|
+
|
|
30
|
+
StateData &getStateDataMutable();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#endif
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#include <react/renderer/components/RNBottomTabs/RNBottomTabsViewState.h>
|
|
2
|
+
|
|
3
|
+
namespace facebook::react {
|
|
4
|
+
|
|
5
|
+
void RNBottomTabsViewState::setImageLoader(
|
|
6
|
+
std::weak_ptr<void> imageLoader) {
|
|
7
|
+
imageLoader_ = imageLoader;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
std::weak_ptr<void> RNBottomTabsViewState::getImageLoader()
|
|
11
|
+
const noexcept {
|
|
12
|
+
return imageLoader_;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#ifdef __cplusplus
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/core/StateData.h>
|
|
6
|
+
#ifdef RN_SERIALIZABLE_STATE
|
|
7
|
+
#include <folly/dynamic.h>
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
namespace facebook::react {
|
|
11
|
+
|
|
12
|
+
class RNBottomTabsViewState final {
|
|
13
|
+
public:
|
|
14
|
+
RNBottomTabsViewState() = default;
|
|
15
|
+
|
|
16
|
+
void setImageLoader(std::weak_ptr<void> imageLoader);
|
|
17
|
+
std::weak_ptr<void> getImageLoader() const noexcept;
|
|
18
|
+
|
|
19
|
+
private:
|
|
20
|
+
std::weak_ptr<void> imageLoader_;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
} // namespace facebook::react
|
|
24
|
+
|
|
25
|
+
#endif
|