2121from textual import work , on
2222from textual .app import App , ComposeResult , SystemCommand
2323from textual .binding import Binding
24- from textual .widgets import Footer , Button , Header , Label , Input , Switch , Select , TabbedContent , TabPane , Log
24+ from textual .widgets import Footer , Button , Header , Label , Input , Switch , Select , TabbedContent , TabPane , Log , Static , ProgressBar
2525from textual .events import Print
26- from textual .containers import ScrollableContainer , Center , Grid , ItemGrid , Vertical
26+ from textual .containers import ScrollableContainer , Center , CenterMiddle , Grid , ItemGrid , Vertical
2727from textual .reactive import reactive
2828from textual .worker import Worker , WorkerState
2929from textual .screen import ModalScreen , Screen
@@ -55,15 +55,29 @@ def compose(self) -> ComposeResult:
5555 # Simple vertical layout: controls on top, big log on the bottom
5656 with Vertical (id = "fetch_layout" ):
5757 with Grid (id = "fetch_grid" ):
58- with Center (id = "center_welcome" ):
59- yield Label ("Who's this?" , id = "welcome_label" )
60- with Center (id = "center_watched" ):
61- yield Button (
62- "Checking if Very Vanilla MQ is up. 🍦" ,
63- id = "update_watched" ,
64- variant = "default" ,
65- tooltip = "is MQ down?" ,
66- )
58+ yield Select [str ](
59+ [("Live" , "LIVE" ), ("Test" , "TEST" ), ("Emu" , "EMU" )],
60+ id = "server_type_fetch" ,
61+ classes = "bordertitles" ,
62+ value = current_env ,
63+ prompt = "Select server type" ,
64+ allow_blank = False ,
65+ tooltip = (
66+ "The type of EQ server. Live and Test are official servers, "
67+ "while Emu is for unofficial servers."
68+ ),
69+ )
70+ with CenterMiddle (id = "centermiddle_welcome" ):
71+ with Center (id = "center_welcome" ):
72+ yield Label ("Who's this?" , id = "welcome_label" )
73+ with Center (id = "center_watched" ):
74+ yield Button (
75+ "Checking if Very Vanilla MQ is up. 🍦" ,
76+ id = "update_watched" ,
77+ variant = "default" ,
78+ tooltip = "is MQ down?" ,
79+ )
80+ yield Static ("" , id = "spacer_for_welcome_centering" )
6781 yield Button (
6882 "Update Single Resource" ,
6983 id = "update_resource_id" ,
@@ -76,16 +90,7 @@ def compose(self) -> ComposeResult:
7690 id = "resource_id_input" ,
7791 tooltip = "Update a single resource by its ID or URL." ,
7892 )
79- yield Select [str ](
80- [("Live" , "LIVE" ), ("Test" , "TEST" ), ("Emu" , "EMU" )],
81- id = "server_type_fetch" ,
82- value = current_env ,
83- allow_blank = False ,
84- tooltip = (
85- "The type of EQ server. Live and Test are official servers, "
86- "while Emu is for unofficial servers."
87- ),
88- )
93+ yield ProgressBar (total = None , show_eta = True , id = "update_progress" , classes = "hidden" )
8994 with Vertical (id = "fetch_log_container" ):
9095 # Toolbar row with log actions
9196 with Grid (id = "log_toolbar" ):
@@ -994,6 +999,7 @@ def on_mount(self) -> None:
994999
9951000 # Set border titles
9961001 self .query_one ("#server_type" ).border_title = "Server type"
1002+ self .query_one ("#server_type_fetch" ).border_title = "Server type"
9971003 self .query_one ("#inputs_grid" ).border_title = "Directories"
9981004 self .query_one ("#settings_grid" ).border_title = "Settings"
9991005 self .query_one ("#special_resources_grid" ).border_title = "Special Resources"
@@ -1750,6 +1756,34 @@ def cancel_update_watched(self):
17501756 if cancelled_workers :
17511757 self .notify ("Update canceled." , severity = "warning" )
17521758
1759+ def on_sync_event (self , event : tuple ) -> None :
1760+ """Handle events from the sync process to update the UI."""
1761+ event_type , resource_id , details = event
1762+ self ._process_sync_event (event_type , resource_id , details )
1763+
1764+ def _process_sync_event (self , event_type : str , resource_id : str | int , details : str | None ) -> None :
1765+ """Process sync events on the main thread."""
1766+ main_screen = self ._get_main_screen ()
1767+ if not main_screen :
1768+ return
1769+
1770+ try :
1771+ fetch_tab = main_screen .query_one (FetchTab )
1772+ progress_bar = fetch_tab .query_one ("#update_progress" , ProgressBar )
1773+ resource_input = fetch_tab .query_one ("#resource_id_input" , Input )
1774+
1775+ if event_type == "total" :
1776+ total_tasks = int (resource_id )
1777+ if total_tasks > 0 :
1778+ progress_bar .total = total_tasks
1779+ progress_bar .progress = 0
1780+ progress_bar .remove_class ("hidden" )
1781+ resource_input .add_class ("hidden" )
1782+ elif event_type == "done" :
1783+ progress_bar .advance (1 )
1784+ except Exception :
1785+ pass
1786+
17531787 async def run_synchronization (self , resource_ids = None ):
17541788 try :
17551789 db_name = f"{ self .current_env } _resources.db"
@@ -1762,14 +1796,25 @@ async def run_synchronization(self, resource_ids=None):
17621796 )
17631797 if not reset_success :
17641798 return False
1765- result = await sync .run_sync (db_path , headers , resource_ids = resource_ids )
1799+ result = await sync .run_sync (db_path , headers , resource_ids = resource_ids , on_event = self . on_sync_event )
17661800 return result
17671801 except Exception as e :
17681802 print (f"Error in run_synchronization: { e } " )
17691803 return False
17701804
17711805 def update_complete (self , result : bool , button : Button ) -> None :
17721806 main_screen = self ._get_main_screen ()
1807+
1808+ if main_screen :
1809+ try :
1810+ fetch_tab = main_screen .query_one (FetchTab )
1811+ progress_bar = fetch_tab .query_one ("#update_progress" , ProgressBar )
1812+ resource_input = fetch_tab .query_one ("#resource_id_input" , Input )
1813+ progress_bar .add_class ("hidden" )
1814+ resource_input .remove_class ("hidden" )
1815+ except Exception :
1816+ pass
1817+
17731818 if result :
17741819 button .variant = "success"
17751820 self .notify ("All resources updated successfully." )
0 commit comments