-
Notifications
You must be signed in to change notification settings - Fork 57
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
Allow configuration of selection/caret color on Aztec view. #1776
Conversation
@chipsnyder Feel free to add the necessary changes for Android on this PR. |
Will do, I'll submit those changes today. |
Added the cursor color and highlight color based on React Native's implementation: Note this approach doesn't work on API 28+ because of Google's restrictions on reflection Once API 29 is supported this can be migrated to use https://developer.android.com/reference/android/widget/TextView#setTextCursorDrawable(android.graphics.drawable.Drawable)
|
Hello @SergioEstevao @chipsnyder, thanks for a PR! I've tested your feature on:
I was also testing colors passed as:
@dratwas could you please check the code? |
LGTM! 👍 |
// 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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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. |
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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? |
… colors if the new color in null
@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. |
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. |
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. |
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. |
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. |
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
* 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. |
@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.
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.
Great! Hope it won’t be much trouble. |
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. |
I’d prefer deferring the last decision to @iamthomasbishop on this. |
Moved milestone to v1.22. |
Do you have any preference for which transparency setting to use for Android? |
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 |
74acf9b
to
13ece3f
Compare
@lukewalczak can you give the final approval on this PR? |
I'm happy to use that feature within |
Fixes #1773
This PR adds a prop to RCTAztecView to allow configuration of the selection/caret color
To test:
selectionColor= { 'orange' }
PR submission checklist:
RELEASE-NOTES.txt
if necessary.