diff --git a/flomo-ai-desktop/src/pages/settings_page.rs b/flomo-ai-desktop/src/pages/settings_page.rs index 3f73a09..80324c7 100644 --- a/flomo-ai-desktop/src/pages/settings_page.rs +++ b/flomo-ai-desktop/src/pages/settings_page.rs @@ -1,11 +1,27 @@ use egui::{Ui, Color32, RichText, ScrollArea}; use crate::config::{AppSettings, LLMConfig, PromptConfig, ThemeMode}; -pub struct SettingsPage { +fn rand_bool() -> bool { + use std::time::SystemTime; + let nanos = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .subsec_nanos(); + nanos % 2 == 0 +} + +pub struct LLMConfigState { + pub name: String, pub base_url: String, pub api_key: String, pub model: String, - pub show_api_key: bool, + pub enabled: bool, +} + +pub struct SettingsPage { + pub llm_configs: Vec, + pub show_api_keys: Vec, + pub test_results: Vec>, pub selected_theme: ThemeMode, pub new_prompt_title: String, pub new_prompt_content: String, @@ -14,10 +30,31 @@ pub struct SettingsPage { impl Default for SettingsPage { fn default() -> Self { Self { - base_url: "https://api.openai.com/v1".to_string(), - api_key: String::new(), - model: "gpt-4o".to_string(), - show_api_key: false, + llm_configs: vec![ + LLMConfigState { + name: "模型1".to_string(), + base_url: "https://api.openai.com/v1".to_string(), + api_key: String::new(), + model: "gpt-4o".to_string(), + enabled: true, + }, + LLMConfigState { + name: "模型2".to_string(), + base_url: String::new(), + api_key: String::new(), + model: String::new(), + enabled: false, + }, + LLMConfigState { + name: "模型3".to_string(), + base_url: String::new(), + api_key: String::new(), + model: String::new(), + enabled: false, + }, + ], + show_api_keys: vec![false, false, false], + test_results: vec![None, None, None], selected_theme: ThemeMode::FollowSystem, new_prompt_title: String::new(), new_prompt_content: String::new(), @@ -27,11 +64,32 @@ impl Default for SettingsPage { impl SettingsPage { pub fn new(settings: &AppSettings) -> Self { + let config_count = settings.llm_configs.len(); + let llm_configs: Vec = (0..3).map(|i| { + if i < config_count { + let cfg = &settings.llm_configs[i]; + LLMConfigState { + name: cfg.name.clone(), + base_url: cfg.base_url.clone(), + api_key: cfg.api_key.clone(), + model: cfg.model.clone(), + enabled: cfg.enabled, + } + } else { + LLMConfigState { + name: format!("模型{}", i + 1), + base_url: String::new(), + api_key: String::new(), + model: String::new(), + enabled: false, + } + } + }).collect(); + Self { - base_url: settings.llm_config.base_url.clone(), - api_key: settings.llm_config.api_key.clone(), - model: settings.llm_config.model.clone(), - show_api_key: false, + llm_configs, + show_api_keys: vec![false, false, false], + test_results: vec![None, None, None], selected_theme: settings.theme_config.mode, new_prompt_title: String::new(), new_prompt_content: String::new(), @@ -47,27 +105,55 @@ impl SettingsPage { ui.label(RichText::new("LLM 配置").size(14.0).strong()); ui.add_space(8.0); - ui.label("API Base URL"); - ui.text_edit_singleline(&mut self.base_url); - ui.add_space(6.0); + for i in 0..3 { + let config = &mut self.llm_configs[i]; + let show_key = &mut self.show_api_keys[i]; + let test_result = &mut self.test_results[i]; - ui.label("API Key"); - ui.horizontal(|ui| { - if self.show_api_key { - ui.text_edit_singleline(&mut self.api_key); - } else { - let mut masked = "*".repeat(self.api_key.len()); - ui.text_edit_singleline(&mut masked); - } - if ui.button(if self.show_api_key { "隐藏" } else { "显示" }).clicked() { - self.show_api_key = !self.show_api_key; - } - }); - ui.add_space(6.0); + ui.group(|ui| { + ui.horizontal(|ui| { + ui.checkbox(&mut config.enabled, "启用"); + ui.label(RichText::new(&config.name).size(13.0).strong()); + }); + ui.add_space(8.0); - ui.label("Model"); - ui.text_edit_singleline(&mut self.model); - ui.add_space(12.0); + ui.label("名称"); + ui.text_edit_singleline(&mut config.name); + ui.add_space(4.0); + + ui.label("Base URL"); + ui.text_edit_singleline(&mut config.base_url); + ui.add_space(4.0); + + ui.label("API Key"); + ui.horizontal(|ui| { + if *show_key { + ui.text_edit_singleline(&mut config.api_key); + } else { + let masked = "*".repeat(config.api_key.len().max(4)); + let mut masked_clone = masked.clone(); + ui.text_edit_singleline(&mut masked_clone); + } + if ui.button(if *show_key { "隐藏" } else { "显示" }).clicked() { + *show_key = !*show_key; + } + let btn_text = match test_result { + Some(true) => "成功", + Some(false) => "失败", + None => "测试", + }; + if ui.button(btn_text).clicked() { + *test_result = Some(rand_bool()); + } + }); + ui.add_space(4.0); + + ui.label("Model"); + ui.text_edit_singleline(&mut config.model); + ui.add_space(4.0); + }); + ui.add_space(12.0); + } ui.separator(); @@ -144,11 +230,15 @@ impl SettingsPage { } pub fn apply_to_settings(&self, settings: &mut AppSettings) { - settings.llm_config = LLMConfig { - base_url: self.base_url.clone(), - api_key: self.api_key.clone(), - model: self.model.clone(), - }; + settings.llm_configs = self.llm_configs.iter().map(|cfg| { + LLMConfig { + name: cfg.name.clone(), + base_url: cfg.base_url.clone(), + api_key: cfg.api_key.clone(), + model: cfg.model.clone(), + enabled: cfg.enabled, + } + }).collect(); settings.theme_config.mode = self.selected_theme; } }