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

Allow configuration of selection/caret color on Aztec view. #1776

Merged
merged 11 commits into from
Jan 27, 2020

Conversation

SergioEstevao
Copy link
Contributor

@SergioEstevao SergioEstevao commented Jan 14, 2020

Fixes #1773

This PR adds a prop to RCTAztecView to allow configuration of the selection/caret color

To test:

  • Change the code on one the block that uses the RichText component, and add a prop like this
    selectionColor= { 'orange' }
  • Start the demo app
  • Add the block changed
  • Check that the caret color and selection are correct.

PR submission checklist:

  • I have considered adding unit tests where possible.
  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

@SergioEstevao
Copy link
Contributor Author

@chipsnyder Feel free to add the necessary changes for Android on this PR.

@chipsnyder
Copy link
Contributor

Will do, I'll submit those changes today.

@chipsnyder
Copy link
Contributor

chipsnyder commented Jan 14, 2020

Added the cursor color and highlight color based on React Native's implementation:
https://github.com/facebook/react-native/blob/233fdfc014bb4b919c7624c90e5dac614479076f/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java#L422-L457

Note this approach doesn't work on API 28+ because of Google's restrictions on reflection
facebook/react-native#22762

Once API 29 is supported this can be migrated to use https://developer.android.com/reference/android/widget/TextView#setTextCursorDrawable(android.graphics.drawable.Drawable)

Cursor Highlight
Screen Shot 2020-01-14 at 3 08 41 PM Screen Shot 2020-01-14 at 2 33 50 PM

@lukewalczak
Copy link
Contributor

Hello @SergioEstevao @chipsnyder, thanks for a PR!

I've tested your feature on:

  1. WordPress-iOS
caret color ✅ selection color ✅
Screenshot 2020-01-15 at 11 52 47 Screenshot 2020-01-15 at 10 57 42
  1. WordPress-Android API 27
caret color ✅ selection color ✅
Screenshot 2020-01-15 at 11 56 03 Screenshot 2020-01-15 at 11 55 39
  1. WordPress-Android API 29
caret color ❎ selection color ✅
Screenshot 2020-01-15 at 12 00 41 Screenshot 2020-01-15 at 12 00 45

I was also testing colors passed as:

  1. rgb()
  2. string
  3. hex

@dratwas could you please check the code?

@dratwas
Copy link
Contributor

dratwas commented Jan 15, 2020

LGTM! 👍

Comment on lines 587 to 609
// Get the original cursor drawable resource.
Field cursorDrawableResField = TextView.class.getDeclaredField("mCursorDrawableRes");
cursorDrawableResField.setAccessible(true);
int drawableResId = cursorDrawableResField.getInt(this);

// The view has no cursor drawable.
if (drawableResId == 0) {
return;
}

Drawable drawable = ContextCompat.getDrawable(getContext(), drawableResId);
if (color != null) {
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
Drawable[] drawables = {drawable, drawable};

// Update the current cursor drawable with the new one.
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editor = editorField.get(this);
Field cursorDrawableField = editor.getClass().getDeclaredField("mCursorDrawable");
cursorDrawableField.setAccessible(true);
cursorDrawableField.set(editor, drawables);
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not understanding the logic here. Why do we need to set accessible=true in multiple places? Is that necessary to be able to set cursor color? @chipsnyder

Copy link
Contributor

Choose a reason for hiding this comment

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

This method is a bit of a hack to get to the desired goal, but I can add some more info. In Android, the cursor color is managed by the theme and not on a control by control basis. You can set it in XML via android:textCursorDrawable. However there isn't an officially supported way to do change this programmatically in API 28 and below.

In API 27 and below, you can use reflection to dynamically lookup the drawable for the current TextView and replace it with a new drawable. Setting setAccessible to true allows us to make the changes we need through reflection. Without that set to true, the app will throw IllegalAccessException

Here's a breakdown of where we set it.

Variable How we use setAccessible
cursorDrawableResField Allows the lookup ofdrawableResId so we can clone it and change the color
editorField So we can get access to the object the holds the cursor drawable
cursorDrawableField So we can update that with the new drawable we created

I can go through and add more step by step inline documentation if you think that will help.

Also worth noting starting in API 28, Google restricts the use of reflection. So this won't work in API 28 and above. Once we update Aztec to target API 29 though we can set the drawable using setTextCursorDrawable

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. We need to make sure the screen reader doesn't say weird things after making these fields accessible. Could you be able to set selectionColor on a RichText and test accessibility/screen reader? Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

API 29 supports setTextCursorDrawable which would be a cleaner way to handle this when an upgrade to that API level occurs.

Also, could you open a tech debt task in this repo and add it to our board to help us remember this in the future?

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you be able to set selectionColor on a RichText and test accessibility/screen reader?

I tested this on my Pixel 3a, which runs API 29, and an API 24 emulator after installing https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback&hl=en_US in the emulator. From my testing, it's behaving the same both before and after this change.

could you open a tech debt task

Just created that here: #1787

@pinarol
Copy link
Contributor

pinarol commented Jan 16, 2020

As far as I see, the output is different on both platforms. On Android, the selection color looks like exactly same with cursor color. But on iOS, selection color seems more opaque(because that's simply how tintColor works so it is supported by system). I am curious if this can go wrong if we want to set selection color to the same color with font color. Could we also test that case?

We need this for Button block, and in Button block both background color and the font color is configurable. So we'll probably need to set the selectionColor=fontColor.

@chipsnyder
Copy link
Contributor

I am curious if this can go wrong if we want to set selection color to the same color with font color.

That's a good point. I didn't think about that. Testing this out if I set the selection color to be black, you end up with something like this in Android:

We can set it so that the highlight color is 50% of either the selection color (which will control the cursor) or the font color. So you end up with something more like this if the font color and selection color match.

We could really go either way with setting the highlight to match either 50% alpha of either the font or selection color. I think having it match the selection color would be the most consistent with how iOS works.

I went ahead and made that change. Just let me know if you would like it to be based on the font color, and I'll make the adjustment.

@@ -362,6 +364,17 @@ public void setColor(ReactAztecText view, @Nullable Integer color) {
view.setTextColor(newColor);
}

@ReactProp(name = "selectionColor", customType = "Color")
public void setSelectionColor(ReactAztecText view, @Nullable Integer color) {
int newColor = Color.BLACK;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd expect this method to change nothing if the passed color is null. Currently it is proceeding with Black.

Copy link
Contributor

Choose a reason for hiding this comment

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

When I first did this I was pretty much just following the pattern in setting color. I was basically thinking they set it they should see some change. I agree though having it make no changes seems to be the best path.

@pinarol
Copy link
Contributor

pinarol commented Jan 20, 2020

We could really go either way with setting the highlight to match either 50% alpha of either the font or selection color. I think having it match the selection color would be the most consistent with how iOS works.

I'd like to go with lowered opacity either, however, do you also think it looks more like a gray rather than a lowered opacity black? 🤔Is that possible we are missing something?

@chipsnyder
Copy link
Contributor

chipsnyder commented Jan 20, 2020

do you also think it looks more like a gray rather than a lowered opacity black?

When I change the background color to a light blue, then it's easier to see the transparency. Comparing iOS and Android, they look pretty similar, although Android might be a touch more opaque. I looked up the iOS applied tint and based on the interface inspector, they use 20% alpha. Here's the comparison. The 20% seems light to me. So I played around and set it to 33%, which I feel is a decent balance between the two. Let me know your thoughts, and I can play around with it more.

Platform Screenshot
iOS
Android 50%
Android 33%
Android 20%

cc @iamthomasbishop

@iamthomasbishop
Copy link
Contributor

@chipsnyder I haven't had a chance to dig through the whole comment history here, but looking at your examples in the previous comment, it looks as if iOS puts the selection highlight over the top of the text, whereas Android is behind the text — is that right or just my imagination?

Is there a "default" highlight alpha on Android? 33% looks fine, but I'm wondering what Android uses by default, because if it's close to 20% maybe we should align both platforms closer to that ballpark.

@chipsnyder
Copy link
Contributor

@iamthomasbishop

highlight over the top of the text, whereas Android is behind the text — is that right or just my imagination?

I think that's right, the default behavior of Android when setting the color is to use the color as provided. So given black, you'll get black with an alpha of 100% like in the first image here #1776 (comment).

When I was debugging, the default color was a lighter shade of the cursor but rendered with full alpha.

@iamthomasbishop
Copy link
Contributor

I think that's right, the default behavior of Android when setting the color is to use the color as provided. So given black, you'll get black with an alpha of 100% like in the first image here #1776 (comment).

Ah, ok. So is the iOS screenshot here using 20% or 33%? The iOS example looks a bit stronger, but maybe that's just because it's over the text vs. under. Both look nice, tbh, so if I had to choose between 20% and 33% I'd choose the one that provides a stronger contrast.

@chipsnyder
Copy link
Contributor

The iOS example is 20%, which is outside of our control to tweak. With Android, we can go with any of those options, or I can create some more options if you'd like to fine-tune it.

@pinarol
Copy link
Contributor

pinarol commented Jan 20, 2020

Thanks for listing the options @chipsnyder! Lowering the alpha seems helping a lot. One more thing that can help us decide would be again using the same selection color with font color. As I mentioned, both background color and the font color is dynamically configurable for Button block. So we'll probably need to set the selectionColor=fontColor there.

@chipsnyder
Copy link
Contributor

same selection color with font color

Sure thing. I have a few instances above that use a black font and selection colors. I'll consolidate them here and add some white font/selection color examples as well. Or were you thinking more directly of not having the selectionColor be its own property and base it on the font only?

Platform Black Font/Selection White Font/Selection
iOS * Simulator Screen Shot - iPhone X - 2020-01-20 at 13 20 56 Simulator Screen Shot - iPhone X - 2020-01-20 at 13 43 17
Android 100% Screenshot_1579544764 Screenshot_1579546390
Android 50% Screenshot_1579544865 Screenshot_1579546281
Android 33% Screenshot_1579545498 Screenshot_1579546062
Android 20% Screenshot_1579545602 Screenshot_1579545893

* System set to 20% of Tint color


On a side note, a friend of mine shared with me a few ideas on how to update the bubble colors using the same technique. I'll update this PR with those changes as well.

@pinarol
Copy link
Contributor

pinarol commented Jan 20, 2020

@chipsnyder Thank you very much! Maybe it is because i am an iOS user and that’s what i am used to see but %20 looks best imho.

Or were you thinking more directly of not having the selectionColor be its own property and base it on the font only?

No, i think we do need the selectionColor prop. I was just trying to say in case of the Button block we’ll probably need to make it same color with font. It is not a general rule.

On a side note, a friend of mine shared with me a few ideas on how to update the bubble colors using the same technique. I'll update this PR with those changes as well.

Great! Hope it won’t be much trouble.

@chipsnyder
Copy link
Contributor

i am an iOS user and that’s what i am used to see but %20 looks best imho.

I'm good with the plan of setting it to be 20% if you think that looks better. I use iOS as my daily driver too but I think what @iamthomasbishop pointed out, the highlight is behind the text on Android, is what made the difference to me. Just pushed that change with the pointer color as well.

@pinarol
Copy link
Contributor

pinarol commented Jan 20, 2020

I’d prefer deferring the last decision to @iamthomasbishop on this.
And bubbles look better now, thanks!

@etoledom etoledom modified the milestones: 1.21, 1.22 Jan 20, 2020
@etoledom
Copy link
Contributor

Moved milestone to v1.22.
Please feel free to re-target if you consider this PR must be shipped together with v1.21.

@chipsnyder chipsnyder added the [Status] Needs Design Review Needs design review or sign-off before shipping label Jan 22, 2020
@chipsnyder
Copy link
Contributor

@iamthomasbishop

I’d prefer deferring the last decision to @iamthomasbishop on this.

Do you have any preference for which transparency setting to use for Android?
Here's a break down of each option: #1776 (comment)

@iamthomasbishop
Copy link
Contributor

Do you have any preference for which transparency setting to use for Android?

20% looks good to me, we can roll with that!

@chipsnyder chipsnyder removed the [Status] Needs Design Review Needs design review or sign-off before shipping label Jan 22, 2020
@chipsnyder
Copy link
Contributor

20% looks good to me, we can roll with that!

This PR is good to go then from the Android side. I'll work with @SergioEstevao to update the Gutenberg reference. The failing test here seems to be something that is failing routinely in develop

@chipsnyder chipsnyder force-pushed the issue/1773_add_option_to_change_caret_color branch from 74acf9b to 13ece3f Compare January 24, 2020 20:25
@SergioEstevao
Copy link
Contributor Author

@lukewalczak can you give the final approval on this PR?

@lukewalczak
Copy link
Contributor

I'm happy to use that feature within Button block 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add option to change caret color in RichText
7 participants