Implement FabricViewStateManager for ReactEditText

Summary:
Implement FabricViewStateManager for ReactEditText.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D22941069

fbshipit-source-id: 44651d1a3500e4dcd36f94f339cb25ea25b1f3f9
This commit is contained in:
Joshua Gross
2020-08-05 01:42:19 -07:00
committed by Facebook GitHub Bot
parent 33bccbe2ec
commit 065fbe3be5
2 changed files with 40 additions and 23 deletions
@@ -39,7 +39,7 @@ import androidx.core.view.ViewCompat;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.views.text.ReactSpan;
import com.facebook.react.views.text.ReactTextUpdate;
@@ -61,7 +61,8 @@ import java.util.ArrayList;
* called this explicitly. This is the default behavior on other platforms as well.
* VisibleForTesting from {@link TextInputEventsTestCase}.
*/
public class ReactEditText extends AppCompatEditText {
public class ReactEditText extends AppCompatEditText
implements FabricViewStateManager.HasFabricViewStateManager {
private final InputMethodManager mInputMethodManager;
// This flag is set to true when we set the text of the EditText explicitly. In that case, no
@@ -100,7 +101,7 @@ public class ReactEditText extends AppCompatEditText {
private ReactViewBackgroundManager mReactBackgroundManager;
protected @Nullable JavaOnlyMap mAttributedString = null;
protected @Nullable StateWrapper mStateWrapper = null;
private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
protected boolean mDisableTextDiffing = false;
protected boolean mIsSettingTextFromState = false;
@@ -605,7 +606,7 @@ public class ReactEditText extends AppCompatEditText {
// wrapper 100% of the time.
// Since the LocalData object is constructed by getting values from the underlying EditText
// view, we don't need to construct one or apply it at all - it provides no use in Fabric.
if (mStateWrapper == null) {
if (!mFabricViewStateManager.hasStateWrapper()) {
ReactContext reactContext = getReactContext(this);
final ReactTextInputLocalData localData = new ReactTextInputLocalData(this);
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
@@ -820,6 +821,11 @@ public class ReactEditText extends AppCompatEditText {
}
}
@Override
public FabricViewStateManager getFabricViewStateManager() {
return mFabricViewStateManager;
}
/**
* This class will redirect *TextChanged calls to the listeners only in the case where the text is
* changed by the user, and not explicitly set by JS.
@@ -50,6 +50,7 @@ import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.BaseViewManager;
import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactStylesDiffMap;
@@ -919,7 +920,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
}
// Fabric: update representation of AttributedString
JavaOnlyMap attributedString = mEditText.mAttributedString;
final JavaOnlyMap attributedString = mEditText.mAttributedString;
if (attributedString != null && attributedString.hasKey("fragments")) {
String changedText = s.subSequence(start, start + count).toString();
@@ -981,27 +982,35 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
// we must recreate these data structures every time. It would be nice to have a
// reusable data-structure to use for TextInput because constructing these and copying
// on every keystroke is very expensive.
if (mEditText.mStateWrapper != null && attributedString != null) {
WritableMap map = new WritableNativeMap();
WritableMap newAttributedString = new WritableNativeMap();
if (mEditText.getFabricViewStateManager().hasStateWrapper() && attributedString != null) {
mEditText
.getFabricViewStateManager()
.setState(
new FabricViewStateManager.StateUpdateCallback() {
@Override
public WritableMap getStateUpdate() {
WritableMap map = new WritableNativeMap();
WritableMap newAttributedString = new WritableNativeMap();
WritableArray fragments = new WritableNativeArray();
WritableArray fragments = new WritableNativeArray();
for (int i = 0; i < attributedString.getArray("fragments").size(); i++) {
ReadableMap readableFragment = attributedString.getArray("fragments").getMap(i);
WritableMap fragment = new WritableNativeMap();
fragment.putDouble("reactTag", readableFragment.getInt("reactTag"));
fragment.putString("string", readableFragment.getString("string"));
fragments.pushMap(fragment);
}
for (int i = 0; i < attributedString.getArray("fragments").size(); i++) {
ReadableMap readableFragment =
attributedString.getArray("fragments").getMap(i);
WritableMap fragment = new WritableNativeMap();
fragment.putDouble("reactTag", readableFragment.getInt("reactTag"));
fragment.putString("string", readableFragment.getString("string"));
fragments.pushMap(fragment);
}
newAttributedString.putString("string", attributedString.getString("string"));
newAttributedString.putArray("fragments", fragments);
newAttributedString.putString("string", attributedString.getString("string"));
newAttributedString.putArray("fragments", fragments);
map.putInt("mostRecentEventCount", mEditText.incrementAndGetEventCounter());
map.putMap("textChanged", newAttributedString);
mEditText.mStateWrapper.updateState(map);
map.putInt("mostRecentEventCount", mEditText.incrementAndGetEventCounter());
map.putMap("textChanged", newAttributedString);
return map;
}
});
}
// The event that contains the event counter and updates it must be sent first.
@@ -1235,6 +1244,9 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
@Override
public Object updateState(
ReactEditText view, ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper) {
view.getFabricViewStateManager().setStateWrapper(stateWrapper);
if (stateWrapper == null) {
throw new IllegalArgumentException("Unable to update a NULL state.");
}
@@ -1254,7 +1266,6 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
int textBreakStrategy =
TextAttributeProps.getTextBreakStrategy(paragraphAttributes.getString("textBreakStrategy"));
view.mStateWrapper = stateWrapper;
return ReactTextUpdate.buildReactTextUpdateFromState(
spanned,
state.getInt("mostRecentEventCount"),