@@ -67,12 +67,35 @@ use tauri::menu::{CheckMenuItem, MenuBuilder, MenuItem, PredefinedMenuItem, Subm
6767use whisper:: cache:: TranscriberCache ;
6868use window_manager:: WindowManager ;
6969
70+ /// Determines if a model should appear as selected in the tray given onboarding status
71+ pub ( crate ) fn should_mark_model_selected (
72+ onboarding_done : bool ,
73+ model_name : & str ,
74+ current_model : & str ,
75+ ) -> bool {
76+ onboarding_done && model_name == current_model
77+ }
78+
79+ /// Formats the tray's model label given onboarding status and an optional resolved display name
80+ pub ( crate ) fn format_tray_model_label (
81+ onboarding_done : bool ,
82+ current_model : & str ,
83+ resolved_display_name : Option < String > ,
84+ ) -> String {
85+ if !onboarding_done || current_model. is_empty ( ) {
86+ "Model: None" . to_string ( )
87+ } else {
88+ let name = resolved_display_name. unwrap_or_else ( || current_model. to_string ( ) ) ;
89+ format ! ( "Model: {}" , name)
90+ }
91+ }
92+
7093// Function to build the tray menu
7194async fn build_tray_menu < R : tauri:: Runtime > (
7295 app : & tauri:: AppHandle < R > ,
7396) -> Result < tauri:: menu:: Menu < R > , Box < dyn std:: error:: Error > > {
7497 // Get current settings for menu state
75- let ( current_model, selected_microphone) = {
98+ let ( current_model, selected_microphone, onboarding_done ) = {
7699 match app. store ( "settings" ) {
77100 Ok ( store) => {
78101 let model = store
@@ -82,9 +105,13 @@ async fn build_tray_menu<R: tauri::Runtime>(
82105 let microphone = store
83106 . get ( "selected_microphone" )
84107 . and_then ( |v| v. as_str ( ) . map ( |s| s. to_string ( ) ) ) ;
85- ( model, microphone)
108+ let onboarding_done = store
109+ . get ( "onboarding_completed" )
110+ . and_then ( |v| v. as_bool ( ) )
111+ . unwrap_or ( false ) ;
112+ ( model, microphone, onboarding_done)
86113 }
87- Err ( _) => ( "" . to_string ( ) , None ) ,
114+ Err ( _) => ( "" . to_string ( ) , None , false ) ,
88115 }
89116 } ;
90117
@@ -123,7 +150,8 @@ async fn build_tray_menu<R: tauri::Runtime>(
123150 let mut model_check_items = Vec :: new ( ) ;
124151
125152 for ( model_name, display_name) in available_models {
126- let is_selected = model_name == current_model;
153+ // Do not show any selection until onboarding is completed
154+ let is_selected = should_mark_model_selected ( onboarding_done, & model_name, & current_model) ;
127155 let model_item = CheckMenuItem :: with_id (
128156 app,
129157 & format ! ( "model_{}" , model_name) ,
@@ -140,12 +168,11 @@ async fn build_tray_menu<R: tauri::Runtime>(
140168 model_items. push ( item) ;
141169 }
142170
143- let current_model_display = if current_model. is_empty ( ) {
144- "Model: None" . to_string ( )
145- } else {
171+ // Resolve a display name only if onboarding is complete and a model is set
172+ let resolved_display_name = if onboarding_done && !current_model. is_empty ( ) {
146173 // Try Whisper first
147- let display_name = if let Some ( info) = whisper_models_info. get ( & current_model) {
148- info. display_name . clone ( )
174+ if let Some ( info) = whisper_models_info. get ( & current_model) {
175+ Some ( info. display_name . clone ( ) )
149176 } else {
150177 // Try Parakeet registry
151178 let parakeet_manager = app. state :: < crate :: parakeet:: ParakeetManager > ( ) ;
@@ -154,16 +181,19 @@ async fn build_tray_menu<R: tauri::Runtime>(
154181 . into_iter ( )
155182 . find ( |m| m. name == current_model)
156183 {
157- pm. display_name
184+ Some ( pm. display_name )
158185 } else if current_model == "soniox" {
159- "Soniox (Cloud)" . to_string ( )
186+ Some ( "Soniox (Cloud)" . to_string ( ) )
160187 } else {
161- current_model. clone ( )
188+ Some ( current_model. clone ( ) )
162189 }
163- } ;
164- format ! ( "Model: {}" , display_name)
190+ }
191+ } else {
192+ None
165193 } ;
166194
195+ let current_model_display = format_tray_model_label ( onboarding_done, & current_model, resolved_display_name) ;
196+
167197 Some ( Submenu :: with_id_and_items (
168198 app,
169199 "models" ,
0 commit comments