From 40ce11bd64127ae699957f7fb37a13737582c3d7 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Fri, 25 Feb 2022 17:35:36 -0800 Subject: [PATCH] RealmInputScreen: Offer nicer experience for copied URL Prompted by Alya's comment on CZO [1]: > One would have to play with pasting behavior to make sure > something reasonable happens if you are trying to paste in a whole > URL, including the `https` part. [1] https://chat.zulip.org/#narrow/stream/48-mobile/topic/can't.20paste.20org.20URL/near/1327170 Fixes: #5228 --- src/start/RealmInputScreen.js | 46 ++++++++++++++++++++++++++++ static/translations/messages_en.json | 1 + 2 files changed, 47 insertions(+) diff --git a/src/start/RealmInputScreen.js b/src/start/RealmInputScreen.js index d407de58280..101e5cd09db 100644 --- a/src/start/RealmInputScreen.js +++ b/src/start/RealmInputScreen.js @@ -2,6 +2,7 @@ import React, { useState, useCallback } from 'react'; import type { Node } from 'react'; import { Keyboard } from 'react-native'; +import Clipboard from '@react-native-clipboard/clipboard'; import type { RouteProp } from '../react-navigation'; import type { AppNavigationProp } from '../nav/AppNavigator'; @@ -15,6 +16,7 @@ import ZulipButton from '../common/ZulipButton'; import { tryParseUrl } from '../utils/url'; import * as api from '../api'; import { navigateToAuth } from '../actions'; +import { useClipboardHasURL } from '../@react-native-clipboard/clipboard'; type Props = $ReadOnly<{| navigation: AppNavigationProp<'realm-input'>, @@ -69,6 +71,24 @@ export default function RealmInputScreen(props: Props): Node { button: { marginTop: 8 }, }; + const tryCopiedUrl = useCallback(async () => { + // The copied string might not be a valid realm URL: + // - It might not be a URL because useClipboardHasURL is subject to + // races (and Clipboard.getString is itself async). + // - It might not be a valid Zulip realm that the client can connect to. + // + // So… + const url = await Clipboard.getString(); + + // …let the user see what string is being tried and edit it if it fails… + setRealmInputValue(url); + + // …and run it through our usual validation. + await tryRealm(url); + }, [tryRealm]); + + const clipboardHasURL = useClipboardHasURL(); + return ( + {clipboardHasURL === true && ( + // We prepopulate the input with https:// to help when you're not + // copy-pasting. (Not everyone has memorized that sequence of + // characters.) + // + // When you *do* want to copy-paste, though, prepopulating with + // https:// can be annoying -- you don't want to end up with + // https://https://chat.zulip.org. + // + // To solve that, it's risky to fuss around with the input value + // while the user is focused on it, or overcomplicate the input + // field (like by breaking it into two parts). I think these kinds + // of solutions risk leaving some users confused or dissatisfied. + // + // Instead, we try to recognize when the user has copied a URL, and + // let them use it without making them enter it into the input. + // + // TODO(?): Instead, use a FAB that persists while + // clipboardHasURL !== true && !progress + + )} ); } diff --git a/static/translations/messages_en.json b/static/translations/messages_en.json index 01b750f5807..05597ad18d9 100644 --- a/static/translations/messages_en.json +++ b/static/translations/messages_en.json @@ -48,6 +48,7 @@ "Welcome": "Welcome", "Enter your Zulip server URL:": "Enter your Zulip server URL:", "e.g. zulip.example.com": "e.g. zulip.example.com", + "Use copied URL": "Use copied URL", "Subscriptions": "Subscriptions", "Search": "Search", "Log in": "Log in",