@@ -71,6 +71,9 @@ const PopupDefaultExample = ({
7171 } ) ;
7272 const [ editingShortcut , setEditingShortcut ] = useState < string | null > ( null ) ;
7373 const [ shortcutError , setShortcutError ] = useState ( '' ) ;
74+ const [ updateStatus , setUpdateStatus ] = useState < 'idle' | 'checking' | 'downloading' | 'ready' | 'up-to-date' | 'error' > ( 'idle' ) ;
75+ const [ updateReleaseName , setUpdateReleaseName ] = useState ( '' ) ;
76+ const [ updateTimer , setUpdateTimer ] = useState < ReturnType < typeof setTimeout > | null > ( null ) ;
7477
7578 useEffect ( ( ) => {
7679 ( window as any ) . electronAPI . getAppVersion ( ) . then ( ( version : string ) => {
@@ -107,6 +110,12 @@ const PopupDefaultExample = ({
107110 ( window as any ) . electronAPI . getShortcuts ( ) . then ( ( s : typeof shortcuts ) => {
108111 if ( s ) setShortcuts ( s ) ;
109112 } ) ;
113+ ( window as any ) . electronAPI . onUpdateStatus ( ( _event : any , data : any ) => {
114+ setUpdateStatus ( data . status ) ;
115+ if ( data . releaseName ) setUpdateReleaseName ( data . releaseName ) ;
116+ // Clear timeout when we get a real response
117+ setUpdateTimer ( ( prev ) => { if ( prev ) clearTimeout ( prev ) ; return null ; } ) ;
118+ } ) ;
110119 } , [ ] ) ;
111120
112121 useEffect ( ( ) => {
@@ -205,6 +214,14 @@ const PopupDefaultExample = ({
205214 setShortcutError ( '' ) ;
206215 } ;
207216
217+ const triggerUpdateCheck = ( ) => {
218+ setUpdateStatus ( 'checking' ) ;
219+ if ( updateTimer ) clearTimeout ( updateTimer ) ;
220+ const timer = setTimeout ( ( ) => setUpdateStatus ( 'error' ) , 30000 ) ;
221+ setUpdateTimer ( timer ) ;
222+ ( window as any ) . electronAPI . checkForUpdate ( ) ;
223+ } ;
224+
208225 const shortcutRows = [
209226 { key : 'quickSwitcher' , label : 'Quick Switcher' } ,
210227 { key : 'aiInsight' , label : 'AI Insight' } ,
@@ -229,9 +246,44 @@ const PopupDefaultExample = ({
229246 } }
230247 >
231248 < style > { `@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }` } </ style >
232- { /* Version + Quit — compact top bar */ }
249+ { /* Version + Update + Quit — compact top bar */ }
233250 < div style = { { display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' , padding : '6px 16px' , borderBottom : '1px solid #333' } } >
234- < span style = { { fontSize : '11px' , color : '#666' } } > v{ appVersion } </ span >
251+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '6px' } } >
252+ < span style = { { fontSize : '11px' , color : '#666' } } > v{ appVersion } </ span >
253+ { updateStatus === 'idle' && (
254+ < span
255+ onClick = { triggerUpdateCheck }
256+ style = { { fontSize : '10px' , color : THEME . primary , cursor : 'pointer' } }
257+ >
258+ Check for Update
259+ </ span >
260+ ) }
261+ { updateStatus === 'checking' && (
262+ < span style = { { fontSize : '10px' , color : '#888' } } > Checking...</ span >
263+ ) }
264+ { updateStatus === 'downloading' && (
265+ < span style = { { fontSize : '10px' , color : '#888' } } > Downloading...</ span >
266+ ) }
267+ { updateStatus === 'ready' && (
268+ < span
269+ onClick = { ( ) => ( window as any ) . electronAPI . installUpdate ( ) }
270+ style = { { fontSize : '10px' , color : '#4CAF50' , cursor : 'pointer' , fontWeight : 600 } }
271+ >
272+ { updateReleaseName ? `${ updateReleaseName } ready — ` : '' } Install & Restart
273+ </ span >
274+ ) }
275+ { updateStatus === 'up-to-date' && (
276+ < span style = { { fontSize : '10px' , color : '#888' } } > Latest</ span >
277+ ) }
278+ { updateStatus === 'error' && (
279+ < span
280+ onClick = { triggerUpdateCheck }
281+ style = { { fontSize : '10px' , color : '#e05252' , cursor : 'pointer' } }
282+ >
283+ Retry
284+ </ span >
285+ ) }
286+ </ div >
235287 < span
236288 onClick = { ( ) => closeAppClick ( ) }
237289 style = { { fontSize : '11px' , color : '#CC6666' , cursor : 'pointer' , textDecoration : 'underline' } }
0 commit comments