22import React , { useState , useCallback } from 'react' ;
33import type { Node } from 'react' ;
44import { Keyboard } from 'react-native' ;
5+ import Clipboard from '@react-native-clipboard/clipboard' ;
56
67import type { RouteProp } from '../react-navigation' ;
78import type { AppNavigationProp } from '../nav/AppNavigator' ;
@@ -15,6 +16,7 @@ import ZulipButton from '../common/ZulipButton';
1516import { tryParseUrl } from '../utils/url' ;
1617import * as api from '../api' ;
1718import { navigateToAuth } from '../actions' ;
19+ import { useClipboardHasURL } from '../@react-native-clipboard/clipboard' ;
1820
1921type Props = $ReadOnly < { |
2022 navigation : AppNavigationProp < 'realm-input' > ,
@@ -69,6 +71,24 @@ export default function RealmInputScreen(props: Props): Node {
6971 button : { marginTop : 8 } ,
7072 } ;
7173
74+ const tryCopiedUrl = useCallback ( async ( ) => {
75+ // The copied string might not be a valid realm URL:
76+ // - It might not be a URL because useClipboardHasURL is subject to
77+ // races (and Clipboard.getString is itself async).
78+ // - It might not be a valid Zulip realm that the client can connect to.
79+ //
80+ // So…
81+ const url = await Clipboard . getString ( ) ;
82+
83+ // …let the user see what string is being tried and edit it if it fails…
84+ setRealmInputValue ( url ) ;
85+
86+ // …and run it through our usual validation.
87+ await tryRealm ( url ) ;
88+ } , [ tryRealm ] ) ;
89+
90+ const clipboardHasURL = useClipboardHasURL ( ) ;
91+
7292 return (
7393 < Screen
7494 title = "Welcome"
@@ -99,6 +119,32 @@ export default function RealmInputScreen(props: Props): Node {
99119 onPress = { handleInputSubmit }
100120 disabled = { tryParseUrl ( realmInputValue ) === undefined }
101121 />
122+ { clipboardHasURL === true && (
123+ // We prepopulate the input with https:// to help when you're not
124+ // copy-pasting. (Not everyone has memorized that sequence of
125+ // characters.)
126+ //
127+ // When you *do* want to copy-paste, though, prepopulating with
128+ // https:// can be annoying -- you don't want to end up with
129+ // https://https://chat.zulip.org.
130+ //
131+ // To solve that, it's risky to fuss around with the input value
132+ // while the user is focused on it, or overcomplicate the input
133+ // field (like by breaking it into two parts). I think these kinds
134+ // of solutions risk leaving some users confused or dissatisfied.
135+ //
136+ // Instead, we try to recognize when the user has copied a URL, and
137+ // let them use it without making them enter it into the input.
138+ //
139+ // TODO(?): Instead, use a FAB that persists while
140+ // clipboardHasURL !== true && !progress
141+ < ZulipButton
142+ style = { styles . button }
143+ text = "Use copied URL"
144+ progress = { progress }
145+ onPress = { tryCopiedUrl }
146+ />
147+ ) }
102148 </ Screen >
103149 ) ;
104150}
0 commit comments