mirror of
https://github.com/status-im/react-native.git
synced 2025-01-17 21:11:45 +00:00
575f7d478d
Summary: This diff implements the HorizontalScrollView component for Android Fabric C++, as part of this diff I also re-named the components AndroidHorizontalScrollContentView for RCTAndroidHorizontalScrollContentView and AndroidHorizontalScrollView for RCTAndroidHorizontalScrollView. This might sound against our plan of removing the RCT preffix, but it is to make it simpler to map components between current implementation of RN and Fabric (otherwise we don't know when to add the RCT preffix in Android side to find the right View Manager), later we can just remove the preffix from C++, Android, iOS and JS. Reviewed By: shergin, achen1 Differential Revision: D9122729 fbshipit-source-id: e9299552857c6dd0c18abfa5fa49a3d50e221729
264 lines
10 KiB
C++
264 lines
10 KiB
C++
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "FabricUIManager.h"
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <fabric/components/view/ViewComponentDescriptor.h>
|
|
#include <fabric/components/view/ViewProps.h>
|
|
#include <fabric/components/view/ViewShadowNode.h>
|
|
#include <fabric/core/componentDescriptor.h>
|
|
#include <fabric/core/LayoutContext.h>
|
|
#include <fabric/core/ShadowNodeFragment.h>
|
|
#include <fabric/debug/DebugStringConvertible.h>
|
|
#include <fabric/debug/DebugStringConvertibleItem.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
// TODO: Kill this flag and remove debug logging.
|
|
const bool isLoggingEnabled = false;
|
|
|
|
static const RawProps rawPropsFromDynamic(const folly::dynamic object) {
|
|
// TODO: Convert this to something smarter, probably returning `std::iterator`.
|
|
RawProps result;
|
|
|
|
if (object.isNull()) {
|
|
return result;
|
|
}
|
|
|
|
assert(object.isObject());
|
|
|
|
for (const auto &pair : object.items()) {
|
|
assert(pair.first.isString());
|
|
result[pair.first.asString()] = pair.second;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static const std::string componentNameByReactViewName(std::string viewName) {
|
|
// We need this function only for the transition period;
|
|
// eventually, all names will be unified.
|
|
|
|
std::string rctPrefix("RCT");
|
|
if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin()).first == rctPrefix.end()) {
|
|
// If `viewName` has "RCT" prefix, remove it.
|
|
viewName.erase(0, rctPrefix.length());
|
|
}
|
|
|
|
// Fabric uses slightly new names for Text components because of differences
|
|
// in semantic.
|
|
if (viewName == "Text") {
|
|
return "Paragraph";
|
|
}
|
|
if (viewName == "VirtualText") {
|
|
return "Text";
|
|
}
|
|
|
|
if (viewName == "ImageView") {
|
|
return "Image";
|
|
}
|
|
|
|
if (viewName == "AndroidHorizontalScrollView") {
|
|
return "ScrollView";
|
|
}
|
|
|
|
// We need this temporarly for testing purposes until we have proper
|
|
// implementation of core components.
|
|
if (
|
|
viewName == "SinglelineTextInputView" ||
|
|
viewName == "MultilineTextInputView" ||
|
|
viewName == "RefreshControl" ||
|
|
viewName == "SafeAreaView" ||
|
|
viewName == "ScrollContentView" ||
|
|
viewName == "AndroidHorizontalScrollContentView" // Android
|
|
) {
|
|
return "View";
|
|
}
|
|
|
|
return viewName;
|
|
}
|
|
|
|
FabricUIManager::~FabricUIManager() {
|
|
if (eventHandler_) {
|
|
releaseEventHandlerFunction_(eventHandler_);
|
|
}
|
|
}
|
|
|
|
void FabricUIManager::setComponentDescriptorRegistry(const SharedComponentDescriptorRegistry &componentDescriptorRegistry) {
|
|
componentDescriptorRegistry_ = componentDescriptorRegistry;
|
|
}
|
|
|
|
void FabricUIManager::setDelegate(UIManagerDelegate *delegate) {
|
|
delegate_ = delegate;
|
|
}
|
|
|
|
UIManagerDelegate *FabricUIManager::getDelegate() {
|
|
return delegate_;
|
|
}
|
|
|
|
void FabricUIManager::setDispatchEventToEmptyTargetFunction(std::function<DispatchEventToEmptyTargetFunction> dispatchEventFunction) {
|
|
dispatchEventToEmptyTargetFunction_ = dispatchEventFunction;
|
|
}
|
|
|
|
void FabricUIManager::setDispatchEventToTargetFunction(std::function<DispatchEventToTargetFunction> dispatchEventFunction) {
|
|
dispatchEventToTargetFunction_ = dispatchEventFunction;
|
|
}
|
|
|
|
void FabricUIManager::setReleaseEventHandlerFunction(std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction) {
|
|
releaseEventHandlerFunction_ = releaseEventHandlerFunction;
|
|
}
|
|
|
|
void FabricUIManager::setReleaseEventTargetFunction(std::function<ReleaseEventTargetFunction> releaseEventTargetFunction) {
|
|
releaseEventTargetFunction_ = releaseEventTargetFunction;
|
|
}
|
|
|
|
void FabricUIManager::dispatchEventToTarget(const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload) const {
|
|
if (eventTarget != EmptyEventTarget) {
|
|
dispatchEventToTargetFunction_(
|
|
eventHandler_,
|
|
eventTarget,
|
|
const_cast<std::string &>(type),
|
|
const_cast<folly::dynamic &>(payload)
|
|
);
|
|
}
|
|
else {
|
|
dispatchEventToEmptyTargetFunction_(
|
|
eventHandler_,
|
|
const_cast<std::string &>(type),
|
|
const_cast<folly::dynamic &>(payload)
|
|
);
|
|
}
|
|
}
|
|
|
|
void FabricUIManager::releaseEventTarget(const EventTarget &eventTarget) const {
|
|
releaseEventTargetFunction_(eventTarget);
|
|
}
|
|
|
|
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, EventTarget eventTarget) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag: " << rootTag << ", props: " << props << ")";
|
|
|
|
ComponentName componentName = componentNameByReactViewName(viewName);
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[componentName];
|
|
RawProps rawProps = rawPropsFromDynamic(props);
|
|
|
|
SharedShadowNode shadowNode =
|
|
componentDescriptor->createShadowNode({
|
|
.tag = tag,
|
|
.rootTag = rootTag,
|
|
.eventEmitter = componentDescriptor->createEventEmitter(eventTarget, tag),
|
|
.props = componentDescriptor->cloneProps(nullptr, rawProps)
|
|
});
|
|
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode() -> " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
|
|
|
|
if (delegate_) {
|
|
delegate_->uiManagerDidCreateShadowNode(shadowNode);
|
|
}
|
|
|
|
return shadowNode;
|
|
}
|
|
|
|
SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
|
|
|
|
SharedShadowNode clonedShadowNode =
|
|
componentDescriptor->cloneShadowNode(*shadowNode, {});
|
|
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
|
|
return clonedShadowNode;
|
|
}
|
|
|
|
SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
|
|
// Assuming semantic: Cloning with same props but empty children.
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
|
|
|
|
SharedShadowNode clonedShadowNode =
|
|
componentDescriptor->cloneShadowNode(
|
|
*shadowNode,
|
|
{
|
|
.children = ShadowNode::emptySharedShadowNodeSharedList()
|
|
}
|
|
);
|
|
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
|
|
return clonedShadowNode;
|
|
}
|
|
|
|
SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
|
|
// Assuming semantic: Cloning with same children and specified props.
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
|
|
RawProps rawProps = rawPropsFromDynamic(props);
|
|
|
|
SharedShadowNode clonedShadowNode =
|
|
componentDescriptor->cloneShadowNode(
|
|
*shadowNode,
|
|
{
|
|
.props = componentDescriptor->cloneProps(shadowNode->getProps(), rawProps)
|
|
}
|
|
);
|
|
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
|
|
return clonedShadowNode;
|
|
}
|
|
|
|
SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
|
|
// Assuming semantic: Cloning with empty children and specified props.
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
|
|
RawProps rawProps = rawPropsFromDynamic(props);
|
|
|
|
SharedShadowNode clonedShadowNode =
|
|
componentDescriptor->cloneShadowNode(
|
|
*shadowNode,
|
|
{
|
|
.props = componentDescriptor->cloneProps(shadowNode->getProps(), rawProps),
|
|
.children = ShadowNode::emptySharedShadowNodeSharedList()
|
|
}
|
|
);
|
|
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
|
|
return clonedShadowNode;
|
|
}
|
|
|
|
void FabricUIManager::appendChild(const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::appendChild(parentShadowNode: " << parentShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", childShadowNode: " << childShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
|
|
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[parentShadowNode];
|
|
componentDescriptor->appendChild(parentShadowNode, childShadowNode);
|
|
}
|
|
|
|
SharedShadowNodeUnsharedList FabricUIManager::createChildSet(int rootTag) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createChildSet(rootTag: " << rootTag << ")";
|
|
return std::make_shared<SharedShadowNodeList>(SharedShadowNodeList({}));
|
|
}
|
|
|
|
void FabricUIManager::appendChildToSet(const SharedShadowNodeUnsharedList &shadowNodeList, const SharedShadowNode &shadowNode) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::appendChildToSet(shadowNodeList: " << shadowNodeList << ", shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
|
|
shadowNodeList->push_back(shadowNode);
|
|
}
|
|
|
|
void FabricUIManager::completeRoot(int rootTag, const SharedShadowNodeUnsharedList &children) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::completeRoot(rootTag: " << rootTag << ", shadowNodeList: " << children << ")";
|
|
|
|
if (delegate_) {
|
|
delegate_->uiManagerDidFinishTransaction(rootTag, children);
|
|
}
|
|
}
|
|
|
|
void FabricUIManager::registerEventHandler(const EventHandler &eventHandler) {
|
|
isLoggingEnabled && LOG(INFO) << "FabricUIManager::registerEventHandler(eventHandler: " << eventHandler << ")";
|
|
eventHandler_ = eventHandler;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|