-
-
Notifications
You must be signed in to change notification settings - Fork 654
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
realm input screen: Offer nicer experience for copied URL #5287
Conversation
Thanks! This is a tricky bit of UI, and in an area that we don't naturally look at often enough compared to its importance. Let's focus on the first part of the branch: about the pre-filled / placeholder text. I think there's enough complexity already there for one PR. I like the idea of getting rid of the quirky thing where the placeholders are separate text elements, not part of the TextInput, plus a special property that touching them focuses the actual input. That's been a source of jankiness. I think cutting out the When I first tried this, there was also an issue (see screenshot in chat thread) where even the I have a few code-level comments, too, which I'll make next. |
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.
And code comments below (on those first 3 commits.)
src/common/SmartUrlInput.js
Outdated
if (Platform.OS === 'android') { | ||
// (This eslint-disable is fine; the relevant rule is not to call Hooks | ||
// conditionally. But this conditional won't vary in its behavior | ||
// between multiple renders of SmartUrlInput.) | ||
// eslint-disable-next-line react-hooks/rules-of-hooks |
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 works. An alternative would be to put the Platform.OS
check just inside the useCallback
. That seems like it might be simpler than giving this explanation… hmm, plus, the fact that we only want it on Android seems like it's a fact about that workaround, not a fact about this specific call site of it.
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.
the fact that we only want it on Android seems like it's a fact about that workaround, not a fact about this specific call site of it.
Mm, I agree. We'll have to suppress some react-hooks/rules-of-hooks
es within the custom hook itself, but that's fine and easy.
src/common/SmartUrlInput.js
Outdated
// conditionally. But this conditional won't vary in its behavior | ||
// between multiple renders of SmartUrlInput.) | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
useRn19366Workaround(textInputRef); |
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.
So IIUC the purpose of this workaround is entirely about making a focus
call effective. Before this branch, there are two focus
calls: one in urlPress
, and this one:
// When the route is focused in the navigation, focus the input.
// Otherwise, if you go back to this screen from the auth screen, the
// input won't be focused.
useFocusEffect(
useCallback(() => {
if (textInputRef.current) {
// `.current` is not type-checked; see definition.
textInputRef.current.focus();
}
}, []),
);
Then after the third commit in the branch ('remove "smart"ness'), the focus
call that was in urlPress
is gone, so the only one that remains for this workaround to support is the latter.
Does that one actually work, though? AFAICT, on Android (which is where this workaround would be needed), it mostly doesn't -- neither at main, nor after these changes.
- Repro recipe: go to this screen; enter "chat.zulip.org"; hit the Enter button; then navigate back.
- Desired behavior: this screen returns, the input is focused, and the keyboard re-appears.
- On iOS, this works great, on a physical phone at v27.181.
- On my physical Pixel 4 running Android 11, at v27.181, it mostly did not work.
- The very first time I tried it, it did.
- Subsequently, what happens is: the keyboard appears and then promptly disappears again. :-/
- On an emulator running Android 11, at the base of this branch, it does not work.
- I think the keyboard is appearing and then disappearing again. But it happens faster than on my phone.
- In fact, it happens fast enough that when I tried this before trying it on my phone, I had a guess that the keyboard was appearing and disappearing but only a guess -- all I could say for sure is that a bunch of movement happens. Having seen it more clearly on my phone, I'm moderately confident that the same thing is happening here.
- On that emulator, at either the tip of this branch or after the first 3 commits, same thing as at the base of the branch.
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.
Does that one actually work, though? AFAICT, on Android (which is where this workaround would be needed), it mostly doesn't -- neither at main, nor after these changes.
This turned out to be a separate bug, one that doesn't involve dismissing the keyboard with the built-in Android back button: https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/realm-input/near/1346623
I'll put a comment on this code pointing to our investigation there.
src/common/SmartUrlInput.js
Outdated
domain: 'zulipchat.com', | ||
protocol: 'https://', |
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.
These get duplicated at this second commit. I believe it's important that they have the same values in those two different places, so both should refer to a common name.
Simplest may be to just have locals with the same names as the old props. When/if a later commit makes one of those locals be referred to in just one spot, it can still be inlined then.
src/common/SmartUrlInput.js
Outdated
@@ -113,26 +110,11 @@ export default function SmartUrlInput(props: Props): Node { | |||
const handleChange = useCallback( | |||
(_value: string) => { | |||
setValue(_value); | |||
|
|||
onChangeText( | |||
fixRealmUrl(autocompleteRealm(_value, { protocol: 'https://', domain: 'zulipchat.com' })), |
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.
These little helper functions exist only for the sake of this component, and are closely tied to the details of its UI. So when deleting these references to them, let's be sure to celebrate by deleting the functions themselves.
40ce11b
to
95e6b65
Compare
Thanks for the review! Revision pushed. |
Thanks for the revision! I've read the revised version of that first part of the branch: 39be99c react utils: Add useConditionalEffect custom hook and it all looks good -- merging now. I'd be glad to see a separate PR for the second part: 3d9cd20 deps: Migrate to @react-native-clipboard/clipboard |
... Hmm, actually, tests fail at that step of the branch! I believe the issue is just that this change: const handleChange = useCallback(
(_value: string) => {
setValue(_value);
-
- onChangeText(
- fixRealmUrl(
- autocompleteRealm(_value, { protocol: defaultProtocol, domain: defaultD
omain }),
- ),
- );
+ onChangeText(_value);
},
[defaultDomain, defaultProtocol, onChangeText],
); should update the dependencies list too, as two of those variables have gone away. If that seems right, then please go ahead and merge those first 7 commits, with that fix. |
95e6b65
to
9303039
Compare
To replace useEdgeTriggeredEffect, which implicitly required a constant callback; see zulip#5300 (comment) and this bit of useEdgeTriggeredEffect's jsdoc: > The callback is not permitted to return a cleanup function, > because it's not clear what the semantics should be of when such a > cleanup function would be run.
…ffect And remove useConditionalEffect; see the previous commit for why useConditionalEffect has a better interface.
These don't need to be configurable.
And just use an ordinary controlled TextInput, always stretched to full width, and never just 1px. The major reason for this is to fix zulip#5228 (can't paste org URL): native copy-paste is activated by long-pressing in the input element itself. But long-pressing is really hard when the element is only 1px wide! Include some placeholder text to help people have some idea of what to put here. Don't require or prefill with "https://"; instead, fill that in if no supported scheme is provided. ("Supported scheme" just means "http://" or "https://"; other schemes just don't make sense in this context.) See discussion at https://chat.zulip.org/#narrow/stream/48-mobile/topic/can't.20paste.20org.20URL/near/1327170 Fixes: zulip#5228
… now Less bothersome because, after the previous commit, the only remaining .focus() call is for convenience (autofocus when back-navigating to the screen), not necessity. With this RN bug, whether we work around it or not, it remains possible to focus a TextInput by tapping on it. So why "necessity"? Before the previous commit, we had a hack where text elements were trying to blend in as part of a TextInput, with the real TextInput being as little as 1px wide when empty. So, pressing the text elements was an important way to give the input focus, and that was achieved with .focus().
9303039
to
0684547
Compare
Yep! Thanks for the review; done. I've sent the rest in #5328. |
(summary TODO)
Fixes: #5228
Supersedes: #4502