diff --git a/README.md b/README.md
index 66452c0..3ad9501 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,9 @@
**Latest:**
-- `Mac`: [ChatGPT_0.1.7_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.1.7/ChatGPT_0.1.7_x64.dmg)
-- `Linux`: [chat-gpt_0.1.7_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.1.7/chat-gpt_0.1.7_amd64.deb)
-- `Windows`: [ChatGPT_0.1.7_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.1.7/ChatGPT_0.1.7_x64_en-US.msi)
+- `Mac`: [ChatGPT_0.1.8_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.1.8/ChatGPT_0.1.8_x64.dmg)
+- `Linux`: [chat-gpt_0.1.8_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.1.8/chat-gpt_0.1.8_amd64.deb)
+- `Windows`: [ChatGPT_0.1.8_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.1.8/ChatGPT_0.1.8_x64_en-US.msi)
[Other version...](https://github.com/lencx/ChatGPT/releases)
@@ -52,6 +52,23 @@ cask "popcorn-time", args: { "no-quarantine": true }
- tray window
- shortcut
+### Menu
+
+- **ChatGPT**
+ - `Restart ChatGPT`: After editing the injection script file, you can restart the application through this menu item to make the script take effect.
+- **Preferences**
+ - `Theme` - `Light`, `Dark` (Only macOS and Windows are supported).
+ - `Always On Top`: Window is always on top of other windows.
+ - `Titlebar`: Only supports macOS.
+ - `Switch Origin` ([#14](https://github.com/lencx/ChatGPT/issues/14)): Modify website address, the default is `https://chat.openai.com`. Please ensure that the mirror address is consistent with the UI of the original URL, otherwise the export function will fail.
+ - `Inject Script`: User scripts that can modify web pages.
+ - `Awesome ChatGPT`: Related resources recommended.
+- **Edit** - `Undo`, `Redo`, `Cut`, `Copy`, `SelectAll`, ...
+- **View** - `Go Back`, `Go Forward`, `Scroll to Top of Screen`, `Scroll to Bottom of Screen`, `Refresh the Screen`, ...
+- **Help**
+ - `Report Bug`: Defects and Suggestions Feedback.
+ - `Toggle Developer Tools`: Developer tools for debugging web pages.
+
## Preview
diff --git a/UPDATE_LOG.md b/UPDATE_LOG.md
index faccfd8..d077fcf 100644
--- a/UPDATE_LOG.md
+++ b/UPDATE_LOG.md
@@ -1,5 +1,11 @@
# UPDATE LOG
+## v0.1.8
+
+feat:
+- menu enhancement: theme, titlebar
+- modify website address
+
## v0.1.7
feat: tray window
diff --git a/package.json b/package.json
index a3651b0..79f4083 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,15 @@
},
"license": "MIT",
"author": "lencx ",
- "keywords": ["chatgpt", "app", "desktop", "tauri", "macos", "linux", "windows"],
+ "keywords": [
+ "chatgpt",
+ "app",
+ "desktop",
+ "tauri",
+ "macos",
+ "linux",
+ "windows"
+ ],
"homepage": "https://github.com/lencx/ChatGPT",
"bugs": "https://github.com/lencx/ChatGPT/issues",
"repository": {
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 47bb13b..1e861a8 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -14,11 +14,11 @@ rust-version = "1.57"
tauri-build = {version = "1.2.1", features = [] }
[dependencies]
+anyhow = "1.0.66"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
-tauri = { version = "1.2.1", features = ["api-all", "devtools", "system-tray", "updater"] }
+tauri = { version = "1.2.2", features = ["api-all", "devtools", "system-tray", "updater"] }
tauri-plugin-positioner = { version = "1.0.4", features = ["system-tray"] }
-anyhow = "1.0.66"
[features]
# by default Tauri runs in production mode
diff --git a/src-tauri/icons/tray-icon.png b/src-tauri/icons/tray-icon.png
new file mode 100644
index 0000000..81d2aeb
Binary files /dev/null and b/src-tauri/icons/tray-icon.png differ
diff --git a/src-tauri/src/app/cmd.rs b/src-tauri/src/app/cmd.rs
index 1003ce1..4c883c7 100644
--- a/src-tauri/src/app/cmd.rs
+++ b/src-tauri/src/app/cmd.rs
@@ -1,4 +1,4 @@
-use crate::utils;
+use crate::{conf::ChatConfJson, utils};
use std::fs;
use tauri::{api, command, AppHandle, Manager};
@@ -28,3 +28,35 @@ pub fn download(_app: AppHandle, name: String, blob: Vec) {
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 form_confirm(app: AppHandle, data: serde_json::Value) {
+ ChatConfJson::amend(&serde_json::json!(data)).unwrap();
+ tauri::api::process::restart(&app.env());
+}
+
+#[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/app/menu.rs b/src-tauri/src/app/menu.rs
index ef88c3f..bc23916 100644
--- a/src-tauri/src/app/menu.rs
+++ b/src-tauri/src/app/menu.rs
@@ -1,4 +1,8 @@
-use crate::{conf, utils};
+use crate::{
+ app::window,
+ conf::{self, ChatConfJson},
+ utils,
+};
use tauri::{
utils::assets::EmbeddedAssets, AboutMetadata, AppHandle, Context, CustomMenuItem, Manager,
Menu, MenuItem, Submenu, SystemTray, SystemTrayEvent, SystemTrayMenu, WindowMenuEvent,
@@ -6,13 +10,19 @@ use tauri::{
use tauri_plugin_positioner::{on_tray_event, Position, WindowExt};
// --- Menu
-pub fn init(chat_conf: &conf::ChatConfJson, context: &Context) -> Menu {
+pub fn init(context: &Context) -> Menu {
+ let chat_conf = ChatConfJson::get_chat_conf();
let name = &context.package_info().name;
let app_menu = Submenu::new(
name,
Menu::new()
.add_native_item(MenuItem::About(name.into(), AboutMetadata::default()))
.add_native_item(MenuItem::Separator)
+ .add_item(
+ CustomMenuItem::new("restart".to_string(), "Restart ChatGPT")
+ .accelerator("CmdOrCtrl+Shift+R"),
+ )
+ .add_native_item(MenuItem::Services)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Hide)
.add_native_item(MenuItem::HideOthers)
@@ -23,24 +33,55 @@ pub fn init(chat_conf: &conf::ChatConfJson, context: &Context) -
let always_on_top = CustomMenuItem::new("always_on_top".to_string(), "Always On Top")
.accelerator("CmdOrCtrl+T");
+ let titlebar =
+ CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B");
+ let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light");
+ let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark");
+ let is_dark = chat_conf.theme == "Dark";
+
+ let always_on_top_menu = if chat_conf.always_on_top {
+ always_on_top.selected()
+ } else {
+ always_on_top
+ };
+ let titlebar_menu = if chat_conf.titlebar {
+ titlebar.selected()
+ } else {
+ titlebar
+ };
let preferences_menu = Submenu::new(
"Preferences",
- Menu::new()
- .add_item(
- CustomMenuItem::new("inject_script".to_string(), "Inject Script")
- .accelerator("CmdOrCtrl+J"),
+ Menu::with_items([
+ Submenu::new(
+ "Theme",
+ Menu::new()
+ .add_item(if is_dark {
+ theme_light
+ } else {
+ theme_light.selected()
+ })
+ .add_item(if is_dark {
+ theme_dark.selected()
+ } else {
+ theme_dark
+ }),
)
- .add_item(if chat_conf.always_on_top {
- always_on_top.selected()
- } else {
- always_on_top
- })
- .add_native_item(MenuItem::Separator)
- .add_item(
- CustomMenuItem::new("awesome".to_string(), "Awesome ChatGPT")
- .accelerator("CmdOrCtrl+Z"),
- ),
+ .into(),
+ always_on_top_menu.into(),
+ #[cfg(target_os = "macos")]
+ titlebar_menu.into(),
+ CustomMenuItem::new("switch_origin".to_string(), "Switch Origin")
+ .accelerator("CmdOrCtrl+O")
+ .into(),
+ CustomMenuItem::new("inject_script".to_string(), "Inject Script")
+ .accelerator("CmdOrCtrl+J")
+ .into(),
+ MenuItem::Separator.into(),
+ CustomMenuItem::new("awesome".to_string(), "Awesome ChatGPT")
+ .accelerator("CmdOrCtrl+Z")
+ .into(),
+ ]),
);
let edit_menu = Submenu::new(
@@ -73,6 +114,7 @@ pub fn init(chat_conf: &conf::ChatConfJson, context: &Context) -
CustomMenuItem::new("scroll_bottom".to_string(), "Scroll to Bottom of Screen")
.accelerator("CmdOrCtrl+Down"),
)
+ .add_native_item(MenuItem::Zoom)
.add_native_item(MenuItem::Separator)
.add_item(
CustomMenuItem::new("reload".to_string(), "Refresh the Screen")
@@ -110,9 +152,29 @@ pub fn menu_handler(event: WindowMenuEvent) {
let menu_handle = core_window.menu_handle();
match menu_id {
+ // App
+ "restart" => tauri::api::process::restart(&app.env()),
// Preferences
"inject_script" => open(&app, script_path),
"awesome" => open(&app, conf::AWESOME_URL.to_string()),
+ "switch_origin" => {
+ window::origin_window(&app);
+ // app.get_window("origin").unwrap().show();
+ }
+ "titlebar" => {
+ let chat_conf = conf::ChatConfJson::get_chat_conf();
+ ChatConfJson::amend(&serde_json::json!({ "titlebar": !chat_conf.titlebar })).unwrap();
+ tauri::api::process::restart(&app.env());
+ }
+ "theme_light" | "theme_dark" => {
+ let theme = if menu_id == "theme_dark" {
+ "Dark"
+ } else {
+ "Light"
+ };
+ ChatConfJson::amend(&serde_json::json!({ "theme": theme })).unwrap();
+ tauri::api::process::restart(&app.env());
+ }
"always_on_top" => {
let mut always_on_top = state.always_on_top.lock().unwrap();
*always_on_top = !*always_on_top;
@@ -121,7 +183,7 @@ pub fn menu_handler(event: WindowMenuEvent) {
.set_selected(*always_on_top)
.unwrap();
win.set_always_on_top(*always_on_top).unwrap();
- conf::ChatConfJson::update_chat_conf(*always_on_top);
+ ChatConfJson::amend(&serde_json::json!({ "always_on_top": *always_on_top })).unwrap();
}
// View
"reload" => win.eval("window.location.reload()").unwrap(),
diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs
index 84cdc5a..3418a8f 100644
--- a/src-tauri/src/app/setup.rs
+++ b/src-tauri/src/app/setup.rs
@@ -1,15 +1,14 @@
-use crate::{app::window, conf, utils};
+use crate::{
+ app::window,
+ conf::{ChatConfJson, USER_AGENT},
+ utils,
+};
use tauri::{utils::config::WindowUrl, window::WindowBuilder, App, Manager};
-#[cfg(target_os = "macos")]
-use tauri::TitleBarStyle;
-
-pub fn init(
- app: &mut App,
- chat_conf: conf::ChatConfJson,
-) -> std::result::Result<(), Box> {
- let conf = utils::get_tauri_conf().unwrap();
- let url = conf.build.dev_path.to_string();
+pub fn init(app: &mut App) -> std::result::Result<(), Box> {
+ let chat_conf = ChatConfJson::get_chat_conf();
+ let url = chat_conf.origin.to_string();
+ let theme = ChatConfJson::theme();
window::mini_window(&app.app_handle());
#[cfg(target_os = "macos")]
@@ -18,14 +17,15 @@ pub fn init(
.fullscreen(false)
.inner_size(800.0, 600.0)
.hidden_title(true)
- .title_bar_style(TitleBarStyle::Overlay)
+ .theme(theme)
.always_on_top(chat_conf.always_on_top)
+ .title_bar_style(ChatConfJson::titlebar())
.initialization_script(&utils::user_script())
.initialization_script(include_str!("../assets/html2canvas.js"))
.initialization_script(include_str!("../assets/jspdf.js"))
.initialization_script(include_str!("../assets/core.js"))
.initialization_script(include_str!("../assets/export.js"))
- .user_agent(conf::USER_AGENT)
+ .user_agent(USER_AGENT)
.build()?;
#[cfg(not(target_os = "macos"))]
@@ -34,13 +34,14 @@ pub fn init(
.resizable(true)
.fullscreen(false)
.inner_size(800.0, 600.0)
+ .theme(theme)
.always_on_top(chat_conf.always_on_top)
.initialization_script(&utils::user_script())
.initialization_script(include_str!("../assets/html2canvas.js"))
.initialization_script(include_str!("../assets/jspdf.js"))
.initialization_script(include_str!("../assets/core.js"))
.initialization_script(include_str!("../assets/export.js"))
- .user_agent(conf::USER_AGENT)
+ .user_agent(USER_AGENT)
.build()?;
Ok(())
diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs
index e969d71..2fc6af3 100644
--- a/src-tauri/src/app/window.rs
+++ b/src-tauri/src/app/window.rs
@@ -2,24 +2,40 @@ use crate::{conf, utils};
use tauri::{utils::config::WindowUrl, window::WindowBuilder};
pub fn mini_window(handle: &tauri::AppHandle) {
- let conf = utils::get_tauri_conf().unwrap();
- let url = conf.build.dev_path.to_string();
+ let chat_conf = conf::ChatConfJson::get_chat_conf();
+ let theme = conf::ChatConfJson::theme();
- WindowBuilder::new(handle, "mini", WindowUrl::App(url.into()))
+ WindowBuilder::new(handle, "mini", WindowUrl::App(chat_conf.origin.into()))
.resizable(false)
.fullscreen(false)
.inner_size(360.0, 540.0)
.decorations(false)
.always_on_top(true)
+ .theme(theme)
.initialization_script(&utils::user_script())
.initialization_script(include_str!("../assets/html2canvas.js"))
.initialization_script(include_str!("../assets/jspdf.js"))
.initialization_script(include_str!("../assets/core.js"))
.initialization_script(include_str!("../assets/export.js"))
.user_agent(conf::PHONE_USER_AGENT)
- .menu(tauri::Menu::new())
.build()
.unwrap()
.hide()
.unwrap();
}
+
+pub fn origin_window(handle: &tauri::AppHandle) {
+ let chat_conf = conf::ChatConfJson::get_chat_conf();
+ // tauri://localhost/origin
+ // let url = chat_conf.origin;
+ WindowBuilder::new(handle, "origin", WindowUrl::App(chat_conf.origin.into()))
+ .resizable(false)
+ .fullscreen(false)
+ .inner_size(400.0, 300.0)
+ .always_on_top(true)
+ .decorations(false)
+ .initialization_script(include_str!("../assets/core.js"))
+ .initialization_script(include_str!("../assets/origin.js"))
+ .build()
+ .unwrap();
+}
diff --git a/src-tauri/src/assets/core.js b/src-tauri/src/assets/core.js
index fe79a00..854b1aa 100644
--- a/src-tauri/src/assets/core.js
+++ b/src-tauri/src/assets/core.js
@@ -54,7 +54,8 @@ async function init() {
}
const _platform = await platform();
- if (/darwin/.test(_platform)) {
+ const chatConf = await invoke('get_chat_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;}`;
document.head.appendChild(topStyleDom);
@@ -70,7 +71,7 @@ async function init() {
document.addEventListener("click", (e) => {
const origin = e.target.closest("a");
if (origin && origin.href && origin.target !== '_self') {
- origin.target = "_self";
+ invoke('open_link', { url: origin.href });
}
});
diff --git a/src-tauri/src/assets/export.js b/src-tauri/src/assets/export.js
index 819675a..41a1851 100644
--- a/src-tauri/src/assets/export.js
+++ b/src-tauri/src/assets/export.js
@@ -2,6 +2,7 @@
// @ref: https://github.com/liady/ChatGPT-pdf/blob/main/src/content_script.js
async function init() {
+ const chatConf = await invoke('get_chat_conf') || {};
if (window.buttonsInterval) {
clearInterval(window.buttonsInterval);
}
@@ -16,7 +17,7 @@ async function init() {
});
if (hasTryAgainButton && buttons.length === 1) {
const TryAgainButton = actionsArea.querySelector("button");
- addActionsButtons(actionsArea, TryAgainButton);
+ addActionsButtons(actionsArea, TryAgainButton, chatConf);
} else if (!hasTryAgainButton) {
removeButtons();
}
@@ -28,7 +29,7 @@ const Format = {
PDF: "pdf",
};
-function addActionsButtons(actionsArea, TryAgainButton) {
+function addActionsButtons(actionsArea, TryAgainButton, chatConf) {
const downloadButton = TryAgainButton.cloneNode(true);
downloadButton.id = "download-png-button";
downloadButton.innerText = "Generate PNG";
@@ -36,6 +37,7 @@ function addActionsButtons(actionsArea, TryAgainButton) {
downloadThread();
};
actionsArea.appendChild(downloadButton);
+
const downloadPdfButton = TryAgainButton.cloneNode(true);
downloadPdfButton.id = "download-pdf-button";
downloadPdfButton.innerText = "Download PDF";
@@ -43,13 +45,16 @@ function addActionsButtons(actionsArea, TryAgainButton) {
downloadThread({ as: Format.PDF });
};
actionsArea.appendChild(downloadPdfButton);
- const exportHtml = TryAgainButton.cloneNode(true);
- exportHtml.id = "download-html-button";
- exportHtml.innerText = "Share Link";
- exportHtml.onclick = () => {
- sendRequest();
- };
- actionsArea.appendChild(exportHtml);
+
+ if (new RegExp('//chat.openai.com').test(chatConf.origin)) {
+ const exportHtml = TryAgainButton.cloneNode(true);
+ exportHtml.id = "download-html-button";
+ exportHtml.innerText = "Share Link";
+ exportHtml.onclick = () => {
+ sendRequest();
+ };
+ actionsArea.appendChild(exportHtml);
+ }
}
function removeButtons() {
diff --git a/src-tauri/src/assets/origin.js b/src-tauri/src/assets/origin.js
new file mode 100644
index 0000000..4220086
--- /dev/null
+++ b/src-tauri/src/assets/origin.js
@@ -0,0 +1,77 @@
+function init() {
+ document.body.innerHTML = `
+ Switch Origin
+
+
+
+
+
`;
+
+ const srcipt = document.createElement('script');
+ srcipt.innerHTML = `const input = document.getElementById('input');
+ const cancelBtn = document.getElementById('cancel');
+ const confirmBtn = document.getElementById('confirm');
+ cancelBtn.addEventListener('click', () => {
+ window.invoke('form_cancel', { label: 'origin', title: 'Switch Origin', msg: 'Sure you want to give up the switch?' });
+ })
+ confirmBtn.addEventListener('click', () => {
+ if (/^https?:\\/\\//.test(input.value)) {
+ window.invoke('form_confirm', { data: { origin: input.value } });
+ } else {
+ window.invoke('form_msg', { label: 'origin', title: 'Switch Origin', msg: 'Invalid URL!' });
+ }
+ })`;
+ document.head.appendChild(srcipt);
+}
+
+// run init
+if (
+ document.readyState === "complete" ||
+ document.readyState === "interactive"
+) {
+ init();
+} else {
+ document.addEventListener("DOMContentLoaded", init);
+}
\ No newline at end of file
diff --git a/src-tauri/src/conf.rs b/src-tauri/src/conf.rs
index 8486d05..12e5179 100644
--- a/src-tauri/src/conf.rs
+++ b/src-tauri/src/conf.rs
@@ -1,19 +1,30 @@
use crate::utils::{chat_root, create_file, exists};
-use std::fs;
-use std::path::PathBuf;
-use std::sync::Mutex;
+use anyhow::Result;
+use serde_json::Value;
+use std::{collections::BTreeMap, fs, path::PathBuf, sync::Mutex};
+use tauri::Theme;
+
+#[cfg(target_os = "macos")]
+use tauri::TitleBarStyle;
pub const USER_AGENT: &str = "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36";
pub const PHONE_USER_AGENT: &str = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
pub const ISSUES_URL: &str = "https://github.com/lencx/ChatGPT/issues";
pub const AWESOME_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/AWESOME.md";
+pub const DEFAULT_CHAT_CONF: &str = r#"{
+ "always_on_top": false,
+ "theme": "Light",
+ "titlebar": true,
+ "default_origin": "https://chat.openai.com",
+ "origin": "https://chat.openai.com"
+}"#;
pub struct ChatState {
pub always_on_top: Mutex,
}
impl ChatState {
- pub fn default(chat_conf: &ChatConfJson) -> Self {
+ pub fn default(chat_conf: ChatConfJson) -> Self {
ChatState {
always_on_top: Mutex::new(chat_conf.always_on_top),
}
@@ -23,6 +34,10 @@ impl ChatState {
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct ChatConfJson {
pub always_on_top: bool,
+ pub theme: String,
+ pub titlebar: bool,
+ pub default_origin: String,
+ pub origin: String,
}
impl ChatConfJson {
@@ -32,7 +47,22 @@ impl ChatConfJson {
let conf_file = ChatConfJson::conf_path();
if !exists(&conf_file) {
create_file(&conf_file).unwrap();
- fs::write(&conf_file, r#"{"always_on_top": false}"#).unwrap();
+
+ #[cfg(target_os = "macos")]
+ fs::write(
+ &conf_file,
+ r#"{
+ "always_on_top": false,
+ "theme": "Light",
+ "titlebar": false,
+ "default_origin": "https://chat.openai.com",
+ "origin": "https://chat.openai.com"
+ }"#,
+ )
+ .unwrap();
+
+ #[cfg(not(target_os = "macos"))]
+ fs::write(&conf_file, DEFAULT_CHAT_CONF).unwrap();
}
conf_file
}
@@ -43,25 +73,49 @@ impl ChatConfJson {
pub fn get_chat_conf() -> Self {
let config_file = fs::read_to_string(ChatConfJson::conf_path()).unwrap();
- let config: serde_json::Value =
+ let config: Value =
serde_json::from_str(&config_file).expect("failed to parse chat.conf.json");
serde_json::from_value(config).unwrap_or_else(|_| ChatConfJson::chat_conf_default())
}
- pub fn update_chat_conf(always_on_top: bool) {
- let mut conf = ChatConfJson::get_chat_conf();
- conf.always_on_top = always_on_top;
+ // https://users.rust-lang.org/t/updating-object-fields-given-dynamic-json/39049/3
+ pub fn amend(new_rules: &Value) -> 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())?;
+
+ for (k, v) in new_rules {
+ config.insert(k, v);
+ }
+
fs::write(
ChatConfJson::conf_path(),
- serde_json::to_string(&conf).unwrap(),
- )
- .unwrap();
+ serde_json::to_string_pretty(&config)?,
+ )?;
+ Ok(())
+ }
+
+ pub fn theme() -> Option {
+ let conf = ChatConfJson::get_chat_conf();
+ if conf.theme == "Dark" {
+ Some(Theme::Dark)
+ } else {
+ Some(Theme::Light)
+ }
+ }
+
+ #[cfg(target_os = "macos")]
+ pub fn titlebar() -> TitleBarStyle {
+ let conf = ChatConfJson::get_chat_conf();
+ if conf.titlebar {
+ TitleBarStyle::Transparent
+ } else {
+ TitleBarStyle::Overlay
+ }
}
pub fn chat_conf_default() -> Self {
- serde_json::from_value(serde_json::json!({
- "always_on_top": false,
- }))
- .unwrap()
+ serde_json::from_value(serde_json::json!(DEFAULT_CHAT_CONF)).unwrap()
}
}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 57b55e0..ce3ad3e 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -8,25 +8,28 @@ mod conf;
mod utils;
use app::{cmd, menu, setup};
-use conf::ChatConfJson;
+use conf::{ChatConfJson, ChatState};
fn main() {
ChatConfJson::init();
- let context = tauri::generate_context!();
let chat_conf = ChatConfJson::get_chat_conf();
- let chat_conf2 = chat_conf.clone();
+ let context = tauri::generate_context!();
tauri::Builder::default()
- .manage(conf::ChatState::default(&chat_conf))
+ .manage(ChatState::default(chat_conf))
.invoke_handler(tauri::generate_handler![
cmd::drag_window,
cmd::fullscreen,
cmd::download,
- cmd::open_link
+ cmd::open_link,
+ cmd::get_chat_conf,
+ cmd::form_cancel,
+ cmd::form_confirm,
+ cmd::form_msg,
])
- .setup(|app| setup::init(app, chat_conf2))
+ .setup(setup::init)
.plugin(tauri_plugin_positioner::init())
- .menu(menu::init(&chat_conf, &context))
+ .menu(menu::init(&context))
.system_tray(menu::tray_menu())
.on_menu_event(menu::menu_handler)
.on_system_tray_event(menu::tray_handler)
diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs
index 15e80a8..58f37fe 100644
--- a/src-tauri/src/utils.rs
+++ b/src-tauri/src/utils.rs
@@ -4,18 +4,18 @@ use std::{
path::{Path, PathBuf},
process::Command,
};
-use tauri::utils::config::Config;
+// use tauri::utils::config::Config;
pub fn chat_root() -> PathBuf {
tauri::api::path::home_dir().unwrap().join(".chatgpt")
}
-pub fn get_tauri_conf() -> Option {
- let config_file = include_str!("../tauri.conf.json");
- let config: Config =
- serde_json::from_str(config_file).expect("failed to parse tauri.conf.json");
- Some(config)
-}
+// pub fn get_tauri_conf() -> Option {
+// let config_file = include_str!("../tauri.conf.json");
+// let config: Config =
+// serde_json::from_str(config_file).expect("failed to parse tauri.conf.json");
+// Some(config)
+// }
pub fn exists(path: &Path) -> bool {
Path::new(path).exists()
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index ef29397..bbf63ce 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -2,20 +2,20 @@
"build": {
"beforeDevCommand": "",
"beforeBuildCommand": "",
- "devPath": "https://chat.openai.com/",
+ "devPath": "../dist",
"distDir": "../dist"
},
"package": {
"productName": "ChatGPT",
- "version": "0.1.7"
+ "version": "0.1.8"
},
"tauri": {
"allowlist": {
"all": true
},
"systemTray": {
- "iconPath": "icons/icon.png",
- "iconAsTemplate": false
+ "iconPath": "icons/tray-icon.png",
+ "iconAsTemplate": true
},
"bundle": {
"active": true,