Skip to content

Commit 029fd40

Browse files
New architecture support (#550)
* Enable new arch & make newer libs compile under 0.72 * Setup codegen * Update podspec * Setup ios code * Fix AutoLayout subviews and footer * Implement `onBlankAreaEvent` on iOS * Update comments * Implement Android * Mound children under AutoLayoutView * Update changelog * Improve event handling * Remove context extension * Disable new arch by default * Update `podfile.lock` * update podfile --------- Co-authored-by: Talha Naqvi <[email protected]>
1 parent 43c7eec commit 029fd40

30 files changed

+957
-91
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
1111
- https://github.com/Shopify/flash-list/pull/1076
1212
- Fix stale reference to onScroll and onLoad
1313
- https://github.com/Shopify/flash-list/pull/1112
14+
- New architecture support
15+
- https://github.com/Shopify/flash-list/pull/550
1416
- Upgrade recyclerlistview to v4.2.1
1517
- https://github.com/Shopify/flash-list/pull/1236
1618

RNFlashList.podspec

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'json'
22

33
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4+
new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED']
45

56
Pod::Spec.new do |s|
67
s.name = 'RNFlashList'
@@ -15,8 +16,18 @@ Pod::Spec.new do |s|
1516
s.requires_arc = true
1617
s.swift_version = '5.0'
1718

18-
# Dependencies
19-
s.dependency 'React-Core'
19+
if new_arch_enabled
20+
s.pod_target_xcconfig = {
21+
'OTHER_SWIFT_FLAGS' => '-D RCT_NEW_ARCH_ENABLED',
22+
}
23+
end
24+
25+
# install_modules_dependencies is available since RN 0.71
26+
if respond_to?(:install_modules_dependencies, true)
27+
install_modules_dependencies(s)
28+
else
29+
s.dependency "React-Core"
30+
end
2031

2132
# Tests spec
2233
s.test_spec 'Tests' do |test_spec|

android/build.gradle

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
def isNewArchitectureEnabled() {
2+
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
3+
}
4+
15
apply plugin: 'com.android.library'
26

37
apply plugin: 'kotlin-android'
48

9+
if (isNewArchitectureEnabled()) {
10+
apply plugin: 'com.facebook.react'
11+
}
12+
513
def _ext = rootProject.ext
614

715
def _reactNativeVersion = _ext.has('reactNative') ? _ext.reactNative : '+'
@@ -40,11 +48,16 @@ android {
4048
debug.java.srcDirs += 'src/debug/kotlin'
4149
test.java.srcDirs += 'src/test/kotlin'
4250
androidTest.java.srcDirs += 'src/androidTest/kotlin'
51+
52+
if (!isNewArchitectureEnabled()) {
53+
main.java.srcDirs += ['src/paper/java']
54+
}
4355
}
4456

4557
defaultConfig {
4658
minSdkVersion _minSdkVersion
4759
targetSdkVersion _targetSdkVersion
60+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
4861
versionCode 1
4962
versionName "1.0"
5063
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import android.widget.ScrollView
1111
import com.facebook.react.bridge.Arguments
1212
import com.facebook.react.bridge.ReactContext
1313
import com.facebook.react.bridge.WritableMap
14+
import com.facebook.react.uimanager.UIManagerHelper
15+
import com.facebook.react.uimanager.events.EventDispatcher
1416
import com.facebook.react.uimanager.events.RCTEventEmitter
1517
import com.facebook.react.views.view.ReactViewGroup
1618

@@ -137,14 +139,20 @@ class AutoLayoutView(context: Context) : ReactViewGroup(context) {
137139
}
138140

139141

140-
/** TODO: Check migration to Fabric */
141142
private fun emitBlankAreaEvent() {
142-
val event: WritableMap = Arguments.createMap()
143-
event.putDouble("offsetStart", alShadow.blankOffsetAtStart / pixelDensity)
144-
event.putDouble("offsetEnd", alShadow.blankOffsetAtEnd / pixelDensity)
145-
val reactContext = context as ReactContext
146-
reactContext
147-
.getJSModule(RCTEventEmitter::class.java)
148-
.receiveEvent(id, "onBlankAreaEvent", event)
143+
val eventDispatcher: EventDispatcher? =
144+
UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id)
145+
146+
if (eventDispatcher != null) {
147+
val surfaceId = UIManagerHelper.getSurfaceId(context as ReactContext)
148+
eventDispatcher.dispatchEvent(
149+
BlankAreaEvent(
150+
surfaceId,
151+
viewTag = id,
152+
offsetStart = alShadow.blankOffsetAtStart / pixelDensity,
153+
offsetEnd = alShadow.blankOffsetAtEnd / pixelDensity
154+
)
155+
)
156+
}
149157
}
150158
}

android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutViewManager.kt

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ package com.shopify.reactnative.flash_list
33
import com.facebook.react.module.annotations.ReactModule
44
import com.facebook.react.uimanager.ThemedReactContext
55
import com.facebook.react.uimanager.annotations.ReactProp
6-
import com.facebook.react.views.view.ReactViewGroup
7-
import com.facebook.react.views.view.ReactViewManager
8-
import com.facebook.react.common.MapBuilder
6+
import com.facebook.react.uimanager.ViewGroupManager
7+
import com.facebook.react.uimanager.ViewManagerDelegate
8+
import com.facebook.react.viewmanagers.AutoLayoutViewManagerDelegate
9+
import com.facebook.react.viewmanagers.AutoLayoutViewManagerInterface
910
import kotlin.math.roundToInt
1011

1112
/** ViewManager for AutoLayoutView - Container for all RecyclerListView children. Automatically removes all gaps and overlaps for GridLayouts with flexible spans.
1213
* Note: This cannot work for masonry layouts i.e, pinterest like layout */
1314
@ReactModule(name = AutoLayoutViewManager.REACT_CLASS)
14-
class AutoLayoutViewManager: ReactViewManager() {
15+
class AutoLayoutViewManager: ViewGroupManager<AutoLayoutView>(), AutoLayoutViewManagerInterface<AutoLayoutView> {
16+
private val mDelegate: AutoLayoutViewManagerDelegate<AutoLayoutView, AutoLayoutViewManager> =
17+
AutoLayoutViewManagerDelegate(this)
1518

1619
companion object {
1720
const val REACT_CLASS = "AutoLayoutView"
@@ -21,45 +24,43 @@ class AutoLayoutViewManager: ReactViewManager() {
2124
return REACT_CLASS
2225
}
2326

24-
override fun createViewInstance(context: ThemedReactContext): ReactViewGroup {
27+
override fun getDelegate(): ViewManagerDelegate<AutoLayoutView> = mDelegate
28+
29+
override fun createViewInstance(context: ThemedReactContext): AutoLayoutView {
2530
return AutoLayoutView(context).also { it.pixelDensity = context.resources.displayMetrics.density.toDouble() }
2631
}
2732

28-
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
29-
return MapBuilder.builder<String, Any>().put(
30-
"onBlankAreaEvent",
31-
MapBuilder.of(
32-
"registrationName", "onBlankAreaEvent")
33-
).build();
34-
}
33+
override fun getExportedCustomDirectEventTypeConstants() = mutableMapOf(
34+
"onBlankAreaEvent" to mutableMapOf("registrationName" to "onBlankAreaEvent"),
35+
)
3536

3637
@ReactProp(name = "horizontal")
37-
fun setHorizontal(view: AutoLayoutView, isHorizontal: Boolean) {
38+
override fun setHorizontal(view: AutoLayoutView, isHorizontal: Boolean) {
3839
view.alShadow.horizontal = isHorizontal
3940
}
4041

4142
@ReactProp(name = "disableAutoLayout")
42-
fun setDisableAutoLayout(view: AutoLayoutView, disableAutoLayout: Boolean) {
43+
override fun setDisableAutoLayout(view: AutoLayoutView, disableAutoLayout: Boolean) {
4344
view.disableAutoLayout = disableAutoLayout
4445
}
4546

4647
@ReactProp(name = "scrollOffset")
47-
fun setScrollOffset(view: AutoLayoutView, scrollOffset: Double) {
48+
override fun setScrollOffset(view: AutoLayoutView, scrollOffset: Double) {
4849
view.alShadow.scrollOffset = convertToPixelLayout(scrollOffset, view.pixelDensity)
4950
}
5051

5152
@ReactProp(name = "windowSize")
52-
fun setWindowSize(view: AutoLayoutView, windowSize: Double) {
53+
override fun setWindowSize(view: AutoLayoutView, windowSize: Double) {
5354
view.alShadow.windowSize = convertToPixelLayout(windowSize, view.pixelDensity)
5455
}
5556

5657
@ReactProp(name = "renderAheadOffset")
57-
fun setRenderAheadOffset(view: AutoLayoutView, renderOffset: Double) {
58+
override fun setRenderAheadOffset(view: AutoLayoutView, renderOffset: Double) {
5859
view.alShadow.renderOffset = convertToPixelLayout(renderOffset, view.pixelDensity)
5960
}
6061

6162
@ReactProp(name = "enableInstrumentation")
62-
fun setEnableInstrumentation(view: AutoLayoutView, enableInstrumentation: Boolean) {
63+
override fun setEnableInstrumentation(view: AutoLayoutView, enableInstrumentation: Boolean) {
6364
view.enableInstrumentation = enableInstrumentation
6465
}
6566

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@file:Suppress("DEPRECATION") // We want to use RCTEventEmitter for interop purposes
2+
package com.shopify.reactnative.flash_list
3+
4+
import com.facebook.react.bridge.Arguments
5+
import com.facebook.react.bridge.WritableMap
6+
import com.facebook.react.uimanager.events.Event
7+
import com.facebook.react.uimanager.events.RCTEventEmitter
8+
9+
class BlankAreaEvent(
10+
surfaceId: Int,
11+
viewTag: Int,
12+
private val offsetStart: Double,
13+
private val offsetEnd: Double
14+
): Event<BlankAreaEvent>(surfaceId, viewTag) {
15+
override fun getEventName() = EVENT_NAME
16+
17+
override fun getEventData(): WritableMap = Arguments.createMap().apply {
18+
putDouble("offsetStart", offsetStart)
19+
putDouble("offsetEnd", offsetEnd)
20+
}
21+
22+
override fun dispatch(rctEventEmitter: RCTEventEmitter) {
23+
rctEventEmitter.receiveEvent(viewTag, eventName, eventData)
24+
}
25+
26+
companion object {
27+
const val EVENT_NAME: String = "onBlankAreaEvent"
28+
}
29+
}

android/src/main/kotlin/com/shopify/reactnative/flash_list/CellContainerManager.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ package com.shopify.reactnative.flash_list
22

33
import com.facebook.react.module.annotations.ReactModule
44
import com.facebook.react.uimanager.ThemedReactContext
5+
import com.facebook.react.uimanager.ViewGroupManager
6+
import com.facebook.react.uimanager.ViewManagerDelegate
57
import com.facebook.react.uimanager.annotations.ReactProp
6-
import com.facebook.react.views.view.ReactViewGroup
7-
import com.facebook.react.views.view.ReactViewManager
8+
import com.facebook.react.viewmanagers.CellContainerManagerDelegate
9+
import com.facebook.react.viewmanagers.CellContainerManagerInterface
810

911
@ReactModule(name = AutoLayoutViewManager.REACT_CLASS)
10-
class CellContainerManager: ReactViewManager() {
12+
class CellContainerManager: ViewGroupManager<CellContainerImpl>(), CellContainerManagerInterface<CellContainerImpl> {
13+
private val mDelegate: CellContainerManagerDelegate<CellContainerImpl, CellContainerManager>
14+
= CellContainerManagerDelegate(this)
15+
1116
companion object {
1217
const val REACT_CLASS = "CellContainer"
1318
}
@@ -16,12 +21,14 @@ class CellContainerManager: ReactViewManager() {
1621
return REACT_CLASS
1722
}
1823

19-
override fun createViewInstance(context: ThemedReactContext): ReactViewGroup {
24+
override fun getDelegate(): ViewManagerDelegate<CellContainerImpl> = mDelegate
25+
26+
override fun createViewInstance(context: ThemedReactContext): CellContainerImpl {
2027
return CellContainerImpl(context)
2128
}
2229

2330
@ReactProp(name = "index")
24-
fun setIndex(view: CellContainerImpl, index: Int) {
31+
override fun setIndex(view: CellContainerImpl, index: Int) {
2532
view.index = index
2633
}
2734
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3+
*
4+
* Do not edit this file as changes may cause incorrect behavior and will be lost
5+
* once the code is regenerated.
6+
*
7+
* @generated by codegen project: GeneratePropsJavaDelegate.js
8+
*/
9+
10+
package com.facebook.react.viewmanagers;
11+
12+
import android.view.View;
13+
import androidx.annotation.Nullable;
14+
import com.facebook.react.uimanager.BaseViewManagerDelegate;
15+
import com.facebook.react.uimanager.BaseViewManagerInterface;
16+
17+
public class AutoLayoutViewManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & AutoLayoutViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
18+
public AutoLayoutViewManagerDelegate(U viewManager) {
19+
super(viewManager);
20+
}
21+
@Override
22+
public void setProperty(T view, String propName, @Nullable Object value) {
23+
switch (propName) {
24+
case "horizontal":
25+
mViewManager.setHorizontal(view, value == null ? false : (boolean) value);
26+
break;
27+
case "scrollOffset":
28+
mViewManager.setScrollOffset(view, value == null ? 0f : ((Double) value).doubleValue());
29+
break;
30+
case "windowSize":
31+
mViewManager.setWindowSize(view, value == null ? 0f : ((Double) value).doubleValue());
32+
break;
33+
case "renderAheadOffset":
34+
mViewManager.setRenderAheadOffset(view, value == null ? 0f : ((Double) value).doubleValue());
35+
break;
36+
case "enableInstrumentation":
37+
mViewManager.setEnableInstrumentation(view, value == null ? false : (boolean) value);
38+
break;
39+
case "disableAutoLayout":
40+
mViewManager.setDisableAutoLayout(view, value == null ? false : (boolean) value);
41+
break;
42+
default:
43+
super.setProperty(view, propName, value);
44+
}
45+
}
46+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3+
*
4+
* Do not edit this file as changes may cause incorrect behavior and will be lost
5+
* once the code is regenerated.
6+
*
7+
* @generated by codegen project: GeneratePropsJavaInterface.js
8+
*/
9+
10+
package com.facebook.react.viewmanagers;
11+
12+
import android.view.View;
13+
14+
public interface AutoLayoutViewManagerInterface<T extends View> {
15+
void setHorizontal(T view, boolean value);
16+
void setScrollOffset(T view, double value);
17+
void setWindowSize(T view, double value);
18+
void setRenderAheadOffset(T view, double value);
19+
void setEnableInstrumentation(T view, boolean value);
20+
void setDisableAutoLayout(T view, boolean value);
21+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3+
*
4+
* Do not edit this file as changes may cause incorrect behavior and will be lost
5+
* once the code is regenerated.
6+
*
7+
* @generated by codegen project: GeneratePropsJavaDelegate.js
8+
*/
9+
10+
package com.facebook.react.viewmanagers;
11+
12+
import android.view.View;
13+
import androidx.annotation.Nullable;
14+
import com.facebook.react.uimanager.BaseViewManagerDelegate;
15+
import com.facebook.react.uimanager.BaseViewManagerInterface;
16+
17+
public class CellContainerManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & CellContainerManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
18+
public CellContainerManagerDelegate(U viewManager) {
19+
super(viewManager);
20+
}
21+
@Override
22+
public void setProperty(T view, String propName, @Nullable Object value) {
23+
switch (propName) {
24+
case "index":
25+
mViewManager.setIndex(view, value == null ? 0 : ((Double) value).intValue());
26+
break;
27+
default:
28+
super.setProperty(view, propName, value);
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)