react-native-list 1.0.1 → 2.0.0-alpha.2
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 +186 -32
- package/ReactNativeList.podspec +39 -0
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/JHybridUiListModule.cpp +192 -0
- package/android/src/main/cpp/JHybridUiListModule.h +50 -0
- package/android/src/main/cpp/cpp-adapter.cpp +12 -0
- package/android/src/main/java/com/hannojg/reactnativelist/ReactNativeListPackage.kt +27 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListDataSource.kt +146 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListLayout.kt +86 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListModule.kt +116 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListView.kt +410 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridViewHolder.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/NativeListAdapter.kt +217 -0
- package/ios/DataSource/HybridNativeListDataSource.swift +213 -0
- package/ios/HybridObjects/HybridUiListModule.swift +49 -0
- package/ios/HybridObjects/HybridViewHolder.swift +16 -0
- package/ios/Layout/HybridNativeListLayout.swift +128 -0
- package/ios/Utils/ErrorUtils.h +26 -0
- package/ios/Utils/HybridIOSWorkletsModuleProxyHolder.swift +10 -0
- package/ios/Utils/SurfaceHelper.h +20 -0
- package/ios/Utils/SurfaceHelper.mm +144 -0
- package/ios/Utils/SurfacePresenterRegistry.h +17 -0
- package/ios/Utils/SurfacePresenterRegistry.m +31 -0
- package/ios/Utils/TurboModuleInstaller.h +18 -0
- package/ios/Utils/TurboModuleInstaller.mm +267 -0
- package/ios/Views/HostCell.swift +216 -0
- package/ios/Views/HybridUiListView.swift +695 -0
- package/lib/ReactFabricMirror.d.ts +4 -0
- package/lib/ReactFabricMirror.js +515 -0
- package/lib/UiListModule.d.ts +2 -0
- package/lib/UiListModule.js +2 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +21 -0
- package/lib/privateGlobals.d.ts +14 -0
- package/lib/privateGlobals.js +2 -0
- package/lib/renderer/RenderHelper.d.ts +2 -0
- package/lib/renderer/RenderHelper.js +11 -0
- package/lib/renderer/UiManagerHelper.d.ts +2 -0
- package/lib/renderer/UiManagerHelper.js +2 -0
- package/lib/renderer/fabric/RenderHelper.d.ts +2 -0
- package/lib/renderer/fabric/RenderHelper.js +11 -0
- package/lib/renderer/fabric/UiManagerHelper.d.ts +2 -0
- package/lib/renderer/fabric/UiManagerHelper.js +2 -0
- package/lib/renderer/react/ReactFabricMirror.d.ts +4 -0
- package/lib/renderer/react/ReactFabricMirror.js +515 -0
- package/lib/renderer/react/ReactFabricRenderer.d.ts +3 -0
- package/lib/renderer/react/ReactFabricRenderer.js +9 -0
- package/lib/specs/IOSWorkletsModuleProxyHolder.nitro.d.ts +6 -0
- package/lib/specs/IOSWorkletsModuleProxyHolder.nitro.js +1 -0
- package/lib/specs/UIListModule.nitro.d.ts +9 -0
- package/lib/specs/UIListModule.nitro.js +1 -0
- package/lib/specs/UIManagerHelper.nitro.d.ts +13 -0
- package/lib/specs/UIManagerHelper.nitro.js +1 -0
- package/lib/specs/UiListView.nitro.d.ts +20 -0
- package/lib/specs/UiListView.nitro.js +1 -0
- package/lib/specs/ViewHolder.nitro.d.ts +6 -0
- package/lib/specs/ViewHolder.nitro.js +1 -0
- package/lib/views/List.d.ts +35 -0
- package/lib/views/List.js +225 -0
- package/lib/views/UiListHostComponent.d.ts +2 -0
- package/lib/views/UiListHostComponent.js +3 -0
- package/metro/RendererProxyThreadSwitch.js +66 -0
- package/metro-config.d.ts +1 -0
- package/metro-config.js +124 -0
- package/nitro.json +47 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.cmake +99 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.gradle +27 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.cpp +156 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JFunc_bool_NativeListItem_NativeListItem.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_bool_double_NativeListItem_double.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_double_std__string.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.cpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.cpp +101 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.hpp +70 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.cpp +65 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.cpp +92 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.hpp +67 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JNativeItemSizeEstimate.hpp +61 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutConfig.hpp +81 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutIOSConfig.hpp +59 -0
- package/nitrogen/generated/android/c++/JNativeListItem.hpp +76 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.hpp +72 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_NativeListItem_NativeListItem.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_double_NativeListItem_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_double_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridIOSWorkletsModuleProxyHolderSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeLinearListLayoutSpec.kt +54 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListDataSourceSpec.kt +87 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListLayoutSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListModuleSpec.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListViewSpec.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridViewHolderSpec.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeItemSizeEstimate.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutConfig.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutIOSConfig.kt +51 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeListItem.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/ReactNativeListOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Variant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/ReactNativeList+autolinking.rb +62 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.cpp +162 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.hpp +368 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Umbrella.hpp +92 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.mm +83 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.swift +86 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.hpp +92 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.hpp +132 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.hpp +93 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.hpp +121 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/views/HybridUiListViewComponent.mm +118 -0
- package/nitrogen/generated/ios/c++/views/HybridViewHolderComponent.mm +118 -0
- package/nitrogen/generated/ios/swift/Func_bool_NativeListItem_NativeListItem.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_bool_double_NativeListItem_double.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_double_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec_cxx.swift +140 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec.swift +62 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec_cxx.swift +222 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec_cxx.swift +175 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec_cxx.swift +227 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec_cxx.swift +147 -0
- package/nitrogen/generated/ios/swift/NativeItemSizeEstimate.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutConfig.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutIOSConfig.swift +35 -0
- package/nitrogen/generated/ios/swift/NativeListItem.swift +75 -0
- package/nitrogen/generated/ios/swift/Variant_NullType__any_HybridIOSWorkletsModuleProxyHolderSpec_.swift +30 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/NativeItemSizeEstimate.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutConfig.hpp +105 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutIOSConfig.hpp +85 -0
- package/nitrogen/generated/shared/c++/NativeListItem.hpp +101 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.hpp +109 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.hpp +109 -0
- package/nitrogen/generated/shared/json/UiListViewConfig.json +9 -0
- package/nitrogen/generated/shared/json/ViewHolderConfig.json +9 -0
- package/package.json +152 -5
- package/react-native.config.js +16 -0
- package/src/ListDataSource.ts +232 -0
- package/src/ListLayout.ts +95 -0
- package/src/UiListModule.ts +5 -0
- package/src/hooks/useChangeEffect.ts +50 -0
- package/src/index.tsx +49 -0
- package/src/privateGlobals.ts +20 -0
- package/src/renderer/fabric/RenderHelper.ts +29 -0
- package/src/renderer/fabric/UiManagerHelper.ts +5 -0
- package/src/renderer/react/ReactFabricMirror.bundle.js +1984 -0
- package/src/renderer/react/ReactFabricMirror.ts +766 -0
- package/src/renderer/react/ReactFabricRenderer.ts +11 -0
- package/src/specs/IOSWorkletsModuleProxyHolder.nitro.ts +6 -0
- package/src/specs/NativeLinearListLayout.nitro.ts +23 -0
- package/src/specs/NativeListDataSource.nitro.ts +28 -0
- package/src/specs/NativeListLayout.nitro.ts +6 -0
- package/src/specs/UIListModule.nitro.ts +13 -0
- package/src/specs/UIManagerHelper.nitro.ts +34 -0
- package/src/specs/UiListView.nitro.ts +31 -0
- package/src/specs/ViewHolder.nitro.ts +11 -0
- package/src/views/List.tsx +525 -0
- package/src/views/UiListHostComponent.ts +8 -0
- package/FillRateHelper.js +0 -179
- package/FlatList.js +0 -494
- package/LICENSE.md +0 -31
- package/MetroListView.js +0 -166
- package/SectionList.js +0 -291
- package/ViewabilityHelper.js +0 -260
- package/VirtualizeUtils.js +0 -163
- package/VirtualizedList.js +0 -861
- package/VirtualizedSectionList.js +0 -397
- package/index.js +0 -5
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#include "JHybridUiListModule.h"
|
|
2
|
+
#include "WorkletsUiCallInvoker.hpp"
|
|
3
|
+
#include "HybridUiManagerHelper.hpp"
|
|
4
|
+
|
|
5
|
+
#include <NitroModules/CallInvokerDispatcher.hpp>
|
|
6
|
+
#include <NitroModules/InstallNitro.hpp>
|
|
7
|
+
#include <react/utils/jsi-utils.h>
|
|
8
|
+
#include <react/fabric/FabricUIManagerBinding.h>
|
|
9
|
+
#include <worklets/android/WorkletsModule.h>
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro::reactnativelist
|
|
12
|
+
{
|
|
13
|
+
static bool isOnAndroidUiThread()
|
|
14
|
+
{
|
|
15
|
+
return getpid() == gettid();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
std::shared_ptr<react::CallInvoker> JHybridUiListModule::uiCallInvoker_ = nullptr;
|
|
19
|
+
std::shared_ptr<worklets::WorkletRuntime> JHybridUiListModule::uiWorkletRuntime_ = nullptr;
|
|
20
|
+
|
|
21
|
+
void JHybridUiListModule::registerNatives()
|
|
22
|
+
{
|
|
23
|
+
javaClassStatic()->registerNatives({
|
|
24
|
+
makeNativeMethod("prepareUiRuntime",
|
|
25
|
+
prepareUiRuntime),
|
|
26
|
+
makeNativeMethod("getUiCallInvokerHolder",
|
|
27
|
+
getUiCallInvokerHolder),
|
|
28
|
+
makeNativeMethod("getUiRuntimeExecutor",
|
|
29
|
+
getUiRuntimeExecutor),
|
|
30
|
+
makeNativeMethod("setupEventInterceptor",
|
|
31
|
+
setupEventInterceptor),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
std::shared_ptr<react::CallInvoker> JHybridUiListModule::getOrInitCallInvoker(
|
|
36
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule)
|
|
37
|
+
{
|
|
38
|
+
if (!workletsModule)
|
|
39
|
+
{
|
|
40
|
+
throw std::runtime_error("WorkletsModule reference is null");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
auto workletsModuleProxy =
|
|
44
|
+
workletsModule->cthis()->getWorkletsModuleProxy();
|
|
45
|
+
|
|
46
|
+
if (!workletsModuleProxy)
|
|
47
|
+
{
|
|
48
|
+
throw std::runtime_error("Failed to get WorkletsModuleProxy from WorkletsModule");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
auto uiScheduler = workletsModuleProxy->getUIScheduler();
|
|
52
|
+
if (!uiScheduler)
|
|
53
|
+
{
|
|
54
|
+
throw std::runtime_error("Failed to get UIScheduler from WorkletsModuleProxy");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
auto uiWorkletRuntime = workletsModuleProxy->getUIWorkletRuntime();
|
|
58
|
+
if (!uiWorkletRuntime)
|
|
59
|
+
{
|
|
60
|
+
throw std::runtime_error("Failed to get UIWorkletRuntime from WorkletsModuleProxy");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (uiCallInvoker_ && uiWorkletRuntime_ == uiWorkletRuntime)
|
|
64
|
+
{
|
|
65
|
+
return uiCallInvoker_;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
uiWorkletRuntime_ = uiWorkletRuntime;
|
|
69
|
+
uiCallInvoker_ = std::make_shared<WorkletsUiCallInvoker>(uiScheduler, uiWorkletRuntime, isOnAndroidUiThread);
|
|
70
|
+
return uiCallInvoker_;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
jni::local_ref<react::CallInvokerHolder::javaobject>
|
|
74
|
+
JHybridUiListModule::getUiCallInvokerHolder(
|
|
75
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
76
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule)
|
|
77
|
+
{
|
|
78
|
+
std::shared_ptr<react::CallInvoker> uiCallInvoker = getOrInitCallInvoker(workletsModule);
|
|
79
|
+
|
|
80
|
+
return react::CallInvokerHolder::newObjectCxxArgs(uiCallInvoker);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
bool JHybridUiListModule::prepareUiRuntime(
|
|
84
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
85
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule)
|
|
86
|
+
{
|
|
87
|
+
if (!workletsModule)
|
|
88
|
+
{
|
|
89
|
+
throw std::runtime_error("WorkletsModule reference is null");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
auto workletsModuleProxy =
|
|
93
|
+
workletsModule->cthis()->getWorkletsModuleProxy();
|
|
94
|
+
|
|
95
|
+
if (!workletsModuleProxy)
|
|
96
|
+
{
|
|
97
|
+
throw std::runtime_error("Failed to get WorkletsModuleProxy from WorkletsModule");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
auto uiWorkletRuntime = workletsModuleProxy->getUIWorkletRuntime();
|
|
101
|
+
if (!uiWorkletRuntime)
|
|
102
|
+
{
|
|
103
|
+
throw std::runtime_error("Failed to get UIWorkletRuntime from WorkletsModuleProxy");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
std::shared_ptr<react::CallInvoker> uiCallInvoker = getOrInitCallInvoker(workletsModule);
|
|
107
|
+
|
|
108
|
+
// React Native checks this global while installing TurboModule bindings.
|
|
109
|
+
// Worklets creates a separate UI runtime, so we mirror the bridgeless marker there.
|
|
110
|
+
bool hasNativeModuleProxy = false;
|
|
111
|
+
uiWorkletRuntime->runSync([&hasNativeModuleProxy](jsi::Runtime &runtime)
|
|
112
|
+
{
|
|
113
|
+
auto global = runtime.global();
|
|
114
|
+
if (!global.hasProperty(runtime, "RN$Bridgeless"))
|
|
115
|
+
{
|
|
116
|
+
react::defineReadOnlyGlobal(runtime, "RN$Bridgeless", jsi::Value(true));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
hasNativeModuleProxy = global.hasProperty(runtime, "nativeModuleProxy");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Do not call the Android Nitro TurboModule installer from the UI runtime.
|
|
123
|
+
// That installer reads ReactApplicationContext.javaScriptContextHolder, which always
|
|
124
|
+
// points at the main RN JS runtime. Install Nitro directly into Worklets' UI runtime
|
|
125
|
+
// so UI-thread imports can reuse global.NitroModulesProxy instead of reinstalling on RN.
|
|
126
|
+
uiWorkletRuntime->runSync([uiCallInvoker](jsi::Runtime &runtime)
|
|
127
|
+
{
|
|
128
|
+
if (runtime.global().hasProperty(runtime, "NitroModulesProxy"))
|
|
129
|
+
{
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (runtime.global().hasProperty(runtime, "__nitroDispatcher"))
|
|
134
|
+
{
|
|
135
|
+
margelo::nitro::install(runtime);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
auto dispatcher =
|
|
140
|
+
std::make_shared<margelo::nitro::CallInvokerDispatcher>(uiCallInvoker);
|
|
141
|
+
margelo::nitro::install(runtime, dispatcher);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return hasNativeModuleProxy;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
jni::local_ref<react::JRuntimeExecutor::javaobject>
|
|
148
|
+
JHybridUiListModule::getUiRuntimeExecutor(
|
|
149
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
150
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule)
|
|
151
|
+
{
|
|
152
|
+
std::shared_ptr<react::CallInvoker> uiCallInvoker = getOrInitCallInvoker(workletsModule);
|
|
153
|
+
|
|
154
|
+
RuntimeExecutor uiRuntimeExecutor = [uiCallInvoker](auto callback)
|
|
155
|
+
{
|
|
156
|
+
if (isOnAndroidUiThread())
|
|
157
|
+
{
|
|
158
|
+
uiCallInvoker->invokeSync(std::move(callback));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
uiCallInvoker->invokeAsync(std::move(callback));
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
return react::JRuntimeExecutor::newObjectCxxArgs(uiRuntimeExecutor);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
void JHybridUiListModule::setupEventInterceptor(
|
|
169
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
170
|
+
jni::alias_ref<JFabricUIManager::javaobject> fabricUIManager)
|
|
171
|
+
{
|
|
172
|
+
if (!uiCallInvoker_)
|
|
173
|
+
{
|
|
174
|
+
throw std::runtime_error(
|
|
175
|
+
"UI CallInvoker must be initialized before setting up event interceptor");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!fabricUIManager)
|
|
179
|
+
{
|
|
180
|
+
throw std::runtime_error("FabricUIManager reference is null");
|
|
181
|
+
}
|
|
182
|
+
std::shared_ptr<react::Scheduler> scheduler = fabricUIManager->getBinding()->getScheduler();
|
|
183
|
+
|
|
184
|
+
if (!scheduler)
|
|
185
|
+
{
|
|
186
|
+
throw std::runtime_error("Failed to get Scheduler from FabricUIManager");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
HybridUiManagerHelper::setupEventInterceptor(scheduler, uiCallInvoker_);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
} // namespace margelo::nitro::reactnativelist
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <ReactCommon/CallInvokerHolder.h>
|
|
4
|
+
#include <react/jni/JRuntimeExecutor.h>
|
|
5
|
+
#include <fbjni/fbjni.h>
|
|
6
|
+
#include <react/fabric/JFabricUIManager.h>
|
|
7
|
+
#include <react/renderer/core/EventListener.h>
|
|
8
|
+
#include <worklets/WorkletRuntime/WorkletRuntime.h>
|
|
9
|
+
#include <worklets/android/WorkletsModule.h>
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro::reactnativelist
|
|
12
|
+
{
|
|
13
|
+
|
|
14
|
+
using namespace facebook;
|
|
15
|
+
|
|
16
|
+
struct JHybridUiListModule : public jni::JavaClass<JHybridUiListModule>
|
|
17
|
+
{
|
|
18
|
+
static auto constexpr kJavaDescriptor =
|
|
19
|
+
"Lcom/margelo/nitro/reactnativelist/HybridUiListModule;";
|
|
20
|
+
|
|
21
|
+
static void registerNatives();
|
|
22
|
+
|
|
23
|
+
private:
|
|
24
|
+
static jni::local_ref<react::CallInvokerHolder::javaobject>
|
|
25
|
+
getUiCallInvokerHolder(
|
|
26
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
27
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule);
|
|
28
|
+
|
|
29
|
+
static jni::local_ref<react::JRuntimeExecutor::javaobject>
|
|
30
|
+
getUiRuntimeExecutor(
|
|
31
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
32
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule);
|
|
33
|
+
|
|
34
|
+
static bool prepareUiRuntime(
|
|
35
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
36
|
+
jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule);
|
|
37
|
+
|
|
38
|
+
static void setupEventInterceptor(
|
|
39
|
+
jni::alias_ref<JHybridUiListModule> jThis,
|
|
40
|
+
jni::alias_ref<JFabricUIManager::javaobject> fabricUIManager);
|
|
41
|
+
|
|
42
|
+
static std::shared_ptr<react::CallInvoker> getOrInitCallInvoker(jni::alias_ref<worklets::WorkletsModule::javaobject> workletsModule);
|
|
43
|
+
|
|
44
|
+
private:
|
|
45
|
+
static std::shared_ptr<react::CallInvoker> uiCallInvoker_;
|
|
46
|
+
static std::shared_ptr<worklets::WorkletRuntime> uiWorkletRuntime_;
|
|
47
|
+
static std::shared_ptr<const react::EventListener> eventInterceptor_;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
} // namespace margelo::nitro::reactnativelist
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#include <jni.h>
|
|
2
|
+
#include "ReactNativeListOnLoad.hpp"
|
|
3
|
+
#include "JHybridUiListModule.h"
|
|
4
|
+
|
|
5
|
+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
|
|
6
|
+
{
|
|
7
|
+
return facebook::jni::initialize(vm, []() {
|
|
8
|
+
margelo::nitro::reactnativelist::registerAllNatives();
|
|
9
|
+
// Register additional native methods (not generated by Nitrogen)
|
|
10
|
+
margelo::nitro::reactnativelist::JHybridUiListModule::registerNatives();
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.hannojg.reactnativelist
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.NativeModule
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
6
|
+
import com.facebook.react.BaseReactPackage
|
|
7
|
+
import com.facebook.react.uimanager.ViewManager
|
|
8
|
+
import com.margelo.nitro.reactnativelist.ReactNativeListOnLoad
|
|
9
|
+
import com.margelo.nitro.reactnativelist.views.HybridUiListViewManager
|
|
10
|
+
|
|
11
|
+
class ReactNativeListPackage : BaseReactPackage() {
|
|
12
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
|
|
13
|
+
|
|
14
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { HashMap() }
|
|
15
|
+
|
|
16
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<in Nothing, in Nothing>> {
|
|
17
|
+
val viewManagers = ArrayList<ViewManager<*, *>>()
|
|
18
|
+
viewManagers.add(HybridUiListViewManager())
|
|
19
|
+
return viewManagers
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
companion object {
|
|
23
|
+
init {
|
|
24
|
+
ReactNativeListOnLoad.initializeNative()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
package com.margelo.nitro.reactnativelist
|
|
2
|
+
|
|
3
|
+
import androidx.recyclerview.widget.DiffUtil
|
|
4
|
+
|
|
5
|
+
internal interface NativeListDataSourceObserver {
|
|
6
|
+
fun dataSourceDidReload(diffResult: DiffUtil.DiffResult?, animated: Boolean)
|
|
7
|
+
fun dataSourceDidInsert(index: Int)
|
|
8
|
+
fun dataSourceDidUpdate(index: Int, previousItem: NativeListItem)
|
|
9
|
+
fun dataSourceDidRemove(index: Int, removedItem: NativeListItem)
|
|
10
|
+
fun dataSourceDidMove(fromIndex: Int, toIndex: Int)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class HybridNativeListDataSource : HybridNativeListDataSourceSpec() {
|
|
14
|
+
internal var observer: NativeListDataSourceObserver? = null
|
|
15
|
+
private var items: List<NativeListItem> = emptyList()
|
|
16
|
+
private var isContentEqual: (oldItem: NativeListItem, newItem: NativeListItem) -> Boolean =
|
|
17
|
+
{ _, _ -> false }
|
|
18
|
+
|
|
19
|
+
override fun dispose() {
|
|
20
|
+
observer = null
|
|
21
|
+
items = emptyList()
|
|
22
|
+
isContentEqual = { _, _ -> false }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override fun setContentEqualCallback(
|
|
26
|
+
isContentEqual: (oldItem: NativeListItem, newItem: NativeListItem) -> Boolean
|
|
27
|
+
) {
|
|
28
|
+
this.isContentEqual = isContentEqual
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override fun replaceData(items: Array<NativeListItem>, animated: Boolean) {
|
|
32
|
+
val nextItems = items.toList()
|
|
33
|
+
if (!animated) {
|
|
34
|
+
this.items = nextItems
|
|
35
|
+
observer?.dataSourceDidReload(null, false)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
val previousItems = this.items
|
|
40
|
+
val callback = NativeDiffCallback(previousItems, nextItems, isContentEqual)
|
|
41
|
+
val diffResult = DiffUtil.calculateDiff(callback, true)
|
|
42
|
+
this.items = nextItems
|
|
43
|
+
observer?.dataSourceDidReload(diffResult, true)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun insertItem(index: Double, item: NativeListItem) {
|
|
47
|
+
val itemIndex = validateInsertionIndex(index.toInt())
|
|
48
|
+
val mutableItems = items.toMutableList()
|
|
49
|
+
mutableItems.add(itemIndex, item)
|
|
50
|
+
items = mutableItems
|
|
51
|
+
observer?.dataSourceDidInsert(itemIndex)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override fun updateItem(index: Double, item: NativeListItem) {
|
|
55
|
+
val itemIndex = validateExistingIndex(index.toInt())
|
|
56
|
+
val mutableItems = items.toMutableList()
|
|
57
|
+
val previousItem = mutableItems[itemIndex]
|
|
58
|
+
mutableItems[itemIndex] = item
|
|
59
|
+
items = mutableItems
|
|
60
|
+
observer?.dataSourceDidUpdate(itemIndex, previousItem)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun removeItem(index: Double) {
|
|
64
|
+
val itemIndex = validateExistingIndex(index.toInt())
|
|
65
|
+
val mutableItems = items.toMutableList()
|
|
66
|
+
val removedItem = mutableItems.removeAt(itemIndex)
|
|
67
|
+
items = mutableItems
|
|
68
|
+
observer?.dataSourceDidRemove(itemIndex, removedItem)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun moveItem(fromIndex: Double, toIndex: Double) {
|
|
72
|
+
val sourceIndex = validateExistingIndex(fromIndex.toInt())
|
|
73
|
+
val targetIndex = validateExistingIndex(toIndex.toInt())
|
|
74
|
+
val mutableItems = items.toMutableList()
|
|
75
|
+
val item = mutableItems.removeAt(sourceIndex)
|
|
76
|
+
mutableItems.add(targetIndex, item)
|
|
77
|
+
items = mutableItems
|
|
78
|
+
observer?.dataSourceDidMove(sourceIndex, targetIndex)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun getCount(): Double {
|
|
82
|
+
return items.size.toDouble()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
override fun getItem(index: Double): NativeListItem {
|
|
86
|
+
val itemIndex = validateExistingIndex(index.toInt())
|
|
87
|
+
return getItemAt(itemIndex)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
internal fun getItemAt(index: Int): NativeListItem {
|
|
91
|
+
return items[index]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
internal fun getCountAsInt(): Int {
|
|
95
|
+
return items.size
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private fun validateExistingIndex(index: Int): Int {
|
|
99
|
+
if (index < 0 || index >= items.size) {
|
|
100
|
+
throw IndexOutOfBoundsException("List index $index is out of bounds.")
|
|
101
|
+
}
|
|
102
|
+
return index
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private fun validateInsertionIndex(index: Int): Int {
|
|
106
|
+
if (index < 0 || index > items.size) {
|
|
107
|
+
throw IndexOutOfBoundsException("List index $index is out of bounds.")
|
|
108
|
+
}
|
|
109
|
+
return index
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private class NativeDiffCallback(
|
|
114
|
+
private val oldItems: List<NativeListItem>,
|
|
115
|
+
private val newItems: List<NativeListItem>,
|
|
116
|
+
private val isContentEqual: (oldItem: NativeListItem, newItem: NativeListItem) -> Boolean
|
|
117
|
+
) : DiffUtil.Callback() {
|
|
118
|
+
|
|
119
|
+
override fun getOldListSize(): Int {
|
|
120
|
+
return oldItems.size
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun getNewListSize(): Int {
|
|
124
|
+
return newItems.size
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
|
128
|
+
val oldItem = oldItems[oldItemPosition]
|
|
129
|
+
val newItem = newItems[newItemPosition]
|
|
130
|
+
return oldItem.key == newItem.key && oldItem.type == newItem.type
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
|
134
|
+
val oldItem = oldItems[oldItemPosition]
|
|
135
|
+
val newItem = newItems[newItemPosition]
|
|
136
|
+
|
|
137
|
+
if (oldItem.width != newItem.width) {
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
if (oldItem.height != newItem.height) {
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return isContentEqual(oldItem, newItem)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
package com.margelo.nitro.reactnativelist
|
|
2
|
+
|
|
3
|
+
import android.graphics.Rect
|
|
4
|
+
import android.view.View
|
|
5
|
+
import androidx.recyclerview.widget.LinearLayoutManager
|
|
6
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
7
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
8
|
+
import kotlin.math.roundToInt
|
|
9
|
+
|
|
10
|
+
open class HybridNativeListLayout : HybridNativeListLayoutSpec()
|
|
11
|
+
|
|
12
|
+
internal interface NativeListLayoutProvider {
|
|
13
|
+
fun applyTo(recyclerView: RecyclerView, reactContext: ThemedReactContext)
|
|
14
|
+
fun itemContentInsets(reactContext: ThemedReactContext): ItemContentInsets
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
data class ItemContentInsets(
|
|
18
|
+
val horizontal: Int,
|
|
19
|
+
val vertical: Int
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class HybridNativeLinearListLayout :
|
|
23
|
+
HybridNativeLinearListLayoutSpec(),
|
|
24
|
+
NativeListLayoutProvider {
|
|
25
|
+
private var topInset = 16
|
|
26
|
+
private var bottomInset = 16
|
|
27
|
+
private var itemSpacing = 12
|
|
28
|
+
private var itemHorizontalInset = 0
|
|
29
|
+
private var itemVerticalInset = 0
|
|
30
|
+
|
|
31
|
+
override fun dispose() {
|
|
32
|
+
topInset = 16
|
|
33
|
+
bottomInset = 16
|
|
34
|
+
itemSpacing = 12
|
|
35
|
+
itemHorizontalInset = 0
|
|
36
|
+
itemVerticalInset = 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun setConfig(config: NativeLinearListLayoutConfig) {
|
|
40
|
+
topInset = config.topInset.roundToInt()
|
|
41
|
+
bottomInset = config.bottomInset.roundToInt()
|
|
42
|
+
itemSpacing = config.itemSpacing.roundToInt()
|
|
43
|
+
itemHorizontalInset = config.itemHorizontalInset.roundToInt()
|
|
44
|
+
itemVerticalInset = config.itemVerticalInset.roundToInt()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun applyTo(recyclerView: RecyclerView, reactContext: ThemedReactContext) {
|
|
48
|
+
recyclerView.layoutManager = LinearLayoutManager(reactContext)
|
|
49
|
+
recyclerView.clipToPadding = false
|
|
50
|
+
val density = reactContext.resources.displayMetrics.density
|
|
51
|
+
val topPadding = (topInset * density).roundToInt()
|
|
52
|
+
val bottomPadding = (bottomInset * density).roundToInt()
|
|
53
|
+
val spacing = (itemSpacing * density).roundToInt()
|
|
54
|
+
|
|
55
|
+
while (recyclerView.itemDecorationCount > 0) {
|
|
56
|
+
recyclerView.removeItemDecorationAt(0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
recyclerView.setPadding(0, topPadding, 0, bottomPadding)
|
|
60
|
+
recyclerView.addItemDecoration(LinearSpacingDecoration(spacing))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun itemContentInsets(reactContext: ThemedReactContext): ItemContentInsets {
|
|
64
|
+
val density = reactContext.resources.displayMetrics.density
|
|
65
|
+
val horizontal = (itemHorizontalInset * density).roundToInt()
|
|
66
|
+
val vertical = (itemVerticalInset * density).roundToInt()
|
|
67
|
+
return ItemContentInsets(horizontal, vertical)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private class LinearSpacingDecoration(
|
|
72
|
+
private val itemSpacing: Int
|
|
73
|
+
) : RecyclerView.ItemDecoration() {
|
|
74
|
+
override fun getItemOffsets(
|
|
75
|
+
outRect: Rect,
|
|
76
|
+
view: View,
|
|
77
|
+
parent: RecyclerView,
|
|
78
|
+
state: RecyclerView.State
|
|
79
|
+
) {
|
|
80
|
+
val position = parent.getChildAdapterPosition(view)
|
|
81
|
+
val itemCount = state.itemCount
|
|
82
|
+
if (position >= 0 && position < itemCount - 1) {
|
|
83
|
+
outRect.bottom = itemSpacing
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
package com.margelo.nitro.reactnativelist
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactActivity
|
|
4
|
+
import com.facebook.react.ReactPackage
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.RuntimeExecutor
|
|
7
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
8
|
+
import com.facebook.react.common.annotations.FrameworkAPI
|
|
9
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
|
10
|
+
import com.facebook.react.fabric.FabricUIManager
|
|
11
|
+
import com.facebook.react.internal.turbomodule.core.TurboModuleManager
|
|
12
|
+
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
|
|
13
|
+
import com.facebook.react.runtime.ReactHostDelegate
|
|
14
|
+
import com.facebook.react.runtime.ReactHostImpl
|
|
15
|
+
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
|
|
16
|
+
import com.facebook.react.turbomodule.core.interfaces.NativeMethodCallInvokerHolder
|
|
17
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
18
|
+
import com.facebook.react.uimanager.common.UIManagerType
|
|
19
|
+
import com.margelo.nitro.NitroModules
|
|
20
|
+
import com.swmansion.worklets.WorkletsModule
|
|
21
|
+
import java.util.ArrayList
|
|
22
|
+
import kotlin.concurrent.Volatile
|
|
23
|
+
|
|
24
|
+
class HybridUiListModule : HybridUiListModuleSpec() {
|
|
25
|
+
override fun iosGetWorkletsModule(): HybridIOSWorkletsModuleProxyHolderSpec {
|
|
26
|
+
throw IllegalStateException("iosGetWorkletsModule is iOS-only and must not be called on Android.")
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@OptIn(UnstableReactNativeAPI::class, FrameworkAPI::class)
|
|
30
|
+
override fun setupRuntime(workletsModuleHolder: Variant_NullType_HybridIOSWorkletsModuleProxyHolderSpec?) {
|
|
31
|
+
if (!UiThreadUtil.isOnUiThread()) {
|
|
32
|
+
throw IllegalStateException("setupRuntime must be called on the UI thread!")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
val context: ReactApplicationContext = NitroModules.applicationContext
|
|
36
|
+
?: throw IllegalStateException("ReactApplicationContext is null! Is Nitro installed?")
|
|
37
|
+
|
|
38
|
+
val workletsModule = context.getNativeModule(WorkletsModule::class.java)
|
|
39
|
+
?: throw IllegalStateException("WorkletsModule is null! Is the WorkletsModule properly registered?")
|
|
40
|
+
val nativeModuleProxyInstalled = prepareUiRuntime(workletsModule)
|
|
41
|
+
|
|
42
|
+
if (!nativeModuleProxyInstalled) {
|
|
43
|
+
val reactActivity = context.currentActivity as? ReactActivity
|
|
44
|
+
?: throw IllegalStateException("Current activity is not a ReactActivity!")
|
|
45
|
+
val reactHost = reactActivity.reactActivityDelegate.reactHost
|
|
46
|
+
?: throw IllegalStateException("ReactNativeHost is null!")
|
|
47
|
+
|
|
48
|
+
// Next: Create a TurboModuleManager for the UI runtime, which will set global.nativeModuleProxy
|
|
49
|
+
// This is whats being used when doing NativeModule.MyNativeModule in JS!
|
|
50
|
+
// TODO: i use a bunch of internals here, can this be improved?
|
|
51
|
+
val reactHostImpl = reactHost as? ReactHostImpl
|
|
52
|
+
?: throw IllegalStateException("ReactHost is not a ReactHostImpl! Is the New Architecture enabled?")
|
|
53
|
+
|
|
54
|
+
val reactHostDelegateField = reactHostImpl.javaClass.getDeclaredField("reactHostDelegate")
|
|
55
|
+
reactHostDelegateField.isAccessible = true
|
|
56
|
+
val reactHostDelegate = reactHostDelegateField.get(reactHostImpl) as? ReactHostDelegate
|
|
57
|
+
?: throw IllegalStateException("ReactHostDelegate is null! Is the New Architecture enabled?")
|
|
58
|
+
|
|
59
|
+
// Get nativeMethodCallInvokerHolder from reactInstance, which lives on reactHostImpl
|
|
60
|
+
val reactInstanceField = reactHostImpl.javaClass.getDeclaredField("reactInstance")
|
|
61
|
+
reactInstanceField.isAccessible = true
|
|
62
|
+
val reactInstance = reactInstanceField.get(reactHostImpl)
|
|
63
|
+
?: throw IllegalStateException("ReactInstance is null! Is the New Architecture enabled?")
|
|
64
|
+
val getNativeMethodCallInvokerHolderMethod = reactInstance.javaClass.getDeclaredMethod("getNativeMethodCallInvokerHolder")
|
|
65
|
+
getNativeMethodCallInvokerHolderMethod.isAccessible = true
|
|
66
|
+
val nativeMethodCallInvokerHolder = getNativeMethodCallInvokerHolderMethod.invoke(reactInstance) as? NativeMethodCallInvokerHolder
|
|
67
|
+
?: throw IllegalStateException("NativeMethodCallInvokerHolder is null! Is the New Architecture enabled?")
|
|
68
|
+
|
|
69
|
+
val reactPackages: MutableList<ReactPackage> = ArrayList<ReactPackage>()
|
|
70
|
+
val coreReactPackageClass = Class.forName("com.facebook.react.runtime.CoreReactPackage")
|
|
71
|
+
val constructor = coreReactPackageClass.declaredConstructors.first()
|
|
72
|
+
constructor.isAccessible = true
|
|
73
|
+
// TODO: this will create dev support modules on the UI runtime which is unnecessary overhead we don't need!
|
|
74
|
+
// In a past version i simply put in the most important core modules from JS, which was somewhat nicer.
|
|
75
|
+
val coreReactPackage = constructor.newInstance(reactHost.devSupportManager, DefaultHardwareBackBtnHandler {}) as ReactPackage
|
|
76
|
+
reactPackages.add(coreReactPackage)
|
|
77
|
+
reactPackages.addAll(reactHostDelegate.reactPackages)
|
|
78
|
+
|
|
79
|
+
val turboModuleManagerDelegate = reactHostDelegate.turboModuleManagerDelegateBuilder
|
|
80
|
+
.setPackages(reactPackages)
|
|
81
|
+
.setReactApplicationContext(context)
|
|
82
|
+
.build()
|
|
83
|
+
|
|
84
|
+
val uiCallInvokerHolder = getUiCallInvokerHolder(workletsModule)
|
|
85
|
+
val uiRuntimeExecutor = getUiRuntimeExecutor(workletsModule)
|
|
86
|
+
|
|
87
|
+
// This will install the JSI bindings
|
|
88
|
+
uiTurboModuleManager = TurboModuleManager(
|
|
89
|
+
// TurboModuleManager will call jni -> cpp, to actually setup nativeModuleProxy
|
|
90
|
+
runtimeExecutor = uiRuntimeExecutor,
|
|
91
|
+
delegate = turboModuleManagerDelegate,
|
|
92
|
+
jsCallInvokerHolder = uiCallInvokerHolder,
|
|
93
|
+
nativeMethodCallInvokerHolder = nativeMethodCallInvokerHolder
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
val uiManager = UIManagerHelper.getUIManager(context, UIManagerType.FABRIC)
|
|
98
|
+
?: throw IllegalStateException("Fabric UIManager is null! Is the Fabric architecture enabled?")
|
|
99
|
+
val fabricUIManager = uiManager as? FabricUIManager
|
|
100
|
+
?: throw IllegalStateException("UIManager is not a FabricUIManager! Is the Fabric architecture enabled?")
|
|
101
|
+
setupEventInterceptor(fabricUIManager)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@OptIn(FrameworkAPI::class)
|
|
105
|
+
private external fun prepareUiRuntime(workletsModule: WorkletsModule): Boolean
|
|
106
|
+
|
|
107
|
+
@OptIn(FrameworkAPI::class)
|
|
108
|
+
private external fun getUiCallInvokerHolder(workletsModule: WorkletsModule): CallInvokerHolderImpl
|
|
109
|
+
|
|
110
|
+
private external fun getUiRuntimeExecutor(workletsModule: WorkletsModule): RuntimeExecutor
|
|
111
|
+
|
|
112
|
+
private external fun setupEventInterceptor(fabricUIManager: FabricUIManager)
|
|
113
|
+
|
|
114
|
+
@Volatile
|
|
115
|
+
private lateinit var uiTurboModuleManager: TurboModuleManager
|
|
116
|
+
}
|