@onekeyfe/react-native-scroll-guard 3.0.95 → 3.0.98
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/android/src/main/java/com/margelo/nitro/scrollguard/ScrollGuardViewGroupManager.kt +23 -5
- package/lib/nitrogen/generated/android/c++/views/JHybridScrollGuardStateUpdater.cpp +38 -20
- package/lib/nitrogen/generated/android/c++/views/JHybridScrollGuardStateUpdater.hpp +6 -1
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/scrollguard/views/HybridScrollGuardManager.kt +26 -10
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/scrollguard/views/HybridScrollGuardStateUpdater.kt +2 -2
- package/lib/nitrogen/generated/ios/c++/views/HybridScrollGuardComponent.mm +44 -22
- package/lib/nitrogen/generated/shared/c++/views/HybridScrollGuardComponent.cpp +6 -55
- package/lib/nitrogen/generated/shared/c++/views/HybridScrollGuardComponent.hpp +23 -49
- package/nitrogen/generated/android/c++/views/JHybridScrollGuardStateUpdater.cpp +38 -20
- package/nitrogen/generated/android/c++/views/JHybridScrollGuardStateUpdater.hpp +6 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/scrollguard/views/HybridScrollGuardManager.kt +26 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/scrollguard/views/HybridScrollGuardStateUpdater.kt +2 -2
- package/nitrogen/generated/ios/c++/views/HybridScrollGuardComponent.mm +44 -22
- package/nitrogen/generated/shared/c++/views/HybridScrollGuardComponent.cpp +6 -55
- package/nitrogen/generated/shared/c++/views/HybridScrollGuardComponent.hpp +23 -49
- package/package.json +4 -4
|
@@ -15,34 +15,52 @@ import com.margelo.nitro.scrollguard.views.HybridScrollGuardStateUpdater
|
|
|
15
15
|
* is a FrameLayout that wraps child scrollable views, we need a ViewGroupManager.
|
|
16
16
|
*/
|
|
17
17
|
class ScrollGuardViewGroupManager : ViewGroupManager<ScrollGuardFrameLayout>() {
|
|
18
|
-
private
|
|
18
|
+
private class HybridViewHolder(
|
|
19
|
+
val hybridView: HybridScrollGuard,
|
|
20
|
+
var lastState: StateWrapper? = null,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
private val views = hashMapOf<View, HybridViewHolder>()
|
|
19
24
|
|
|
20
25
|
override fun getName(): String = "ScrollGuard"
|
|
21
26
|
|
|
22
27
|
override fun createViewInstance(reactContext: ThemedReactContext): ScrollGuardFrameLayout {
|
|
23
28
|
val hybridView = HybridScrollGuard(reactContext)
|
|
24
29
|
val view = hybridView.view as ScrollGuardFrameLayout
|
|
25
|
-
views[view] = hybridView
|
|
30
|
+
views[view] = HybridViewHolder(hybridView)
|
|
26
31
|
return view
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
override fun onDropViewInstance(view: ScrollGuardFrameLayout) {
|
|
35
|
+
views[view]?.lastState = null
|
|
30
36
|
super.onDropViewInstance(view)
|
|
31
37
|
views.remove(view)
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
override fun prepareToRecycleView(
|
|
41
|
+
reactContext: ThemedReactContext,
|
|
42
|
+
view: ScrollGuardFrameLayout,
|
|
43
|
+
): ScrollGuardFrameLayout? {
|
|
44
|
+
views[view]?.lastState = null
|
|
45
|
+
return super.prepareToRecycleView(reactContext, view)
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
override fun updateState(
|
|
35
49
|
view: ScrollGuardFrameLayout,
|
|
36
50
|
props: ReactStylesDiffMap,
|
|
37
51
|
stateWrapper: StateWrapper
|
|
38
52
|
): Any? {
|
|
39
|
-
val
|
|
53
|
+
val holder = views[view]
|
|
40
54
|
?: throw Error("Couldn't find view $view in local views table!")
|
|
55
|
+
val hybridView = holder.hybridView
|
|
56
|
+
val oldState = holder.lastState
|
|
57
|
+
val newState = stateWrapper
|
|
41
58
|
|
|
42
59
|
hybridView.beforeUpdate()
|
|
43
|
-
HybridScrollGuardStateUpdater.updateViewProps(hybridView,
|
|
60
|
+
HybridScrollGuardStateUpdater.updateViewProps(hybridView, newState, oldState)
|
|
44
61
|
hybridView.afterUpdate()
|
|
62
|
+
holder.lastState = newState
|
|
45
63
|
|
|
46
|
-
return super.updateState(view, props,
|
|
64
|
+
return super.updateState(view, props, newState)
|
|
47
65
|
}
|
|
48
66
|
}
|
|
@@ -15,41 +15,59 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
15
15
|
using namespace facebook;
|
|
16
16
|
using ConcreteStateData = react::ConcreteState<HybridScrollGuardState>;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
std::shared_ptr<const HybridScrollGuardProps> JHybridScrollGuardStateUpdater::getPropsFromStateWrapper(
|
|
19
|
+
jni::alias_ref<JStateWrapper::javaobject> stateWrapper) {
|
|
20
|
+
if (stateWrapper.get() == nullptr) {
|
|
21
|
+
return nullptr;
|
|
22
|
+
}
|
|
23
23
|
// Get concrete StateWrapperImpl from passed StateWrapper interface object
|
|
24
|
-
jobject rawStateWrapper =
|
|
25
|
-
if (!
|
|
26
|
-
|
|
24
|
+
jobject rawStateWrapper = stateWrapper.get();
|
|
25
|
+
if (!stateWrapper->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] {
|
|
26
|
+
throw std::runtime_error("StateWrapper is not a StateWrapperImpl");
|
|
27
|
+
}
|
|
28
|
+
auto stateWrapperImpl = jni::alias_ref<react::StateWrapperImpl::javaobject>{
|
|
29
|
+
static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)
|
|
30
|
+
};
|
|
31
|
+
std::shared_ptr<const react::State> state = stateWrapperImpl->cthis()->getState();
|
|
32
|
+
if (state == nullptr) {
|
|
33
|
+
return nullptr;
|
|
27
34
|
}
|
|
28
|
-
auto stateWrapper = jni::alias_ref<react::StateWrapperImpl::javaobject>{
|
|
29
|
-
static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)};
|
|
30
|
-
std::shared_ptr<const react::State> state = stateWrapper->cthis()->getState();
|
|
31
35
|
auto concreteState = std::static_pointer_cast<const ConcreteStateData>(state);
|
|
32
36
|
const HybridScrollGuardState& data = concreteState->getData();
|
|
33
|
-
const std::shared_ptr<HybridScrollGuardProps>& props = data.getProps();
|
|
37
|
+
const std::shared_ptr<const HybridScrollGuardProps>& props = data.getProps();
|
|
34
38
|
if (props == nullptr) [[unlikely]] {
|
|
35
|
-
// Props aren't set yet!
|
|
36
39
|
throw std::runtime_error("HybridScrollGuardState's data doesn't contain any props!");
|
|
37
40
|
}
|
|
41
|
+
return props;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void JHybridScrollGuardStateUpdater::updateViewProps(jni::alias_ref<jni::JClass> /* class */,
|
|
45
|
+
jni::alias_ref<JHybridScrollGuardSpec::JavaPart> javaView,
|
|
46
|
+
jni::alias_ref<JStateWrapper::javaobject> newState,
|
|
47
|
+
jni::alias_ref<JStateWrapper::javaobject> oldState) {
|
|
48
|
+
std::shared_ptr<JHybridScrollGuardSpec> hybridView = javaView->getJHybridScrollGuardSpec();
|
|
49
|
+
std::shared_ptr<const HybridScrollGuardProps> newProps = getPropsFromStateWrapper(newState);
|
|
50
|
+
std::shared_ptr<const HybridScrollGuardProps> oldProps = getPropsFromStateWrapper(oldState);
|
|
51
|
+
if (newProps == nullptr) [[unlikely]] {
|
|
52
|
+
throw std::runtime_error("Current StateWrapper doesn't contain any props!");
|
|
53
|
+
}
|
|
38
54
|
|
|
39
|
-
// Update
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
// Update only props that differ from the previous State snapshot.
|
|
56
|
+
if (oldProps == nullptr
|
|
57
|
+
? newProps->direction.isProvided()
|
|
58
|
+
: !newProps->direction.hasSameValue(oldProps->direction)) {
|
|
59
|
+
hybridView->setDirection(newProps->direction.get());
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
// Update hybridRef if it changed
|
|
46
|
-
if (
|
|
63
|
+
if (oldProps == nullptr
|
|
64
|
+
? newProps->hybridRef.isProvided()
|
|
65
|
+
: !newProps->hybridRef.hasSameValue(oldProps->hybridRef)) {
|
|
47
66
|
// hybridRef changed - call it with new this
|
|
48
|
-
const auto& maybeFunc =
|
|
67
|
+
const auto& maybeFunc = newProps->hybridRef.get();
|
|
49
68
|
if (maybeFunc.has_value()) {
|
|
50
69
|
maybeFunc.value()(hybridView);
|
|
51
70
|
}
|
|
52
|
-
props->hybridRef.isDirty = false;
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
|
|
@@ -31,7 +31,12 @@ public:
|
|
|
31
31
|
public:
|
|
32
32
|
static void updateViewProps(jni::alias_ref<jni::JClass> /* class */,
|
|
33
33
|
jni::alias_ref<JHybridScrollGuardSpec::JavaPart> view,
|
|
34
|
-
jni::alias_ref<JStateWrapper::javaobject>
|
|
34
|
+
jni::alias_ref<JStateWrapper::javaobject> newState,
|
|
35
|
+
jni::alias_ref<JStateWrapper::javaobject> oldState);
|
|
36
|
+
|
|
37
|
+
private:
|
|
38
|
+
static std::shared_ptr<const HybridScrollGuardProps> getPropsFromStateWrapper(
|
|
39
|
+
jni::alias_ref<JStateWrapper::javaobject> stateWrapper);
|
|
35
40
|
|
|
36
41
|
public:
|
|
37
42
|
static void registerNatives() {
|
|
@@ -20,6 +20,14 @@ import com.margelo.nitro.scrollguard.*
|
|
|
20
20
|
* Represents the React Native `ViewManager` for the "ScrollGuard" Nitro HybridView.
|
|
21
21
|
*/
|
|
22
22
|
public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
23
|
+
/**
|
|
24
|
+
* Represents the View and its last state snapshot (mutable)
|
|
25
|
+
*/
|
|
26
|
+
private class HybridViewHolder(
|
|
27
|
+
val hybridView: HybridScrollGuard,
|
|
28
|
+
var lastState: StateWrapper? = null,
|
|
29
|
+
)
|
|
30
|
+
|
|
23
31
|
init {
|
|
24
32
|
if (RecyclableView::class.java.isAssignableFrom(HybridScrollGuard::class.java)) {
|
|
25
33
|
// Enable view recycling
|
|
@@ -34,33 +42,41 @@ public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
|
34
42
|
override fun createViewInstance(reactContext: ThemedReactContext): View {
|
|
35
43
|
val hybridView = HybridScrollGuard(reactContext)
|
|
36
44
|
val view = hybridView.view
|
|
37
|
-
view.setTag(associated_hybrid_view_tag, hybridView)
|
|
45
|
+
view.setTag(associated_hybrid_view_tag, HybridViewHolder(hybridView))
|
|
38
46
|
return view
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? {
|
|
42
|
-
val
|
|
50
|
+
val holder = getHybridViewHolder(view)
|
|
43
51
|
?: throw Error("Couldn't find view $view in local views table!")
|
|
52
|
+
val hybridView = holder.hybridView
|
|
53
|
+
val oldState = holder.lastState
|
|
54
|
+
val newState = stateWrapper
|
|
44
55
|
|
|
45
56
|
// 1. Update each prop individually
|
|
46
57
|
hybridView.beforeUpdate()
|
|
47
|
-
HybridScrollGuardStateUpdater.updateViewProps(hybridView,
|
|
58
|
+
HybridScrollGuardStateUpdater.updateViewProps(hybridView, newState, oldState)
|
|
48
59
|
hybridView.afterUpdate()
|
|
60
|
+
holder.lastState = newState
|
|
49
61
|
|
|
50
62
|
// 2. Continue in base View props
|
|
51
|
-
return super.updateState(view, props,
|
|
63
|
+
return super.updateState(view, props, newState)
|
|
52
64
|
}
|
|
53
65
|
|
|
54
66
|
override fun onDropViewInstance(view: View) {
|
|
55
|
-
val
|
|
56
|
-
|
|
67
|
+
val holder = getHybridViewHolder(view)
|
|
68
|
+
holder?.lastState = null
|
|
69
|
+
holder?.hybridView?.onDropView()
|
|
57
70
|
return super.onDropViewInstance(view)
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
protected override fun prepareToRecycleView(reactContext: ThemedReactContext, view: View): View? {
|
|
61
|
-
super.prepareToRecycleView(reactContext, view)
|
|
62
|
-
|
|
74
|
+
val preparedView = super.prepareToRecycleView(reactContext, view)
|
|
75
|
+
?: return null
|
|
76
|
+
val holder = getHybridViewHolder(preparedView)
|
|
63
77
|
?: return null
|
|
78
|
+
val hybridView = holder.hybridView
|
|
79
|
+
holder.lastState = null
|
|
64
80
|
|
|
65
81
|
@Suppress("USELESS_IS_CHECK")
|
|
66
82
|
if (hybridView is RecyclableView) {
|
|
@@ -74,7 +90,7 @@ public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
|
74
90
|
}
|
|
75
91
|
}
|
|
76
92
|
|
|
77
|
-
private fun
|
|
78
|
-
return view.getTag(associated_hybrid_view_tag) as?
|
|
93
|
+
private fun getHybridViewHolder(view: View): HybridViewHolder? {
|
|
94
|
+
return view.getTag(associated_hybrid_view_tag) as? HybridViewHolder
|
|
79
95
|
}
|
|
80
96
|
}
|
|
@@ -14,10 +14,10 @@ internal class HybridScrollGuardStateUpdater {
|
|
|
14
14
|
companion object {
|
|
15
15
|
/**
|
|
16
16
|
* Updates the props for [view] through C++.
|
|
17
|
-
* The [
|
|
17
|
+
* The [newState] prop is expected to contain [view]'s props as wrapped Fabric state.
|
|
18
18
|
*/
|
|
19
19
|
@Suppress("KotlinJniMissingFunction")
|
|
20
20
|
@JvmStatic
|
|
21
|
-
external fun updateViewProps(view: HybridScrollGuardSpec,
|
|
21
|
+
external fun updateViewProps(view: HybridScrollGuardSpec, newState: StateWrapper, oldState: StateWrapper?)
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -37,6 +37,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
37
37
|
|
|
38
38
|
@implementation HybridScrollGuardComponent {
|
|
39
39
|
std::shared_ptr<HybridScrollGuardSpecSwift> _hybridView;
|
|
40
|
+
BOOL _didDropView;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
+ (void) load {
|
|
@@ -50,6 +51,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
50
51
|
|
|
51
52
|
- (instancetype) init {
|
|
52
53
|
if (self = [super init]) {
|
|
54
|
+
_props = HybridScrollGuardShadowNode::defaultSharedProps();
|
|
53
55
|
std::shared_ptr<HybridScrollGuardSpec> hybridView = ScrollGuard::ScrollGuardAutolinking::createScrollGuard();
|
|
54
56
|
_hybridView = std::dynamic_pointer_cast<HybridScrollGuardSpecSwift>(hybridView);
|
|
55
57
|
[self updateView];
|
|
@@ -69,35 +71,55 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
69
71
|
[self setContentView:view];
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
- (void) notifyOnDropView {
|
|
75
|
+
// A recycled component can later be invalidated. Notify only once per mount.
|
|
76
|
+
if (_didDropView) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
80
|
+
swiftPart.onDropView();
|
|
81
|
+
_didDropView = YES;
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
- (void) updateProps:(const std::shared_ptr<const react::Props>&)props
|
|
73
85
|
oldProps:(const std::shared_ptr<const react::Props>&)oldProps {
|
|
86
|
+
// A props update marks a newly mounted or still-active component.
|
|
87
|
+
_didDropView = NO;
|
|
88
|
+
|
|
74
89
|
// 1. Downcast props
|
|
75
|
-
const auto&
|
|
76
|
-
auto
|
|
90
|
+
const auto& newViewProps = *std::static_pointer_cast<const HybridScrollGuardProps>(props);
|
|
91
|
+
const auto* oldViewProps = static_cast<const HybridScrollGuardProps*>(oldProps.get());
|
|
77
92
|
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
78
93
|
|
|
79
|
-
// 2. Update
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
swiftPart.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
// 2. Update only props that differ from the previous Props snapshot.
|
|
95
|
+
const bool hasTransactionPropChanges = oldViewProps == nullptr
|
|
96
|
+
? newViewProps.hasAnyProvidedProps()
|
|
97
|
+
: !newViewProps.hasSameProps(*oldViewProps);
|
|
98
|
+
if (hasTransactionPropChanges) {
|
|
99
|
+
swiftPart.beforeUpdate();
|
|
100
|
+
|
|
101
|
+
// direction: optional
|
|
102
|
+
if (oldViewProps == nullptr
|
|
103
|
+
? newViewProps.direction.isProvided()
|
|
104
|
+
: !newViewProps.direction.hasSameValue(oldViewProps->direction)) {
|
|
105
|
+
swiftPart.setDirection(newViewProps.direction.get());
|
|
106
|
+
}
|
|
89
107
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
maybeFunc.
|
|
108
|
+
// Update hybridRef if it changed
|
|
109
|
+
if (oldViewProps == nullptr
|
|
110
|
+
? newViewProps.hybridRef.isProvided()
|
|
111
|
+
: !newViewProps.hybridRef.hasSameValue(oldViewProps->hybridRef)) {
|
|
112
|
+
// hybridRef changed - call it with new this
|
|
113
|
+
const auto& maybeFunc = newViewProps.hybridRef.get();
|
|
114
|
+
if (maybeFunc.has_value()) {
|
|
115
|
+
maybeFunc.value()(_hybridView);
|
|
116
|
+
}
|
|
96
117
|
}
|
|
97
|
-
|
|
118
|
+
|
|
119
|
+
swiftPart.afterUpdate();
|
|
98
120
|
}
|
|
99
121
|
|
|
100
|
-
//
|
|
122
|
+
// 3. Continue in base class
|
|
101
123
|
[super updateProps:props oldProps:oldProps];
|
|
102
124
|
}
|
|
103
125
|
|
|
@@ -106,6 +128,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
106
128
|
}
|
|
107
129
|
|
|
108
130
|
- (void)prepareForRecycle {
|
|
131
|
+
[self notifyOnDropView];
|
|
109
132
|
[super prepareForRecycle];
|
|
110
133
|
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
111
134
|
swiftPart.maybePrepareForRecycle();
|
|
@@ -113,8 +136,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
113
136
|
|
|
114
137
|
#ifdef ENABLE_RCT_COMPONENT_VIEW_INVALIDATE
|
|
115
138
|
- (void)invalidate {
|
|
116
|
-
|
|
117
|
-
swiftPart.onDropView();
|
|
139
|
+
[self notifyOnDropView];
|
|
118
140
|
[super invalidate];
|
|
119
141
|
}
|
|
120
142
|
#endif
|
|
@@ -7,45 +7,21 @@
|
|
|
7
7
|
|
|
8
8
|
#include "HybridScrollGuardComponent.hpp"
|
|
9
9
|
|
|
10
|
-
#include <
|
|
11
|
-
#include <
|
|
12
|
-
#include <utility>
|
|
13
|
-
#include <NitroModules/NitroDefines.hpp>
|
|
14
|
-
#include <NitroModules/JSIConverter.hpp>
|
|
15
|
-
#include <NitroModules/PropNameIDCache.hpp>
|
|
16
|
-
#include <react/renderer/core/RawValue.h>
|
|
17
|
-
#include <react/renderer/core/ShadowNode.h>
|
|
18
|
-
#include <react/renderer/core/ComponentDescriptor.h>
|
|
19
|
-
#include <react/renderer/components/view/ViewProps.h>
|
|
10
|
+
#include <NitroModules/NitroHash.hpp>
|
|
11
|
+
#include <NitroModules/ReactProp.hpp>
|
|
20
12
|
|
|
21
13
|
namespace margelo::nitro::scrollguard::views {
|
|
22
14
|
|
|
15
|
+
using namespace facebook;
|
|
16
|
+
|
|
23
17
|
extern const char HybridScrollGuardComponentName[] = "ScrollGuard";
|
|
24
18
|
|
|
25
19
|
HybridScrollGuardProps::HybridScrollGuardProps(const react::PropsParserContext& context,
|
|
26
20
|
const HybridScrollGuardProps& sourceProps,
|
|
27
21
|
const react::RawProps& rawProps):
|
|
28
22
|
react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
|
|
29
|
-
direction(
|
|
30
|
-
|
|
31
|
-
const react::RawValue* rawValue = rawProps.at("direction", nullptr, nullptr);
|
|
32
|
-
if (rawValue == nullptr) return sourceProps.direction;
|
|
33
|
-
const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
|
|
34
|
-
return CachedProp<std::optional<ScrollGuardDirection>>::fromRawValue(*runtime, value, sourceProps.direction);
|
|
35
|
-
} catch (const std::exception& exc) {
|
|
36
|
-
throw std::runtime_error(std::string("ScrollGuard.direction: ") + exc.what());
|
|
37
|
-
}
|
|
38
|
-
}()),
|
|
39
|
-
hybridRef([&]() -> CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>> {
|
|
40
|
-
try {
|
|
41
|
-
const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr);
|
|
42
|
-
if (rawValue == nullptr) return sourceProps.hybridRef;
|
|
43
|
-
const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
|
|
44
|
-
return CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef);
|
|
45
|
-
} catch (const std::exception& exc) {
|
|
46
|
-
throw std::runtime_error(std::string("ScrollGuard.hybridRef: ") + exc.what());
|
|
47
|
-
}
|
|
48
|
-
}()) { }
|
|
23
|
+
direction(nitro::ReactProp<std::optional<ScrollGuardDirection>>::fromRawValue("ScrollGuard", "direction", rawProps, sourceProps.direction)),
|
|
24
|
+
hybridRef(nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>>::fromRawValue("ScrollGuard", "hybridRef", rawProps, sourceProps.hybridRef)) { }
|
|
49
25
|
|
|
50
26
|
bool HybridScrollGuardProps::filterObjectKeys(const std::string& propName) {
|
|
51
27
|
switch (hashString(propName)) {
|
|
@@ -55,29 +31,4 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
55
31
|
}
|
|
56
32
|
}
|
|
57
33
|
|
|
58
|
-
HybridScrollGuardComponentDescriptor::HybridScrollGuardComponentDescriptor(const react::ComponentDescriptorParameters& parameters)
|
|
59
|
-
: ConcreteComponentDescriptor(parameters,
|
|
60
|
-
react::RawPropsParser()) {}
|
|
61
|
-
|
|
62
|
-
std::shared_ptr<const react::Props> HybridScrollGuardComponentDescriptor::cloneProps(const react::PropsParserContext& context,
|
|
63
|
-
const std::shared_ptr<const react::Props>& props,
|
|
64
|
-
react::RawProps rawProps) const {
|
|
65
|
-
// 1. Prepare raw props parser
|
|
66
|
-
rawProps.parse(rawPropsParser_);
|
|
67
|
-
// 2. Copy props with Nitro's cached copy constructor
|
|
68
|
-
return HybridScrollGuardShadowNode::Props(context, /* & */ rawProps, props);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
#ifdef ANDROID
|
|
72
|
-
void HybridScrollGuardComponentDescriptor::adopt(react::ShadowNode& shadowNode) const {
|
|
73
|
-
// This is called immediately after `ShadowNode` is created, cloned or in progress.
|
|
74
|
-
// On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++.
|
|
75
|
-
auto& concreteShadowNode = static_cast<HybridScrollGuardShadowNode&>(shadowNode);
|
|
76
|
-
const std::shared_ptr<const HybridScrollGuardProps>& constProps = concreteShadowNode.getConcreteSharedProps();
|
|
77
|
-
const std::shared_ptr<HybridScrollGuardProps>& props = std::const_pointer_cast<HybridScrollGuardProps>(constProps);
|
|
78
|
-
HybridScrollGuardState state{props};
|
|
79
|
-
concreteShadowNode.setStateData(std::move(state));
|
|
80
|
-
}
|
|
81
|
-
#endif
|
|
82
|
-
|
|
83
34
|
} // namespace margelo::nitro::scrollguard::views
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
-
#include <
|
|
11
|
-
#include <NitroModules/
|
|
12
|
-
#include <NitroModules/
|
|
13
|
-
#include <NitroModules/CachedProp.hpp>
|
|
14
|
-
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
15
|
-
#include <react/renderer/core/PropsParserContext.h>
|
|
10
|
+
#include <NitroModules/ReactProp.hpp>
|
|
11
|
+
#include <NitroModules/ViewComponentDescriptor.hpp>
|
|
12
|
+
#include <NitroModules/ViewPropsHolderState.hpp>
|
|
16
13
|
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
17
14
|
#include <react/renderer/components/view/ViewProps.h>
|
|
15
|
+
#include <react/renderer/core/PropsParserContext.h>
|
|
16
|
+
#include <react/renderer/core/RawProps.h>
|
|
17
|
+
|
|
18
|
+
#include <string>
|
|
18
19
|
|
|
19
20
|
#include "ScrollGuardDirection.hpp"
|
|
20
21
|
#include <optional>
|
|
@@ -42,8 +43,20 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
42
43
|
const react::RawProps& rawProps);
|
|
43
44
|
|
|
44
45
|
public:
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
nitro::ReactProp<std::optional<ScrollGuardDirection>> direction;
|
|
47
|
+
nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>> hybridRef;
|
|
48
|
+
|
|
49
|
+
[[nodiscard]]
|
|
50
|
+
bool hasSameProps(const HybridScrollGuardProps& other) const noexcept {
|
|
51
|
+
return direction.hasSameValue(other.direction) &&
|
|
52
|
+
hybridRef.hasSameValue(other.hybridRef);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[[nodiscard]]
|
|
56
|
+
bool hasAnyProvidedProps() const noexcept {
|
|
57
|
+
return direction.isProvided() ||
|
|
58
|
+
hybridRef.isProvided();
|
|
59
|
+
}
|
|
47
60
|
|
|
48
61
|
private:
|
|
49
62
|
static bool filterObjectKeys(const std::string& propName);
|
|
@@ -52,32 +65,7 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
52
65
|
/**
|
|
53
66
|
* State for the "ScrollGuard" View.
|
|
54
67
|
*/
|
|
55
|
-
|
|
56
|
-
public:
|
|
57
|
-
HybridScrollGuardState() = default;
|
|
58
|
-
explicit HybridScrollGuardState(const std::shared_ptr<HybridScrollGuardProps>& props):
|
|
59
|
-
_props(props) {}
|
|
60
|
-
|
|
61
|
-
public:
|
|
62
|
-
[[nodiscard]]
|
|
63
|
-
const std::shared_ptr<HybridScrollGuardProps>& getProps() const {
|
|
64
|
-
return _props;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public:
|
|
68
|
-
#ifdef ANDROID
|
|
69
|
-
HybridScrollGuardState(const HybridScrollGuardState& /* previousState */, folly::dynamic /* data */) {}
|
|
70
|
-
folly::dynamic getDynamic() const {
|
|
71
|
-
throw std::runtime_error("HybridScrollGuardState does not support folly!");
|
|
72
|
-
}
|
|
73
|
-
react::MapBuffer getMapBuffer() const {
|
|
74
|
-
throw std::runtime_error("HybridScrollGuardState does not support MapBuffer!");
|
|
75
|
-
};
|
|
76
|
-
#endif
|
|
77
|
-
|
|
78
|
-
private:
|
|
79
|
-
std::shared_ptr<HybridScrollGuardProps> _props;
|
|
80
|
-
};
|
|
68
|
+
using HybridScrollGuardState = nitro::ViewPropsHolderState<HybridScrollGuardProps>;
|
|
81
69
|
|
|
82
70
|
/**
|
|
83
71
|
* The Shadow Node for the "ScrollGuard" View.
|
|
@@ -90,21 +78,7 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
90
78
|
/**
|
|
91
79
|
* The Component Descriptor for the "ScrollGuard" View.
|
|
92
80
|
*/
|
|
93
|
-
|
|
94
|
-
public:
|
|
95
|
-
explicit HybridScrollGuardComponentDescriptor(const react::ComponentDescriptorParameters& parameters);
|
|
96
|
-
|
|
97
|
-
public:
|
|
98
|
-
/**
|
|
99
|
-
* A faster path for cloning props - reuses the caching logic from `HybridScrollGuardProps`.
|
|
100
|
-
*/
|
|
101
|
-
std::shared_ptr<const react::Props> cloneProps(const react::PropsParserContext& context,
|
|
102
|
-
const std::shared_ptr<const react::Props>& props,
|
|
103
|
-
react::RawProps rawProps) const override;
|
|
104
|
-
#ifdef ANDROID
|
|
105
|
-
void adopt(react::ShadowNode& shadowNode) const override;
|
|
106
|
-
#endif
|
|
107
|
-
};
|
|
81
|
+
using HybridScrollGuardComponentDescriptor = nitro::ViewComponentDescriptor<HybridScrollGuardShadowNode>;
|
|
108
82
|
|
|
109
83
|
/* The actual view for "ScrollGuard" needs to be implemented in platform-specific code. */
|
|
110
84
|
|
|
@@ -15,41 +15,59 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
15
15
|
using namespace facebook;
|
|
16
16
|
using ConcreteStateData = react::ConcreteState<HybridScrollGuardState>;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
std::shared_ptr<const HybridScrollGuardProps> JHybridScrollGuardStateUpdater::getPropsFromStateWrapper(
|
|
19
|
+
jni::alias_ref<JStateWrapper::javaobject> stateWrapper) {
|
|
20
|
+
if (stateWrapper.get() == nullptr) {
|
|
21
|
+
return nullptr;
|
|
22
|
+
}
|
|
23
23
|
// Get concrete StateWrapperImpl from passed StateWrapper interface object
|
|
24
|
-
jobject rawStateWrapper =
|
|
25
|
-
if (!
|
|
26
|
-
|
|
24
|
+
jobject rawStateWrapper = stateWrapper.get();
|
|
25
|
+
if (!stateWrapper->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) [[unlikely]] {
|
|
26
|
+
throw std::runtime_error("StateWrapper is not a StateWrapperImpl");
|
|
27
|
+
}
|
|
28
|
+
auto stateWrapperImpl = jni::alias_ref<react::StateWrapperImpl::javaobject>{
|
|
29
|
+
static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)
|
|
30
|
+
};
|
|
31
|
+
std::shared_ptr<const react::State> state = stateWrapperImpl->cthis()->getState();
|
|
32
|
+
if (state == nullptr) {
|
|
33
|
+
return nullptr;
|
|
27
34
|
}
|
|
28
|
-
auto stateWrapper = jni::alias_ref<react::StateWrapperImpl::javaobject>{
|
|
29
|
-
static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)};
|
|
30
|
-
std::shared_ptr<const react::State> state = stateWrapper->cthis()->getState();
|
|
31
35
|
auto concreteState = std::static_pointer_cast<const ConcreteStateData>(state);
|
|
32
36
|
const HybridScrollGuardState& data = concreteState->getData();
|
|
33
|
-
const std::shared_ptr<HybridScrollGuardProps>& props = data.getProps();
|
|
37
|
+
const std::shared_ptr<const HybridScrollGuardProps>& props = data.getProps();
|
|
34
38
|
if (props == nullptr) [[unlikely]] {
|
|
35
|
-
// Props aren't set yet!
|
|
36
39
|
throw std::runtime_error("HybridScrollGuardState's data doesn't contain any props!");
|
|
37
40
|
}
|
|
41
|
+
return props;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void JHybridScrollGuardStateUpdater::updateViewProps(jni::alias_ref<jni::JClass> /* class */,
|
|
45
|
+
jni::alias_ref<JHybridScrollGuardSpec::JavaPart> javaView,
|
|
46
|
+
jni::alias_ref<JStateWrapper::javaobject> newState,
|
|
47
|
+
jni::alias_ref<JStateWrapper::javaobject> oldState) {
|
|
48
|
+
std::shared_ptr<JHybridScrollGuardSpec> hybridView = javaView->getJHybridScrollGuardSpec();
|
|
49
|
+
std::shared_ptr<const HybridScrollGuardProps> newProps = getPropsFromStateWrapper(newState);
|
|
50
|
+
std::shared_ptr<const HybridScrollGuardProps> oldProps = getPropsFromStateWrapper(oldState);
|
|
51
|
+
if (newProps == nullptr) [[unlikely]] {
|
|
52
|
+
throw std::runtime_error("Current StateWrapper doesn't contain any props!");
|
|
53
|
+
}
|
|
38
54
|
|
|
39
|
-
// Update
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
// Update only props that differ from the previous State snapshot.
|
|
56
|
+
if (oldProps == nullptr
|
|
57
|
+
? newProps->direction.isProvided()
|
|
58
|
+
: !newProps->direction.hasSameValue(oldProps->direction)) {
|
|
59
|
+
hybridView->setDirection(newProps->direction.get());
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
// Update hybridRef if it changed
|
|
46
|
-
if (
|
|
63
|
+
if (oldProps == nullptr
|
|
64
|
+
? newProps->hybridRef.isProvided()
|
|
65
|
+
: !newProps->hybridRef.hasSameValue(oldProps->hybridRef)) {
|
|
47
66
|
// hybridRef changed - call it with new this
|
|
48
|
-
const auto& maybeFunc =
|
|
67
|
+
const auto& maybeFunc = newProps->hybridRef.get();
|
|
49
68
|
if (maybeFunc.has_value()) {
|
|
50
69
|
maybeFunc.value()(hybridView);
|
|
51
70
|
}
|
|
52
|
-
props->hybridRef.isDirty = false;
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
|
|
@@ -31,7 +31,12 @@ public:
|
|
|
31
31
|
public:
|
|
32
32
|
static void updateViewProps(jni::alias_ref<jni::JClass> /* class */,
|
|
33
33
|
jni::alias_ref<JHybridScrollGuardSpec::JavaPart> view,
|
|
34
|
-
jni::alias_ref<JStateWrapper::javaobject>
|
|
34
|
+
jni::alias_ref<JStateWrapper::javaobject> newState,
|
|
35
|
+
jni::alias_ref<JStateWrapper::javaobject> oldState);
|
|
36
|
+
|
|
37
|
+
private:
|
|
38
|
+
static std::shared_ptr<const HybridScrollGuardProps> getPropsFromStateWrapper(
|
|
39
|
+
jni::alias_ref<JStateWrapper::javaobject> stateWrapper);
|
|
35
40
|
|
|
36
41
|
public:
|
|
37
42
|
static void registerNatives() {
|
|
@@ -20,6 +20,14 @@ import com.margelo.nitro.scrollguard.*
|
|
|
20
20
|
* Represents the React Native `ViewManager` for the "ScrollGuard" Nitro HybridView.
|
|
21
21
|
*/
|
|
22
22
|
public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
23
|
+
/**
|
|
24
|
+
* Represents the View and its last state snapshot (mutable)
|
|
25
|
+
*/
|
|
26
|
+
private class HybridViewHolder(
|
|
27
|
+
val hybridView: HybridScrollGuard,
|
|
28
|
+
var lastState: StateWrapper? = null,
|
|
29
|
+
)
|
|
30
|
+
|
|
23
31
|
init {
|
|
24
32
|
if (RecyclableView::class.java.isAssignableFrom(HybridScrollGuard::class.java)) {
|
|
25
33
|
// Enable view recycling
|
|
@@ -34,33 +42,41 @@ public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
|
34
42
|
override fun createViewInstance(reactContext: ThemedReactContext): View {
|
|
35
43
|
val hybridView = HybridScrollGuard(reactContext)
|
|
36
44
|
val view = hybridView.view
|
|
37
|
-
view.setTag(associated_hybrid_view_tag, hybridView)
|
|
45
|
+
view.setTag(associated_hybrid_view_tag, HybridViewHolder(hybridView))
|
|
38
46
|
return view
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? {
|
|
42
|
-
val
|
|
50
|
+
val holder = getHybridViewHolder(view)
|
|
43
51
|
?: throw Error("Couldn't find view $view in local views table!")
|
|
52
|
+
val hybridView = holder.hybridView
|
|
53
|
+
val oldState = holder.lastState
|
|
54
|
+
val newState = stateWrapper
|
|
44
55
|
|
|
45
56
|
// 1. Update each prop individually
|
|
46
57
|
hybridView.beforeUpdate()
|
|
47
|
-
HybridScrollGuardStateUpdater.updateViewProps(hybridView,
|
|
58
|
+
HybridScrollGuardStateUpdater.updateViewProps(hybridView, newState, oldState)
|
|
48
59
|
hybridView.afterUpdate()
|
|
60
|
+
holder.lastState = newState
|
|
49
61
|
|
|
50
62
|
// 2. Continue in base View props
|
|
51
|
-
return super.updateState(view, props,
|
|
63
|
+
return super.updateState(view, props, newState)
|
|
52
64
|
}
|
|
53
65
|
|
|
54
66
|
override fun onDropViewInstance(view: View) {
|
|
55
|
-
val
|
|
56
|
-
|
|
67
|
+
val holder = getHybridViewHolder(view)
|
|
68
|
+
holder?.lastState = null
|
|
69
|
+
holder?.hybridView?.onDropView()
|
|
57
70
|
return super.onDropViewInstance(view)
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
protected override fun prepareToRecycleView(reactContext: ThemedReactContext, view: View): View? {
|
|
61
|
-
super.prepareToRecycleView(reactContext, view)
|
|
62
|
-
|
|
74
|
+
val preparedView = super.prepareToRecycleView(reactContext, view)
|
|
75
|
+
?: return null
|
|
76
|
+
val holder = getHybridViewHolder(preparedView)
|
|
63
77
|
?: return null
|
|
78
|
+
val hybridView = holder.hybridView
|
|
79
|
+
holder.lastState = null
|
|
64
80
|
|
|
65
81
|
@Suppress("USELESS_IS_CHECK")
|
|
66
82
|
if (hybridView is RecyclableView) {
|
|
@@ -74,7 +90,7 @@ public class HybridScrollGuardManager: SimpleViewManager<View>() {
|
|
|
74
90
|
}
|
|
75
91
|
}
|
|
76
92
|
|
|
77
|
-
private fun
|
|
78
|
-
return view.getTag(associated_hybrid_view_tag) as?
|
|
93
|
+
private fun getHybridViewHolder(view: View): HybridViewHolder? {
|
|
94
|
+
return view.getTag(associated_hybrid_view_tag) as? HybridViewHolder
|
|
79
95
|
}
|
|
80
96
|
}
|
|
@@ -14,10 +14,10 @@ internal class HybridScrollGuardStateUpdater {
|
|
|
14
14
|
companion object {
|
|
15
15
|
/**
|
|
16
16
|
* Updates the props for [view] through C++.
|
|
17
|
-
* The [
|
|
17
|
+
* The [newState] prop is expected to contain [view]'s props as wrapped Fabric state.
|
|
18
18
|
*/
|
|
19
19
|
@Suppress("KotlinJniMissingFunction")
|
|
20
20
|
@JvmStatic
|
|
21
|
-
external fun updateViewProps(view: HybridScrollGuardSpec,
|
|
21
|
+
external fun updateViewProps(view: HybridScrollGuardSpec, newState: StateWrapper, oldState: StateWrapper?)
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -37,6 +37,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
37
37
|
|
|
38
38
|
@implementation HybridScrollGuardComponent {
|
|
39
39
|
std::shared_ptr<HybridScrollGuardSpecSwift> _hybridView;
|
|
40
|
+
BOOL _didDropView;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
+ (void) load {
|
|
@@ -50,6 +51,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
50
51
|
|
|
51
52
|
- (instancetype) init {
|
|
52
53
|
if (self = [super init]) {
|
|
54
|
+
_props = HybridScrollGuardShadowNode::defaultSharedProps();
|
|
53
55
|
std::shared_ptr<HybridScrollGuardSpec> hybridView = ScrollGuard::ScrollGuardAutolinking::createScrollGuard();
|
|
54
56
|
_hybridView = std::dynamic_pointer_cast<HybridScrollGuardSpecSwift>(hybridView);
|
|
55
57
|
[self updateView];
|
|
@@ -69,35 +71,55 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
69
71
|
[self setContentView:view];
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
- (void) notifyOnDropView {
|
|
75
|
+
// A recycled component can later be invalidated. Notify only once per mount.
|
|
76
|
+
if (_didDropView) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
80
|
+
swiftPart.onDropView();
|
|
81
|
+
_didDropView = YES;
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
- (void) updateProps:(const std::shared_ptr<const react::Props>&)props
|
|
73
85
|
oldProps:(const std::shared_ptr<const react::Props>&)oldProps {
|
|
86
|
+
// A props update marks a newly mounted or still-active component.
|
|
87
|
+
_didDropView = NO;
|
|
88
|
+
|
|
74
89
|
// 1. Downcast props
|
|
75
|
-
const auto&
|
|
76
|
-
auto
|
|
90
|
+
const auto& newViewProps = *std::static_pointer_cast<const HybridScrollGuardProps>(props);
|
|
91
|
+
const auto* oldViewProps = static_cast<const HybridScrollGuardProps*>(oldProps.get());
|
|
77
92
|
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
78
93
|
|
|
79
|
-
// 2. Update
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
swiftPart.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
// 2. Update only props that differ from the previous Props snapshot.
|
|
95
|
+
const bool hasTransactionPropChanges = oldViewProps == nullptr
|
|
96
|
+
? newViewProps.hasAnyProvidedProps()
|
|
97
|
+
: !newViewProps.hasSameProps(*oldViewProps);
|
|
98
|
+
if (hasTransactionPropChanges) {
|
|
99
|
+
swiftPart.beforeUpdate();
|
|
100
|
+
|
|
101
|
+
// direction: optional
|
|
102
|
+
if (oldViewProps == nullptr
|
|
103
|
+
? newViewProps.direction.isProvided()
|
|
104
|
+
: !newViewProps.direction.hasSameValue(oldViewProps->direction)) {
|
|
105
|
+
swiftPart.setDirection(newViewProps.direction.get());
|
|
106
|
+
}
|
|
89
107
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
maybeFunc.
|
|
108
|
+
// Update hybridRef if it changed
|
|
109
|
+
if (oldViewProps == nullptr
|
|
110
|
+
? newViewProps.hybridRef.isProvided()
|
|
111
|
+
: !newViewProps.hybridRef.hasSameValue(oldViewProps->hybridRef)) {
|
|
112
|
+
// hybridRef changed - call it with new this
|
|
113
|
+
const auto& maybeFunc = newViewProps.hybridRef.get();
|
|
114
|
+
if (maybeFunc.has_value()) {
|
|
115
|
+
maybeFunc.value()(_hybridView);
|
|
116
|
+
}
|
|
96
117
|
}
|
|
97
|
-
|
|
118
|
+
|
|
119
|
+
swiftPart.afterUpdate();
|
|
98
120
|
}
|
|
99
121
|
|
|
100
|
-
//
|
|
122
|
+
// 3. Continue in base class
|
|
101
123
|
[super updateProps:props oldProps:oldProps];
|
|
102
124
|
}
|
|
103
125
|
|
|
@@ -106,6 +128,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
106
128
|
}
|
|
107
129
|
|
|
108
130
|
- (void)prepareForRecycle {
|
|
131
|
+
[self notifyOnDropView];
|
|
109
132
|
[super prepareForRecycle];
|
|
110
133
|
ScrollGuard::HybridScrollGuardSpec_cxx& swiftPart = _hybridView->getSwiftPart();
|
|
111
134
|
swiftPart.maybePrepareForRecycle();
|
|
@@ -113,8 +136,7 @@ using namespace margelo::nitro::scrollguard::views;
|
|
|
113
136
|
|
|
114
137
|
#ifdef ENABLE_RCT_COMPONENT_VIEW_INVALIDATE
|
|
115
138
|
- (void)invalidate {
|
|
116
|
-
|
|
117
|
-
swiftPart.onDropView();
|
|
139
|
+
[self notifyOnDropView];
|
|
118
140
|
[super invalidate];
|
|
119
141
|
}
|
|
120
142
|
#endif
|
|
@@ -7,45 +7,21 @@
|
|
|
7
7
|
|
|
8
8
|
#include "HybridScrollGuardComponent.hpp"
|
|
9
9
|
|
|
10
|
-
#include <
|
|
11
|
-
#include <
|
|
12
|
-
#include <utility>
|
|
13
|
-
#include <NitroModules/NitroDefines.hpp>
|
|
14
|
-
#include <NitroModules/JSIConverter.hpp>
|
|
15
|
-
#include <NitroModules/PropNameIDCache.hpp>
|
|
16
|
-
#include <react/renderer/core/RawValue.h>
|
|
17
|
-
#include <react/renderer/core/ShadowNode.h>
|
|
18
|
-
#include <react/renderer/core/ComponentDescriptor.h>
|
|
19
|
-
#include <react/renderer/components/view/ViewProps.h>
|
|
10
|
+
#include <NitroModules/NitroHash.hpp>
|
|
11
|
+
#include <NitroModules/ReactProp.hpp>
|
|
20
12
|
|
|
21
13
|
namespace margelo::nitro::scrollguard::views {
|
|
22
14
|
|
|
15
|
+
using namespace facebook;
|
|
16
|
+
|
|
23
17
|
extern const char HybridScrollGuardComponentName[] = "ScrollGuard";
|
|
24
18
|
|
|
25
19
|
HybridScrollGuardProps::HybridScrollGuardProps(const react::PropsParserContext& context,
|
|
26
20
|
const HybridScrollGuardProps& sourceProps,
|
|
27
21
|
const react::RawProps& rawProps):
|
|
28
22
|
react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
|
|
29
|
-
direction(
|
|
30
|
-
|
|
31
|
-
const react::RawValue* rawValue = rawProps.at("direction", nullptr, nullptr);
|
|
32
|
-
if (rawValue == nullptr) return sourceProps.direction;
|
|
33
|
-
const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
|
|
34
|
-
return CachedProp<std::optional<ScrollGuardDirection>>::fromRawValue(*runtime, value, sourceProps.direction);
|
|
35
|
-
} catch (const std::exception& exc) {
|
|
36
|
-
throw std::runtime_error(std::string("ScrollGuard.direction: ") + exc.what());
|
|
37
|
-
}
|
|
38
|
-
}()),
|
|
39
|
-
hybridRef([&]() -> CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>> {
|
|
40
|
-
try {
|
|
41
|
-
const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr);
|
|
42
|
-
if (rawValue == nullptr) return sourceProps.hybridRef;
|
|
43
|
-
const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
|
|
44
|
-
return CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.hybridRef);
|
|
45
|
-
} catch (const std::exception& exc) {
|
|
46
|
-
throw std::runtime_error(std::string("ScrollGuard.hybridRef: ") + exc.what());
|
|
47
|
-
}
|
|
48
|
-
}()) { }
|
|
23
|
+
direction(nitro::ReactProp<std::optional<ScrollGuardDirection>>::fromRawValue("ScrollGuard", "direction", rawProps, sourceProps.direction)),
|
|
24
|
+
hybridRef(nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>>::fromRawValue("ScrollGuard", "hybridRef", rawProps, sourceProps.hybridRef)) { }
|
|
49
25
|
|
|
50
26
|
bool HybridScrollGuardProps::filterObjectKeys(const std::string& propName) {
|
|
51
27
|
switch (hashString(propName)) {
|
|
@@ -55,29 +31,4 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
55
31
|
}
|
|
56
32
|
}
|
|
57
33
|
|
|
58
|
-
HybridScrollGuardComponentDescriptor::HybridScrollGuardComponentDescriptor(const react::ComponentDescriptorParameters& parameters)
|
|
59
|
-
: ConcreteComponentDescriptor(parameters,
|
|
60
|
-
react::RawPropsParser()) {}
|
|
61
|
-
|
|
62
|
-
std::shared_ptr<const react::Props> HybridScrollGuardComponentDescriptor::cloneProps(const react::PropsParserContext& context,
|
|
63
|
-
const std::shared_ptr<const react::Props>& props,
|
|
64
|
-
react::RawProps rawProps) const {
|
|
65
|
-
// 1. Prepare raw props parser
|
|
66
|
-
rawProps.parse(rawPropsParser_);
|
|
67
|
-
// 2. Copy props with Nitro's cached copy constructor
|
|
68
|
-
return HybridScrollGuardShadowNode::Props(context, /* & */ rawProps, props);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
#ifdef ANDROID
|
|
72
|
-
void HybridScrollGuardComponentDescriptor::adopt(react::ShadowNode& shadowNode) const {
|
|
73
|
-
// This is called immediately after `ShadowNode` is created, cloned or in progress.
|
|
74
|
-
// On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++.
|
|
75
|
-
auto& concreteShadowNode = static_cast<HybridScrollGuardShadowNode&>(shadowNode);
|
|
76
|
-
const std::shared_ptr<const HybridScrollGuardProps>& constProps = concreteShadowNode.getConcreteSharedProps();
|
|
77
|
-
const std::shared_ptr<HybridScrollGuardProps>& props = std::const_pointer_cast<HybridScrollGuardProps>(constProps);
|
|
78
|
-
HybridScrollGuardState state{props};
|
|
79
|
-
concreteShadowNode.setStateData(std::move(state));
|
|
80
|
-
}
|
|
81
|
-
#endif
|
|
82
|
-
|
|
83
34
|
} // namespace margelo::nitro::scrollguard::views
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
-
#include <
|
|
11
|
-
#include <NitroModules/
|
|
12
|
-
#include <NitroModules/
|
|
13
|
-
#include <NitroModules/CachedProp.hpp>
|
|
14
|
-
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
15
|
-
#include <react/renderer/core/PropsParserContext.h>
|
|
10
|
+
#include <NitroModules/ReactProp.hpp>
|
|
11
|
+
#include <NitroModules/ViewComponentDescriptor.hpp>
|
|
12
|
+
#include <NitroModules/ViewPropsHolderState.hpp>
|
|
16
13
|
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
17
14
|
#include <react/renderer/components/view/ViewProps.h>
|
|
15
|
+
#include <react/renderer/core/PropsParserContext.h>
|
|
16
|
+
#include <react/renderer/core/RawProps.h>
|
|
17
|
+
|
|
18
|
+
#include <string>
|
|
18
19
|
|
|
19
20
|
#include "ScrollGuardDirection.hpp"
|
|
20
21
|
#include <optional>
|
|
@@ -42,8 +43,20 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
42
43
|
const react::RawProps& rawProps);
|
|
43
44
|
|
|
44
45
|
public:
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
nitro::ReactProp<std::optional<ScrollGuardDirection>> direction;
|
|
47
|
+
nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridScrollGuardSpec>& /* ref */)>>> hybridRef;
|
|
48
|
+
|
|
49
|
+
[[nodiscard]]
|
|
50
|
+
bool hasSameProps(const HybridScrollGuardProps& other) const noexcept {
|
|
51
|
+
return direction.hasSameValue(other.direction) &&
|
|
52
|
+
hybridRef.hasSameValue(other.hybridRef);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[[nodiscard]]
|
|
56
|
+
bool hasAnyProvidedProps() const noexcept {
|
|
57
|
+
return direction.isProvided() ||
|
|
58
|
+
hybridRef.isProvided();
|
|
59
|
+
}
|
|
47
60
|
|
|
48
61
|
private:
|
|
49
62
|
static bool filterObjectKeys(const std::string& propName);
|
|
@@ -52,32 +65,7 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
52
65
|
/**
|
|
53
66
|
* State for the "ScrollGuard" View.
|
|
54
67
|
*/
|
|
55
|
-
|
|
56
|
-
public:
|
|
57
|
-
HybridScrollGuardState() = default;
|
|
58
|
-
explicit HybridScrollGuardState(const std::shared_ptr<HybridScrollGuardProps>& props):
|
|
59
|
-
_props(props) {}
|
|
60
|
-
|
|
61
|
-
public:
|
|
62
|
-
[[nodiscard]]
|
|
63
|
-
const std::shared_ptr<HybridScrollGuardProps>& getProps() const {
|
|
64
|
-
return _props;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public:
|
|
68
|
-
#ifdef ANDROID
|
|
69
|
-
HybridScrollGuardState(const HybridScrollGuardState& /* previousState */, folly::dynamic /* data */) {}
|
|
70
|
-
folly::dynamic getDynamic() const {
|
|
71
|
-
throw std::runtime_error("HybridScrollGuardState does not support folly!");
|
|
72
|
-
}
|
|
73
|
-
react::MapBuffer getMapBuffer() const {
|
|
74
|
-
throw std::runtime_error("HybridScrollGuardState does not support MapBuffer!");
|
|
75
|
-
};
|
|
76
|
-
#endif
|
|
77
|
-
|
|
78
|
-
private:
|
|
79
|
-
std::shared_ptr<HybridScrollGuardProps> _props;
|
|
80
|
-
};
|
|
68
|
+
using HybridScrollGuardState = nitro::ViewPropsHolderState<HybridScrollGuardProps>;
|
|
81
69
|
|
|
82
70
|
/**
|
|
83
71
|
* The Shadow Node for the "ScrollGuard" View.
|
|
@@ -90,21 +78,7 @@ namespace margelo::nitro::scrollguard::views {
|
|
|
90
78
|
/**
|
|
91
79
|
* The Component Descriptor for the "ScrollGuard" View.
|
|
92
80
|
*/
|
|
93
|
-
|
|
94
|
-
public:
|
|
95
|
-
explicit HybridScrollGuardComponentDescriptor(const react::ComponentDescriptorParameters& parameters);
|
|
96
|
-
|
|
97
|
-
public:
|
|
98
|
-
/**
|
|
99
|
-
* A faster path for cloning props - reuses the caching logic from `HybridScrollGuardProps`.
|
|
100
|
-
*/
|
|
101
|
-
std::shared_ptr<const react::Props> cloneProps(const react::PropsParserContext& context,
|
|
102
|
-
const std::shared_ptr<const react::Props>& props,
|
|
103
|
-
react::RawProps rawProps) const override;
|
|
104
|
-
#ifdef ANDROID
|
|
105
|
-
void adopt(react::ShadowNode& shadowNode) const override;
|
|
106
|
-
#endif
|
|
107
|
-
};
|
|
81
|
+
using HybridScrollGuardComponentDescriptor = nitro::ViewComponentDescriptor<HybridScrollGuardShadowNode>;
|
|
108
82
|
|
|
109
83
|
/* The actual view for "ScrollGuard" needs to be implemented in platform-specific code. */
|
|
110
84
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-scroll-guard",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.98",
|
|
4
4
|
"description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -62,17 +62,17 @@
|
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@react-native/babel-preset": "0.86.2",
|
|
64
64
|
"del-cli": "^6.0.0",
|
|
65
|
-
"nitrogen": "0.
|
|
65
|
+
"nitrogen": "0.37.0",
|
|
66
66
|
"react": "19.2.3",
|
|
67
67
|
"react-native": "patch:react-native@npm%3A0.86.2#~/.yarn/patches/react-native-npm-0.86.2-c9d546616f.patch",
|
|
68
68
|
"react-native-builder-bob": "^0.40.13",
|
|
69
|
-
"react-native-nitro-modules": "0.
|
|
69
|
+
"react-native-nitro-modules": "0.37.0",
|
|
70
70
|
"typescript": "^5.9.2"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"react": "*",
|
|
74
74
|
"react-native": "*",
|
|
75
|
-
"react-native-nitro-modules": "0.
|
|
75
|
+
"react-native-nitro-modules": "0.37.0"
|
|
76
76
|
},
|
|
77
77
|
"packageManager": "yarn@4.11.0",
|
|
78
78
|
"react-native-builder-bob": {
|