feat(mobile): add cid in entry view

pull/90/head
moonrailgun 2 years ago
parent 3c121e42eb
commit 781d413527

@ -17,6 +17,7 @@
"@formatjs/intl": "^2.6.9", "@formatjs/intl": "^2.6.9",
"@notifee/react-native": "^7.6.1", "@notifee/react-native": "^7.6.1",
"@react-native-async-storage/async-storage": "^1.17.11", "@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-community/clipboard": "^1.5.1",
"immer": "^9.0.19", "immer": "^9.0.19",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mini-star": "^2.0.8", "mini-star": "^2.0.8",

@ -1,5 +1,6 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Alert, ScrollView, StyleSheet, TextInput } from 'react-native'; import { Alert, StyleSheet, ScrollView } from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import { ServerCard } from './components/ServerCard'; import { ServerCard } from './components/ServerCard';
import { useServerStore } from './store/server'; import { useServerStore } from './store/server';
import Dialog from 'react-native-ui-lib/dialog'; import Dialog from 'react-native-ui-lib/dialog';
@ -9,9 +10,13 @@ import {
Text, Text,
View, View,
ActionSheet, ActionSheet,
TextField,
TouchableOpacity,
} from 'react-native-ui-lib'; } from 'react-native-ui-lib';
import { isValidUrl } from './lib/utils'; import { isValidUrl } from './lib/utils';
import { translate } from './lib/i18n'; import { translate } from './lib/i18n';
import { getClientId } from './lib/notifications/getui';
import { useToast } from './hooks/useToast';
export const Entry: React.FC = React.memo(() => { export const Entry: React.FC = React.memo(() => {
const { serverList, selectServer, addServer, removeServer } = const { serverList, selectServer, addServer, removeServer } =
@ -20,86 +25,112 @@ export const Entry: React.FC = React.memo(() => {
const [serverUrl, setServerUrl] = useState(''); const [serverUrl, setServerUrl] = useState('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [selectedServer, setSelectedServer] = useState(''); const [selectedServer, setSelectedServer] = useState('');
const [cid, setCid] = useState('');
const { toastEl, showToast } = useToast();
useEffect(() => {
getClientId().then((cid) => {
setCid(cid);
});
}, []);
return ( return (
<ScrollView style={styles.root}> <View style={styles.root}>
{serverList.map((serverInfo, i) => { <ScrollView style={styles.main}>
return ( {serverList.map((serverInfo, i) => {
<ServerCard return (
key={`${i}#${serverInfo.url}`} <ServerCard
style={styles.item} key={`${i}#${serverInfo.url}`}
name={serverInfo.name ?? serverInfo.url} style={styles.item}
url={serverInfo.url} name={serverInfo.name ?? serverInfo.url}
version={serverInfo.version} url={serverInfo.url}
onPress={() => selectServer(serverInfo)} version={serverInfo.version}
onLongPress={() => { onPress={() => selectServer(serverInfo)}
if (i !== 0) { onLongPress={() => {
setSelectedServer(serverInfo.url); if (i !== 0) {
} setSelectedServer(serverInfo.url);
}} }
/> }}
); />
})} );
})}
<ServerCard <ServerCard
name={translate('core.addServer')} name={translate('core.addServer')}
onPress={() => setDialogVisible(true)} onPress={() => setDialogVisible(true)}
/> />
<ActionSheet <ActionSheet
visible={!!selectedServer} visible={!!selectedServer}
message={`${translate('core.selectedServer')}: ${selectedServer}`} message={`${translate('core.selectedServer')}: ${selectedServer}`}
onDismiss={() => setSelectedServer('')} onDismiss={() => setSelectedServer('')}
destructiveButtonIndex={0} destructiveButtonIndex={0}
options={[ options={[
{ {
label: translate('core.deleteServer'), label: translate('core.deleteServer'),
onPress: () => { onPress: () => {
removeServer(selectedServer); removeServer(selectedServer);
},
}, },
}, ]}
]} showCancelButton={true}
showCancelButton={true} />
/>
<Dialog
visible={dialogVisible}
panDirection={PanningProvider.Directions.DOWN}
onDismiss={() => setDialogVisible(false)}
>
<View backgroundColor="white" style={styles.dialog}>
<Text>{translate('core.inputServerUrl')}:</Text>
<Dialog <TextField
visible={dialogVisible} style={styles.textInput}
panDirection={PanningProvider.Directions.DOWN} migrate={true}
onDismiss={() => setDialogVisible(false)} inputMode="url"
> value={serverUrl}
<View backgroundColor="white" style={styles.dialog}> onChangeText={setServerUrl}
<Text>{translate('core.inputServerUrl')}:</Text> />
<TextInput <Button
style={styles.textInput} label={translate('core.confirm')}
inputMode="url" disabled={loading}
value={serverUrl} onPress={async () => {
onChangeText={setServerUrl} if (!isValidUrl(serverUrl)) {
/> Alert.alert(translate('core.invalidUrl'));
return;
}
<Button setLoading(true);
label={translate('core.confirm')} try {
disabled={loading} await addServer(serverUrl);
onPress={async () => { setDialogVisible(false);
if (!isValidUrl(serverUrl)) { } catch (e) {
Alert.alert(translate('core.invalidUrl')); Alert.alert(translate('core.addServerError'));
return; }
}
setLoading(true); setLoading(false);
try { }}
await addServer(serverUrl); />
setDialogVisible(false); </View>
} catch (e) { </Dialog>
Alert.alert(translate('core.addServerError')); </ScrollView>
}
setLoading(false); <View>
}} <TouchableOpacity
/> onPress={() => {
</View> Clipboard.setString(cid);
</Dialog> showToast(translate('core.copySuccess'));
</ScrollView> }}
>
<Text grey40 center={true}>
cid: {cid}
</Text>
</TouchableOpacity>
</View>
{toastEl}
</View>
); );
}); });
Entry.displayName = 'Entry'; Entry.displayName = 'Entry';
@ -109,6 +140,9 @@ const styles = StyleSheet.create({
height: '100%', height: '100%',
padding: 20, padding: 20,
}, },
main: {
flex: 1,
},
item: { item: {
marginBottom: 8, marginBottom: 8,
}, },

@ -1,11 +1,6 @@
import React from 'react'; import React from 'react';
import { import { StyleProp, StyleSheet, ViewStyle } from 'react-native';
StyleProp, import { TouchableOpacity, Text } from 'react-native-ui-lib';
StyleSheet,
Text,
TouchableOpacity,
ViewStyle,
} from 'react-native';
interface ServerCardProps { interface ServerCardProps {
style?: StyleProp<ViewStyle>; style?: StyleProp<ViewStyle>;
@ -24,10 +19,16 @@ export const ServerCard: React.FC<ServerCardProps> = React.memo((props) => {
> >
<Text style={styles.name}>{props.name}</Text> <Text style={styles.name}>{props.name}</Text>
{props.url && <Text style={styles.url}>{props.url}</Text>} {props.url && (
<Text style={styles.url} grey30>
{props.url}
</Text>
)}
{props.version && ( {props.version && (
<Text style={styles.version}>version: {props.version}</Text> <Text style={styles.version} grey30>
version: {props.version}
</Text>
)} )}
</TouchableOpacity> </TouchableOpacity>
); );
@ -49,12 +50,12 @@ const styles = StyleSheet.create({
textAlign: 'center', textAlign: 'center',
}, },
version: { version: {
color: '#999', // color: '#999',
textAlign: 'center', textAlign: 'center',
fontSize: 10, fontSize: 10,
}, },
url: { url: {
color: '#999', // color: '#999',
textAlign: 'center', textAlign: 'center',
}, },
}); });

@ -0,0 +1,28 @@
import React, { useCallback, useState } from 'react';
import { Incubator, ToastPresets } from 'react-native-ui-lib';
const { Toast } = Incubator;
export function useToast() {
const [visible, setVisible] = useState(false);
const [message, setMessage] = useState('');
const showToast = useCallback((text: string) => {
setVisible(true);
setMessage(text);
}, []);
return {
showToast,
toastEl: (
<Toast
preset={ToastPresets.SUCCESS}
visible={visible}
message={message}
onDismiss={() => setVisible(false)}
autoDismiss={3500}
swipeable={true}
/>
),
};
}

@ -4,6 +4,7 @@
"core.deleteServer": "Delete Server", "core.deleteServer": "Delete Server",
"core.inputServerUrl": "Input Server Url", "core.inputServerUrl": "Input Server Url",
"core.confirm": "Confirm", "core.confirm": "Confirm",
"core.copySuccess": "Copy Success",
"core.invalidUrl": "Input is not a valid url", "core.invalidUrl": "Input is not a valid url",
"core.addServerError": "Failed to add server, maybe the address entered is not a Tailchat service address", "core.addServerError": "Failed to add server, maybe the address entered is not a Tailchat service address",
"core.foregroundServiceTip": "Continue to keep the service running normally, and may not be able to receive message pushes after closing", "core.foregroundServiceTip": "Continue to keep the service running normally, and may not be able to receive message pushes after closing",

@ -4,6 +4,7 @@
"core.deleteServer": "删除服务器", "core.deleteServer": "删除服务器",
"core.inputServerUrl": "输入服务器地址", "core.inputServerUrl": "输入服务器地址",
"core.confirm": "确认", "core.confirm": "确认",
"core.copySuccess": "复制成功",
"core.invalidUrl": "输入不是一个有效的url", "core.invalidUrl": "输入不是一个有效的url",
"core.addServerError": "添加服务器失败, 可能输入的地址不是一个Tailchat服务地址", "core.addServerError": "添加服务器失败, 可能输入的地址不是一个Tailchat服务地址",
"core.foregroundServiceTip": "持续保持服务正常运行, 关闭后可能无法正常接受到消息推送", "core.foregroundServiceTip": "持续保持服务正常运行, 关闭后可能无法正常接受到消息推送",

@ -1679,6 +1679,11 @@
prompts "^2.4.0" prompts "^2.4.0"
semver "^6.3.0" semver "^6.3.0"
"@react-native-community/clipboard@^1.5.1":
version "1.5.1"
resolved "https://registry.npmmirror.com/@react-native-community/clipboard/-/clipboard-1.5.1.tgz#32abb3ea2eb91ee3f9c5fb1d32d5783253c9fabe"
integrity sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA==
"@react-native-community/eslint-config@^3.2.0": "@react-native-community/eslint-config@^3.2.0":
version "3.2.0" version "3.2.0"
resolved "https://registry.npmmirror.com/@react-native-community/eslint-config/-/eslint-config-3.2.0.tgz#42f677d5fff385bccf1be1d3b8faa8c086cf998d" resolved "https://registry.npmmirror.com/@react-native-community/eslint-config/-/eslint-config-3.2.0.tgz#42f677d5fff385bccf1be1d3b8faa8c086cf998d"

Loading…
Cancel
Save