Files
react-native/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputState.h
T
Joshua Gross 5be86695a3 AndroidTextInput uses default padding from Android theme
Summary:
For backwards-compatibility with Paper, we're implementing a feature in Fabric that will allow TextInputs to use the default padding from the theme in Android.

Note that this uses some pretty ugly hacks that probably shouldn't be used inside of components at all: looking directly at rawProps, overriding props/Yoga styles in the component descriptor, etc. I would (personally) really like to kill this feature entirely unless and until we can find a more elegant solution.

Changelog: [Internal]

TextInputs are still not pixel-perfect with Paper, but they're much closer, and the underline visual glitchiness is no longer an issue.

Reviewed By: mdvacca

Differential Revision: D20109605

fbshipit-source-id: 543282843e0a9f03a504d72d7a014431099bd64c
2020-02-26 13:46:57 -08:00

169 lines
6.2 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/attributedstring/AttributedString.h>
#include <react/attributedstring/ParagraphAttributes.h>
#include <react/textlayoutmanager/TextLayoutManager.h>
#ifdef ANDROID
#include <folly/dynamic.h>
#endif
namespace facebook {
namespace react {
/*
* State for <Paragraph> component.
* Represents what to render and how to render.
*/
class AndroidTextInputState final {
public:
int64_t mostRecentEventCount{0};
/*
* All content of <TextInput> component represented as an `AttributedString`.
*/
AttributedString attributedString{};
/*
* All content of <TextInput> component represented as an `AttributedString`.
* This stores the previous computed *from the React tree*. This usually
* doesn't change as the TextInput contents are being updated. If it does
* change, we need to wipe out current contents of the TextInput and replace
* with the new value from the tree.
*/
AttributedString reactTreeAttributedString{};
/*
* Represents all visual attributes of a paragraph of text represented as
* a ParagraphAttributes.
*/
ParagraphAttributes paragraphAttributes{};
/**
* Default TextAttributes used if we need to construct a new Fragment.
* Only used if text is inserted into an AttributedString with no existing
* Fragments.
*/
TextAttributes defaultTextAttributes;
/**
* Default parent ShadowView used if we need to construct a new Fragment.
* Only used if text is inserted into an AttributedString with no existing
* Fragments.
*/
ShadowView defaultParentShadowView;
/*
* `TextLayoutManager` provides a connection to platform-specific
* text rendering infrastructure which is capable to render the
* `AttributedString`.
*/
SharedTextLayoutManager layoutManager{};
/**
* Communicates Android theme padding back to the ShadowNode / Component Descriptor for layout.
*/
float defaultThemePaddingStart{NAN};
float defaultThemePaddingEnd{NAN};
float defaultThemePaddingTop{NAN};
float defaultThemePaddingBottom{NAN};
#ifdef ANDROID
AttributedString updateAttributedString(
TextAttributes const &defaultTextAttributes,
ShadowView const &defaultParentShadowView,
AttributedString const &original,
folly::dynamic const &data) {
if (data["textChanged"].empty()) {
return original;
}
// TODO: parse other attributes besides just string?
// on the other hand, not much should be driven from Java
// TODO: it'd be really nice to treat these as operational transforms
// instead of having to pass the whole string across.
// Unfortunately we don't have a good way of communicating from Java to C++
// *which* version of the State changes should be applied to; and if there's
// a conflict, we don't have any recourse of any way to bail out of a
// commit.
auto str = AttributedString{};
int i = 0;
folly::dynamic fragments = data["textChanged"]["fragments"];
for (auto const &fragment : original.getFragments()) {
str.appendFragment(AttributedString::Fragment{
fragments.size() > i ? fragments[i]["string"].getString() : "",
fragment.textAttributes,
fragment.parentShadowView});
i++;
}
if (fragments.size() > original.getFragments().size()) {
for (; i < fragments.size(); i++) {
str.appendFragment(
AttributedString::Fragment{fragments[i]["string"].getString(),
defaultTextAttributes,
defaultParentShadowView});
}
}
return str;
}
AndroidTextInputState(
int64_t mostRecentEventCount,
AttributedString const &attributedString,
AttributedString const &reactTreeAttributedString,
ParagraphAttributes const &paragraphAttributes,
TextAttributes const &defaultTextAttributes,
ShadowView const &defaultParentShadowView,
SharedTextLayoutManager const &layoutManager,
float defaultThemePaddingStart,
float defaultThemePaddingEnd,
float defaultThemePaddingTop,
float defaultThemePaddingBottom)
: mostRecentEventCount(mostRecentEventCount),
attributedString(attributedString),
reactTreeAttributedString(reactTreeAttributedString),
paragraphAttributes(paragraphAttributes),
defaultTextAttributes(defaultTextAttributes),
defaultParentShadowView(defaultParentShadowView),
layoutManager(layoutManager),
defaultThemePaddingStart(defaultThemePaddingStart),
defaultThemePaddingEnd(defaultThemePaddingEnd),
defaultThemePaddingTop(defaultThemePaddingTop),
defaultThemePaddingBottom(defaultThemePaddingBottom) {}
AndroidTextInputState() = default;
AndroidTextInputState(
AndroidTextInputState const &previousState,
folly::dynamic const &data)
: mostRecentEventCount(data.getDefault("mostRecentEventCount", previousState.mostRecentEventCount).getInt()),
attributedString(updateAttributedString(
previousState.defaultTextAttributes,
previousState.defaultParentShadowView,
previousState.attributedString,
data)),
reactTreeAttributedString(previousState.reactTreeAttributedString),
paragraphAttributes(previousState.paragraphAttributes),
defaultTextAttributes(previousState.defaultTextAttributes),
defaultParentShadowView(previousState.defaultParentShadowView),
layoutManager(previousState.layoutManager),
defaultThemePaddingStart(data.getDefault("themePaddingStart", previousState.defaultThemePaddingStart).getDouble()),
defaultThemePaddingEnd(data.getDefault("themePaddingEnd", previousState.defaultThemePaddingEnd).getDouble()),
defaultThemePaddingTop(data.getDefault("themePaddingTop", previousState.defaultThemePaddingTop).getDouble()),
defaultThemePaddingBottom(data.getDefault("themePaddingBottom", previousState.defaultThemePaddingBottom).getDouble()) {};
folly::dynamic getDynamic() const;
#endif
};
} // namespace react
} // namespace facebook