Skip to content

Commit a6dc348

Browse files
committed
Add open URL and copy text click events support.
1 parent 4965b0b commit a6dc348

File tree

3 files changed

+58
-19
lines changed

3 files changed

+58
-19
lines changed

src/minecraft/chatToJsx.tsx

+21-11
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ export interface TranslatedChat {
7575
export type MinecraftChat = PlainTextChat | TranslatedChat | string
7676

7777
export interface ClickEvent {
78-
// TODO: Build actual support for this.
7978
action:
8079
| 'open_url'
8180
| 'open_file'
@@ -166,6 +165,7 @@ const parseChatToJsx = (
166165
chat: MinecraftChat,
167166
Component: React.ComponentType<TextProps>,
168167
colorMap: ColorMap,
168+
clickEventHandler: (clickEvent: ClickEvent) => void = () => {},
169169
componentProps?: {},
170170
trim = false
171171
) => {
@@ -197,8 +197,15 @@ const parseChatToJsx = (
197197
if (c.color && c.color.startsWith('#')) style.color = c.color
198198
else if (c.color && colorMap[c.color]) style.color = colorMap[c.color]
199199

200+
const ce = c.clickEvent
200201
return (
201-
<Component key={i} style={style}>
202+
<Component
203+
key={i}
204+
style={style}
205+
selectable
206+
onPress={ce ? () => clickEventHandler(ce) : undefined}
207+
onLongPress={() => {}}
208+
>
202209
{c.text ? (trim ? trimLines(c.text) : c.text) : ''}
203210
</Component>
204211
)
@@ -208,21 +215,24 @@ const parseChatToJsx = (
208215
}
209216

210217
// React Component-ised.
211-
const ChatToJsxNonMemo = ({
212-
chat,
213-
component,
214-
colorMap,
215-
componentProps,
216-
trim
217-
}: {
218+
const ChatToJsxNonMemo = (props: {
218219
chat: MinecraftChat
219220
component: React.ComponentType<TextProps>
220221
colorMap: ColorMap
221222
componentProps?: {}
223+
clickEventHandler?: (clickEvent: ClickEvent) => void
222224
trim?: boolean
223-
}) => parseChatToJsx(chat, component, colorMap, componentProps, trim)
225+
}) =>
226+
parseChatToJsx(
227+
props.chat,
228+
props.component,
229+
props.colorMap,
230+
props.clickEventHandler,
231+
props.componentProps,
232+
props.trim
233+
)
224234
// Memoisation means this is only re-rendered if the props changed.
225-
// TODO: This over parsing might be hurting performance...
235+
// TODO: This might be hurting performance...
226236
export const ChatToJsx = React.memo(ChatToJsxNonMemo)
227237

228238
export const parseValidJson = (text: string) => {

src/screens/ChatScreen.tsx

+36-7
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import {
44
StyleSheet,
55
View,
66
ActivityIndicator,
7-
Platform
7+
Platform,
8+
Linking,
9+
Clipboard
810
} from 'react-native'
911
import Ionicons from 'react-native-vector-icons/Ionicons'
1012
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
1113

1214
import globalStyle from '../globalStyle'
1315
import useDarkMode from '../context/useDarkMode'
14-
import SettingsContext from '../context/settingsContext'
1516
import ConnectionContext from '../context/connectionContext'
17+
import SettingsContext, { Settings } from '../context/settingsContext'
1618
import {
1719
ChatToJsx,
1820
parseValidJson,
@@ -37,22 +39,45 @@ interface Message {
3739
text: MinecraftChat
3840
}
3941

40-
const renderItem = (colorMap: ColorMap) => {
42+
const renderItem = (colorMap: ColorMap, settings: Settings) => {
4143
const ItemRenderer = ({ item }: { item: Message }) => (
4244
<View style={styles.androidScaleInvert}>
43-
<ChatToJsx chat={item.text} component={Text} colorMap={colorMap} />
45+
<ChatToJsx
46+
chat={item.text}
47+
component={Text}
48+
colorMap={colorMap}
49+
clickEventHandler={async ce => {
50+
// TODO: run_command, suggest_command and URL prompt support.
51+
if (
52+
ce.action === 'open_url' &&
53+
settings.webLinks &&
54+
(ce.value.startsWith('https://') || ce.value.startsWith('http://'))
55+
) {
56+
await Linking.openURL(ce.value)
57+
} else if (ce.action === 'copy_to_clipboard') {
58+
Clipboard.setString(ce.value)
59+
} // No open_file/change_page handling.
60+
}}
61+
/>
4462
</View>
4563
)
4664
return ItemRenderer // LOW-TODO: Performance implications?
4765
} // https://reactnative.dev/docs/optimizing-flatlist-configuration
48-
const ChatMessageList = (props: { messages: Message[]; darkMode: boolean }) => {
66+
const ChatMessageList = (props: {
67+
messages: Message[]
68+
darkMode: boolean
69+
settings: Settings
70+
}) => {
4971
return (
5072
<FlatList
5173
inverted={Platform.OS !== 'android'}
5274
data={props.messages}
5375
style={[styles.androidScaleInvert, styles.chatArea]}
5476
contentContainerStyle={styles.chatAreaScrollView}
55-
renderItem={renderItem(props.darkMode ? mojangColorMap : lightColorMap)}
77+
renderItem={renderItem(
78+
props.darkMode ? mojangColorMap : lightColorMap,
79+
props.settings
80+
)}
5681
/>
5782
)
5883
}
@@ -207,7 +232,11 @@ const ChatScreen = ({ navigation }: { navigation: ChatNavigationProp }) => {
207232
)}
208233
{loggedIn && (
209234
<>
210-
<ChatMessageListMemo messages={messages} darkMode={darkMode} />
235+
<ChatMessageListMemo
236+
messages={messages}
237+
darkMode={darkMode}
238+
settings={settings}
239+
/>
211240
<View style={darkMode ? styles.textAreaDark : styles.textArea}>
212241
<TextField
213242
value={message}

src/screens/settings/SettingScreen.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const SettingScreen = (props: { button?: JSX.Element }) => {
4040
setValue={sendSpawnCommand => setSettings({ sendSpawnCommand })}
4141
/>
4242
<Setting
43-
name='Enable web links'
43+
name='Enable clicking web links'
4444
value={settings.webLinks}
4545
setValue={webLinks => setSettings({ webLinks })}
4646
/>

0 commit comments

Comments
 (0)