101101 friendly_connection_error ,
102102)
103103from office_app .ui .views import StudentListView
104- from office_app .ui .views .settings_view import SettingsView
104+ from office_app .ui .views .settings_figma_view import SettingsView
105105from office_app .services .updater_service import UpdaterService
106106
107107def app_version_label () -> str :
@@ -1410,6 +1410,12 @@ def __init__(self, sb: Client, initial_user: str = "Joshua"):
14101410 self .settings_view .connection_settings_requested .connect (
14111411 self ._open_connection_settings
14121412 )
1413+ self .settings_view .test_connection_requested .connect (
1414+ self ._test_settings_connection
1415+ )
1416+ self .settings_view .sync_now_requested .connect (
1417+ self .sync_google_sheet_now
1418+ )
14131419 self .settings_view .preferences_changed .connect (
14141420 self ._apply_accessibility_preferences
14151421 )
@@ -1446,6 +1452,9 @@ def _set_connection_state(self, text: str, state: str) -> None:
14461452 badge = getattr (self , "connection_badge" , None )
14471453 if badge is not None :
14481454 badge .set_state (state , text )
1455+ settings_view = getattr (self , "settings_view" , None )
1456+ if settings_view is not None :
1457+ settings_view .set_connection_state (text , state )
14491458
14501459 def _refresh_database_updated_label (self ):
14511460 if self ._last_database_update_at is None :
@@ -1513,7 +1522,10 @@ def _update_page_header(self, index: int) -> None:
15131522 4 : ("Expenses" , "Budget and expense history for the selected student" ),
15141523 5 : ("Workbook" , "Review and safely update the local master workbook" ),
15151524 6 : ("Coordinators" , "Contact directory for ministry coordinators" ),
1516- 7 : ("Settings" , "Local workbook and appearance preferences" ),
1525+ 7 : (
1526+ "Settings" ,
1527+ "Configure appearance, accessibility, and office connections." ,
1528+ ),
15171529 }
15181530 title , subtitle = pages .get (index , ("SSM Workspace" , "Student support records" ))
15191531 self .page_title_label .setText (title )
@@ -1600,6 +1612,8 @@ def _update_compact_header(self) -> None:
16001612 self ._update_page_header (self .stacked_widget .currentIndex ())
16011613 if hasattr (self , "sync_panel" ):
16021614 self .sync_panel .setFixedHeight (126 if compact else 96 )
1615+ if hasattr (self , "settings_view" ):
1616+ self .settings_view .set_compact (compact )
16031617 self .page_eyebrow_label .hide ()
16041618
16051619 def _dashboard_greeting (self ) -> str :
@@ -2094,6 +2108,9 @@ def nav_coordinators(self):
20942108 def nav_settings (self ):
20952109 self ._set_active_nav (self .btn_settings )
20962110 self ._switch_page (7 )
2111+ self .settings_view .load_settings ()
2112+ self .refresh_sync_status ()
2113+ self ._test_settings_connection (silent = True )
20972114
20982115 def _on_user_changed (self , name ):
20992116 if not name :
@@ -2132,6 +2149,28 @@ def _open_connection_settings(self) -> None:
21322149 ),
21332150 )
21342151
2152+ def _test_settings_connection (self , * _args , silent = False ) -> None :
2153+ """Test the live repository without blocking the Settings screen."""
2154+ self .settings_view .set_connection_state ("Checking" , "loading" )
2155+
2156+ def connected (_rows ):
2157+ self ._mark_database_updated ()
2158+ if not silent :
2159+ self .status_bar .showMessage ("Database connection is working." , 4000 )
2160+
2161+ def failed (error ):
2162+ self ._set_connection_state ("Connection issue" , "danger" )
2163+ self .status_bar .showMessage (
2164+ "Could not reach the office database. Check the saved connection." ,
2165+ 7000 ,
2166+ )
2167+ logging .getLogger (__name__ ).warning (
2168+ "Settings connection test failed: %s" ,
2169+ str (error ).strip ().splitlines ()[- 1 ],
2170+ )
2171+
2172+ self ._run_background (self .student_repository .ping , connected , failed )
2173+
21352174 def _audit (self , action , entity_type , entity_id = None , details = None ):
21362175 operator = getattr (self , "_current_operator" , self ._initial_user )
21372176 self ._run_background (
@@ -2658,6 +2697,11 @@ def apply_status(entry):
26582697 )
26592698 self .sync_last_label .setText ("No successful sync recorded" )
26602699 self .sync_records_label .setText ("—" )
2700+ self .settings_view .set_sync_status (
2701+ configured = has_token ,
2702+ state = "Ready to sync" if has_token else "Token needed" ,
2703+ last_sync = "No successful sync recorded" ,
2704+ )
26612705 return
26622706 details = entry .get ("details" ) or {}
26632707 self .sync_state_badge .set_state (
@@ -2672,6 +2716,19 @@ def apply_status(entry):
26722716 self .sync_records_label .setText (
26732717 self ._format_sync_counts (details )
26742718 )
2719+ self .settings_view .set_sync_status (
2720+ configured = has_token ,
2721+ state = "Ready to sync" if has_token else "Token needed" ,
2722+ last_sync = self .sheet_sync_service .format_timestamp (
2723+ entry .get ("created_at" )
2724+ ),
2725+ active_rows = int (details .get ("students" ) or 0 ),
2726+ source = str (
2727+ details .get ("source" )
2728+ or details .get ("source_sheet_name" )
2729+ or "SSM Masterlist / Current workbook"
2730+ ),
2731+ )
26752732
26762733 def failed (error ):
26772734 self ._sync_pulse .stop ()
@@ -2681,6 +2738,11 @@ def failed(error):
26812738 self .sync_state_badge .set_state ("warning" , "Status unavailable" )
26822739 self .sync_last_label .setText ("Could not read the audit log" )
26832740 self .sync_records_label .setText ("—" )
2741+ self .settings_view .set_sync_status (
2742+ configured = bool (get_sheet_sync_token ()),
2743+ state = "Status unavailable" ,
2744+ last_sync = "Could not read the audit log" ,
2745+ )
26842746
26852747 return self ._run_background (
26862748 self .sheet_sync_service .latest_success ,
@@ -2697,7 +2759,7 @@ def sync_google_sheet_now(self):
26972759 "Add the private Google Sheet sync token in Settings." , 6000
26982760 )
26992761 self .nav_settings ()
2700- self .settings_view .sync_token_input . setFocus ( )
2762+ QTimer . singleShot ( 0 , self .settings_view .prompt_replace_token )
27012763 return None
27022764
27032765 decision = QMessageBox .question (
@@ -2752,6 +2814,7 @@ def synchronized(result):
27522814 self .student_list_view .load_student_list ()
27532815 if self .stacked_widget .currentIndex () == 6 :
27542816 self .load_coordinators ()
2817+ self .refresh_sync_status ()
27552818
27562819 def failed (error ):
27572820 self ._set_sync_busy (False )
@@ -2768,6 +2831,7 @@ def _set_sync_busy(self, busy: bool) -> None:
27682831 self .sync_now_button .setEnabled (not busy )
27692832 self .sync_now_button .setText ("Syncing…" if busy else "Sync now" )
27702833 self .refresh_data_button .setEnabled (not busy )
2834+ self .settings_view .set_sync_busy (busy )
27712835
27722836 @staticmethod
27732837 def _format_sync_counts (details ) -> str :
@@ -3565,7 +3629,7 @@ def create_profile_screen(self):
35653629
35663630 self .photo_label = QLabel ("Photo" )
35673631 self .photo_label .setObjectName ("ProfileAvatar" )
3568- self .photo_label .setFixedSize (72 , 72 )
3632+ self .photo_label .setFixedSize (96 , 96 )
35693633 self .photo_label .setAlignment (Qt .AlignmentFlag .AlignCenter )
35703634 summary_layout .addWidget (self .photo_label )
35713635
0 commit comments