Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New architecture support #550

Merged
merged 16 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
- https://github.com/Shopify/flash-list/pull/1076
- Fix stale reference to onScroll and onLoad
- https://github.com/Shopify/flash-list/pull/1112
- New architecture support
- https://github.com/Shopify/flash-list/pull/550
- Upgrade recyclerlistview to v4.2.1
- https://github.com/Shopify/flash-list/pull/1236

Expand Down
15 changes: 13 additions & 2 deletions RNFlashList.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'json'

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

Pod::Spec.new do |s|
s.name = 'RNFlashList'
Expand All @@ -15,8 +16,18 @@ Pod::Spec.new do |s|
s.requires_arc = true
s.swift_version = '5.0'

# Dependencies
s.dependency 'React-Core'
if new_arch_enabled
s.pod_target_xcconfig = {
'OTHER_SWIFT_FLAGS' => '-D RCT_NEW_ARCH_ENABLED',
}
end

# install_modules_dependencies is available since RN 0.71
if respond_to?(:install_modules_dependencies, true)
install_modules_dependencies(s)
else
s.dependency "React-Core"
end

# Tests spec
s.test_spec 'Tests' do |test_spec|
Expand Down
13 changes: 13 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
def isNewArchitectureEnabled() {
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

apply plugin: 'com.android.library'

apply plugin: 'kotlin-android'

if (isNewArchitectureEnabled()) {
apply plugin: 'com.facebook.react'
}

def _ext = rootProject.ext

def _reactNativeVersion = _ext.has('reactNative') ? _ext.reactNative : '+'
Expand Down Expand Up @@ -40,11 +48,16 @@ android {
debug.java.srcDirs += 'src/debug/kotlin'
test.java.srcDirs += 'src/test/kotlin'
androidTest.java.srcDirs += 'src/androidTest/kotlin'

if (!isNewArchitectureEnabled()) {
main.java.srcDirs += ['src/paper/java']
}
}

defaultConfig {
minSdkVersion _minSdkVersion
targetSdkVersion _targetSdkVersion
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
versionCode 1
versionName "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import android.widget.ScrollView
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.facebook.react.views.view.ReactViewGroup

Expand Down Expand Up @@ -137,14 +139,20 @@ class AutoLayoutView(context: Context) : ReactViewGroup(context) {
}


/** TODO: Check migration to Fabric */
private fun emitBlankAreaEvent() {
val event: WritableMap = Arguments.createMap()
event.putDouble("offsetStart", alShadow.blankOffsetAtStart / pixelDensity)
event.putDouble("offsetEnd", alShadow.blankOffsetAtEnd / pixelDensity)
val reactContext = context as ReactContext
reactContext
.getJSModule(RCTEventEmitter::class.java)
.receiveEvent(id, "onBlankAreaEvent", event)
val eventDispatcher: EventDispatcher? =
UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id)

if (eventDispatcher != null) {
val surfaceId = UIManagerHelper.getSurfaceId(context as ReactContext)
eventDispatcher.dispatchEvent(
BlankAreaEvent(
surfaceId,
viewTag = id,
offsetStart = alShadow.blankOffsetAtStart / pixelDensity,
offsetEnd = alShadow.blankOffsetAtEnd / pixelDensity
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ package com.shopify.reactnative.flash_list
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.views.view.ReactViewGroup
import com.facebook.react.views.view.ReactViewManager
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.viewmanagers.AutoLayoutViewManagerDelegate
import com.facebook.react.viewmanagers.AutoLayoutViewManagerInterface
import kotlin.math.roundToInt

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

companion object {
const val REACT_CLASS = "AutoLayoutView"
Expand All @@ -21,45 +24,43 @@ class AutoLayoutViewManager: ReactViewManager() {
return REACT_CLASS
}

override fun createViewInstance(context: ThemedReactContext): ReactViewGroup {
override fun getDelegate(): ViewManagerDelegate<AutoLayoutView> = mDelegate

override fun createViewInstance(context: ThemedReactContext): AutoLayoutView {
return AutoLayoutView(context).also { it.pixelDensity = context.resources.displayMetrics.density.toDouble() }
}

override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
return MapBuilder.builder<String, Any>().put(
"onBlankAreaEvent",
MapBuilder.of(
"registrationName", "onBlankAreaEvent")
).build();
}
override fun getExportedCustomDirectEventTypeConstants() = mutableMapOf(
"onBlankAreaEvent" to mutableMapOf("registrationName" to "onBlankAreaEvent"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need here both onBlankAreaEvent and topOnBlankAreaEvent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I don't remember 😅. It's been a while since I've written this, but it doesn't seem to be causing any issues when I removed topOnBlankAreaEvent.

)

@ReactProp(name = "horizontal")
fun setHorizontal(view: AutoLayoutView, isHorizontal: Boolean) {
override fun setHorizontal(view: AutoLayoutView, isHorizontal: Boolean) {
view.alShadow.horizontal = isHorizontal
}

@ReactProp(name = "disableAutoLayout")
fun setDisableAutoLayout(view: AutoLayoutView, disableAutoLayout: Boolean) {
override fun setDisableAutoLayout(view: AutoLayoutView, disableAutoLayout: Boolean) {
view.disableAutoLayout = disableAutoLayout
}

@ReactProp(name = "scrollOffset")
fun setScrollOffset(view: AutoLayoutView, scrollOffset: Double) {
override fun setScrollOffset(view: AutoLayoutView, scrollOffset: Double) {
view.alShadow.scrollOffset = convertToPixelLayout(scrollOffset, view.pixelDensity)
}

@ReactProp(name = "windowSize")
fun setWindowSize(view: AutoLayoutView, windowSize: Double) {
override fun setWindowSize(view: AutoLayoutView, windowSize: Double) {
view.alShadow.windowSize = convertToPixelLayout(windowSize, view.pixelDensity)
}

@ReactProp(name = "renderAheadOffset")
fun setRenderAheadOffset(view: AutoLayoutView, renderOffset: Double) {
override fun setRenderAheadOffset(view: AutoLayoutView, renderOffset: Double) {
view.alShadow.renderOffset = convertToPixelLayout(renderOffset, view.pixelDensity)
}

@ReactProp(name = "enableInstrumentation")
fun setEnableInstrumentation(view: AutoLayoutView, enableInstrumentation: Boolean) {
override fun setEnableInstrumentation(view: AutoLayoutView, enableInstrumentation: Boolean) {
view.enableInstrumentation = enableInstrumentation
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@file:Suppress("DEPRECATION") // We want to use RCTEventEmitter for interop purposes
package com.shopify.reactnative.flash_list

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.Event
import com.facebook.react.uimanager.events.RCTEventEmitter

class BlankAreaEvent(
surfaceId: Int,
viewTag: Int,
private val offsetStart: Double,
private val offsetEnd: Double
): Event<BlankAreaEvent>(surfaceId, viewTag) {
override fun getEventName() = EVENT_NAME

override fun getEventData(): WritableMap = Arguments.createMap().apply {
putDouble("offsetStart", offsetStart)
putDouble("offsetEnd", offsetEnd)
}

override fun dispatch(rctEventEmitter: RCTEventEmitter) {
rctEventEmitter.receiveEvent(viewTag, eventName, eventData)
}

companion object {
const val EVENT_NAME: String = "onBlankAreaEvent"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package com.shopify.reactnative.flash_list

import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.views.view.ReactViewGroup
import com.facebook.react.views.view.ReactViewManager
import com.facebook.react.viewmanagers.CellContainerManagerDelegate
import com.facebook.react.viewmanagers.CellContainerManagerInterface

@ReactModule(name = AutoLayoutViewManager.REACT_CLASS)
class CellContainerManager: ReactViewManager() {
class CellContainerManager: ViewGroupManager<CellContainerImpl>(), CellContainerManagerInterface<CellContainerImpl> {
private val mDelegate: CellContainerManagerDelegate<CellContainerImpl, CellContainerManager>
= CellContainerManagerDelegate(this)

companion object {
const val REACT_CLASS = "CellContainer"
}
Expand All @@ -16,12 +21,14 @@ class CellContainerManager: ReactViewManager() {
return REACT_CLASS
}

override fun createViewInstance(context: ThemedReactContext): ReactViewGroup {
override fun getDelegate(): ViewManagerDelegate<CellContainerImpl> = mDelegate

override fun createViewInstance(context: ThemedReactContext): CellContainerImpl {
return CellContainerImpl(context)
}

@ReactProp(name = "index")
fun setIndex(view: CellContainerImpl, index: Int) {
override fun setIndex(view: CellContainerImpl, index: Int) {
view.index = index
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the generator always creating code for paper as well? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not. I copied those files without modifying them. Do you think those comments should be removed?

*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;

public class AutoLayoutViewManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & AutoLayoutViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public AutoLayoutViewManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "horizontal":
mViewManager.setHorizontal(view, value == null ? false : (boolean) value);
break;
case "scrollOffset":
mViewManager.setScrollOffset(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "windowSize":
mViewManager.setWindowSize(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "renderAheadOffset":
mViewManager.setRenderAheadOffset(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "enableInstrumentation":
mViewManager.setEnableInstrumentation(view, value == null ? false : (boolean) value);
break;
case "disableAutoLayout":
mViewManager.setDisableAutoLayout(view, value == null ? false : (boolean) value);
break;
default:
super.setProperty(view, propName, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;

public interface AutoLayoutViewManagerInterface<T extends View> {
void setHorizontal(T view, boolean value);
void setScrollOffset(T view, double value);
void setWindowSize(T view, double value);
void setRenderAheadOffset(T view, double value);
void setEnableInstrumentation(T view, boolean value);
void setDisableAutoLayout(T view, boolean value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;

public class CellContainerManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & CellContainerManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public CellContainerManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "index":
mViewManager.setIndex(view, value == null ? 0 : ((Double) value).intValue());
break;
default:
super.setProperty(view, propName, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;

public interface CellContainerManagerInterface<T extends View> {
void setIndex(T view, int value);
}
Loading
Loading