11import { listen } from "@tauri-apps/api/event" ;
22import { relaunch } from "@tauri-apps/plugin-process" ;
33import { check } from "@tauri-apps/plugin-updater" ;
4+ import { RefreshCw } from "lucide-react" ;
45import type React from "react" ;
56import { useCallback , useEffect , useRef , useState } from "react" ;
67import ProgressBar from "@/components/shared/progress-bar" ;
78import { Button } from "@/components/ui/button" ;
89import { Spinner } from "@/components/ui/spinner" ;
10+ import {
11+ Tooltip ,
12+ TooltipContent ,
13+ TooltipProvider ,
14+ TooltipTrigger ,
15+ } from "@/components/ui/tooltip" ;
916import { cn } from "@/lib/utils" ;
1017
1118interface UpdateCheckerProps {
1219 className ?: string ;
1320}
1421
1522const UpdateChecker : React . FC < UpdateCheckerProps > = ( { className = "" } ) => {
16- // Update checking state
1723 const [ isChecking , setIsChecking ] = useState ( false ) ;
1824 const [ updateAvailable , setUpdateAvailable ] = useState ( false ) ;
1925 const [ isInstalling , setIsInstalling ] = useState ( false ) ;
@@ -28,7 +34,6 @@ const UpdateChecker: React.FC<UpdateCheckerProps> = ({ className = "" }) => {
2834 const downloadedBytesRef = useRef ( 0 ) ;
2935 const contentLengthRef = useRef ( 0 ) ;
3036
31- // Update checking functions
3237 const checkForUpdates = useCallback ( async ( ) => {
3338 if ( isCheckingRef . current ) {
3439 return ;
@@ -72,7 +77,6 @@ const UpdateChecker: React.FC<UpdateCheckerProps> = ({ className = "" }) => {
7277 useEffect ( ( ) => {
7378 checkForUpdates ( ) ;
7479
75- // Listen for update check events
7680 const updateUnlisten = listen ( "check-for-updates" , ( ) => {
7781 handleManualUpdateCheck ( ) ;
7882 } ) ;
@@ -130,23 +134,6 @@ const UpdateChecker: React.FC<UpdateCheckerProps> = ({ className = "" }) => {
130134 }
131135 } ;
132136
133- // Update status functions
134- const getUpdateStatusText = ( ) => {
135- if ( isInstalling ) {
136- if ( downloadProgress > 0 && downloadProgress < 100 ) {
137- return `Downloading... ${ downloadProgress . toString ( ) . padStart ( 3 ) } %` ;
138- }
139- return downloadProgress === 100 ? "Installing..." : "" ;
140- }
141- if ( showUpToDate ) {
142- return "Up to date" ;
143- }
144- if ( updateAvailable ) {
145- return "Update available" ;
146- }
147- return "Check for updates" ;
148- } ;
149-
150137 const getUpdateStatusAction = ( ) => {
151138 if ( updateAvailable && ! isInstalling ) {
152139 return installUpdate ;
@@ -162,40 +149,72 @@ const UpdateChecker: React.FC<UpdateCheckerProps> = ({ className = "" }) => {
162149 ! isUpdateDisabled && ( updateAvailable || ! isChecking ) ;
163150
164151 const showSpinner = isChecking || ( isInstalling && downloadProgress === 0 ) ;
152+ const isDownloading =
153+ isInstalling && downloadProgress > 0 && downloadProgress < 100 ;
154+ const showStatusText = updateAvailable || showUpToDate ;
155+
156+ const renderIconButton = ( ) => (
157+ < TooltipProvider >
158+ < Tooltip >
159+ < TooltipTrigger asChild >
160+ < Button
161+ className = "text-muted-foreground hover:text-foreground"
162+ disabled = { ! isUpdateClickable }
163+ onClick = { getUpdateStatusAction ( ) }
164+ size = "xs"
165+ variant = "ghost"
166+ >
167+ { showSpinner ? (
168+ < Spinner className = "size-3!" />
169+ ) : (
170+ < RefreshCw className = "size-3!" />
171+ ) }
172+ < span className = "sr-only" > Check for updates</ span >
173+ </ Button >
174+ </ TooltipTrigger >
175+ < TooltipContent side = "bottom" >
176+ { showSpinner ? "Checking..." : "Check for updates" }
177+ </ TooltipContent >
178+ </ Tooltip >
179+ </ TooltipProvider >
180+ ) ;
165181
166- return (
167- < div className = { cn ( "flex items-center gap-3" , className ) } >
168- < Button
169- className = { cn (
170- "min-w-32 items-center gap-2" ,
171- updateAvailable
172- ? "font-medium text-brand hover:text-brand/80"
173- : "text-text/60 hover:text-text/80"
174- ) }
175- disabled = { ! isUpdateClickable }
176- onClick = { getUpdateStatusAction ( ) }
177- size = "xs"
178- variant = "ghost"
179- >
180- { showSpinner ? (
181- < Spinner className = "size-3" />
182- ) : (
183- < span className = "tabular-nums" > { getUpdateStatusText ( ) } </ span >
184- ) }
185- </ Button >
186-
187- { isInstalling && downloadProgress > 0 && downloadProgress < 100 && (
188- < ProgressBar
189- progress = { [
190- {
191- id : "update" ,
192- percentage : downloadProgress ,
193- } ,
194- ] }
195- size = "large"
196- />
182+ const renderStatusText = ( ) => (
183+ < Button
184+ className = { cn (
185+ "items-center gap-2" ,
186+ updateAvailable
187+ ? "text-brand hover:text-brand/80"
188+ : "text-muted-foreground"
197189 ) }
198- </ div >
190+ disabled = { ! isUpdateClickable }
191+ onClick = { getUpdateStatusAction ( ) }
192+ size = "xs"
193+ variant = "ghost"
194+ >
195+ { updateAvailable ? "Update available" : "Up to date" }
196+ </ Button >
197+ ) ;
198+
199+ const renderProgressBar = ( ) => (
200+ < ProgressBar
201+ progress = { [ { id : "update" , percentage : downloadProgress } ] }
202+ size = "large"
203+ />
204+ ) ;
205+
206+ const renderContent = ( ) => {
207+ if ( isDownloading ) {
208+ return renderProgressBar ( ) ;
209+ }
210+ if ( showStatusText ) {
211+ return renderStatusText ( ) ;
212+ }
213+ return renderIconButton ( ) ;
214+ } ;
215+
216+ return (
217+ < div className = { cn ( "flex items-center" , className ) } > { renderContent ( ) } </ div >
199218 ) ;
200219} ;
201220
0 commit comments