11import { invoke } from "@tauri-apps/api" ;
22import {
3- LogicalSize ,
43 appWindow ,
4+ LogicalSize ,
55 type PhysicalSize ,
66} from "@tauri-apps/api/window" ;
7- import { useCallback , useEffect , useRef , useState } from "react" ;
7+ import {
8+ lazy ,
9+ memo ,
10+ useCallback ,
11+ useEffect ,
12+ useMemo ,
13+ useRef ,
14+ useState ,
15+ } from "react" ;
816import { StyleSheet , View } from "react-native" ;
917import { DEBUG_MODE , IN_GAME , IN_GAME_PROCESS_ID } from "./constants/app" ;
10- import AddThirdPartyServerModal from "./containers/AddThirdPartyServer" ;
11- import ExternalServerHandler from "./containers/ExternalServerHandler" ;
12- import JoinServerPrompt from "./containers/JoinServerPrompt" ;
1318import LoadingScreen from "./containers/LoadingScreen" ;
14- import MainView from "./containers/MainBody" ;
15- import MessageBox from "./containers/MessageBox" ;
16- import NavBar from "./containers/NavBar" ;
17- import Notification from "./containers/Notification" ;
18- import ContextMenu from "./containers/ServerContextMenu" ;
19- import SettingsModal from "./containers/Settings" ;
2019import WindowTitleBar from "./containers/WindowTitleBar" ;
21- import i18n from "./locales" ;
20+ import { changeLanguage } from "./locales" ;
2221import { useGenericPersistentState } from "./states/genericStates" ;
2322import { useTheme } from "./states/theme" ;
24- import { debounce } from "./utils/debounce" ;
23+ import { throttle } from "./utils/debounce" ;
2524import {
2625 checkIfProcessAlive ,
2726 fetchServers ,
2827 fetchUpdateInfo ,
2928 generateLanguageFilters ,
3029} from "./utils/helpers" ;
30+ import PerformanceMonitor from "./utils/performance" ;
3131import { sc } from "./utils/sizeScaler" ;
32- // import MouseFollower from "./components/MouseFollower";
3332
34- const App = ( ) => {
33+ // Lazy load heavy components for better initial load time
34+ const MainView = lazy ( ( ) => import ( "./containers/MainBody" ) ) ;
35+ const NavBar = lazy ( ( ) => import ( "./containers/NavBar" ) ) ;
36+ const AddThirdPartyServerModal = lazy (
37+ ( ) => import ( "./containers/AddThirdPartyServer" )
38+ ) ;
39+ const ExternalServerHandler = lazy (
40+ ( ) => import ( "./containers/ExternalServerHandler" )
41+ ) ;
42+ const JoinServerPrompt = lazy ( ( ) => import ( "./containers/JoinServerPrompt" ) ) ;
43+ const MessageBox = lazy ( ( ) => import ( "./containers/MessageBox" ) ) ;
44+ const Notification = lazy ( ( ) => import ( "./containers/Notification" ) ) ;
45+ const ContextMenu = lazy ( ( ) => import ( "./containers/ServerContextMenu" ) ) ;
46+ const SettingsModal = lazy ( ( ) => import ( "./containers/Settings" ) ) ;
47+
48+ const App = memo ( ( ) => {
3549 const [ loading , setLoading ] = useState ( ! IN_GAME ) ;
3650 const [ maximized , setMaximized ] = useState ( false ) ;
3751 const { theme } = useTheme ( ) ;
3852 const { language } = useGenericPersistentState ( ) ;
3953 const windowSize = useRef < PhysicalSize > ( ) ;
4054 const mainWindowSize = useRef < LogicalSize > ( ) ;
55+ const processCheckInterval = useRef < NodeJS . Timeout > ( ) ;
4156
4257 const windowResizeListener = useCallback (
43- debounce ( async ( { payload } : { payload : PhysicalSize } ) => {
44- if (
45- payload . width !== windowSize . current ?. width ||
46- payload . height !== windowSize . current ?. height
47- )
48- setMaximized ( await appWindow . isMaximized ( ) ) ;
49-
50- windowSize . current = payload ;
51- } , 50 ) ,
58+ throttle ( async ( { payload } : { payload : PhysicalSize } ) => {
59+ const endTimer = PerformanceMonitor . time ( "window-resize" ) ;
60+
61+ try {
62+ const hasChanged =
63+ payload . width !== windowSize . current ?. width ||
64+ payload . height !== windowSize . current ?. height ;
65+
66+ if ( hasChanged ) {
67+ const isMaximized = await appWindow . isMaximized ( ) ;
68+ setMaximized ( isMaximized ) ;
69+ windowSize . current = payload ;
70+ }
71+ } finally {
72+ endTimer ( ) ;
73+ }
74+ } , 100 ) , // Increased throttle delay for better performance
5275 [ ]
5376 ) ;
5477
55- const initializeApp = async ( ) => {
56- fetchServers ( ) ;
57- fetchUpdateInfo ( ) ;
58- generateLanguageFilters ( ) ;
59-
60- mainWindowSize . current = ( await appWindow . innerSize ( ) ) . toLogical (
61- await appWindow . scaleFactor ( )
62- ) ;
63- // Set window attributes for loading screen
64- appWindow . setResizable ( false ) ;
65- appWindow . setSize ( new LogicalSize ( 250 , 300 ) ) ;
66- appWindow . center ( ) ;
67- } ;
78+ const initializeApp = useCallback ( async ( ) => {
79+ const endTimer = PerformanceMonitor . time ( "app-initialization" ) ;
80+
81+ try {
82+ const [ innerSize , scaleFactor ] = await Promise . all ( [
83+ appWindow . innerSize ( ) ,
84+ appWindow . scaleFactor ( ) ,
85+ ] ) ;
86+
87+ mainWindowSize . current = innerSize . toLogical ( scaleFactor ) ;
88+
89+ // Set window attributes for loading screen
90+ await Promise . all ( [
91+ appWindow . setSize ( new LogicalSize ( 250 , 300 ) ) ,
92+ appWindow . setResizable ( false ) ,
93+ appWindow . center ( ) ,
94+ ] ) ;
95+
96+ // Run independent operations in parallel
97+ await Promise . all ( [
98+ // Start these operations without waiting
99+ fetchServers ( ) ,
100+ fetchUpdateInfo ( ) ,
101+ generateLanguageFilters ( ) ,
102+ ] ) ;
103+ } finally {
104+ endTimer ( ) ;
105+ }
106+ } , [ ] ) ;
68107
69108 useEffect ( ( ) => {
70- i18n . changeLanguage ( language ) ;
109+ changeLanguage ( language as any ) ;
71110 } , [ language ] ) ;
72111
73112 useEffect ( ( ) => {
74113 let killResizeListener : ( ( ) => void ) | null = null ;
75114
76115 const setupListeners = async ( ) => {
77- document . addEventListener ( "contextmenu" , ( event ) => {
78- try {
79- if ( DEBUG_MODE == false ) {
80- event . preventDefault ( ) ;
81- }
82- } catch ( e ) { }
83- } ) ;
116+ // Optimize context menu handler
117+ if ( ! DEBUG_MODE ) {
118+ const handleContextMenu = ( event : Event ) => {
119+ event . preventDefault ( ) ;
120+ } ;
121+ document . addEventListener ( "contextmenu" , handleContextMenu , {
122+ passive : false ,
123+ } ) ;
124+ }
84125
85126 killResizeListener = await appWindow . onResized ( windowResizeListener ) ;
86127 } ;
87128
129+ const setupGameMonitoring = ( ) => {
130+ if ( IN_GAME ) {
131+ processCheckInterval . current = setInterval ( async ( ) => {
132+ try {
133+ const isAlive = await checkIfProcessAlive ( IN_GAME_PROCESS_ID ) ;
134+ if ( ! isAlive ) {
135+ await invoke ( "send_message_to_game" , {
136+ id : IN_GAME_PROCESS_ID ,
137+ message : "close_overlay" ,
138+ } ) ;
139+ setTimeout ( ( ) => appWindow . close ( ) , 300 ) ;
140+ }
141+ } catch ( error ) {
142+ console . error ( "Game process check failed:" , error ) ;
143+ }
144+ } , 1000 ) ; // Reduced frequency for better performance
145+ }
146+ } ;
147+
88148 setupListeners ( ) ;
89149 initializeApp ( ) ;
90-
91- if ( IN_GAME ) {
92- setInterval ( async ( ) => {
93- if ( ( await checkIfProcessAlive ( IN_GAME_PROCESS_ID ) ) == false ) {
94- invoke ( "send_message_to_game" , {
95- id : IN_GAME_PROCESS_ID ,
96- message : "close_overlay" ,
97- } ) ;
98- setTimeout ( ( ) => {
99- appWindow . close ( ) ;
100- } , 300 ) ;
101- }
102- } , 200 ) ;
103- }
150+ setupGameMonitoring ( ) ;
104151
105152 return ( ) => {
106- if ( killResizeListener ) killResizeListener ( ) ;
153+ killResizeListener ?.( ) ;
154+ if ( processCheckInterval . current ) {
155+ clearInterval ( processCheckInterval . current ) ;
156+ }
107157 } ;
158+ } , [ windowResizeListener , initializeApp ] ) ;
159+
160+ const handleLoadingEnd = useCallback ( async ( ) => {
161+ const endTimer = PerformanceMonitor . time ( "loading-end" ) ;
162+
163+ try {
164+ const targetSize = mainWindowSize . current || new LogicalSize ( 1000 , 700 ) ;
165+
166+ await Promise . all ( [
167+ appWindow . setResizable ( true ) ,
168+ appWindow . setSize ( targetSize ) ,
169+ appWindow . center ( ) ,
170+ ] ) ;
171+
172+ setLoading ( false ) ;
173+ } finally {
174+ endTimer ( ) ;
175+ }
108176 } , [ ] ) ;
109177
178+ const appStyle = useMemo (
179+ ( ) => [ styles . app , { padding : maximized || IN_GAME ? 0 : 4 } ] ,
180+ [ maximized ]
181+ ) ;
182+
183+ const appViewStyle = useMemo (
184+ ( ) => [
185+ styles . appView ,
186+ {
187+ borderRadius : maximized || IN_GAME ? 0 : 10 ,
188+ backgroundColor : theme . secondary ,
189+ } ,
190+ ] ,
191+ [ maximized , theme . secondary ]
192+ ) ;
193+
110194 if ( loading ) {
111- return (
112- < LoadingScreen
113- onEnd = { async ( ) => {
114- await appWindow . setResizable ( true ) ;
115- await appWindow . setSize (
116- mainWindowSize . current
117- ? mainWindowSize . current
118- : new LogicalSize ( 1000 , 700 )
119- ) ;
120- await appWindow . center ( ) ;
121- setLoading ( false ) ;
122- } }
123- />
124- ) ;
195+ return < LoadingScreen onEnd = { handleLoadingEnd } /> ;
125196 }
126197
127198 return (
128- < View
129- style = { [ styles . app , { padding : maximized || IN_GAME ? 0 : 4 } ] }
130- key = { language }
131- >
132- < View
133- style = { [
134- styles . appView ,
135- {
136- borderRadius : maximized || IN_GAME ? 0 : sc ( 10 ) ,
137- backgroundColor : theme . secondary ,
138- } ,
139- ] }
140- >
199+ < View style = { appStyle } key = { language } >
200+ < View style = { appViewStyle } >
141201 < WindowTitleBar />
142202 < View style = { styles . appBody } >
143203 < NavBar />
@@ -153,7 +213,9 @@ const App = () => {
153213 </ View >
154214 </ View >
155215 ) ;
156- } ;
216+ } ) ;
217+
218+ App . displayName = "App" ;
157219
158220const styles = StyleSheet . create ( {
159221 app : {
0 commit comments