react-native-platform-components 1.1.0 → 1.3.0
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/README.md +23 -12
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +46 -2
- package/android/src/main/java/com/platformcomponents/PCNativeTheme.kt +174 -0
- package/android/src/main/java/com/platformcomponents/PCNativeThemeModule.kt +45 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +36 -3
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +14 -0
- package/android/src/main/java/com/platformcomponents/PCThemeSupport.kt +40 -5
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +25 -5
- package/android/src/main/jni/CMakeLists.txt +13 -1
- package/android/src/main/res/values/styles.xml +131 -0
- package/ios/PCNativeTheme.swift +56 -0
- package/ios/PCNativeThemeModule.mm +49 -0
- package/ios/PCSelectionMenu.swift +9 -1
- package/lib/commonjs/ContextMenuNativeComponent.ts +5 -4
- package/lib/commonjs/DatePickerNativeComponent.ts +17 -11
- package/lib/commonjs/LiquidGlass.js +24 -4
- package/lib/commonjs/LiquidGlass.js.map +1 -1
- package/lib/commonjs/LiquidGlassNativeComponent.ts +6 -5
- package/lib/commonjs/NativePlatformComponentsTheme.js +10 -0
- package/lib/commonjs/NativePlatformComponentsTheme.js.map +1 -0
- package/lib/commonjs/NativeTheme.js +51 -0
- package/lib/commonjs/NativeTheme.js.map +1 -0
- package/lib/commonjs/SegmentedControlNativeComponent.ts +12 -11
- package/lib/commonjs/SelectionMenuNativeComponent.ts +6 -5
- package/lib/commonjs/codegenTypes.js +6 -0
- package/lib/commonjs/codegenTypes.js.map +1 -0
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +10 -1
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/module/ContextMenuNativeComponent.ts +5 -4
- package/lib/module/DatePickerNativeComponent.ts +17 -11
- package/lib/module/LiquidGlass.js +24 -4
- package/lib/module/LiquidGlass.js.map +1 -1
- package/lib/module/LiquidGlassNativeComponent.ts +6 -5
- package/lib/module/NativePlatformComponentsTheme.js +7 -0
- package/lib/module/NativePlatformComponentsTheme.js.map +1 -0
- package/lib/module/NativeTheme.js +45 -0
- package/lib/module/NativeTheme.js.map +1 -0
- package/lib/module/SegmentedControlNativeComponent.ts +12 -11
- package/lib/module/SelectionMenuNativeComponent.ts +6 -5
- package/lib/module/codegenTypes.js +4 -0
- package/lib/module/codegenTypes.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +7 -0
- package/lib/module/index.web.js.map +1 -1
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +5 -4
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +12 -11
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts +4 -3
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +6 -5
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts +19 -0
- package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/NativeTheme.d.ts +30 -0
- package/lib/typescript/commonjs/src/NativeTheme.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +7 -6
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +6 -5
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/codegenTypes.d.ts +12 -0
- package/lib/typescript/commonjs/src/codegenTypes.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.web.d.ts +8 -1
- package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/sharedTypes.d.ts +2 -2
- package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +5 -4
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +12 -11
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlass.d.ts +4 -3
- package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +6 -5
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts +19 -0
- package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts.map +1 -0
- package/lib/typescript/module/src/NativeTheme.d.ts +30 -0
- package/lib/typescript/module/src/NativeTheme.d.ts.map +1 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +7 -6
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +6 -5
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/codegenTypes.d.ts +12 -0
- package/lib/typescript/module/src/codegenTypes.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.web.d.ts +8 -1
- package/lib/typescript/module/src/index.web.d.ts.map +1 -1
- package/lib/typescript/module/src/sharedTypes.d.ts +2 -2
- package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
- package/package.json +8 -4
- package/shared/PCDatePickerState-custom.h +2 -2
- package/shared/PCSegmentedControlState-custom.h +2 -2
- package/shared/PCSelectionMenuState-custom.h +2 -2
- package/src/ContextMenuNativeComponent.ts +5 -4
- package/src/DatePickerNativeComponent.ts +17 -11
- package/src/LiquidGlass.tsx +24 -5
- package/src/LiquidGlassNativeComponent.ts +6 -5
- package/src/NativePlatformComponentsTheme.ts +22 -0
- package/src/NativeTheme.ts +53 -0
- package/src/SegmentedControlNativeComponent.ts +12 -11
- package/src/SelectionMenuNativeComponent.ts +6 -5
- package/src/codegenTypes.ts +40 -0
- package/src/index.tsx +1 -0
- package/src/index.web.tsx +17 -1
- package/src/sharedTypes.ts +2 -2
- /package/{app.plugin.cjs → app.plugin.js} +0 -0
package/README.md
CHANGED
|
@@ -14,20 +14,23 @@ Native **DatePicker**, **ContextMenu**, **SelectionMenu**, **SegmentedControl**
|
|
|
14
14
|
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu">SelectionMenu</a></td>
|
|
15
15
|
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol">SegmentedControl</a></td>
|
|
16
16
|
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass">LiquidGlass</a></td>
|
|
17
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/guides/theming">Theme</a></td>
|
|
17
18
|
</tr>
|
|
18
19
|
<tr>
|
|
19
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/datepicker"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-datepicker.gif" width="
|
|
20
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-contextmenu.gif" width="
|
|
21
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-selectionmenu.gif" width="
|
|
22
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-segmentedcontrol.gif" width="
|
|
23
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-liquidglass.gif" width="
|
|
20
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/datepicker"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-datepicker.gif" width="100" alt="DatePicker on iOS" /></a></td>
|
|
21
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-contextmenu.gif" width="100" alt="ContextMenu on iOS" /></a></td>
|
|
22
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-selectionmenu.gif" width="100" alt="SelectionMenu on iOS" /></a></td>
|
|
23
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-segmentedcontrol.gif" width="100" alt="SegmentedControl on iOS" /></a></td>
|
|
24
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-liquidglass.gif" width="100" alt="LiquidGlass on iOS" /></a></td>
|
|
25
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/guides/theming"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/ios-theme.gif" width="100" alt="Brand color and dark mode on iOS" /></a></td>
|
|
24
26
|
</tr>
|
|
25
27
|
<tr>
|
|
26
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/datepicker"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-datepicker.gif" width="
|
|
27
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-contextmenu.gif" width="
|
|
28
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-selectionmenu.gif" width="
|
|
29
|
-
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-segmentedcontrol.gif" width="
|
|
28
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/datepicker"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-datepicker.gif" width="100" alt="DatePicker on Android" /></a></td>
|
|
29
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-contextmenu.gif" width="100" alt="ContextMenu on Android" /></a></td>
|
|
30
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-selectionmenu.gif" width="100" alt="SelectionMenu on Android" /></a></td>
|
|
31
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-segmentedcontrol.gif" width="100" alt="SegmentedControl on Android" /></a></td>
|
|
30
32
|
<td align="center" valign="middle"><sub>iOS 26+ only.<br/>Plain View on Android.</sub></td>
|
|
33
|
+
<td align="center"><a href="https://jarx-concepts.github.io/react-native-platform-components/guides/theming"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/android-theme.gif" width="100" alt="Brand color and dark mode on Android" /></a></td>
|
|
31
34
|
</tr>
|
|
32
35
|
</table>
|
|
33
36
|
|
|
@@ -104,6 +107,9 @@ yarn add react-native-platform-components
|
|
|
104
107
|
}
|
|
105
108
|
```
|
|
106
109
|
|
|
110
|
+
Either form of the reference works: `react-native-platform-components/app.plugin`
|
|
111
|
+
as above, or the bare package name.
|
|
112
|
+
|
|
107
113
|
```sh
|
|
108
114
|
npx expo install react-native-platform-components
|
|
109
115
|
npx expo prebuild
|
|
@@ -119,8 +125,13 @@ The library is built for the New Architecture (Fabric + Codegen) and does not su
|
|
|
119
125
|
| React Native | 0.81 with the New Architecture enabled |
|
|
120
126
|
| Expo SDK | 54, with a dev client or EAS Build (not Expo Go) |
|
|
121
127
|
| React | 19 |
|
|
122
|
-
| iOS |
|
|
123
|
-
| Android | API 24 (Android 7.0); Material Components 1.
|
|
128
|
+
| iOS | 15.1 (LiquidGlass needs iOS 26) |
|
|
129
|
+
| Android | API 24 (Android 7.0); Material Components 1.14 is bundled |
|
|
130
|
+
|
|
131
|
+
iOS sets that minimum. LiquidGlass uses iOS 26 APIs, so the library has to be
|
|
132
|
+
built with Xcode 26, and React Native's bundled `fmt` only compiles under Xcode
|
|
133
|
+
26 from 0.81 on. The Android code itself builds against React Native 0.76, and
|
|
134
|
+
CI keeps it that way.
|
|
124
135
|
|
|
125
136
|
Full details: [Installation](https://jarx-concepts.github.io/react-native-platform-components/installation).
|
|
126
137
|
|
|
@@ -132,7 +143,7 @@ Everything else lives on the documentation site:
|
|
|
132
143
|
- [DatePicker](https://jarx-concepts.github.io/react-native-platform-components/components/datepicker), [ContextMenu](https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu), [SelectionMenu](https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu), [SegmentedControl](https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol), [LiquidGlass](https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass): props, platform options and behavior
|
|
133
144
|
- [Android Theme Configuration](https://jarx-concepts.github.io/react-native-platform-components/guides/android-theme): Material 3 setup and what happens without it
|
|
134
145
|
- [Icons](https://jarx-concepts.github.io/react-native-platform-components/guides/icons): SF Symbols, drawables and images
|
|
135
|
-
- [Theming and Colors](https://jarx-concepts.github.io/react-native-platform-components/guides/theming):
|
|
146
|
+
- [Theming and Colors](https://jarx-concepts.github.io/react-native-platform-components/guides/theming): light/dark mode and your brand color from JavaScript (`useNativeTheme`), accepted color formats
|
|
136
147
|
|
|
137
148
|
## Contributing
|
|
138
149
|
|
package/android/build.gradle
CHANGED
|
@@ -76,5 +76,5 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
76
76
|
dependencies {
|
|
77
77
|
implementation "com.facebook.react:react-android"
|
|
78
78
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
79
|
-
implementation "com.google.android.material:material:1.
|
|
79
|
+
implementation "com.google.android.material:material:1.14.0"
|
|
80
80
|
}
|
|
@@ -74,6 +74,12 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
74
74
|
// --- Modal state ---
|
|
75
75
|
private var showingModal = false
|
|
76
76
|
|
|
77
|
+
// --- Native theme ---
|
|
78
|
+
// Widgets read theme colors when they are created, so they are rebuilt when the
|
|
79
|
+
// native theme changes (brand color, light/dark switch).
|
|
80
|
+
private var builtThemeVersion = PCNativeTheme.version
|
|
81
|
+
private val nativeThemeListener = PCNativeTheme.Listener { rebuildForNativeTheme() }
|
|
82
|
+
|
|
77
83
|
init {
|
|
78
84
|
rebuildUI()
|
|
79
85
|
}
|
|
@@ -226,6 +232,33 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
226
232
|
syncInlineFromState()
|
|
227
233
|
}
|
|
228
234
|
|
|
235
|
+
override fun onAttachedToWindow() {
|
|
236
|
+
super.onAttachedToWindow()
|
|
237
|
+
PCNativeTheme.addListener(nativeThemeListener)
|
|
238
|
+
PCNativeTheme.attach(context)
|
|
239
|
+
if (builtThemeVersion != PCNativeTheme.version) rebuildForNativeTheme()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
override fun onDetachedFromWindow() {
|
|
243
|
+
PCNativeTheme.removeListener(nativeThemeListener)
|
|
244
|
+
super.onDetachedFromWindow()
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* A theme change isn't a React commit, so nothing measures the rebuilt inline
|
|
249
|
+
* pickers; lay them out in the frame Yoga already gave this view.
|
|
250
|
+
*/
|
|
251
|
+
private fun rebuildForNativeTheme() {
|
|
252
|
+
PCThemeSupport.clearColorStateListCaches(this)
|
|
253
|
+
rebuildUI()
|
|
254
|
+
if (!isInline() || width == 0 || height == 0) return
|
|
255
|
+
measure(
|
|
256
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
257
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
258
|
+
)
|
|
259
|
+
layout(left, top, right, bottom)
|
|
260
|
+
}
|
|
261
|
+
|
|
229
262
|
// -----------------------------
|
|
230
263
|
// UI construction
|
|
231
264
|
// -----------------------------
|
|
@@ -233,6 +266,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
233
266
|
private fun isInline(): Boolean = presentation == "inline" || presentation == "embedded"
|
|
234
267
|
|
|
235
268
|
private fun rebuildUI() {
|
|
269
|
+
builtThemeVersion = PCNativeTheme.version
|
|
236
270
|
removeAllViews()
|
|
237
271
|
inlineContainer = null
|
|
238
272
|
inlineDatePicker = null
|
|
@@ -742,10 +776,20 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
742
776
|
* theme instead (0 = use the activity theme).
|
|
743
777
|
*/
|
|
744
778
|
private fun m3CalendarTheme(act: FragmentActivity): Int =
|
|
745
|
-
PCThemeSupport.materialDialogThemeOverride(
|
|
779
|
+
PCThemeSupport.materialDialogThemeOverride(
|
|
780
|
+
act,
|
|
781
|
+
"DatePicker",
|
|
782
|
+
R.style.PCMaterial3CalendarDialogTheme,
|
|
783
|
+
R.style.PCMaterial3CalendarDialogTheme_NativeTheme
|
|
784
|
+
)
|
|
746
785
|
|
|
747
786
|
private fun m3TimePickerTheme(act: FragmentActivity): Int =
|
|
748
|
-
PCThemeSupport.materialDialogThemeOverride(
|
|
787
|
+
PCThemeSupport.materialDialogThemeOverride(
|
|
788
|
+
act,
|
|
789
|
+
"DatePicker",
|
|
790
|
+
R.style.PCMaterial3TimePickerDialogTheme,
|
|
791
|
+
R.style.PCMaterial3TimePickerDialogTheme_NativeTheme
|
|
792
|
+
)
|
|
749
793
|
|
|
750
794
|
private fun buildM3CalendarConstraints(): CalendarConstraints? {
|
|
751
795
|
val min = minDateMs
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
package com.platformcomponents
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.ContextWrapper
|
|
6
|
+
import android.content.pm.PackageManager
|
|
7
|
+
import android.content.res.Configuration
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import androidx.core.content.OnConfigurationChangedProvider
|
|
11
|
+
import androidx.core.util.Consumer
|
|
12
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
13
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
14
|
+
import com.google.android.material.color.DynamicColors
|
|
15
|
+
import com.google.android.material.color.DynamicColorsOptions
|
|
16
|
+
import java.lang.ref.WeakReference
|
|
17
|
+
import java.util.WeakHashMap
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The native theme set from JS with `useNativeTheme` / `setNativeTheme`.
|
|
21
|
+
*
|
|
22
|
+
* The brand color seeds Material dynamic colors on the activity, so Material and
|
|
23
|
+
* AppCompat widgets created afterwards use a Material 3 scheme generated from it.
|
|
24
|
+
* Content-based dynamic colors need Android 13+ (and some Android 12 devices); on
|
|
25
|
+
* older versions the app's own theme colors stay in place.
|
|
26
|
+
*
|
|
27
|
+
* Widgets resolve theme colors when they are created, so library views register as
|
|
28
|
+
* listeners and rebuild on every change: a new brand color, or a light/dark switch
|
|
29
|
+
* (including `Appearance.setColorScheme`), which also needs the scheme regenerated.
|
|
30
|
+
*
|
|
31
|
+
* Main thread only.
|
|
32
|
+
*/
|
|
33
|
+
internal object PCNativeTheme {
|
|
34
|
+
private const val TAG = "PlatformComponents"
|
|
35
|
+
|
|
36
|
+
fun interface Listener {
|
|
37
|
+
fun onNativeThemeChanged()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Brand color from JS, or null to use the app's theme colors. */
|
|
41
|
+
var primaryColor: Int? = null
|
|
42
|
+
private set
|
|
43
|
+
|
|
44
|
+
/** Bumped on every change; views compare it to the version they were built with. */
|
|
45
|
+
var version = 0
|
|
46
|
+
private set
|
|
47
|
+
|
|
48
|
+
/** True when widgets should re-apply the brand colors over their own theme. */
|
|
49
|
+
val isActive: Boolean
|
|
50
|
+
get() = primaryColor != null && DynamicColors.isDynamicColorAvailable()
|
|
51
|
+
|
|
52
|
+
private data class Applied(val primaryColor: Int, val nightMode: Int)
|
|
53
|
+
|
|
54
|
+
private var warnedUnsupported = false
|
|
55
|
+
|
|
56
|
+
private val listeners = LinkedHashSet<Listener>()
|
|
57
|
+
private val applied = WeakHashMap<Activity, Applied>()
|
|
58
|
+
private val observed = WeakHashMap<Activity, Consumer<Configuration>>()
|
|
59
|
+
|
|
60
|
+
fun addListener(listener: Listener) {
|
|
61
|
+
listeners.add(listener)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fun removeListener(listener: Listener) {
|
|
65
|
+
listeners.remove(listener)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fun setPrimaryColor(activity: Activity?, color: Int?) {
|
|
69
|
+
UiThreadUtil.assertOnUiThread()
|
|
70
|
+
if (color == primaryColor) return
|
|
71
|
+
primaryColor = color
|
|
72
|
+
activity?.let {
|
|
73
|
+
observe(it)
|
|
74
|
+
apply(it)
|
|
75
|
+
}
|
|
76
|
+
changed()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Called when a library view attaches: follows its activity's configuration and
|
|
81
|
+
* applies the current theme if the activity doesn't have it yet (for example after
|
|
82
|
+
* the activity was recreated).
|
|
83
|
+
*/
|
|
84
|
+
fun attach(context: Context) {
|
|
85
|
+
val activity = findActivity(context) ?: return
|
|
86
|
+
observe(activity)
|
|
87
|
+
if (applied[activity] != wanted(activity)) {
|
|
88
|
+
apply(activity)
|
|
89
|
+
changed()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fun findActivity(context: Context): Activity? {
|
|
94
|
+
(context as? ThemedReactContext)?.currentActivity?.let { return it }
|
|
95
|
+
var current: Context? = context
|
|
96
|
+
while (current is ContextWrapper) {
|
|
97
|
+
if (current is Activity) return current
|
|
98
|
+
current = current.baseContext
|
|
99
|
+
}
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private fun nightMode(context: Context): Int =
|
|
104
|
+
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
105
|
+
|
|
106
|
+
/** What the activity should have applied: null when there is no brand color. */
|
|
107
|
+
private fun wanted(activity: Activity): Applied? =
|
|
108
|
+
primaryColor?.let { Applied(it, nightMode(activity)) }
|
|
109
|
+
|
|
110
|
+
private fun apply(activity: Activity) {
|
|
111
|
+
val color = primaryColor
|
|
112
|
+
|
|
113
|
+
if (color == null) {
|
|
114
|
+
// Re-applying the activity theme resets the color attributes the overlay set.
|
|
115
|
+
if (applied.remove(activity) != null) {
|
|
116
|
+
activityThemeResId(activity)?.let { activity.theme.applyStyle(it, true) }
|
|
117
|
+
}
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
applied[activity] = Applied(color, nightMode(activity))
|
|
122
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !DynamicColors.isDynamicColorAvailable()) {
|
|
123
|
+
if (!warnedUnsupported) {
|
|
124
|
+
warnedUnsupported = true
|
|
125
|
+
Log.w(TAG, "useNativeTheme: brand colors need Android 13 or later; keeping the app theme colors.")
|
|
126
|
+
}
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Generates the scheme for the activity's current light/dark mode, overrides the
|
|
131
|
+
// Material "personalized" color resources with it and applies them to the theme.
|
|
132
|
+
// Material 1.13+ is needed to apply it more than once to the same activity.
|
|
133
|
+
DynamicColors.applyToActivityIfAvailable(
|
|
134
|
+
activity,
|
|
135
|
+
DynamicColorsOptions.Builder().setContentBasedSource(color).build()
|
|
136
|
+
)
|
|
137
|
+
activity.theme.applyStyle(R.style.PCNativeThemeOverlay, true)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private fun observe(activity: Activity) {
|
|
141
|
+
if (observed.containsKey(activity)) return
|
|
142
|
+
val provider = activity as? OnConfigurationChangedProvider ?: return
|
|
143
|
+
|
|
144
|
+
// The listener lives as long as the activity; don't let it keep the activity alive.
|
|
145
|
+
val activityRef = WeakReference(activity)
|
|
146
|
+
var lastNightMode = nightMode(activity)
|
|
147
|
+
val listener = Consumer<Configuration> { config ->
|
|
148
|
+
val nightMode = config.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
149
|
+
if (nightMode == lastNightMode) return@Consumer
|
|
150
|
+
lastNightMode = nightMode
|
|
151
|
+
val current = activityRef.get() ?: return@Consumer
|
|
152
|
+
// AppCompat re-applies the activity theme on a night mode switch, and the
|
|
153
|
+
// scheme depends on the mode, so the brand colors are applied again.
|
|
154
|
+
if (primaryColor != null) apply(current)
|
|
155
|
+
changed()
|
|
156
|
+
}
|
|
157
|
+
provider.addOnConfigurationChangedListener(listener)
|
|
158
|
+
observed[activity] = listener
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private fun changed() {
|
|
162
|
+
version += 1
|
|
163
|
+
listeners.toList().forEach { it.onNativeThemeChanged() }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private fun activityThemeResId(activity: Activity): Int? =
|
|
167
|
+
try {
|
|
168
|
+
activity.packageManager.getActivityInfo(activity.componentName, 0).themeResource
|
|
169
|
+
.takeIf { it != 0 }
|
|
170
|
+
?: activity.applicationInfo.theme.takeIf { it != 0 }
|
|
171
|
+
} catch (_: PackageManager.NameNotFoundException) {
|
|
172
|
+
null
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
package com.platformcomponents
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.facebook.react.bridge.ColorPropConverter
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap
|
|
7
|
+
import com.facebook.react.bridge.ReadableType
|
|
8
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
9
|
+
|
|
10
|
+
/** `setNativeTheme` / `useNativeTheme` on Android. See [PCNativeTheme]. */
|
|
11
|
+
class PCNativeThemeModule(reactContext: ReactApplicationContext) :
|
|
12
|
+
NativePlatformComponentsThemeSpec(reactContext) {
|
|
13
|
+
|
|
14
|
+
override fun setTheme(theme: ReadableMap) {
|
|
15
|
+
val primary: Any? =
|
|
16
|
+
when (if (theme.hasKey("primary")) theme.getType("primary") else ReadableType.Null) {
|
|
17
|
+
ReadableType.Number -> theme.getDouble("primary")
|
|
18
|
+
ReadableType.Map -> theme.getMap("primary")
|
|
19
|
+
else -> null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
UiThreadUtil.runOnUiThread {
|
|
23
|
+
val activity = reactApplicationContext.currentActivity
|
|
24
|
+
val color =
|
|
25
|
+
primary?.let {
|
|
26
|
+
try {
|
|
27
|
+
// Resolves PlatformColor resource paths as well as plain colors.
|
|
28
|
+
ColorPropConverter.getColor(it, activity ?: reactApplicationContext)
|
|
29
|
+
} catch (e: RuntimeException) {
|
|
30
|
+
Log.w(TAG, "setNativeTheme: could not resolve colors.primary", e)
|
|
31
|
+
null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
PCNativeTheme.setPrimaryColor(activity, color)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Liquid Glass is an iOS effect; Android renders the fallback View. */
|
|
39
|
+
override fun isLiquidGlassSupported(): Boolean = false
|
|
40
|
+
|
|
41
|
+
companion object {
|
|
42
|
+
const val NAME = "PlatformComponentsTheme"
|
|
43
|
+
private const val TAG = "PlatformComponents"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -11,6 +11,7 @@ import android.widget.FrameLayout
|
|
|
11
11
|
import android.widget.LinearLayout
|
|
12
12
|
import com.facebook.react.bridge.WritableNativeMap
|
|
13
13
|
import com.facebook.react.uimanager.PixelUtil
|
|
14
|
+
import com.facebook.react.uimanager.ReactCompoundViewGroup
|
|
14
15
|
import com.facebook.react.uimanager.StateWrapper
|
|
15
16
|
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper
|
|
16
17
|
import com.facebook.react.views.scroll.ReactScrollViewHelper
|
|
@@ -20,7 +21,10 @@ import com.google.android.material.badge.BadgeUtils
|
|
|
20
21
|
import com.google.android.material.button.MaterialButton
|
|
21
22
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
|
22
23
|
|
|
23
|
-
class PCSegmentedControlView(context: Context) :
|
|
24
|
+
class PCSegmentedControlView(context: Context) :
|
|
25
|
+
FrameLayout(context),
|
|
26
|
+
ReactScrollViewHelper.HasStateWrapper,
|
|
27
|
+
ReactCompoundViewGroup {
|
|
24
28
|
|
|
25
29
|
data class Segment(
|
|
26
30
|
val label: String,
|
|
@@ -88,6 +92,15 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
88
92
|
/** Bumped on every rebuild so late image loads can't touch stale buttons. */
|
|
89
93
|
private var rebuildGeneration = 0
|
|
90
94
|
|
|
95
|
+
// --- Native theme ---
|
|
96
|
+
// Widgets read theme colors when they are created, so they are rebuilt when the
|
|
97
|
+
// native theme changes (brand color, light/dark switch).
|
|
98
|
+
private var builtThemeVersion = PCNativeTheme.version
|
|
99
|
+
private val nativeThemeListener = PCNativeTheme.Listener {
|
|
100
|
+
PCThemeSupport.clearColorStateListCaches(this)
|
|
101
|
+
rebuildUI()
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
init {
|
|
92
105
|
minimumHeight = (PCConstants.MIN_TOUCH_TARGET_HEIGHT_DP * resources.displayMetrics.density).toInt()
|
|
93
106
|
// Badges overhang the button corner
|
|
@@ -182,9 +195,29 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
182
195
|
rebuildUI()
|
|
183
196
|
}
|
|
184
197
|
|
|
198
|
+
// The buttons have generated view ids, which React Native's touch handling would
|
|
199
|
+
// take for React tags and dispatch JS touch events to unrelated views. Claim the
|
|
200
|
+
// touch for this view instead; the buttons still receive it natively.
|
|
201
|
+
override fun interceptsTouchEvent(touchX: Float, touchY: Float): Boolean = true
|
|
202
|
+
|
|
203
|
+
override fun reactTagForTouch(touchX: Float, touchY: Float): Int = id
|
|
204
|
+
|
|
205
|
+
override fun onAttachedToWindow() {
|
|
206
|
+
super.onAttachedToWindow()
|
|
207
|
+
PCNativeTheme.addListener(nativeThemeListener)
|
|
208
|
+
PCNativeTheme.attach(context)
|
|
209
|
+
if (builtThemeVersion != PCNativeTheme.version) nativeThemeListener.onNativeThemeChanged()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
override fun onDetachedFromWindow() {
|
|
213
|
+
PCNativeTheme.removeListener(nativeThemeListener)
|
|
214
|
+
super.onDetachedFromWindow()
|
|
215
|
+
}
|
|
216
|
+
|
|
185
217
|
// ---- UI Building ----
|
|
186
218
|
|
|
187
219
|
private fun rebuildUI() {
|
|
220
|
+
builtThemeVersion = PCNativeTheme.version
|
|
188
221
|
removeAllViews()
|
|
189
222
|
buttonIdToSegment.clear()
|
|
190
223
|
rebuildGeneration += 1
|
|
@@ -286,13 +319,13 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
286
319
|
|
|
287
320
|
when (segment.iconType) {
|
|
288
321
|
"drawable" -> {
|
|
289
|
-
button.icon = ResourceDrawableIdHelper.getResourceDrawable(context, segment.iconName)
|
|
322
|
+
button.icon = ResourceDrawableIdHelper.instance.getResourceDrawable(context, segment.iconName)
|
|
290
323
|
}
|
|
291
324
|
"image" -> {
|
|
292
325
|
val uri = segment.iconUri
|
|
293
326
|
val isResourceName = !uri.contains(':')
|
|
294
327
|
if (isResourceName) {
|
|
295
|
-
button.icon = ResourceDrawableIdHelper.getResourceDrawable(context, uri)
|
|
328
|
+
button.icon = ResourceDrawableIdHelper.instance.getResourceDrawable(context, uri)
|
|
296
329
|
} else {
|
|
297
330
|
PCImageLoader.load(context, uri, segment.iconScale) { bitmap ->
|
|
298
331
|
if (bitmap == null || generation != rebuildGeneration) return@load
|
|
@@ -64,6 +64,15 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
|
|
|
64
64
|
private var headlessDismissAfterSelect = false
|
|
65
65
|
private var headlessOpenToken = 0
|
|
66
66
|
|
|
67
|
+
// --- Native theme ---
|
|
68
|
+
// Widgets read theme colors when they are created, so they are rebuilt when the
|
|
69
|
+
// native theme changes (brand color, light/dark switch).
|
|
70
|
+
private var builtThemeVersion = PCNativeTheme.version
|
|
71
|
+
private val nativeThemeListener = PCNativeTheme.Listener {
|
|
72
|
+
PCThemeSupport.clearColorStateListCaches(this)
|
|
73
|
+
rebuildUI()
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
init {
|
|
68
77
|
minimumHeight = 0
|
|
69
78
|
minimumWidth = 0
|
|
@@ -306,6 +315,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
|
|
|
306
315
|
// ---- UI building ----
|
|
307
316
|
|
|
308
317
|
private fun rebuildUI() {
|
|
318
|
+
builtThemeVersion = PCNativeTheme.version
|
|
309
319
|
if (headlessMenuShowing) {
|
|
310
320
|
headlessDismissProgrammatic = true
|
|
311
321
|
headlessMenu?.dismiss()
|
|
@@ -713,6 +723,9 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
|
|
|
713
723
|
|
|
714
724
|
override fun onAttachedToWindow() {
|
|
715
725
|
super.onAttachedToWindow()
|
|
726
|
+
PCNativeTheme.addListener(nativeThemeListener)
|
|
727
|
+
PCNativeTheme.attach(context)
|
|
728
|
+
if (builtThemeVersion != PCNativeTheme.version) nativeThemeListener.onNativeThemeChanged()
|
|
716
729
|
// When attached, trigger a measure/layout pass to ensure correct sizing
|
|
717
730
|
if (anchorMode == "inline") {
|
|
718
731
|
// Use ViewTreeObserver to wait until after the first layout pass
|
|
@@ -741,6 +754,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
|
|
|
741
754
|
|
|
742
755
|
override fun onDetachedFromWindow() {
|
|
743
756
|
detachInlineDropdownOverlay()
|
|
757
|
+
PCNativeTheme.removeListener(nativeThemeListener)
|
|
744
758
|
super.onDetachedFromWindow()
|
|
745
759
|
}
|
|
746
760
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
package com.platformcomponents
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.content.res.Resources
|
|
4
5
|
import android.util.Log
|
|
5
6
|
import android.util.TypedValue
|
|
6
7
|
import android.view.ContextThemeWrapper
|
|
8
|
+
import android.view.View
|
|
9
|
+
import android.view.ViewGroup
|
|
7
10
|
import androidx.annotation.AttrRes
|
|
8
11
|
import androidx.appcompat.R as AppCompatR
|
|
12
|
+
import androidx.core.content.res.ResourcesCompat
|
|
9
13
|
import com.google.android.material.R as MaterialR
|
|
10
14
|
|
|
11
15
|
/**
|
|
@@ -39,9 +43,34 @@ internal object PCThemeSupport {
|
|
|
39
43
|
* renders with Material 3 defaults instead of throwing.
|
|
40
44
|
*/
|
|
41
45
|
fun materialContext(context: Context, component: String): Context {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
val base =
|
|
47
|
+
if (hasMaterialTheme(context)) {
|
|
48
|
+
context
|
|
49
|
+
} else {
|
|
50
|
+
warnMaterial(component)
|
|
51
|
+
ContextThemeWrapper(context, MaterialR.style.Theme_Material3_DayNight_NoActionBar)
|
|
52
|
+
}
|
|
53
|
+
if (!PCNativeTheme.isActive) return base
|
|
54
|
+
// Re-applies the native theme's brand colors, which the Material 3 fallback resets.
|
|
55
|
+
return ContextThemeWrapper(base, R.style.PCNativeThemeOverlay)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Clears AndroidX's color state list cache for the themes the views under [root] were
|
|
60
|
+
* built with. Material widgets load their colors through that cache, keyed by theme,
|
|
61
|
+
* and widgets rebuilt for a new brand color use the same theme keys as the ones they
|
|
62
|
+
* replace, so without this they would get the previous brand colors back.
|
|
63
|
+
*/
|
|
64
|
+
fun clearColorStateListCaches(root: View) {
|
|
65
|
+
val themes = HashSet<Resources.Theme>()
|
|
66
|
+
fun collect(view: View) {
|
|
67
|
+
themes.add(view.context.theme)
|
|
68
|
+
if (view is ViewGroup) {
|
|
69
|
+
for (i in 0 until view.childCount) collect(view.getChildAt(i))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
collect(root)
|
|
73
|
+
themes.forEach { ResourcesCompat.clearCachesForTheme(it) }
|
|
45
74
|
}
|
|
46
75
|
|
|
47
76
|
/**
|
|
@@ -57,11 +86,17 @@ internal object PCThemeSupport {
|
|
|
57
86
|
/**
|
|
58
87
|
* Theme override for MaterialDatePicker / MaterialTimePicker when the activity
|
|
59
88
|
* theme is not a Material theme. Returns 0 (no override) when it is.
|
|
89
|
+
* [nativeThemeFallback] is the variant that keeps the native theme's brand colors.
|
|
60
90
|
*/
|
|
61
|
-
fun materialDialogThemeOverride(
|
|
91
|
+
fun materialDialogThemeOverride(
|
|
92
|
+
context: Context,
|
|
93
|
+
component: String,
|
|
94
|
+
fallbackTheme: Int,
|
|
95
|
+
nativeThemeFallback: Int
|
|
96
|
+
): Int {
|
|
62
97
|
if (hasMaterialTheme(context)) return 0
|
|
63
98
|
warnMaterial(component)
|
|
64
|
-
return fallbackTheme
|
|
99
|
+
return if (PCNativeTheme.isActive) nativeThemeFallback else fallbackTheme
|
|
65
100
|
}
|
|
66
101
|
|
|
67
102
|
private fun resolves(context: Context, @AttrRes attr: Int): Boolean =
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
package com.platformcomponents
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
6
8
|
import com.facebook.react.uimanager.ViewManager
|
|
7
|
-
import java.util.ArrayList
|
|
8
9
|
|
|
9
|
-
class PlatformComponentsViewPackage :
|
|
10
|
+
class PlatformComponentsViewPackage : BaseReactPackage() {
|
|
10
11
|
override fun createViewManagers(
|
|
11
12
|
reactContext: ReactApplicationContext
|
|
12
13
|
): List<ViewManager<*, *>> {
|
|
@@ -19,7 +20,26 @@ class PlatformComponentsViewPackage : ReactPackage {
|
|
|
19
20
|
)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
override fun
|
|
23
|
-
|
|
23
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
|
|
24
|
+
when (name) {
|
|
25
|
+
PCNativeThemeModule.NAME -> PCNativeThemeModule(reactContext)
|
|
26
|
+
else -> null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider {
|
|
30
|
+
mapOf(
|
|
31
|
+
PCNativeThemeModule.NAME to
|
|
32
|
+
// Positional arguments on purpose: React Native 0.76 names the
|
|
33
|
+
// parameters of this constructor `_name` / `_className`, so named
|
|
34
|
+
// arguments only compile against newer releases.
|
|
35
|
+
ReactModuleInfo(
|
|
36
|
+
PCNativeThemeModule.NAME,
|
|
37
|
+
PCNativeThemeModule::class.java.name,
|
|
38
|
+
/* canOverrideExistingModule = */ false,
|
|
39
|
+
/* needsEagerInit = */ false,
|
|
40
|
+
/* isCxxModule = */ false,
|
|
41
|
+
/* isTurboModule = */ true,
|
|
42
|
+
)
|
|
43
|
+
)
|
|
24
44
|
}
|
|
25
45
|
}
|
|
@@ -44,4 +44,16 @@ target_link_libraries(
|
|
|
44
44
|
reactnative
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
target_compile_reactnative_options(
|
|
47
|
+
# target_compile_reactnative_options() arrived in React Native 0.80. On older
|
|
48
|
+
# releases, apply the equivalent flags directly so the library still builds.
|
|
49
|
+
if(COMMAND target_compile_reactnative_options)
|
|
50
|
+
target_compile_reactnative_options(react_codegen_PlatformComponentsViewSpec PRIVATE)
|
|
51
|
+
else()
|
|
52
|
+
target_compile_options(react_codegen_PlatformComponentsViewSpec PRIVATE
|
|
53
|
+
-DLOG_TAG=\"ReactNative\"
|
|
54
|
+
-fexceptions
|
|
55
|
+
-frtti
|
|
56
|
+
-std=c++20
|
|
57
|
+
-Wall
|
|
58
|
+
)
|
|
59
|
+
endif()
|