Skip to content

Commit d49f3e5

Browse files
committed
Reorganise ChatScreen code, reduce unneeded state.
1 parent 3a3d805 commit d49f3e5

File tree

7 files changed

+102
-94
lines changed

7 files changed

+102
-94
lines changed

src/App.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import {
1515
} from '@react-navigation/native-stack'
1616
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'
1717

18-
import useAsyncStorage from './storage/useAsyncStorage'
19-
import useJsonAsyncStorage from './storage/useJsonAsyncStorage'
18+
import useAsyncStorage from './utilities/storage/useAsyncStorage'
19+
import useJsonAsyncStorage from './utilities/storage/useJsonAsyncStorage'
2020
import ConnectionContext, {
2121
type DisconnectReason
2222
} from './context/connectionContext'
@@ -29,7 +29,7 @@ import ServersContext, { type Servers } from './context/serversContext'
2929
import { ColorSchemeContext } from './context/useDarkMode'
3030
import DisconnectDialog from './components/DisconnectDialog'
3131
import { type ServerConnection } from './minecraft/connection'
32-
import ChatScreen from './screens/chat/ChatScreen'
32+
import ChatScreen from './screens/ChatScreen'
3333
import ServerScreen from './screens/ServerScreen'
3434
import AccountScreen from './screens/AccountScreen'
3535
import SettingScreen from './screens/SettingScreen'
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React, { useCallback } from 'react'
2+
import { FlatList, StyleSheet, type ListRenderItem } from 'react-native'
3+
import {
4+
ChatToJsx,
5+
type MinecraftChat,
6+
type ClickEvent,
7+
type ColorMap
8+
} from '../../minecraft/chatToJsx'
9+
import Text from '../../components/Text'
10+
11+
export interface Message {
12+
key: number
13+
text: MinecraftChat
14+
}
15+
16+
const MessageRenderer = (props: {
17+
item: Message
18+
colorMap: ColorMap
19+
clickEventHandler: (event: ClickEvent) => void
20+
}): JSX.Element => (
21+
<ChatToJsx
22+
chat={props.item.text}
23+
component={Text}
24+
colorMap={props.colorMap}
25+
clickEventHandler={props.clickEventHandler}
26+
/>
27+
)
28+
29+
const MessageRendererMemo = React.memo(
30+
MessageRenderer,
31+
(prev, next) =>
32+
prev.item.key === next.item.key &&
33+
prev.colorMap === next.colorMap &&
34+
prev.clickEventHandler === next.clickEventHandler
35+
)
36+
37+
const ChatMessageList = (props: {
38+
messages: Message[]
39+
colorMap: ColorMap
40+
clickEventHandler: (ce: ClickEvent) => void
41+
}): JSX.Element => {
42+
// If colorMap/clickEventHandler changes, this will change and cause a re-render.
43+
// If messages changes, FlatList will execute this function for all messages, and
44+
// ItemRendererMemo will check if props have changed instead of this useCallback.
45+
const renderItem = useCallback<ListRenderItem<Message>>(
46+
({ item }) => (
47+
<MessageRendererMemo
48+
item={item}
49+
colorMap={props.colorMap}
50+
clickEventHandler={props.clickEventHandler}
51+
/>
52+
),
53+
[props.colorMap, props.clickEventHandler]
54+
)
55+
return (
56+
<FlatList
57+
inverted
58+
data={props.messages}
59+
style={styles.chatArea}
60+
contentContainerStyle={styles.chatAreaScrollView}
61+
renderItem={renderItem}
62+
/>
63+
)
64+
}
65+
66+
const styles = StyleSheet.create({
67+
chatArea: { padding: 8, flex: 1 },
68+
chatAreaScrollView: { paddingBottom: 16 }
69+
})
70+
71+
export default ChatMessageList

src/screens/chat/ChatScreen.tsx renamed to src/screens/ChatScreen.tsx

+27-84
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ import React, {
66
useState
77
} from 'react'
88
import {
9-
FlatList,
109
StyleSheet,
1110
View,
1211
ActivityIndicator,
1312
Platform,
14-
Linking,
15-
type ListRenderItem
13+
Linking
1614
} from 'react-native'
1715
import Ionicons from 'react-native-vector-icons/Ionicons'
1816
import Clipboard from '@react-native-clipboard/clipboard'
@@ -22,89 +20,37 @@ import {
2220
packetHandler,
2321
enderChatPrefix,
2422
sendMessageError
25-
} from './packetHandler'
26-
import { getSession, createConnection } from './sessionBuilder'
27-
import { type RootStackParamList } from '../../App'
28-
import globalStyle from '../../globalStyle'
29-
import useDarkMode from '../../context/useDarkMode'
30-
import AccountsContext from '../../context/accountsContext'
31-
import ServersContext from '../../context/serversContext'
32-
import useSessionStore from '../../context/sessionStore'
33-
import SettingsContext from '../../context/settingsContext'
23+
} from '../utilities/connection/packetHandler'
24+
import {
25+
getSession,
26+
createConnection
27+
} from '../utilities/connection/connectionBuilder'
28+
import { type RootStackParamList } from '../App'
29+
import globalStyle from '../globalStyle'
30+
import useDarkMode from '../context/useDarkMode'
31+
import AccountsContext from '../context/accountsContext'
32+
import ServersContext from '../context/serversContext'
33+
import useSessionStore from '../context/sessionStore'
34+
import SettingsContext from '../context/settingsContext'
3435
import ConnectionContext, {
3536
type DisconnectReason
36-
} from '../../context/connectionContext'
37+
} from '../context/connectionContext'
3738
import {
38-
ChatToJsx,
3939
mojangColorMap,
4040
lightColorMap,
4141
type MinecraftChat,
42-
type ClickEvent,
43-
type ColorMap
44-
} from '../../minecraft/chatToJsx'
45-
import { makeChatMessagePacket } from '../../minecraft/packets/chat'
46-
import TextField from '../../components/TextField'
47-
import Text from '../../components/Text'
42+
type ClickEvent
43+
} from '../minecraft/chatToJsx'
44+
import { makeChatMessagePacket } from '../minecraft/packets/chat'
45+
import TextField from '../components/TextField'
46+
import Text from '../components/Text'
47+
import ChatMessageList, {
48+
type Message
49+
} from '../components/chat/ChatMessageList'
4850

4951
type Props = NativeStackScreenProps<RootStackParamList, 'Chat'>
5052

51-
export type Status = 'OPENING' | 'CONNECTING' | 'CONNECTED' | 'CLOSED'
52-
53-
interface Message {
54-
key: number
55-
text: MinecraftChat
56-
}
57-
58-
const ItemRenderer = (props: {
59-
item: Message
60-
colorMap: ColorMap
61-
clickEventHandler: (event: ClickEvent) => void
62-
}): JSX.Element => (
63-
<ChatToJsx
64-
chat={props.item.text}
65-
component={Text}
66-
colorMap={props.colorMap}
67-
clickEventHandler={props.clickEventHandler}
68-
/>
69-
)
70-
71-
const ItemRendererMemo = React.memo(
72-
ItemRenderer,
73-
(prev, next) =>
74-
prev.item.key === next.item.key &&
75-
prev.colorMap === next.colorMap &&
76-
prev.clickEventHandler === next.clickEventHandler
77-
)
78-
79-
const ChatMessageList = (props: {
80-
messages: Message[]
81-
colorMap: ColorMap
82-
clickEventHandler: (ce: ClickEvent) => void
83-
}): JSX.Element => {
84-
// If colorMap/clickEventHandler changes, this will change and cause a re-render.
85-
// If messages changes, FlatList will execute this function for all messages, and
86-
// ItemRendererMemo will check if props have changed instead of this useCallback.
87-
const renderItem = useCallback<ListRenderItem<Message>>(
88-
({ item }) => (
89-
<ItemRendererMemo
90-
item={item}
91-
colorMap={props.colorMap}
92-
clickEventHandler={props.clickEventHandler}
93-
/>
94-
),
95-
[props.colorMap, props.clickEventHandler]
96-
)
97-
return (
98-
<FlatList
99-
inverted
100-
data={props.messages}
101-
style={styles.chatArea}
102-
contentContainerStyle={styles.chatAreaScrollView}
103-
renderItem={renderItem}
104-
/>
105-
)
106-
}
107-
53+
export type Status = 'CONNECTING' | 'CONNECTED' | 'CLOSED'
10854
const handleError =
10955
(addMessage: (text: MinecraftChat) => void, translated: string) =>
11056
(error: unknown) => {
@@ -130,7 +76,7 @@ const ChatScreen = ({ navigation, route }: Props): JSX.Element => {
13076

13177
const messagesBufferRef = useRef<Message[]>([])
13278
const healthRef = useRef<number | null>(null)
133-
const statusRef = useRef<Status>(connection ? 'CONNECTING' : 'OPENING')
79+
const statusRef = useRef<Status>(connection ? 'CONNECTED' : 'CONNECTING')
13480
const idRef = useRef(0)
13581

13682
const { version, serverName } = route.params
@@ -173,8 +119,8 @@ const ChatScreen = ({ navigation, route }: Props): JSX.Element => {
173119

174120
// Create connection useEffect.
175121
useEffect(() => {
176-
if (statusRef.current === 'OPENING') {
177-
statusRef.current = 'CONNECTING'
122+
if (statusRef.current === 'CONNECTING') {
123+
statusRef.current = 'CONNECTED'
178124
;(async () => {
179125
const session = await getSession(
180126
version,
@@ -198,7 +144,7 @@ const ChatScreen = ({ navigation, route }: Props): JSX.Element => {
198144
setConnection,
199145
closeChatScreen
200146
)
201-
if ((statusRef.current as 'CLOSED' | 'CONNECTING') !== 'CLOSED') {
147+
if ((statusRef.current as Status) !== 'CLOSED') {
202148
if (typeof conn === 'string') {
203149
closeChatScreen({ server: serverName, reason: conn })
204150
} else {
@@ -224,7 +170,6 @@ const ChatScreen = ({ navigation, route }: Props): JSX.Element => {
224170
'packet',
225171
packetHandler(
226172
healthRef,
227-
statusRef,
228173
setLoading,
229174
connection,
230175
addMessage,
@@ -358,8 +303,6 @@ const styles = StyleSheet.create({
358303
backButton: { marginRight: 8 },
359304
backButtonIcon: { marginRight: 0 },
360305
sendButtonIcon: { marginRight: 0, marginLeft: 4 },
361-
chatArea: { padding: 8, flex: 1 },
362-
chatAreaScrollView: { paddingBottom: 16 },
363306
loadingScreen: { flex: 1, alignItems: 'center', justifyContent: 'center' },
364307
loadingScreenText: { paddingTop: 24, fontSize: 20 },
365308
textAreaDark: {

src/screens/chat/packetHandler.ts renamed to src/utilities/connection/packetHandler.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type React from 'react'
2-
import { type Status } from './ChatScreen'
32
import { type MinecraftChat, parseValidJson } from '../../minecraft/chatToJsx'
43
import {
54
ConnectionState,
@@ -90,7 +89,6 @@ const handleSystemMessage = (
9089
export const packetHandler =
9190
(
9291
healthRef: React.MutableRefObject<number | null>,
93-
statusRef: React.MutableRefObject<Status>,
9492
setLoading: React.Dispatch<React.SetStateAction<string>>,
9593
connection: ServerConnection,
9694
addMessage: (text: MinecraftChat) => any,
@@ -102,12 +100,8 @@ export const packetHandler =
102100
) =>
103101
(packet: Packet) => {
104102
const { protocolVersion: version } = connection.options
105-
if (
106-
statusRef.current === 'CONNECTING' &&
107-
connection.state === ConnectionState.LOGIN
108-
) {
103+
if (connection.state === ConnectionState.LOGIN) {
109104
setLoading('')
110-
statusRef.current = 'CONNECTED'
111105
const messageToSend = joinMessage.substring(0, charLimit).trim()
112106
if (sendJoinMessage && messageToSend) {
113107
connection

0 commit comments

Comments
 (0)