@@ -43,6 +43,7 @@ class CodexUsageIndicator extends PanelMenu.Button {
4343 this . _extension = extension ;
4444 this . _settings = extension . getSettings ( ) ;
4545 this . _refreshId = 0 ;
46+ this . _refreshSpinId = 0 ;
4647 this . _refreshInFlight = false ;
4748 this . _snapshot = null ;
4849 this . _errorMessage = null ;
@@ -70,6 +71,11 @@ class CodexUsageIndicator extends PanelMenu.Button {
7071 this . _refreshId = 0 ;
7172 }
7273
74+ if ( this . _refreshSpinId ) {
75+ GLib . source_remove ( this . _refreshSpinId ) ;
76+ this . _refreshSpinId = 0 ;
77+ }
78+
7379 if ( this . _settingsChangedId ) {
7480 this . _settings . disconnect ( this . _settingsChangedId ) ;
7581 this . _settingsChangedId = 0 ;
@@ -211,8 +217,10 @@ class CodexUsageIndicator extends PanelMenu.Button {
211217 x_align : Clutter . ActorAlign . END ,
212218 y_align : Clutter . ActorAlign . CENTER ,
213219 } ) ;
220+ const refreshIcon = refreshButton . child ;
221+ refreshIcon . set_pivot_point ( 0.5 , 0.5 ) ;
214222 refreshButton . connect ( 'clicked' , ( ) => {
215- void this . _refreshUsage ( ) ;
223+ void this . _refreshUsage ( { manual : true } ) ;
216224 } ) ;
217225
218226 const datetimeLabel = new St . Label ( {
@@ -227,6 +235,7 @@ class CodexUsageIndicator extends PanelMenu.Button {
227235 box . add_child ( datetimeLabel ) ;
228236 item . add_child ( box ) ;
229237 item . datetimeLabel = datetimeLabel ;
238+ item . refreshIcon = refreshIcon ;
230239 item . refreshButton = refreshButton ;
231240
232241 return item ;
@@ -309,18 +318,23 @@ class CodexUsageIndicator extends PanelMenu.Button {
309318 ) ;
310319 }
311320
312- async _refreshUsage ( ) {
321+ async _refreshUsage ( { manual = false } = { } ) {
313322 if ( this . _refreshInFlight )
314323 return ;
315324
316325 this . _refreshInFlight = true ;
317326
327+ if ( manual )
328+ this . _startRefreshSpin ( ) ;
329+
318330 try {
319331 this . _snapshot = await fetchCodexUsageSnapshot ( ) ;
320332 this . _errorMessage = null ;
321333 } catch ( error ) {
322334 this . _errorMessage = error ?. message ?? 'Unable to load Codex usage.' ;
323335 } finally {
336+ if ( manual )
337+ this . _stopRefreshSpin ( ) ;
324338 this . _refreshInFlight = false ;
325339 this . _syncLabel ( ) ;
326340 this . _syncMenu ( ) ;
@@ -344,6 +358,38 @@ class CodexUsageIndicator extends PanelMenu.Button {
344358 return safeMinutes * 60 ;
345359 }
346360
361+ _startRefreshSpin ( ) {
362+ if ( ! this . _headerItem ?. refreshIcon || this . _refreshSpinId )
363+ return ;
364+
365+ this . _headerItem . refreshButton . reactive = false ;
366+ this . _headerItem . refreshButton . can_focus = false ;
367+
368+ this . _refreshSpinId = GLib . timeout_add (
369+ GLib . PRIORITY_DEFAULT ,
370+ 30 ,
371+ ( ) => {
372+ this . _headerItem . refreshIcon . rotation_angle_z =
373+ ( this . _headerItem . refreshIcon . rotation_angle_z + 18 ) % 360 ;
374+ return GLib . SOURCE_CONTINUE ;
375+ }
376+ ) ;
377+ }
378+
379+ _stopRefreshSpin ( ) {
380+ if ( this . _refreshSpinId ) {
381+ GLib . source_remove ( this . _refreshSpinId ) ;
382+ this . _refreshSpinId = 0 ;
383+ }
384+
385+ if ( ! this . _headerItem ?. refreshIcon )
386+ return ;
387+
388+ this . _headerItem . refreshIcon . rotation_angle_z = 0 ;
389+ this . _headerItem . refreshButton . reactive = true ;
390+ this . _headerItem . refreshButton . can_focus = true ;
391+ }
392+
347393 _syncLabel ( ) {
348394 if ( ! this . _snapshot ) {
349395 this . _label . text = this . _errorMessage ? 'CX !' : 'CX --' ;
0 commit comments