From f9f173407ec5bd50d34161176a870589d8854d33 Mon Sep 17 00:00:00 2001 From: lencx Date: Fri, 27 Jan 2023 00:23:05 +0800 Subject: [PATCH] refactor: app conf --- src-tauri/src/app/cmd.rs | 56 +---- src-tauri/src/app/gpt.rs | 20 +- src-tauri/src/app/menu.rs | 110 ++++++---- src-tauri/src/app/setup.rs | 29 +-- src-tauri/src/app/window.rs | 152 ++++++------- src-tauri/src/conf.rs | 319 ++++++++++++++-------------- src-tauri/src/main.rs | 68 +++--- src-tauri/src/scripts/core.js | 2 +- src-tauri/src/scripts/export.js | 2 +- src-tauri/src/scripts/popup.core.js | 2 +- src-tauri/src/utils.rs | 8 +- src/utils.ts | 2 +- src/view/dashboard/index.tsx | 4 +- src/view/settings/index.tsx | 10 +- 14 files changed, 388 insertions(+), 396 deletions(-) diff --git a/src-tauri/src/app/cmd.rs b/src-tauri/src/app/cmd.rs index 64493cf..4c1b3ed 100644 --- a/src-tauri/src/app/cmd.rs +++ b/src-tauri/src/app/cmd.rs @@ -1,10 +1,7 @@ -use crate::{ - conf::ChatConfJson, - utils::{self, chat_root, create_file}, -}; +use crate::utils; use log::info; use std::{fs, path::PathBuf}; -use tauri::{api, command, AppHandle, Manager, Theme}; +use tauri::{api, command, AppHandle, Manager}; #[command] pub fn drag_window(app: AppHandle) { @@ -23,16 +20,16 @@ pub fn fullscreen(app: AppHandle) { #[command] pub fn download(_app: AppHandle, name: String, blob: Vec) { - let path = chat_root().join(PathBuf::from(name)); - create_file(&path).unwrap(); + let path = utils::app_root().join(PathBuf::from(name)); + utils::create_file(&path).unwrap(); fs::write(&path, blob).unwrap(); utils::open_file(path); } #[command] pub fn save_file(_app: AppHandle, name: String, content: String) { - let path = chat_root().join(PathBuf::from(name)); - create_file(&path).unwrap(); + let path = utils::app_root().join(PathBuf::from(name)); + utils::create_file(&path).unwrap(); fs::write(&path, content).unwrap(); utils::open_file(path); } @@ -42,52 +39,11 @@ pub fn open_link(app: AppHandle, url: String) { api::shell::open(&app.shell_scope(), url, None).unwrap(); } -#[command] -pub fn get_chat_conf() -> ChatConfJson { - ChatConfJson::get_chat_conf() -} - -#[command] -pub fn reset_chat_conf() -> ChatConfJson { - ChatConfJson::reset_chat_conf() -} - -#[command] -pub fn get_theme() -> String { - ChatConfJson::theme().unwrap_or(Theme::Light).to_string() -} - #[command] pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option) { utils::run_check_update(app, silent, has_msg); } -#[command] -pub fn form_confirm(_app: AppHandle, data: serde_json::Value) { - ChatConfJson::amend(&serde_json::json!(data), None).unwrap(); -} - -#[command] -pub fn form_cancel(app: AppHandle, label: &str, title: &str, msg: &str) { - let win = app.app_handle().get_window(label).unwrap(); - tauri::api::dialog::ask( - app.app_handle().get_window(label).as_ref(), - title, - msg, - move |is_cancel| { - if is_cancel { - win.close().unwrap(); - } - }, - ); -} - -#[command] -pub fn form_msg(app: AppHandle, label: &str, title: &str, msg: &str) { - let win = app.app_handle().get_window(label); - tauri::api::dialog::message(win.as_ref(), title, msg); -} - #[command] pub fn open_file(path: PathBuf) { utils::open_file(path); diff --git a/src-tauri/src/app/gpt.rs b/src-tauri/src/app/gpt.rs index 392c15f..ebaa6d3 100644 --- a/src-tauri/src/app/gpt.rs +++ b/src-tauri/src/app/gpt.rs @@ -1,7 +1,7 @@ use crate::{ app::{fs_extra, window}, conf::GITHUB_PROMPTS_CSV_URL, - utils::{self, chat_root}, + utils, }; use log::info; use regex::Regex; @@ -11,7 +11,7 @@ use walkdir::WalkDir; #[command] pub fn get_chat_model_cmd() -> serde_json::Value { - let path = utils::chat_root().join("chat.model.cmd.json"); + let path = utils::app_root().join("chat.model.cmd.json"); let content = fs::read_to_string(path).unwrap_or_else(|_| r#"{"data":[]}"#.to_string()); serde_json::from_str(&content).unwrap() } @@ -55,7 +55,7 @@ pub struct ModelRecord { #[command] pub fn cmd_list() -> Vec { let mut list = vec![]; - for entry in WalkDir::new(utils::chat_root().join("cache_model")) + for entry in WalkDir::new(utils::app_root().join("cache_model")) .into_iter() .filter_map(|e| e.ok()) { @@ -82,7 +82,7 @@ pub struct FileMetadata { #[tauri::command] pub fn get_download_list(pathname: &str) -> (Vec, PathBuf) { info!("get_download_list: {}", pathname); - let download_path = chat_root().join(PathBuf::from(pathname)); + let download_path = utils::app_root().join(PathBuf::from(pathname)); let content = fs::read_to_string(&download_path).unwrap_or_else(|err| { info!("download_list_error: {}", err); fs::write(&download_path, "[]").unwrap(); @@ -104,7 +104,7 @@ pub fn download_list(pathname: &str, dir: &str, filename: Option, id: Op let mut idmap = HashMap::new(); utils::vec_to_hashmap(data.0.into_iter(), "id", &mut idmap); - for entry in WalkDir::new(utils::chat_root().join(dir)) + for entry in WalkDir::new(utils::app_root().join(dir)) .into_iter() .filter_entry(|e| !utils::is_hidden(e)) .filter_map(|e| e.ok()) @@ -182,9 +182,9 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> let data2 = data.clone(); - let model = utils::chat_root().join("chat.model.json"); - let model_cmd = utils::chat_root().join("chat.model.cmd.json"); - let chatgpt_prompts = utils::chat_root() + let model = utils::app_root().join("chat.model.json"); + let model_cmd = utils::app_root().join("chat.model.cmd.json"); + let chatgpt_prompts = utils::app_root() .join("cache_model") .join("chatgpt_prompts.json"); @@ -238,8 +238,8 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> "Sync Prompts", "ChatGPT Prompts data has been synchronized!", ); - window::window_reload(app.clone(), "core"); - window::window_reload(app, "tray"); + window::cmd::window_reload(app.clone(), "core"); + window::cmd::window_reload(app, "tray"); return Some(data2); } diff --git a/src-tauri/src/app/menu.rs b/src-tauri/src/app/menu.rs index 450e027..622b715 100644 --- a/src-tauri/src/app/menu.rs +++ b/src-tauri/src/app/menu.rs @@ -1,6 +1,6 @@ use crate::{ app::window, - conf::{self, ChatConfJson}, + conf::{self, AppConf}, utils, }; use tauri::{ @@ -14,7 +14,7 @@ use tauri::AboutMetadata; // --- Menu pub fn init() -> Menu { - let chat_conf = ChatConfJson::get_chat_conf(); + let app_conf = AppConf::read(); let name = "ChatGPT"; let app_menu = Submenu::new( name, @@ -35,7 +35,7 @@ pub fn init() -> Menu { let stay_on_top = CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T"); - let stay_on_top_menu = if chat_conf.stay_on_top { + let stay_on_top_menu = if app_conf.stay_on_top { stay_on_top.selected() } else { stay_on_top @@ -44,15 +44,15 @@ pub fn init() -> Menu { let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light"); let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark"); let theme_system = CustomMenuItem::new("theme_system".to_string(), "System"); - let is_dark = chat_conf.theme == "Dark"; - let is_system = chat_conf.theme == "System"; + let is_dark = app_conf.clone().theme_check("dark"); + let is_system = app_conf.clone().theme_check("system"); let update_prompt = CustomMenuItem::new("update_prompt".to_string(), "Prompt"); let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent"); let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable"); let popup_search = CustomMenuItem::new("popup_search".to_string(), "Pop-up Search"); - let popup_search_menu = if chat_conf.popup_search { + let popup_search_menu = if app_conf.popup_search { popup_search.selected() } else { popup_search @@ -61,14 +61,14 @@ pub fn init() -> Menu { #[cfg(target_os = "macos")] let titlebar = CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B"); #[cfg(target_os = "macos")] - let titlebar_menu = if chat_conf.titlebar { + let titlebar_menu = if app_conf.titlebar { titlebar.selected() } else { titlebar }; let system_tray = CustomMenuItem::new("system_tray".to_string(), "System Tray"); - let system_tray_menu = if chat_conf.tray { + let system_tray_menu = if app_conf.tray { system_tray.selected() } else { system_tray @@ -114,16 +114,16 @@ pub fn init() -> Menu { Submenu::new( "Auto Update", Menu::new() - .add_item(if chat_conf.auto_update == "Prompt" { + .add_item(if app_conf.auto_update == "Prompt" { update_prompt.selected() } else { update_prompt }) - .add_item(if chat_conf.auto_update == "Silent" { + .add_item(if app_conf.auto_update == "Silent" { update_silent.selected() } else { update_silent - }), // .add_item(if chat_conf.auto_update == "Disable" { + }), // .add_item(if app_conf.auto_update == "Disable" { // update_disable.selected() // } else { // update_disable @@ -241,23 +241,25 @@ pub fn menu_handler(event: WindowMenuEvent) { utils::run_check_update(app, false, None); } // Preferences - "control_center" => window::control_window(app), + "control_center" => window::cmd::control_window(app), "restart" => tauri::api::process::restart(&app.env()), "inject_script" => open(&app, script_path), - "go_conf" => utils::open_file(utils::chat_root()), + "go_conf" => utils::open_file(utils::app_root()), "clear_conf" => utils::clear_conf(&app), "awesome" => open(&app, conf::AWESOME_URL.to_string()), "buy_coffee" => open(&app, conf::BUY_COFFEE.to_string()), "popup_search" => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - let popup_search = !chat_conf.popup_search; + let app_conf = AppConf::read(); + let popup_search = !app_conf.popup_search; menu_handle .get_item(menu_id) .set_selected(popup_search) .unwrap(); - ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None).unwrap(); - window::window_reload(app.clone(), "core"); - window::window_reload(app, "tray"); + app_conf + .amend(serde_json::json!({ "popup_search": popup_search })) + .write(); + window::cmd::window_reload(app.clone(), "core"); + window::cmd::window_reload(app, "tray"); } "sync_prompts" => { tauri::api::dialog::ask( @@ -276,29 +278,37 @@ pub fn menu_handler(event: WindowMenuEvent) { ); } "hide_dock_icon" => { - ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap() + AppConf::read() + .amend(serde_json::json!({ "hide_dock_icon": true })) + .write() + .restart(app); } "titlebar" => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - ChatConfJson::amend( - &serde_json::json!({ "titlebar": !chat_conf.titlebar }), - None, - ) - .unwrap(); - tauri::api::process::restart(&app.env()); + let app_conf = AppConf::read(); + app_conf + .clone() + .amend(serde_json::json!({ "titlebar": !app_conf.titlebar })) + .write() + .restart(app); } "system_tray" => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - ChatConfJson::amend(&serde_json::json!({ "tray": !chat_conf.tray }), None).unwrap(); - tauri::api::process::restart(&app.env()); + let app_conf = AppConf::read(); + app_conf + .clone() + .amend(serde_json::json!({ "tray": !app_conf.tray })) + .write() + .restart(app); } "theme_light" | "theme_dark" | "theme_system" => { let theme = match menu_id { - "theme_dark" => "Dark", - "theme_system" => "System", - _ => "Light", + "theme_dark" => "dark", + "theme_system" => "system", + _ => "light", }; - ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap(); + AppConf::read() + .amend(serde_json::json!({ "theme": theme })) + .write() + .restart(app); } "update_prompt" | "update_silent" | "update_disable" => { // for id in ["update_prompt", "update_silent", "update_disable"] { @@ -328,17 +338,21 @@ pub fn menu_handler(event: WindowMenuEvent) { "Prompt" } }; - ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap(); + AppConf::read() + .amend(serde_json::json!({ "auto_update": auto_update })) + .write(); } "stay_on_top" => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - let stay_on_top = !chat_conf.stay_on_top; + let app_conf = AppConf::read(); + let stay_on_top = !app_conf.stay_on_top; menu_handle .get_item(menu_id) .set_selected(stay_on_top) .unwrap(); win.set_always_on_top(stay_on_top).unwrap(); - ChatConfJson::amend(&serde_json::json!({ "stay_on_top": stay_on_top }), None).unwrap(); + app_conf + .amend(serde_json::json!({ "stay_on_top": stay_on_top })) + .write(); } // Window "dalle2" => window::dalle2_window(&app, None, None, Some(false)), @@ -367,7 +381,7 @@ pub fn menu_handler(event: WindowMenuEvent) { ) .unwrap(), // Help - "chatgpt_log" => utils::open_file(utils::chat_root().join("chatgpt.log")), + "chatgpt_log" => utils::open_file(utils::app_root().join("chatgpt.log")), "update_log" => open(&app, conf::UPDATE_LOG_URL.to_string()), "report_bug" => open(&app, conf::ISSUES_URL.to_string()), "dev_tools" => { @@ -422,9 +436,9 @@ pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) { match event { SystemTrayEvent::LeftClick { .. } => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); + let app_conf = AppConf::read(); - if !chat_conf.hide_dock_icon { + if !app_conf.hide_dock_icon { let core_win = handle.get_window("core").unwrap(); core_win.minimize().unwrap(); } @@ -439,15 +453,21 @@ pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) { } } SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { - "control_center" => window::control_window(app), + "control_center" => window::cmd::control_window(app), "restart" => tauri::api::process::restart(&handle.env()), "show_dock_icon" => { - ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": false }), Some(app)).unwrap(); + AppConf::read() + .amend(serde_json::json!({ "hide_dock_icon": false })) + .write() + .restart(app); } "hide_dock_icon" => { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - if !chat_conf.hide_dock_icon { - ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap(); + let app_conf = AppConf::read(); + if !app_conf.hide_dock_icon { + app_conf + .amend(serde_json::json!({ "hide_dock_icon": true })) + .write() + .restart(app); } } "show_core" => { diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs index 236e696..0f23024 100644 --- a/src-tauri/src/app/setup.rs +++ b/src-tauri/src/app/setup.rs @@ -1,20 +1,20 @@ -use crate::{app::window, conf::ChatConfJson, utils}; +use crate::{app::window, conf::AppConf, utils}; use log::info; use tauri::{utils::config::WindowUrl, window::WindowBuilder, App, GlobalShortcutManager, Manager}; use wry::application::accelerator::Accelerator; pub fn init(app: &mut App) -> std::result::Result<(), Box> { info!("stepup"); - let chat_conf = ChatConfJson::get_chat_conf(); - let url = chat_conf.main_origin.to_string(); - let theme = ChatConfJson::theme(); + let app_conf = AppConf::read(); + let url = app_conf.main_origin.to_string(); + let theme = AppConf::theme_mode(); let handle = app.app_handle(); tauri::async_runtime::spawn(async move { window::tray_window(&handle); }); - if let Some(v) = chat_conf.global_shortcut { + if let Some(v) = app_conf.clone().global_shortcut { info!("global_shortcut: `{}`", v); match v.parse::() { Ok(_) => { @@ -44,13 +44,14 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box info!("global_shortcut_unregister"); }; - if chat_conf.hide_dock_icon { + let app_conf2 = app_conf.clone(); + if app_conf.hide_dock_icon { #[cfg(target_os = "macos")] app.set_activation_policy(tauri::ActivationPolicy::Accessory); } else { let app = app.handle(); tauri::async_runtime::spawn(async move { - let link = if chat_conf.main_dashboard { + let link = if app_conf2.main_dashboard { "index.html" } else { &url @@ -60,20 +61,20 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box .resizable(true) .fullscreen(false) .inner_size(800.0, 600.0) - .theme(theme) - .always_on_top(chat_conf.stay_on_top) + .theme(Some(theme)) + .always_on_top(app_conf2.stay_on_top) .initialization_script(&utils::user_script()) .initialization_script(include_str!("../scripts/core.js")) - .user_agent(&chat_conf.ua_window); + .user_agent(&app_conf2.ua_window); #[cfg(target_os = "macos")] { main_win = main_win - .title_bar_style(ChatConfJson::titlebar()) + .title_bar_style(app_conf2.clone().titlebar()) .hidden_title(true); } - if url == "https://chat.openai.com" && !chat_conf.main_dashboard { + if url == "https://chat.openai.com" && !app_conf2.main_dashboard { main_win = main_win .initialization_script(include_str!("../vendors/floating-ui-core.js")) .initialization_script(include_str!("../vendors/floating-ui-dom.js")) @@ -92,10 +93,10 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box } // auto_update - if chat_conf.auto_update != "Disable" { + if app_conf.auto_update != "Disable" { info!("stepup::run_check_update"); let app = app.handle(); - utils::run_check_update(app, chat_conf.auto_update == "Silent", None); + utils::run_check_update(app, app_conf.auto_update == "Silent", None); } Ok(()) diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs index cd7cf87..b03e805 100644 --- a/src-tauri/src/app/window.rs +++ b/src-tauri/src/app/window.rs @@ -1,18 +1,18 @@ -use crate::{conf, utils}; +use crate::{conf::AppConf, utils}; use log::info; use std::time::SystemTime; use tauri::{utils::config::WindowUrl, window::WindowBuilder, Manager}; pub fn tray_window(handle: &tauri::AppHandle) { - let chat_conf = conf::ChatConfJson::get_chat_conf(); - let theme = conf::ChatConfJson::theme(); + let app_conf = AppConf::read(); + let theme = AppConf::theme_mode(); let app = handle.clone(); tauri::async_runtime::spawn(async move { - let link = if chat_conf.tray_dashboard { + let link = if app_conf.tray_dashboard { "index.html" } else { - &chat_conf.tray_origin + &app_conf.tray_origin }; let mut tray_win = WindowBuilder::new(&app, "tray", WindowUrl::App(link.into())) .title("ChatGPT") @@ -21,12 +21,12 @@ pub fn tray_window(handle: &tauri::AppHandle) { .inner_size(360.0, 540.0) .decorations(false) .always_on_top(true) - .theme(theme) + .theme(Some(theme)) .initialization_script(&utils::user_script()) .initialization_script(include_str!("../scripts/core.js")) - .user_agent(&chat_conf.ua_tray); + .user_agent(&app_conf.ua_tray); - if chat_conf.tray_origin == "https://chat.openai.com" && !chat_conf.tray_dashboard { + if app_conf.tray_origin == "https://chat.openai.com" && !app_conf.tray_dashboard { tray_win = tray_win .initialization_script(include_str!("../vendors/floating-ui-core.js")) .initialization_script(include_str!("../vendors/floating-ui-dom.js")) @@ -45,7 +45,7 @@ pub fn dalle2_window( is_new: Option, ) { info!("dalle2_query: {:?}", query); - let theme = conf::ChatConfJson::theme(); + let theme = AppConf::theme_mode(); let app = handle.clone(); let query = if query.is_some() { @@ -76,7 +76,7 @@ pub fn dalle2_window( .fullscreen(false) .inner_size(800.0, 600.0) .always_on_top(false) - .theme(theme) + .theme(Some(theme)) .initialization_script(include_str!("../scripts/core.js")) .initialization_script(&query) .initialization_script(include_str!("../scripts/dalle2.js")) @@ -90,78 +90,84 @@ pub fn dalle2_window( } } -#[tauri::command] -pub fn dalle2_search_window(app: tauri::AppHandle, query: String) { - dalle2_window( - &app.app_handle(), - Some(query), - Some("ChatGPT & DALL·E 2".to_string()), - None, - ); -} +pub mod cmd { + use super::*; + use log::info; + use tauri::{command, utils::config::WindowUrl, window::WindowBuilder, Manager}; -#[tauri::command] -pub fn control_window(handle: tauri::AppHandle) { - tauri::async_runtime::spawn(async move { - if handle.get_window("main").is_none() { - WindowBuilder::new( - &handle, - "main", - WindowUrl::App("index.html?type=control".into()), - ) - .title("Control Center") - .resizable(true) - .fullscreen(false) - .inner_size(1200.0, 700.0) - .min_inner_size(1000.0, 600.0) - .build() - .unwrap(); - } else { - let main_win = handle.get_window("main").unwrap(); - main_win.show().unwrap(); - main_win.set_focus().unwrap(); - } - }); -} + #[tauri::command] + pub fn dalle2_search_window(app: tauri::AppHandle, query: String) { + dalle2_window( + &app.app_handle(), + Some(query), + Some("ChatGPT & DALL·E 2".to_string()), + None, + ); + } -#[tauri::command] -pub async fn wa_window( - app: tauri::AppHandle, - label: String, - title: String, - url: String, - script: Option, -) { - info!("wa_window: {} :=> {}", title, url); - let win = app.get_window(&label); - if win.is_none() { + #[tauri::command] + pub fn control_window(handle: tauri::AppHandle) { tauri::async_runtime::spawn(async move { - tauri::WindowBuilder::new(&app, label, tauri::WindowUrl::App(url.parse().unwrap())) - .initialization_script(&script.unwrap_or_default()) - .initialization_script(include_str!("../scripts/core.js")) - .title(title) + if handle.get_window("main").is_none() { + WindowBuilder::new( + &handle, + "main", + WindowUrl::App("index.html?type=control".into()), + ) + .title("Control Center") + .resizable(true) + .fullscreen(false) + .inner_size(1200.0, 700.0) + .min_inner_size(1000.0, 600.0) .build() .unwrap(); + } else { + let main_win = handle.get_window("main").unwrap(); + main_win.show().unwrap(); + main_win.set_focus().unwrap(); + } }); - } else { - if !win.clone().unwrap().is_visible().unwrap() { - win.clone().unwrap().show().unwrap(); + } + + #[command] + pub async fn wa_window( + app: tauri::AppHandle, + label: String, + title: String, + url: String, + script: Option, + ) { + info!("wa_window: {} :=> {}", title, url); + let win = app.get_window(&label); + if win.is_none() { + tauri::async_runtime::spawn(async move { + tauri::WindowBuilder::new(&app, label, tauri::WindowUrl::App(url.parse().unwrap())) + .initialization_script(&script.unwrap_or_default()) + .initialization_script(include_str!("../scripts/core.js")) + .title(title) + .build() + .unwrap(); + }); + } else { + if !win.clone().unwrap().is_visible().unwrap() { + win.clone().unwrap().show().unwrap(); + } + win + .clone() + .unwrap() + .eval("window.location.reload()") + .unwrap(); + win.unwrap().set_focus().unwrap(); } - win - .clone() + } + + #[command] + pub fn window_reload(app: tauri::AppHandle, label: &str) { + app + .app_handle() + .get_window(label) .unwrap() .eval("window.location.reload()") .unwrap(); - win.unwrap().set_focus().unwrap(); } } - -#[tauri::command] -pub fn window_reload(app: tauri::AppHandle, label: &str) { - app - .app_handle() - .get_window(label) - .unwrap() - .eval("window.location.reload()") - .unwrap(); -} diff --git a/src-tauri/src/conf.rs b/src-tauri/src/conf.rs index e6832be..6f9961e 100644 --- a/src-tauri/src/conf.rs +++ b/src-tauri/src/conf.rs @@ -1,15 +1,12 @@ -use crate::utils::{chat_root, create_file, exists}; -use anyhow::Result; -use log::info; +use log::{error, info}; use serde_json::Value; -use std::{collections::BTreeMap, fs, path::PathBuf}; +use std::{collections::BTreeMap, path::PathBuf}; use tauri::{Manager, Theme}; #[cfg(target_os = "macos")] use tauri::TitleBarStyle; -// pub const USER_AGENT: &str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15"; -// pub const PHONE_USER_AGENT: &str = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"; +use crate::utils::{app_root, create_file, exists}; pub const ISSUES_URL: &str = "https://github.com/lencx/ChatGPT/issues"; pub const UPDATE_LOG_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md"; @@ -17,163 +14,129 @@ pub const AWESOME_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/AWESOM pub const BUY_COFFEE: &str = "https://www.buymeacoffee.com/lencx"; pub const GITHUB_PROMPTS_CSV_URL: &str = "https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv"; -pub const DEFAULT_CHAT_CONF: &str = r#"{ - "stay_on_top": false, - "auto_update": "Prompt", - "theme": "Light", - "tray": true, - "titlebar": true, - "popup_search": false, - "global_shortcut": "", - "hide_dock_icon": false, - "main_dashboard": false, - "tray_dashboard": false, - "main_origin": "https://chat.openai.com", - "tray_origin": "https://chat.openai.com", - "default_origin": "https://chat.openai.com", - "ua_window": "", - "ua_tray": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1" -}"#; -pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{ - "stay_on_top": false, - "auto_update": "Prompt", - "theme": "Light", - "tray": true, - "titlebar": false, - "popup_search": false, - "global_shortcut": "", - "hide_dock_icon": false, - "main_dashboard": false, - "tray_dashboard": false, - "main_origin": "https://chat.openai.com", - "tray_origin": "https://chat.openai.com", - "default_origin": "https://chat.openai.com", - "ua_window": "", - "ua_tray": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1" -}"#; -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct ChatConfJson { - // support macOS only - pub titlebar: bool, - pub hide_dock_icon: bool, +pub const APP_CONF_PATH: &str = "chat.conf.json"; +pub const CHATGPT_URL: &str = "https://chat.openai.com"; +pub const UA_MOBILE: &str = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"; - // macOS and Windows, Light/Dark/System - pub theme: String, - // auto update policy, Prompt/Silent/Disable - pub auto_update: String, - pub tray: bool, - pub popup_search: bool, - pub stay_on_top: bool, - pub main_dashboard: bool, - pub tray_dashboard: bool, - pub main_origin: String, - pub tray_origin: String, - pub default_origin: String, - pub ua_window: String, - pub ua_tray: String, - pub global_shortcut: Option, +macro_rules! pub_struct { + ($name:ident {$($field:ident: $t:ty,)*}) => { + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] + pub struct $name { + $(pub $field: $t),* + } + } } -impl ChatConfJson { - /// init chat.conf.json - /// path: ~/.chatgpt/chat.conf.json - pub fn init() -> PathBuf { - info!("chat_conf_init"); - let conf_file = ChatConfJson::conf_path(); - let content = if cfg!(target_os = "macos") { - DEFAULT_CHAT_CONF_MAC - } else { - DEFAULT_CHAT_CONF - }; +pub_struct!(AppConf { + titlebar: bool, + hide_dock_icon: bool, + // macOS and Windows: Light / Dark / System + theme: String, + // auto update policy: Prompt / Silent / Disable + auto_update: String, + tray: bool, + popup_search: bool, + stay_on_top: bool, + main_dashboard: bool, + tray_dashboard: bool, + main_origin: String, + tray_origin: String, + default_origin: String, + ua_window: String, + ua_tray: String, + global_shortcut: Option, +}); - if !exists(&conf_file) { - create_file(&conf_file).unwrap(); - fs::write(&conf_file, content).unwrap(); - return conf_file; +impl AppConf { + pub fn new() -> Self { + info!("conf_init"); + Self { + titlebar: !cfg!(target_os = "macos"), + hide_dock_icon: false, + theme: "Light".into(), + auto_update: "Prompt".into(), + tray: true, + popup_search: false, + stay_on_top: false, + main_dashboard: false, + tray_dashboard: false, + main_origin: CHATGPT_URL.into(), + tray_origin: CHATGPT_URL.into(), + default_origin: CHATGPT_URL.into(), + ua_tray: UA_MOBILE.into(), + ua_window: "".into(), + global_shortcut: None, } + } - let conf_file = ChatConfJson::conf_path(); - let file_content = fs::read_to_string(&conf_file).unwrap(); - match serde_json::from_str(&file_content) { - Ok(v) => v, + pub fn file_path() -> PathBuf { + app_root().join(APP_CONF_PATH) + } + + pub fn read() -> Self { + match std::fs::read_to_string(Self::file_path()) { + Ok(v) => serde_json::from_str::(&v).unwrap(), Err(err) => { - if err.to_string() == "invalid type: map, expected unit at line 1 column 0" { - return conf_file; - } - fs::write(&conf_file, content).unwrap(); - } - }; - - conf_file - } - - pub fn conf_path() -> PathBuf { - chat_root().join("chat.conf.json") - } - - pub fn get_chat_conf() -> Self { - let conf_file = ChatConfJson::conf_path(); - let file_content = fs::read_to_string(&conf_file).unwrap(); - let content = if cfg!(target_os = "macos") { - DEFAULT_CHAT_CONF_MAC - } else { - DEFAULT_CHAT_CONF - }; - - match serde_json::from_value(match serde_json::from_str(&file_content) { - Ok(v) => v, - Err(_) => { - fs::write(&conf_file, content).unwrap(); - serde_json::from_str(content).unwrap() - } - }) { - Ok(v) => v, - Err(_) => { - fs::write(&conf_file, content).unwrap(); - serde_json::from_value(serde_json::from_str(content).unwrap()).unwrap() + error!("conf_read_error: {}", err); + Self::default() } } } - pub fn reset_chat_conf() -> Self { - let conf_file = ChatConfJson::conf_path(); - let content = if cfg!(target_os = "macos") { - DEFAULT_CHAT_CONF_MAC + pub fn write(self) -> Self { + let path = &Self::file_path(); + if !exists(path) { + create_file(path).unwrap(); + info!("conf_init") + } + if let Ok(v) = serde_json::to_string_pretty(&self) { + std::fs::write(path, v).unwrap_or_else(|err| { + error!("conf_write_error: {}", err); + Self::default().write(); + }); } else { - DEFAULT_CHAT_CONF - }; - fs::write(&conf_file, content).unwrap(); - serde_json::from_str(content).unwrap() + error!("conf_ser_error"); + } + self } - // https://users.rust-lang.org/t/updating-object-fields-given-dynamic-json/39049/3 - pub fn amend(new_rules: &Value, app: Option) -> Result<()> { - let config = ChatConfJson::get_chat_conf(); - let config: Value = serde_json::to_value(&config)?; - let mut config: BTreeMap = serde_json::from_value(config)?; - let new_rules: BTreeMap = serde_json::from_value(new_rules.clone())?; + pub fn amend(self, json: Value) -> Self { + let val = serde_json::to_value(&self).unwrap(); + let mut config: BTreeMap = serde_json::from_value(val).unwrap(); + let new_json: BTreeMap = serde_json::from_value(json).unwrap(); - for (k, v) in new_rules { + for (k, v) in new_json { config.insert(k, v); } - fs::write( - ChatConfJson::conf_path(), - serde_json::to_string_pretty(&config)?, - )?; - - if let Some(handle) = app { - tauri::api::process::restart(&handle.env()); + match serde_json::to_string_pretty(&config) { + Ok(v) => match serde_json::from_str::(&v) { + Ok(v) => v, + Err(err) => { + error!("conf_amend_parse_error: {}", err); + self + } + }, + Err(err) => { + error!("conf_amend_str_error: {}", err); + self + } } - - Ok(()) } - pub fn theme() -> Option { - let conf = ChatConfJson::get_chat_conf(); - let theme = match conf.theme.as_str() { - "System" => match dark_light::detect() { + #[cfg(target_os = "macos")] + pub fn titlebar(self) -> TitleBarStyle { + if self.titlebar { + TitleBarStyle::Transparent + } else { + TitleBarStyle::Overlay + } + } + + pub fn theme_mode() -> Theme { + match cmd::get_theme().to_lowercase().as_str() { + "system" => match dark_light::detect() { // Dark mode dark_light::Mode::Dark => Theme::Dark, // Light mode @@ -181,20 +144,68 @@ impl ChatConfJson { // Unspecified dark_light::Mode::Default => Theme::Light, }, - "Dark" => Theme::Dark, + "dark" => Theme::Dark, _ => Theme::Light, - }; - - Some(theme) - } - - #[cfg(target_os = "macos")] - pub fn titlebar() -> TitleBarStyle { - let conf = ChatConfJson::get_chat_conf(); - if conf.titlebar { - TitleBarStyle::Transparent - } else { - TitleBarStyle::Overlay } } + + pub fn theme_check(self, mode: &str) -> bool { + self.theme.to_lowercase() == mode + } + + pub fn restart(self, app: tauri::AppHandle) { + tauri::api::process::restart(&app.env()); + } +} + +impl Default for AppConf { + fn default() -> Self { + Self::new() + } +} + +pub mod cmd { + use super::AppConf; + use tauri::{command, AppHandle, Manager}; + + #[command] + pub fn get_app_conf() -> AppConf { + AppConf::read() + } + + #[command] + pub fn reset_app_conf() -> AppConf { + AppConf::default().write() + } + + #[command] + pub fn get_theme() -> String { + AppConf::read().theme + } + + #[command] + pub fn form_confirm(_app: AppHandle, data: serde_json::Value) { + AppConf::read().amend(serde_json::json!(data)).write(); + } + + #[command] + pub fn form_cancel(app: AppHandle, label: &str, title: &str, msg: &str) { + let win = app.app_handle().get_window(label).unwrap(); + tauri::api::dialog::ask( + app.app_handle().get_window(label).as_ref(), + title, + msg, + move |is_cancel| { + if is_cancel { + win.close().unwrap(); + } + }, + ); + } + + #[command] + pub fn form_msg(app: AppHandle, label: &str, title: &str, msg: &str) { + let win = app.app_handle().get_window(label); + tauri::api::dialog::message(win.as_ref(), title, msg); + } } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 601d4dc..c41be6c 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -8,8 +8,7 @@ mod conf; mod utils; use app::{cmd, fs_extra, gpt, menu, setup, window}; -use conf::ChatConfJson; -use tauri::api::path; +use conf::AppConf; use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_log::{ fern::colors::{Color, ColoredLevelConfig}, @@ -18,56 +17,59 @@ use tauri_plugin_log::{ #[tokio::main] async fn main() { - ChatConfJson::init(); + let app_conf = AppConf::read().write(); // If the file does not exist, creating the file will block menu synchronization utils::create_chatgpt_prompts(); let context = tauri::generate_context!(); - let colors = ColoredLevelConfig { - error: Color::Red, - warn: Color::Yellow, - debug: Color::Blue, - info: Color::BrightGreen, - trace: Color::Cyan, - }; gpt::download_list("chat.download.json", "download", None, None); gpt::download_list("chat.notes.json", "notes", None, None); - let chat_conf = ChatConfJson::get_chat_conf(); + let mut log = tauri_plugin_log::Builder::default() + .targets([ + // LogTarget::LogDir, + // LOG PATH: ~/.chatgpt/ChatGPT.log + LogTarget::Folder(utils::app_root()), + LogTarget::Stdout, + LogTarget::Webview, + ]) + .level(log::LevelFilter::Debug); + + if cfg!(debug_assertions) { + log = log.with_colors(ColoredLevelConfig { + error: Color::Red, + warn: Color::Yellow, + debug: Color::Blue, + info: Color::BrightGreen, + trace: Color::Cyan, + }); + } let mut builder = tauri::Builder::default() // https://github.com/tauri-apps/tauri/pull/2736 - .plugin( - tauri_plugin_log::Builder::default() - .targets([ - // LogTarget::LogDir, - // LOG PATH: ~/.chatgpt/ChatGPT.log - LogTarget::Folder(path::home_dir().unwrap().join(".chatgpt")), - LogTarget::Stdout, - LogTarget::Webview, - ]) - .level(log::LevelFilter::Debug) - .with_colors(colors) - .build(), - ) + .plugin(log.build()) .plugin(tauri_plugin_positioner::init()) .plugin(tauri_plugin_autostart::init( MacosLauncher::LaunchAgent, None, )) .invoke_handler(tauri::generate_handler![ + conf::cmd::get_app_conf, + conf::cmd::reset_app_conf, + conf::cmd::get_theme, + conf::cmd::form_confirm, + conf::cmd::form_cancel, + conf::cmd::form_msg, + window::cmd::wa_window, + window::cmd::control_window, + window::cmd::window_reload, + window::cmd::dalle2_search_window, cmd::drag_window, cmd::fullscreen, cmd::download, cmd::save_file, cmd::open_link, - cmd::get_chat_conf, - cmd::get_theme, - cmd::reset_chat_conf, cmd::run_check_update, - cmd::form_cancel, - cmd::form_confirm, - cmd::form_msg, cmd::open_file, cmd::get_data, gpt::get_chat_model_cmd, @@ -77,16 +79,12 @@ async fn main() { gpt::cmd_list, gpt::download_list, gpt::get_download_list, - window::wa_window, - window::control_window, - window::window_reload, - window::dalle2_search_window, fs_extra::metadata, ]) .setup(setup::init) .menu(menu::init()); - if chat_conf.tray { + if app_conf.tray { builder = builder.system_tray(menu::tray_menu()); } diff --git a/src-tauri/src/scripts/core.js b/src-tauri/src/scripts/core.js index c054687..c683d67 100644 --- a/src-tauri/src/scripts/core.js +++ b/src-tauri/src/scripts/core.js @@ -54,7 +54,7 @@ async function init() { if (__TAURI_METADATA__.__currentWindow.label !== 'tray') { const _platform = await platform(); - const chatConf = await invoke('get_chat_conf') || {}; + const chatConf = await invoke('get_app_conf') || {}; if (/darwin/.test(_platform) && !chatConf.titlebar) { const topStyleDom = document.createElement("style"); topStyleDom.innerHTML = `#chatgpt-app-window-top{position:fixed;top:0;z-index:999999999;width:100%;height:24px;background:transparent;cursor:grab;cursor:-webkit-grab;user-select:none;-webkit-user-select:none;}#chatgpt-app-window-top:active {cursor:grabbing;cursor:-webkit-grabbing;}`; diff --git a/src-tauri/src/scripts/export.js b/src-tauri/src/scripts/export.js index e400e76..0896ca8 100644 --- a/src-tauri/src/scripts/export.js +++ b/src-tauri/src/scripts/export.js @@ -3,7 +3,7 @@ async function init() { const buttonOuterHTMLFallback = ``; if (window.innerWidth < 767) return; - const chatConf = await invoke('get_chat_conf') || {}; + const chatConf = await invoke('get_app_conf') || {}; if (window.buttonsInterval) { clearInterval(window.buttonsInterval); } diff --git a/src-tauri/src/scripts/popup.core.js b/src-tauri/src/scripts/popup.core.js index 3cbbe18..cbf42f1 100644 --- a/src-tauri/src/scripts/popup.core.js +++ b/src-tauri/src/scripts/popup.core.js @@ -1,7 +1,7 @@ // *** Core Script - DALL·E 2 Core *** async function init() { - const chatConf = await invoke('get_chat_conf') || {}; + const chatConf = await invoke('get_app_conf') || {}; if (!chatConf.popup_search) return; if (!window.FloatingUIDOM) return; diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 8afe5bb..cecf449 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -11,7 +11,7 @@ use std::{ use tauri::updater::UpdateResponse; use tauri::{utils::config::Config, AppHandle, Manager, Wry}; -pub fn chat_root() -> PathBuf { +pub fn app_root() -> PathBuf { tauri::api::path::home_dir().unwrap().join(".chatgpt") } @@ -33,7 +33,7 @@ pub fn create_file(path: &Path) -> Result { } pub fn create_chatgpt_prompts() { - let sync_file = chat_root().join("cache_model").join("chatgpt_prompts.json"); + let sync_file = app_root().join("cache_model").join("chatgpt_prompts.json"); if !exists(&sync_file) { create_file(&sync_file).unwrap(); fs::write(&sync_file, "[]").unwrap(); @@ -41,7 +41,7 @@ pub fn create_chatgpt_prompts() { } pub fn script_path() -> PathBuf { - let script_file = chat_root().join("main.js"); + let script_file = app_root().join("main.js"); if !exists(&script_file) { create_file(&script_file).unwrap(); fs::write( @@ -96,7 +96,7 @@ pub fn convert_path(path_str: &str) -> String { } pub fn clear_conf(app: &tauri::AppHandle) { - let root = chat_root(); + let root = app_root(); let msg = format!( "Path: {}\n Are you sure you want to clear all ChatGPT configurations? Performing this operation data can not be restored, please back up in advance.\n diff --git a/src/utils.ts b/src/utils.ts index 7582c68..f1f62b5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,7 +2,7 @@ import { readTextFile, writeTextFile, exists, createDir } from '@tauri-apps/api/ import { homeDir, join, dirname } from '@tauri-apps/api/path'; import dayjs from 'dayjs'; -export const CHAT_CONF_JSON = 'chat.conf.json'; +export const APP_CONF_JSON = 'chat.conf.json'; export const CHAT_MODEL_JSON = 'chat.model.json'; export const CHAT_MODEL_CMD_JSON = 'chat.model.cmd.json'; export const CHAT_DOWNLOAD_JSON = 'chat.download.json'; diff --git a/src/view/dashboard/index.tsx b/src/view/dashboard/index.tsx index ef5a8a1..0f9b851 100644 --- a/src/view/dashboard/index.tsx +++ b/src/view/dashboard/index.tsx @@ -7,7 +7,7 @@ import { os, invoke } from '@tauri-apps/api'; import useInit from '@/hooks/useInit'; import useJson from '@/hooks/useJson'; -import { CHAT_AWESOME_JSON, CHAT_CONF_JSON, readJSON } from '@/utils'; +import { CHAT_AWESOME_JSON, APP_CONF_JSON, readJSON } from '@/utils'; import './index.scss'; export default function Dashboard() { @@ -19,7 +19,7 @@ export default function Dashboard() { useInit(async () => { const getOS = await os.platform(); - const conf = await readJSON(CHAT_CONF_JSON); + const conf = await readJSON(APP_CONF_JSON); const appTheme = await invoke('get_theme'); setTheme(appTheme as string); setClass(!conf?.titlebar && getOS === 'darwin'); diff --git a/src/view/settings/index.tsx b/src/view/settings/index.tsx index 1b41f15..05f7037 100644 --- a/src/view/settings/index.tsx +++ b/src/view/settings/index.tsx @@ -6,7 +6,7 @@ import { clone, omit, isEqual } from 'lodash'; import useInit from '@/hooks/useInit'; import FilePath from '@/components/FilePath'; -import { chatRoot, CHAT_CONF_JSON } from '@/utils'; +import { chatRoot, APP_CONF_JSON } from '@/utils'; import General from './General'; import MainWindow from './MainWindow'; import TrayWindow from './TrayWindow'; @@ -24,8 +24,8 @@ export default function Settings() { }, [key]); useInit(async () => { - setChatConf(await invoke('get_chat_conf')); - setPath(await path.join(await chatRoot(), CHAT_CONF_JSON)); + setChatConf(await invoke('get_app_conf')); + setPath(await path.join(await chatRoot(), APP_CONF_JSON)); }); useEffect(() => { @@ -37,7 +37,7 @@ export default function Settings() { }; const onReset = async () => { - const chatData = await invoke('reset_chat_conf'); + const chatData = await invoke('reset_app_conf'); setChatConf(chatData); const isOk = await dialog.ask(`Configuration reset successfully, whether to restart?`, { title: 'ChatGPT Preferences', @@ -69,7 +69,7 @@ export default function Settings() { return (
- +