mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: add rustfmt.toml
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
tauri_build::build()
|
tauri_build::build()
|
||||||
}
|
}
|
||||||
|
|||||||
4
src-tauri/rustfmt.toml
Normal file
4
src-tauri/rustfmt.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
edition = "2021"
|
||||||
|
max_width = 120
|
||||||
|
tab_spaces = 2
|
||||||
|
newline_style = "Auto"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{fs_extra, window},
|
app::{fs_extra, window},
|
||||||
conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL},
|
conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL},
|
||||||
utils::{self, chat_root, create_file},
|
utils::{self, chat_root, create_file},
|
||||||
};
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -11,390 +11,383 @@ use walkdir::WalkDir;
|
|||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn drag_window(app: AppHandle) {
|
pub fn drag_window(app: AppHandle) {
|
||||||
app.get_window("core").unwrap().start_dragging().unwrap();
|
app.get_window("core").unwrap().start_dragging().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn dalle2_window(app: AppHandle, query: String) {
|
pub fn dalle2_window(app: AppHandle, query: String) {
|
||||||
window::dalle2_window(
|
window::dalle2_window(
|
||||||
&app.app_handle(),
|
&app.app_handle(),
|
||||||
Some(query),
|
Some(query),
|
||||||
Some("ChatGPT & DALL·E 2".to_string()),
|
Some("ChatGPT & DALL·E 2".to_string()),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn fullscreen(app: AppHandle) {
|
pub fn fullscreen(app: AppHandle) {
|
||||||
let win = app.get_window("core").unwrap();
|
let win = app.get_window("core").unwrap();
|
||||||
if win.is_fullscreen().unwrap() {
|
if win.is_fullscreen().unwrap() {
|
||||||
win.set_fullscreen(false).unwrap();
|
win.set_fullscreen(false).unwrap();
|
||||||
} else {
|
} else {
|
||||||
win.set_fullscreen(true).unwrap();
|
win.set_fullscreen(true).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn download(_app: AppHandle, name: String, blob: Vec<u8>) {
|
pub fn download(_app: AppHandle, name: String, blob: Vec<u8>) {
|
||||||
let path = chat_root().join(PathBuf::from(name));
|
let path = chat_root().join(PathBuf::from(name));
|
||||||
create_file(&path).unwrap();
|
create_file(&path).unwrap();
|
||||||
fs::write(&path, blob).unwrap();
|
fs::write(&path, blob).unwrap();
|
||||||
utils::open_file(path);
|
utils::open_file(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn save_file(_app: AppHandle, name: String, content: String) {
|
pub fn save_file(_app: AppHandle, name: String, content: String) {
|
||||||
let path = chat_root().join(PathBuf::from(name));
|
let path = chat_root().join(PathBuf::from(name));
|
||||||
create_file(&path).unwrap();
|
create_file(&path).unwrap();
|
||||||
fs::write(&path, content).unwrap();
|
fs::write(&path, content).unwrap();
|
||||||
utils::open_file(path);
|
utils::open_file(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn open_link(app: AppHandle, url: String) {
|
pub fn open_link(app: AppHandle, url: String) {
|
||||||
api::shell::open(&app.shell_scope(), url, None).unwrap();
|
api::shell::open(&app.shell_scope(), url, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn get_chat_conf() -> ChatConfJson {
|
pub fn get_chat_conf() -> ChatConfJson {
|
||||||
ChatConfJson::get_chat_conf()
|
ChatConfJson::get_chat_conf()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn get_theme() -> String {
|
pub fn get_theme() -> String {
|
||||||
ChatConfJson::theme().unwrap_or(Theme::Light).to_string()
|
ChatConfJson::theme().unwrap_or(Theme::Light).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn reset_chat_conf() -> ChatConfJson {
|
pub fn reset_chat_conf() -> ChatConfJson {
|
||||||
ChatConfJson::reset_chat_conf()
|
ChatConfJson::reset_chat_conf()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option<bool>) {
|
pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option<bool>) {
|
||||||
utils::run_check_update(app, silent, has_msg);
|
utils::run_check_update(app, silent, has_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn form_confirm(_app: AppHandle, data: serde_json::Value) {
|
pub fn form_confirm(_app: AppHandle, data: serde_json::Value) {
|
||||||
ChatConfJson::amend(&serde_json::json!(data), None).unwrap();
|
ChatConfJson::amend(&serde_json::json!(data), None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn form_cancel(app: AppHandle, label: &str, title: &str, msg: &str) {
|
pub fn form_cancel(app: AppHandle, label: &str, title: &str, msg: &str) {
|
||||||
let win = app.app_handle().get_window(label).unwrap();
|
let win = app.app_handle().get_window(label).unwrap();
|
||||||
tauri::api::dialog::ask(
|
tauri::api::dialog::ask(
|
||||||
app.app_handle().get_window(label).as_ref(),
|
app.app_handle().get_window(label).as_ref(),
|
||||||
title,
|
title,
|
||||||
msg,
|
msg,
|
||||||
move |is_cancel| {
|
move |is_cancel| {
|
||||||
if is_cancel {
|
if is_cancel {
|
||||||
win.close().unwrap();
|
win.close().unwrap();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn form_msg(app: AppHandle, label: &str, title: &str, msg: &str) {
|
pub fn form_msg(app: AppHandle, label: &str, title: &str, msg: &str) {
|
||||||
let win = app.app_handle().get_window(label);
|
let win = app.app_handle().get_window(label);
|
||||||
tauri::api::dialog::message(win.as_ref(), title, msg);
|
tauri::api::dialog::message(win.as_ref(), title, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn open_file(path: PathBuf) {
|
pub fn open_file(path: PathBuf) {
|
||||||
utils::open_file(path);
|
utils::open_file(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn get_chat_model_cmd() -> serde_json::Value {
|
pub fn get_chat_model_cmd() -> serde_json::Value {
|
||||||
let path = utils::chat_root().join("chat.model.cmd.json");
|
let path = utils::chat_root().join("chat.model.cmd.json");
|
||||||
let content = fs::read_to_string(path).unwrap_or_else(|_| r#"{"data":[]}"#.to_string());
|
let content = fs::read_to_string(path).unwrap_or_else(|_| r#"{"data":[]}"#.to_string());
|
||||||
serde_json::from_str(&content).unwrap()
|
serde_json::from_str(&content).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct PromptRecord {
|
pub struct PromptRecord {
|
||||||
pub cmd: Option<String>,
|
pub cmd: Option<String>,
|
||||||
pub act: String,
|
pub act: String,
|
||||||
pub prompt: String,
|
pub prompt: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn parse_prompt(data: String) -> Vec<PromptRecord> {
|
pub fn parse_prompt(data: String) -> Vec<PromptRecord> {
|
||||||
let mut rdr = csv::Reader::from_reader(data.as_bytes());
|
let mut rdr = csv::Reader::from_reader(data.as_bytes());
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
for result in rdr.deserialize() {
|
for result in rdr.deserialize() {
|
||||||
let record: PromptRecord = result.unwrap_or_else(|err| {
|
let record: PromptRecord = result.unwrap_or_else(|err| {
|
||||||
info!("parse_prompt_error: {}", err);
|
info!("parse_prompt_error: {}", err);
|
||||||
PromptRecord {
|
PromptRecord {
|
||||||
cmd: None,
|
cmd: None,
|
||||||
act: "".to_string(),
|
act: "".to_string(),
|
||||||
prompt: "".to_string(),
|
prompt: "".to_string(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if !record.act.is_empty() {
|
if !record.act.is_empty() {
|
||||||
list.push(record);
|
list.push(record);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
list
|
}
|
||||||
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn window_reload(app: AppHandle, label: &str) {
|
pub fn window_reload(app: AppHandle, label: &str) {
|
||||||
app.app_handle()
|
app
|
||||||
.get_window(label)
|
.app_handle()
|
||||||
.unwrap()
|
.get_window(label)
|
||||||
.eval("window.location.reload()")
|
.unwrap()
|
||||||
.unwrap();
|
.eval("window.location.reload()")
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct ModelRecord {
|
pub struct ModelRecord {
|
||||||
pub cmd: String,
|
pub cmd: String,
|
||||||
pub act: String,
|
pub act: String,
|
||||||
pub prompt: String,
|
pub prompt: String,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn cmd_list() -> Vec<ModelRecord> {
|
pub fn cmd_list() -> Vec<ModelRecord> {
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
for entry in WalkDir::new(utils::chat_root().join("cache_model"))
|
for entry in WalkDir::new(utils::chat_root().join("cache_model"))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
{
|
{
|
||||||
let file = fs::read_to_string(entry.path().display().to_string());
|
let file = fs::read_to_string(entry.path().display().to_string());
|
||||||
if let Ok(v) = file {
|
if let Ok(v) = file {
|
||||||
let data: Vec<ModelRecord> = serde_json::from_str(&v).unwrap_or_else(|_| vec![]);
|
let data: Vec<ModelRecord> = serde_json::from_str(&v).unwrap_or_else(|_| vec![]);
|
||||||
let enable_list = data.into_iter().filter(|v| v.enable);
|
let enable_list = data.into_iter().filter(|v| v.enable);
|
||||||
list.extend(enable_list)
|
list.extend(enable_list)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// dbg!(&list);
|
}
|
||||||
list.sort_by(|a, b| a.cmd.len().cmp(&b.cmd.len()));
|
// dbg!(&list);
|
||||||
list
|
list.sort_by(|a, b| a.cmd.len().cmp(&b.cmd.len()));
|
||||||
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct FileMetadata {
|
pub struct FileMetadata {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub ext: String,
|
pub ext: String,
|
||||||
pub created: u64,
|
pub created: u64,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_download_list(pathname: &str) -> (Vec<serde_json::Value>, PathBuf) {
|
pub fn get_download_list(pathname: &str) -> (Vec<serde_json::Value>, PathBuf) {
|
||||||
info!("get_download_list: {}", pathname);
|
info!("get_download_list: {}", pathname);
|
||||||
let download_path = chat_root().join(PathBuf::from(pathname));
|
let download_path = chat_root().join(PathBuf::from(pathname));
|
||||||
let content = fs::read_to_string(&download_path).unwrap_or_else(|err| {
|
let content = fs::read_to_string(&download_path).unwrap_or_else(|err| {
|
||||||
info!("download_list_error: {}", err);
|
info!("download_list_error: {}", err);
|
||||||
fs::write(&download_path, "[]").unwrap();
|
fs::write(&download_path, "[]").unwrap();
|
||||||
"[]".to_string()
|
"[]".to_string()
|
||||||
});
|
});
|
||||||
let list = serde_json::from_str::<Vec<serde_json::Value>>(&content).unwrap_or_else(|err| {
|
let list = serde_json::from_str::<Vec<serde_json::Value>>(&content).unwrap_or_else(|err| {
|
||||||
info!("download_list_parse_error: {}", err);
|
info!("download_list_parse_error: {}", err);
|
||||||
vec![]
|
vec![]
|
||||||
});
|
});
|
||||||
|
|
||||||
(list, download_path)
|
(list, download_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub fn download_list(pathname: &str, dir: &str, filename: Option<String>, id: Option<String>) {
|
pub fn download_list(pathname: &str, dir: &str, filename: Option<String>, id: Option<String>) {
|
||||||
info!("download_list: {}", pathname);
|
info!("download_list: {}", pathname);
|
||||||
let data = get_download_list(pathname);
|
let data = get_download_list(pathname);
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
let mut idmap = HashMap::new();
|
let mut idmap = HashMap::new();
|
||||||
utils::vec_to_hashmap(data.0.into_iter(), "id", &mut idmap);
|
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::chat_root().join(dir))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_entry(|e| !utils::is_hidden(e))
|
.filter_entry(|e| !utils::is_hidden(e))
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
{
|
{
|
||||||
let metadata = entry.metadata().unwrap();
|
let metadata = entry.metadata().unwrap();
|
||||||
if metadata.is_file() {
|
if metadata.is_file() {
|
||||||
let file_path = entry.path().display().to_string();
|
let file_path = entry.path().display().to_string();
|
||||||
let re = Regex::new(r"(?P<id>[\d\w]+).(?P<ext>\w+)$").unwrap();
|
let re = Regex::new(r"(?P<id>[\d\w]+).(?P<ext>\w+)$").unwrap();
|
||||||
let caps = re.captures(&file_path).unwrap();
|
let caps = re.captures(&file_path).unwrap();
|
||||||
let fid = &caps["id"];
|
let fid = &caps["id"];
|
||||||
let fext = &caps["ext"];
|
let fext = &caps["ext"];
|
||||||
|
|
||||||
let mut file_data = FileMetadata {
|
let mut file_data = FileMetadata {
|
||||||
name: fid.to_string(),
|
name: fid.to_string(),
|
||||||
id: fid.to_string(),
|
id: fid.to_string(),
|
||||||
ext: fext.to_string(),
|
ext: fext.to_string(),
|
||||||
created: fs_extra::system_time_to_ms(metadata.created()),
|
created: fs_extra::system_time_to_ms(metadata.created()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if idmap.get(fid).is_some() {
|
if idmap.get(fid).is_some() {
|
||||||
let name = idmap.get(fid).unwrap().get("name").unwrap().clone();
|
let name = idmap.get(fid).unwrap().get("name").unwrap().clone();
|
||||||
match name {
|
match name {
|
||||||
serde_json::Value::String(v) => {
|
serde_json::Value::String(v) => {
|
||||||
file_data.name = v.clone();
|
file_data.name = v.clone();
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
_ => "".to_string(),
|
_ => "".to_string(),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.is_some() && id.is_some() {
|
||||||
|
if let Some(ref v) = id {
|
||||||
|
if fid == v {
|
||||||
|
if let Some(ref v2) = filename {
|
||||||
|
file_data.name = v2.to_string();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if filename.is_some() && id.is_some() {
|
|
||||||
if let Some(ref v) = id {
|
|
||||||
if fid == v {
|
|
||||||
if let Some(ref v2) = filename {
|
|
||||||
file_data.name = v2.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.push(serde_json::to_value(file_data).unwrap());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
list.push(serde_json::to_value(file_data).unwrap());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dbg!(&list);
|
// dbg!(&list);
|
||||||
list.sort_by(|a, b| {
|
list.sort_by(|a, b| {
|
||||||
let a1 = a.get("created").unwrap().as_u64().unwrap();
|
let a1 = a.get("created").unwrap().as_u64().unwrap();
|
||||||
let b1 = b.get("created").unwrap().as_u64().unwrap();
|
let b1 = b.get("created").unwrap().as_u64().unwrap();
|
||||||
a1.cmp(&b1).reverse()
|
a1.cmp(&b1).reverse()
|
||||||
});
|
});
|
||||||
|
|
||||||
fs::write(data.1, serde_json::to_string_pretty(&list).unwrap()).unwrap();
|
fs::write(data.1, serde_json::to_string_pretty(&list).unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>> {
|
pub async fn sync_prompts(app: AppHandle, time: u64) -> Option<Vec<ModelRecord>> {
|
||||||
let res = utils::get_data(GITHUB_PROMPTS_CSV_URL, Some(&app))
|
let res = utils::get_data(GITHUB_PROMPTS_CSV_URL, Some(&app)).await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(v) = res {
|
if let Some(v) = res {
|
||||||
let data = parse_prompt(v)
|
let data = parse_prompt(v)
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |i| ModelRecord {
|
.map(move |i| ModelRecord {
|
||||||
cmd: if i.cmd.is_some() {
|
cmd: if i.cmd.is_some() {
|
||||||
i.cmd.clone().unwrap()
|
i.cmd.clone().unwrap()
|
||||||
} else {
|
} else {
|
||||||
utils::gen_cmd(i.act.clone())
|
utils::gen_cmd(i.act.clone())
|
||||||
},
|
},
|
||||||
act: i.act.clone(),
|
act: i.act.clone(),
|
||||||
prompt: i.prompt.clone(),
|
prompt: i.prompt.clone(),
|
||||||
tags: vec!["chatgpt-prompts".to_string()],
|
tags: vec!["chatgpt-prompts".to_string()],
|
||||||
enable: true,
|
enable: true,
|
||||||
})
|
})
|
||||||
.collect::<Vec<ModelRecord>>();
|
.collect::<Vec<ModelRecord>>();
|
||||||
|
|
||||||
let data2 = data.clone();
|
let data2 = data.clone();
|
||||||
|
|
||||||
let model = utils::chat_root().join("chat.model.json");
|
let model = utils::chat_root().join("chat.model.json");
|
||||||
let model_cmd = utils::chat_root().join("chat.model.cmd.json");
|
let model_cmd = utils::chat_root().join("chat.model.cmd.json");
|
||||||
let chatgpt_prompts = utils::chat_root()
|
let chatgpt_prompts = utils::chat_root().join("cache_model").join("chatgpt_prompts.json");
|
||||||
.join("cache_model")
|
|
||||||
.join("chatgpt_prompts.json");
|
|
||||||
|
|
||||||
if !utils::exists(&model) {
|
if !utils::exists(&model) {
|
||||||
fs::write(
|
fs::write(
|
||||||
&model,
|
&model,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"name": "ChatGPT Model",
|
"name": "ChatGPT Model",
|
||||||
"link": "https://github.com/lencx/ChatGPT"
|
"link": "https://github.com/lencx/ChatGPT"
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
// chatgpt_prompts.json
|
|
||||||
fs::write(
|
|
||||||
chatgpt_prompts,
|
|
||||||
serde_json::to_string_pretty(&data).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let cmd_data = cmd_list();
|
|
||||||
|
|
||||||
// chat.model.cmd.json
|
|
||||||
fs::write(
|
|
||||||
model_cmd,
|
|
||||||
serde_json::to_string_pretty(&serde_json::json!({
|
|
||||||
"name": "ChatGPT CMD",
|
|
||||||
"last_updated": time,
|
|
||||||
"data": cmd_data,
|
|
||||||
}))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let mut kv = HashMap::new();
|
|
||||||
kv.insert(
|
|
||||||
"sync_prompts".to_string(),
|
|
||||||
serde_json::json!({ "id": "chatgpt_prompts", "last_updated": time }),
|
|
||||||
);
|
|
||||||
let model_data = utils::merge(
|
|
||||||
&serde_json::from_str(&fs::read_to_string(&model).unwrap()).unwrap(),
|
|
||||||
&kv,
|
|
||||||
);
|
|
||||||
|
|
||||||
// chat.model.json
|
|
||||||
fs::write(model, serde_json::to_string_pretty(&model_data).unwrap()).unwrap();
|
|
||||||
|
|
||||||
// refresh window
|
|
||||||
api::dialog::message(
|
|
||||||
app.get_window("core").as_ref(),
|
|
||||||
"Sync Prompts",
|
|
||||||
"ChatGPT Prompts data has been synchronized!",
|
|
||||||
);
|
|
||||||
window_reload(app.clone(), "core");
|
|
||||||
window_reload(app, "tray");
|
|
||||||
|
|
||||||
return Some(data2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
// chatgpt_prompts.json
|
||||||
|
fs::write(chatgpt_prompts, serde_json::to_string_pretty(&data).unwrap()).unwrap();
|
||||||
|
let cmd_data = cmd_list();
|
||||||
|
|
||||||
|
// chat.model.cmd.json
|
||||||
|
fs::write(
|
||||||
|
model_cmd,
|
||||||
|
serde_json::to_string_pretty(&serde_json::json!({
|
||||||
|
"name": "ChatGPT CMD",
|
||||||
|
"last_updated": time,
|
||||||
|
"data": cmd_data,
|
||||||
|
}))
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut kv = HashMap::new();
|
||||||
|
kv.insert(
|
||||||
|
"sync_prompts".to_string(),
|
||||||
|
serde_json::json!({ "id": "chatgpt_prompts", "last_updated": time }),
|
||||||
|
);
|
||||||
|
let model_data = utils::merge(
|
||||||
|
&serde_json::from_str(&fs::read_to_string(&model).unwrap()).unwrap(),
|
||||||
|
&kv,
|
||||||
|
);
|
||||||
|
|
||||||
|
// chat.model.json
|
||||||
|
fs::write(model, serde_json::to_string_pretty(&model_data).unwrap()).unwrap();
|
||||||
|
|
||||||
|
// refresh window
|
||||||
|
api::dialog::message(
|
||||||
|
app.get_window("core").as_ref(),
|
||||||
|
"Sync Prompts",
|
||||||
|
"ChatGPT Prompts data has been synchronized!",
|
||||||
|
);
|
||||||
|
window_reload(app.clone(), "core");
|
||||||
|
window_reload(app, "tray");
|
||||||
|
|
||||||
|
return Some(data2);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn sync_user_prompts(url: String, data_type: String) -> Option<Vec<ModelRecord>> {
|
pub async fn sync_user_prompts(url: String, data_type: String) -> Option<Vec<ModelRecord>> {
|
||||||
let res = utils::get_data(&url, None).await.unwrap_or_else(|err| {
|
let res = utils::get_data(&url, None).await.unwrap_or_else(|err| {
|
||||||
info!("chatgpt_http_error: {}", err);
|
info!("chatgpt_http_error: {}", err);
|
||||||
None
|
None
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("chatgpt_http_url: {}", url);
|
info!("chatgpt_http_url: {}", url);
|
||||||
|
|
||||||
if let Some(v) = res {
|
if let Some(v) = res {
|
||||||
let data;
|
let data;
|
||||||
if data_type == "csv" {
|
if data_type == "csv" {
|
||||||
info!("chatgpt_http_csv_parse");
|
info!("chatgpt_http_csv_parse");
|
||||||
data = parse_prompt(v);
|
data = parse_prompt(v);
|
||||||
} else if data_type == "json" {
|
} else if data_type == "json" {
|
||||||
info!("chatgpt_http_json_parse");
|
info!("chatgpt_http_json_parse");
|
||||||
data = serde_json::from_str(&v).unwrap_or_else(|err| {
|
data = serde_json::from_str(&v).unwrap_or_else(|err| {
|
||||||
info!("chatgpt_http_json_parse_error: {}", err);
|
info!("chatgpt_http_json_parse_error: {}", err);
|
||||||
vec![]
|
vec![]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
info!("chatgpt_http_unknown_type");
|
info!("chatgpt_http_unknown_type");
|
||||||
data = vec![];
|
data = vec![];
|
||||||
}
|
|
||||||
|
|
||||||
let data = data
|
|
||||||
.iter()
|
|
||||||
.map(move |i| ModelRecord {
|
|
||||||
cmd: if i.cmd.is_some() {
|
|
||||||
i.cmd.clone().unwrap()
|
|
||||||
} else {
|
|
||||||
utils::gen_cmd(i.act.clone())
|
|
||||||
},
|
|
||||||
act: i.act.clone(),
|
|
||||||
prompt: i.prompt.clone(),
|
|
||||||
tags: vec!["user-sync".to_string()],
|
|
||||||
enable: true,
|
|
||||||
})
|
|
||||||
.collect::<Vec<ModelRecord>>();
|
|
||||||
|
|
||||||
return Some(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
let data = data
|
||||||
|
.iter()
|
||||||
|
.map(move |i| ModelRecord {
|
||||||
|
cmd: if i.cmd.is_some() {
|
||||||
|
i.cmd.clone().unwrap()
|
||||||
|
} else {
|
||||||
|
utils::gen_cmd(i.act.clone())
|
||||||
|
},
|
||||||
|
act: i.act.clone(),
|
||||||
|
prompt: i.prompt.clone(),
|
||||||
|
tags: vec!["user-sync".to_string()],
|
||||||
|
enable: true,
|
||||||
|
})
|
||||||
|
.collect::<Vec<ModelRecord>>();
|
||||||
|
|
||||||
|
return Some(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{ser::Serializer, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
use tauri::command;
|
use tauri::command;
|
||||||
|
|
||||||
@@ -20,101 +20,102 @@ type Result<T> = std::result::Result<T, Error>;
|
|||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Error {
|
impl Serialize for Error {
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_str(self.to_string().as_ref())
|
serializer.serialize_str(self.to_string().as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct Permissions {
|
struct Permissions {
|
||||||
readonly: bool,
|
readonly: bool,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mode: u32,
|
mode: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct UnixMetadata {
|
struct UnixMetadata {
|
||||||
dev: u64,
|
dev: u64,
|
||||||
ino: u64,
|
ino: u64,
|
||||||
mode: u32,
|
mode: u32,
|
||||||
nlink: u64,
|
nlink: u64,
|
||||||
uid: u32,
|
uid: u32,
|
||||||
gid: u32,
|
gid: u32,
|
||||||
rdev: u64,
|
rdev: u64,
|
||||||
blksize: u64,
|
blksize: u64,
|
||||||
blocks: u64,
|
blocks: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
accessed_at_ms: u64,
|
accessed_at_ms: u64,
|
||||||
pub created_at_ms: u64,
|
pub created_at_ms: u64,
|
||||||
modified_at_ms: u64,
|
modified_at_ms: u64,
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
is_file: bool,
|
is_file: bool,
|
||||||
is_symlink: bool,
|
is_symlink: bool,
|
||||||
size: u64,
|
size: u64,
|
||||||
permissions: Permissions,
|
permissions: Permissions,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
unix: UnixMetadata,
|
unix: UnixMetadata,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
file_attributes: u32,
|
file_attributes: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system_time_to_ms(time: std::io::Result<SystemTime>) -> u64 {
|
pub fn system_time_to_ms(time: std::io::Result<SystemTime>) -> u64 {
|
||||||
time.map(|t| {
|
time
|
||||||
let duration_since_epoch = t.duration_since(UNIX_EPOCH).unwrap();
|
.map(|t| {
|
||||||
duration_since_epoch.as_millis() as u64
|
let duration_since_epoch = t.duration_since(UNIX_EPOCH).unwrap();
|
||||||
|
duration_since_epoch.as_millis() as u64
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub async fn metadata(path: PathBuf) -> Result<Metadata> {
|
pub async fn metadata(path: PathBuf) -> Result<Metadata> {
|
||||||
let metadata = std::fs::metadata(path)?;
|
let metadata = std::fs::metadata(path)?;
|
||||||
let file_type = metadata.file_type();
|
let file_type = metadata.file_type();
|
||||||
let permissions = metadata.permissions();
|
let permissions = metadata.permissions();
|
||||||
Ok(Metadata {
|
Ok(Metadata {
|
||||||
accessed_at_ms: system_time_to_ms(metadata.accessed()),
|
accessed_at_ms: system_time_to_ms(metadata.accessed()),
|
||||||
created_at_ms: system_time_to_ms(metadata.created()),
|
created_at_ms: system_time_to_ms(metadata.created()),
|
||||||
modified_at_ms: system_time_to_ms(metadata.modified()),
|
modified_at_ms: system_time_to_ms(metadata.modified()),
|
||||||
is_dir: file_type.is_dir(),
|
is_dir: file_type.is_dir(),
|
||||||
is_file: file_type.is_file(),
|
is_file: file_type.is_file(),
|
||||||
is_symlink: file_type.is_symlink(),
|
is_symlink: file_type.is_symlink(),
|
||||||
size: metadata.len(),
|
size: metadata.len(),
|
||||||
permissions: Permissions {
|
permissions: Permissions {
|
||||||
readonly: permissions.readonly(),
|
readonly: permissions.readonly(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mode: permissions.mode(),
|
mode: permissions.mode(),
|
||||||
},
|
},
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unix: UnixMetadata {
|
unix: UnixMetadata {
|
||||||
dev: metadata.dev(),
|
dev: metadata.dev(),
|
||||||
ino: metadata.ino(),
|
ino: metadata.ino(),
|
||||||
mode: metadata.mode(),
|
mode: metadata.mode(),
|
||||||
nlink: metadata.nlink(),
|
nlink: metadata.nlink(),
|
||||||
uid: metadata.uid(),
|
uid: metadata.uid(),
|
||||||
gid: metadata.gid(),
|
gid: metadata.gid(),
|
||||||
rdev: metadata.rdev(),
|
rdev: metadata.rdev(),
|
||||||
blksize: metadata.blksize(),
|
blksize: metadata.blksize(),
|
||||||
blocks: metadata.blocks(),
|
blocks: metadata.blocks(),
|
||||||
},
|
},
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
file_attributes: metadata.file_attributes(),
|
file_attributes: metadata.file_attributes(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[command]
|
// #[command]
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{cmd, window},
|
app::{cmd, window},
|
||||||
conf::{self, ChatConfJson},
|
conf::{self, ChatConfJson},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
AppHandle, CustomMenuItem, Manager, Menu, MenuItem, Submenu, SystemTray, SystemTrayEvent,
|
AppHandle, CustomMenuItem, Manager, Menu, MenuItem, Submenu, SystemTray, SystemTrayEvent, SystemTrayMenu,
|
||||||
SystemTrayMenu, SystemTrayMenuItem, WindowMenuEvent,
|
SystemTrayMenuItem, WindowMenuEvent,
|
||||||
};
|
};
|
||||||
use tauri_plugin_positioner::{on_tray_event, Position, WindowExt};
|
use tauri_plugin_positioner::{on_tray_event, Position, WindowExt};
|
||||||
|
|
||||||
@@ -14,461 +14,404 @@ use tauri::AboutMetadata;
|
|||||||
|
|
||||||
// --- Menu
|
// --- Menu
|
||||||
pub fn init() -> Menu {
|
pub fn init() -> Menu {
|
||||||
let chat_conf = ChatConfJson::get_chat_conf();
|
let chat_conf = ChatConfJson::get_chat_conf();
|
||||||
let name = "ChatGPT";
|
let name = "ChatGPT";
|
||||||
let app_menu = Submenu::new(
|
let app_menu = Submenu::new(
|
||||||
name,
|
name,
|
||||||
Menu::with_items([
|
Menu::with_items([
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
MenuItem::About(name.into(), AboutMetadata::default()).into(),
|
MenuItem::About(name.into(), AboutMetadata::default()).into(),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
CustomMenuItem::new("about".to_string(), "About ChatGPT").into(),
|
CustomMenuItem::new("about".to_string(), "About ChatGPT").into(),
|
||||||
CustomMenuItem::new("check_update".to_string(), "Check for Updates").into(),
|
CustomMenuItem::new("check_update".to_string(), "Check for Updates").into(),
|
||||||
MenuItem::Services.into(),
|
MenuItem::Services.into(),
|
||||||
MenuItem::Hide.into(),
|
MenuItem::Hide.into(),
|
||||||
MenuItem::HideOthers.into(),
|
MenuItem::HideOthers.into(),
|
||||||
MenuItem::ShowAll.into(),
|
MenuItem::ShowAll.into(),
|
||||||
MenuItem::Separator.into(),
|
MenuItem::Separator.into(),
|
||||||
MenuItem::Quit.into(),
|
MenuItem::Quit.into(),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let stay_on_top =
|
let stay_on_top = CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T");
|
||||||
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 chat_conf.stay_on_top {
|
stay_on_top.selected()
|
||||||
stay_on_top.selected()
|
} else {
|
||||||
} else {
|
stay_on_top
|
||||||
stay_on_top
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light");
|
let theme_light = CustomMenuItem::new("theme_light".to_string(), "Light");
|
||||||
let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark");
|
let theme_dark = CustomMenuItem::new("theme_dark".to_string(), "Dark");
|
||||||
let theme_system = CustomMenuItem::new("theme_system".to_string(), "System");
|
let theme_system = CustomMenuItem::new("theme_system".to_string(), "System");
|
||||||
let is_dark = chat_conf.theme == "Dark";
|
let is_dark = chat_conf.theme == "Dark";
|
||||||
let is_system = chat_conf.theme == "System";
|
let is_system = chat_conf.theme == "System";
|
||||||
|
|
||||||
let update_prompt = CustomMenuItem::new("update_prompt".to_string(), "Prompt");
|
let update_prompt = CustomMenuItem::new("update_prompt".to_string(), "Prompt");
|
||||||
let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent");
|
let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent");
|
||||||
let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable");
|
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 = CustomMenuItem::new("popup_search".to_string(), "Pop-up Search");
|
||||||
let popup_search_menu = if chat_conf.popup_search {
|
let popup_search_menu = if chat_conf.popup_search {
|
||||||
popup_search.selected()
|
popup_search.selected()
|
||||||
} else {
|
} else {
|
||||||
popup_search
|
popup_search
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let titlebar =
|
let titlebar = CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B");
|
||||||
CustomMenuItem::new("titlebar".to_string(), "Titlebar").accelerator("CmdOrCtrl+B");
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "macos")]
|
let titlebar_menu = if chat_conf.titlebar {
|
||||||
let titlebar_menu = if chat_conf.titlebar {
|
titlebar.selected()
|
||||||
titlebar.selected()
|
} else {
|
||||||
} else {
|
titlebar
|
||||||
titlebar
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let system_tray = CustomMenuItem::new("system_tray".to_string(), "System Tray");
|
let system_tray = CustomMenuItem::new("system_tray".to_string(), "System Tray");
|
||||||
let system_tray_menu = if chat_conf.tray {
|
let system_tray_menu = if chat_conf.tray {
|
||||||
system_tray.selected()
|
system_tray.selected()
|
||||||
} else {
|
} else {
|
||||||
system_tray
|
system_tray
|
||||||
};
|
};
|
||||||
|
|
||||||
let preferences_menu = Submenu::new(
|
let preferences_menu = Submenu::new(
|
||||||
"Preferences",
|
"Preferences",
|
||||||
Menu::with_items([
|
Menu::with_items([
|
||||||
CustomMenuItem::new("control_center".to_string(), "Control Center")
|
CustomMenuItem::new("control_center".to_string(), "Control Center")
|
||||||
.accelerator("CmdOrCtrl+Shift+P")
|
.accelerator("CmdOrCtrl+Shift+P")
|
||||||
.into(),
|
.into(),
|
||||||
MenuItem::Separator.into(),
|
MenuItem::Separator.into(),
|
||||||
stay_on_top_menu.into(),
|
stay_on_top_menu.into(),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
titlebar_menu.into(),
|
titlebar_menu.into(),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(),
|
CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(),
|
||||||
system_tray_menu.into(),
|
system_tray_menu.into(),
|
||||||
CustomMenuItem::new("inject_script".to_string(), "Inject Script")
|
CustomMenuItem::new("inject_script".to_string(), "Inject Script")
|
||||||
.accelerator("CmdOrCtrl+J")
|
.accelerator("CmdOrCtrl+J")
|
||||||
.into(),
|
.into(),
|
||||||
MenuItem::Separator.into(),
|
MenuItem::Separator.into(),
|
||||||
Submenu::new(
|
Submenu::new(
|
||||||
"Theme",
|
"Theme",
|
||||||
Menu::new()
|
|
||||||
.add_item(if is_dark || is_system {
|
|
||||||
theme_light
|
|
||||||
} else {
|
|
||||||
theme_light.selected()
|
|
||||||
})
|
|
||||||
.add_item(if is_dark {
|
|
||||||
theme_dark.selected()
|
|
||||||
} else {
|
|
||||||
theme_dark
|
|
||||||
})
|
|
||||||
.add_item(if is_system {
|
|
||||||
theme_system.selected()
|
|
||||||
} else {
|
|
||||||
theme_system
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
Submenu::new(
|
|
||||||
"Auto Update",
|
|
||||||
Menu::new()
|
|
||||||
.add_item(if chat_conf.auto_update == "Prompt" {
|
|
||||||
update_prompt.selected()
|
|
||||||
} else {
|
|
||||||
update_prompt
|
|
||||||
})
|
|
||||||
.add_item(if chat_conf.auto_update == "Silent" {
|
|
||||||
update_silent.selected()
|
|
||||||
} else {
|
|
||||||
update_silent
|
|
||||||
}), // .add_item(if chat_conf.auto_update == "Disable" {
|
|
||||||
// update_disable.selected()
|
|
||||||
// } else {
|
|
||||||
// update_disable
|
|
||||||
// })
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
MenuItem::Separator.into(),
|
|
||||||
popup_search_menu.into(),
|
|
||||||
CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(),
|
|
||||||
MenuItem::Separator.into(),
|
|
||||||
CustomMenuItem::new("go_conf".to_string(), "Go to Config")
|
|
||||||
.accelerator("CmdOrCtrl+Shift+G")
|
|
||||||
.into(),
|
|
||||||
CustomMenuItem::new("clear_conf".to_string(), "Clear Config")
|
|
||||||
.accelerator("CmdOrCtrl+Shift+D")
|
|
||||||
.into(),
|
|
||||||
CustomMenuItem::new("restart".to_string(), "Restart ChatGPT")
|
|
||||||
.accelerator("CmdOrCtrl+Shift+R")
|
|
||||||
.into(),
|
|
||||||
MenuItem::Separator.into(),
|
|
||||||
CustomMenuItem::new("awesome".to_string(), "Awesome ChatGPT")
|
|
||||||
.accelerator("CmdOrCtrl+Shift+A")
|
|
||||||
.into(),
|
|
||||||
CustomMenuItem::new("buy_coffee".to_string(), "Buy lencx a coffee").into(),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
|
|
||||||
let edit_menu = Submenu::new(
|
|
||||||
"Edit",
|
|
||||||
Menu::new()
|
Menu::new()
|
||||||
.add_native_item(MenuItem::Undo)
|
.add_item(if is_dark || is_system {
|
||||||
.add_native_item(MenuItem::Redo)
|
theme_light
|
||||||
.add_native_item(MenuItem::Separator)
|
} else {
|
||||||
.add_native_item(MenuItem::Cut)
|
theme_light.selected()
|
||||||
.add_native_item(MenuItem::Copy)
|
})
|
||||||
.add_native_item(MenuItem::Paste)
|
.add_item(if is_dark { theme_dark.selected() } else { theme_dark })
|
||||||
.add_native_item(MenuItem::SelectAll),
|
.add_item(if is_system {
|
||||||
);
|
theme_system.selected()
|
||||||
|
} else {
|
||||||
let view_menu = Submenu::new(
|
theme_system
|
||||||
"View",
|
}),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
Submenu::new(
|
||||||
|
"Auto Update",
|
||||||
Menu::new()
|
Menu::new()
|
||||||
.add_item(
|
.add_item(if chat_conf.auto_update == "Prompt" {
|
||||||
CustomMenuItem::new("go_back".to_string(), "Go Back").accelerator("CmdOrCtrl+Left"),
|
update_prompt.selected()
|
||||||
)
|
} else {
|
||||||
.add_item(
|
update_prompt
|
||||||
CustomMenuItem::new("go_forward".to_string(), "Go Forward")
|
})
|
||||||
.accelerator("CmdOrCtrl+Right"),
|
.add_item(if chat_conf.auto_update == "Silent" {
|
||||||
)
|
update_silent.selected()
|
||||||
.add_item(
|
} else {
|
||||||
CustomMenuItem::new("scroll_top".to_string(), "Scroll to Top of Screen")
|
update_silent
|
||||||
.accelerator("CmdOrCtrl+Up"),
|
}), // .add_item(if chat_conf.auto_update == "Disable" {
|
||||||
)
|
// update_disable.selected()
|
||||||
.add_item(
|
// } else {
|
||||||
CustomMenuItem::new("scroll_bottom".to_string(), "Scroll to Bottom of Screen")
|
// update_disable
|
||||||
.accelerator("CmdOrCtrl+Down"),
|
// })
|
||||||
)
|
)
|
||||||
.add_native_item(MenuItem::Separator)
|
.into(),
|
||||||
.add_item(
|
MenuItem::Separator.into(),
|
||||||
CustomMenuItem::new("reload".to_string(), "Refresh the Screen")
|
popup_search_menu.into(),
|
||||||
.accelerator("CmdOrCtrl+R"),
|
CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(),
|
||||||
),
|
MenuItem::Separator.into(),
|
||||||
);
|
CustomMenuItem::new("go_conf".to_string(), "Go to Config")
|
||||||
|
.accelerator("CmdOrCtrl+Shift+G")
|
||||||
let window_menu = Submenu::new(
|
.into(),
|
||||||
"Window",
|
CustomMenuItem::new("clear_conf".to_string(), "Clear Config")
|
||||||
Menu::new()
|
.accelerator("CmdOrCtrl+Shift+D")
|
||||||
.add_item(CustomMenuItem::new("dalle2".to_string(), "DALL·E 2"))
|
.into(),
|
||||||
.add_native_item(MenuItem::Separator)
|
CustomMenuItem::new("restart".to_string(), "Restart ChatGPT")
|
||||||
.add_native_item(MenuItem::Minimize)
|
.accelerator("CmdOrCtrl+Shift+R")
|
||||||
.add_native_item(MenuItem::Zoom),
|
.into(),
|
||||||
);
|
MenuItem::Separator.into(),
|
||||||
|
CustomMenuItem::new("awesome".to_string(), "Awesome ChatGPT")
|
||||||
let help_menu = Submenu::new(
|
.accelerator("CmdOrCtrl+Shift+A")
|
||||||
"Help",
|
.into(),
|
||||||
Menu::new()
|
CustomMenuItem::new("buy_coffee".to_string(), "Buy lencx a coffee").into(),
|
||||||
.add_item(CustomMenuItem::new(
|
]),
|
||||||
"chatgpt_log".to_string(),
|
);
|
||||||
"ChatGPT Log",
|
|
||||||
))
|
|
||||||
.add_item(CustomMenuItem::new("update_log".to_string(), "Update Log"))
|
|
||||||
.add_item(CustomMenuItem::new("report_bug".to_string(), "Report Bug"))
|
|
||||||
.add_item(
|
|
||||||
CustomMenuItem::new("dev_tools".to_string(), "Toggle Developer Tools")
|
|
||||||
.accelerator("CmdOrCtrl+Shift+I"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
let edit_menu = Submenu::new(
|
||||||
|
"Edit",
|
||||||
Menu::new()
|
Menu::new()
|
||||||
.add_submenu(app_menu)
|
.add_native_item(MenuItem::Undo)
|
||||||
.add_submenu(preferences_menu)
|
.add_native_item(MenuItem::Redo)
|
||||||
.add_submenu(window_menu)
|
.add_native_item(MenuItem::Separator)
|
||||||
.add_submenu(edit_menu)
|
.add_native_item(MenuItem::Cut)
|
||||||
.add_submenu(view_menu)
|
.add_native_item(MenuItem::Copy)
|
||||||
.add_submenu(help_menu)
|
.add_native_item(MenuItem::Paste)
|
||||||
|
.add_native_item(MenuItem::SelectAll),
|
||||||
|
);
|
||||||
|
|
||||||
|
let view_menu = Submenu::new(
|
||||||
|
"View",
|
||||||
|
Menu::new()
|
||||||
|
.add_item(CustomMenuItem::new("go_back".to_string(), "Go Back").accelerator("CmdOrCtrl+Left"))
|
||||||
|
.add_item(CustomMenuItem::new("go_forward".to_string(), "Go Forward").accelerator("CmdOrCtrl+Right"))
|
||||||
|
.add_item(CustomMenuItem::new("scroll_top".to_string(), "Scroll to Top of Screen").accelerator("CmdOrCtrl+Up"))
|
||||||
|
.add_item(
|
||||||
|
CustomMenuItem::new("scroll_bottom".to_string(), "Scroll to Bottom of Screen").accelerator("CmdOrCtrl+Down"),
|
||||||
|
)
|
||||||
|
.add_native_item(MenuItem::Separator)
|
||||||
|
.add_item(CustomMenuItem::new("reload".to_string(), "Refresh the Screen").accelerator("CmdOrCtrl+R")),
|
||||||
|
);
|
||||||
|
|
||||||
|
let window_menu = Submenu::new(
|
||||||
|
"Window",
|
||||||
|
Menu::new()
|
||||||
|
.add_item(CustomMenuItem::new("dalle2".to_string(), "DALL·E 2"))
|
||||||
|
.add_native_item(MenuItem::Separator)
|
||||||
|
.add_native_item(MenuItem::Minimize)
|
||||||
|
.add_native_item(MenuItem::Zoom),
|
||||||
|
);
|
||||||
|
|
||||||
|
let help_menu = Submenu::new(
|
||||||
|
"Help",
|
||||||
|
Menu::new()
|
||||||
|
.add_item(CustomMenuItem::new("chatgpt_log".to_string(), "ChatGPT Log"))
|
||||||
|
.add_item(CustomMenuItem::new("update_log".to_string(), "Update Log"))
|
||||||
|
.add_item(CustomMenuItem::new("report_bug".to_string(), "Report Bug"))
|
||||||
|
.add_item(
|
||||||
|
CustomMenuItem::new("dev_tools".to_string(), "Toggle Developer Tools").accelerator("CmdOrCtrl+Shift+I"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Menu::new()
|
||||||
|
.add_submenu(app_menu)
|
||||||
|
.add_submenu(preferences_menu)
|
||||||
|
.add_submenu(window_menu)
|
||||||
|
.add_submenu(edit_menu)
|
||||||
|
.add_submenu(view_menu)
|
||||||
|
.add_submenu(help_menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Menu Event
|
// --- Menu Event
|
||||||
pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
|
||||||
let win = Some(event.window()).unwrap();
|
let win = Some(event.window()).unwrap();
|
||||||
let app = win.app_handle();
|
let app = win.app_handle();
|
||||||
let script_path = utils::script_path().to_string_lossy().to_string();
|
let script_path = utils::script_path().to_string_lossy().to_string();
|
||||||
let menu_id = event.menu_item_id();
|
let menu_id = event.menu_item_id();
|
||||||
let menu_handle = win.menu_handle();
|
let menu_handle = win.menu_handle();
|
||||||
|
|
||||||
match menu_id {
|
match menu_id {
|
||||||
// App
|
// App
|
||||||
"about" => {
|
"about" => {
|
||||||
let tauri_conf = utils::get_tauri_conf().unwrap();
|
let tauri_conf = utils::get_tauri_conf().unwrap();
|
||||||
tauri::api::dialog::message(
|
tauri::api::dialog::message(
|
||||||
app.get_window("core").as_ref(),
|
app.get_window("core").as_ref(),
|
||||||
"ChatGPT",
|
"ChatGPT",
|
||||||
format!("Version {}", tauri_conf.package.version.unwrap()),
|
format!("Version {}", tauri_conf.package.version.unwrap()),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
"check_update" => {
|
||||||
|
utils::run_check_update(app, false, None);
|
||||||
|
}
|
||||||
|
// Preferences
|
||||||
|
"control_center" => window::control_window(&app),
|
||||||
|
"restart" => tauri::api::process::restart(&app.env()),
|
||||||
|
"inject_script" => open(&app, script_path),
|
||||||
|
"go_conf" => utils::open_file(utils::chat_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;
|
||||||
|
menu_handle.get_item(menu_id).set_selected(popup_search).unwrap();
|
||||||
|
ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None).unwrap();
|
||||||
|
cmd::window_reload(app.clone(), "core");
|
||||||
|
cmd::window_reload(app, "tray");
|
||||||
|
}
|
||||||
|
"sync_prompts" => {
|
||||||
|
tauri::api::dialog::ask(
|
||||||
|
app.get_window("core").as_ref(),
|
||||||
|
"Sync Prompts",
|
||||||
|
"Data sync will enable all prompts, are you sure you want to sync?",
|
||||||
|
move |is_restart| {
|
||||||
|
if is_restart {
|
||||||
|
app
|
||||||
|
.get_window("core")
|
||||||
|
.unwrap()
|
||||||
|
.eval("window.__sync_prompts && window.__sync_prompts()")
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"hide_dock_icon" => ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap(),
|
||||||
|
"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());
|
||||||
|
}
|
||||||
|
"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());
|
||||||
|
}
|
||||||
|
"theme_light" | "theme_dark" | "theme_system" => {
|
||||||
|
let theme = match menu_id {
|
||||||
|
"theme_dark" => "Dark",
|
||||||
|
"theme_system" => "System",
|
||||||
|
_ => "Light",
|
||||||
|
};
|
||||||
|
ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap();
|
||||||
|
}
|
||||||
|
"update_prompt" | "update_silent" | "update_disable" => {
|
||||||
|
// for id in ["update_prompt", "update_silent", "update_disable"] {
|
||||||
|
for id in ["update_prompt", "update_silent"] {
|
||||||
|
menu_handle.get_item(id).set_selected(false).unwrap();
|
||||||
|
}
|
||||||
|
let auto_update = match menu_id {
|
||||||
|
"update_silent" => {
|
||||||
|
menu_handle.get_item("update_silent").set_selected(true).unwrap();
|
||||||
|
"Silent"
|
||||||
}
|
}
|
||||||
"check_update" => {
|
"update_disable" => {
|
||||||
utils::run_check_update(app, false, None);
|
menu_handle.get_item("update_disable").set_selected(true).unwrap();
|
||||||
|
"Disable"
|
||||||
}
|
}
|
||||||
// Preferences
|
_ => {
|
||||||
"control_center" => window::control_window(&app),
|
menu_handle.get_item("update_prompt").set_selected(true).unwrap();
|
||||||
"restart" => tauri::api::process::restart(&app.env()),
|
"Prompt"
|
||||||
"inject_script" => open(&app, script_path),
|
|
||||||
"go_conf" => utils::open_file(utils::chat_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;
|
|
||||||
menu_handle
|
|
||||||
.get_item(menu_id)
|
|
||||||
.set_selected(popup_search)
|
|
||||||
.unwrap();
|
|
||||||
ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None)
|
|
||||||
.unwrap();
|
|
||||||
cmd::window_reload(app.clone(), "core");
|
|
||||||
cmd::window_reload(app, "tray");
|
|
||||||
}
|
}
|
||||||
"sync_prompts" => {
|
};
|
||||||
tauri::api::dialog::ask(
|
ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap();
|
||||||
app.get_window("core").as_ref(),
|
}
|
||||||
"Sync Prompts",
|
"stay_on_top" => {
|
||||||
"Data sync will enable all prompts, are you sure you want to sync?",
|
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||||
move |is_restart| {
|
let stay_on_top = !chat_conf.stay_on_top;
|
||||||
if is_restart {
|
menu_handle.get_item(menu_id).set_selected(stay_on_top).unwrap();
|
||||||
app.get_window("core")
|
win.set_always_on_top(stay_on_top).unwrap();
|
||||||
.unwrap()
|
ChatConfJson::amend(&serde_json::json!({ "stay_on_top": stay_on_top }), None).unwrap();
|
||||||
.eval("window.__sync_prompts && window.__sync_prompts()")
|
}
|
||||||
.unwrap()
|
// Window
|
||||||
}
|
"dalle2" => window::dalle2_window(&app, None, None, Some(false)),
|
||||||
},
|
// View
|
||||||
);
|
"reload" => win.eval("window.location.reload()").unwrap(),
|
||||||
}
|
"go_back" => win.eval("window.history.go(-1)").unwrap(),
|
||||||
"hide_dock_icon" => {
|
"go_forward" => win.eval("window.history.go(1)").unwrap(),
|
||||||
ChatConfJson::amend(&serde_json::json!({ "hide_dock_icon": true }), Some(app)).unwrap()
|
// core: document.querySelector('main .overflow-y-auto')
|
||||||
}
|
"scroll_top" => win
|
||||||
"titlebar" => {
|
.eval(
|
||||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
r#"window.scroll({
|
||||||
ChatConfJson::amend(
|
|
||||||
&serde_json::json!({ "titlebar": !chat_conf.titlebar }),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
tauri::api::process::restart(&app.env());
|
|
||||||
}
|
|
||||||
"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());
|
|
||||||
}
|
|
||||||
"theme_light" | "theme_dark" | "theme_system" => {
|
|
||||||
let theme = match menu_id {
|
|
||||||
"theme_dark" => "Dark",
|
|
||||||
"theme_system" => "System",
|
|
||||||
_ => "Light",
|
|
||||||
};
|
|
||||||
ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap();
|
|
||||||
}
|
|
||||||
"update_prompt" | "update_silent" | "update_disable" => {
|
|
||||||
// for id in ["update_prompt", "update_silent", "update_disable"] {
|
|
||||||
for id in ["update_prompt", "update_silent"] {
|
|
||||||
menu_handle.get_item(id).set_selected(false).unwrap();
|
|
||||||
}
|
|
||||||
let auto_update = match menu_id {
|
|
||||||
"update_silent" => {
|
|
||||||
menu_handle
|
|
||||||
.get_item("update_silent")
|
|
||||||
.set_selected(true)
|
|
||||||
.unwrap();
|
|
||||||
"Silent"
|
|
||||||
}
|
|
||||||
"update_disable" => {
|
|
||||||
menu_handle
|
|
||||||
.get_item("update_disable")
|
|
||||||
.set_selected(true)
|
|
||||||
.unwrap();
|
|
||||||
"Disable"
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
menu_handle
|
|
||||||
.get_item("update_prompt")
|
|
||||||
.set_selected(true)
|
|
||||||
.unwrap();
|
|
||||||
"Prompt"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap();
|
|
||||||
}
|
|
||||||
"stay_on_top" => {
|
|
||||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
|
||||||
let stay_on_top = !chat_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();
|
|
||||||
}
|
|
||||||
// Window
|
|
||||||
"dalle2" => window::dalle2_window(&app, None, None, Some(false)),
|
|
||||||
// View
|
|
||||||
"reload" => win.eval("window.location.reload()").unwrap(),
|
|
||||||
"go_back" => win.eval("window.history.go(-1)").unwrap(),
|
|
||||||
"go_forward" => win.eval("window.history.go(1)").unwrap(),
|
|
||||||
// core: document.querySelector('main .overflow-y-auto')
|
|
||||||
"scroll_top" => win
|
|
||||||
.eval(
|
|
||||||
r#"window.scroll({
|
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
behavior: "smooth"
|
behavior: "smooth"
|
||||||
})"#,
|
})"#,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"scroll_bottom" => win
|
"scroll_bottom" => win
|
||||||
.eval(
|
.eval(
|
||||||
r#"window.scroll({
|
r#"window.scroll({
|
||||||
top: document.body.scrollHeight,
|
top: document.body.scrollHeight,
|
||||||
left: 0,
|
left: 0,
|
||||||
behavior: "smooth"})"#,
|
behavior: "smooth"})"#,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
// Help
|
// Help
|
||||||
"chatgpt_log" => utils::open_file(utils::chat_root().join("chatgpt.log")),
|
"chatgpt_log" => utils::open_file(utils::chat_root().join("chatgpt.log")),
|
||||||
"update_log" => open(&app, conf::UPDATE_LOG_URL.to_string()),
|
"update_log" => open(&app, conf::UPDATE_LOG_URL.to_string()),
|
||||||
"report_bug" => open(&app, conf::ISSUES_URL.to_string()),
|
"report_bug" => open(&app, conf::ISSUES_URL.to_string()),
|
||||||
"dev_tools" => {
|
"dev_tools" => {
|
||||||
win.open_devtools();
|
win.open_devtools();
|
||||||
win.close_devtools();
|
win.close_devtools();
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SystemTray Menu
|
// --- SystemTray Menu
|
||||||
pub fn tray_menu() -> SystemTray {
|
pub fn tray_menu() -> SystemTray {
|
||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
SystemTray::new().with_menu(
|
SystemTray::new().with_menu(
|
||||||
SystemTrayMenu::new()
|
SystemTrayMenu::new()
|
||||||
.add_item(CustomMenuItem::new(
|
.add_item(CustomMenuItem::new("control_center".to_string(), "Control Center"))
|
||||||
"control_center".to_string(),
|
.add_native_item(SystemTrayMenuItem::Separator)
|
||||||
"Control Center",
|
.add_item(CustomMenuItem::new("show_dock_icon".to_string(), "Show Dock Icon"))
|
||||||
))
|
.add_item(CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon"))
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
||||||
.add_item(CustomMenuItem::new(
|
.add_native_item(SystemTrayMenuItem::Separator)
|
||||||
"show_dock_icon".to_string(),
|
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
||||||
"Show Dock Icon",
|
)
|
||||||
))
|
} else {
|
||||||
.add_item(CustomMenuItem::new(
|
SystemTray::new().with_menu(
|
||||||
"hide_dock_icon".to_string(),
|
SystemTrayMenu::new()
|
||||||
"Hide Dock Icon",
|
.add_item(CustomMenuItem::new("control_center".to_string(), "Control Center"))
|
||||||
))
|
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
||||||
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
.add_native_item(SystemTrayMenuItem::Separator)
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
||||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
)
|
||||||
)
|
}
|
||||||
} else {
|
|
||||||
SystemTray::new().with_menu(
|
|
||||||
SystemTrayMenu::new()
|
|
||||||
.add_item(CustomMenuItem::new(
|
|
||||||
"control_center".to_string(),
|
|
||||||
"Control Center",
|
|
||||||
))
|
|
||||||
.add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT"))
|
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
|
||||||
.add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SystemTray Event
|
// --- SystemTray Event
|
||||||
pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) {
|
pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) {
|
||||||
on_tray_event(handle, &event);
|
on_tray_event(handle, &event);
|
||||||
|
|
||||||
let app = handle.clone();
|
let app = handle.clone();
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
SystemTrayEvent::LeftClick { .. } => {
|
SystemTrayEvent::LeftClick { .. } => {
|
||||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||||
|
|
||||||
if !chat_conf.hide_dock_icon {
|
if !chat_conf.hide_dock_icon {
|
||||||
let core_win = handle.get_window("core").unwrap();
|
let core_win = handle.get_window("core").unwrap();
|
||||||
core_win.minimize().unwrap();
|
core_win.minimize().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let tray_win = handle.get_window("tray").unwrap();
|
let tray_win = handle.get_window("tray").unwrap();
|
||||||
tray_win.move_window(Position::TrayCenter).unwrap();
|
tray_win.move_window(Position::TrayCenter).unwrap();
|
||||||
|
|
||||||
if tray_win.is_visible().unwrap() {
|
if tray_win.is_visible().unwrap() {
|
||||||
tray_win.hide().unwrap();
|
tray_win.hide().unwrap();
|
||||||
} else {
|
} else {
|
||||||
tray_win.show().unwrap();
|
tray_win.show().unwrap();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
|
||||||
"control_center" => window::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();
|
|
||||||
}
|
|
||||||
"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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"show_core" => {
|
|
||||||
let core_win = app.get_window("core").unwrap();
|
|
||||||
let tray_win = app.get_window("tray").unwrap();
|
|
||||||
if !core_win.is_visible().unwrap() {
|
|
||||||
core_win.show().unwrap();
|
|
||||||
core_win.set_focus().unwrap();
|
|
||||||
tray_win.hide().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"quit" => std::process::exit(0),
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
||||||
|
"control_center" => window::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();
|
||||||
|
}
|
||||||
|
"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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"show_core" => {
|
||||||
|
let core_win = app.get_window("core").unwrap();
|
||||||
|
let tray_win = app.get_window("tray").unwrap();
|
||||||
|
if !core_win.is_visible().unwrap() {
|
||||||
|
core_win.show().unwrap();
|
||||||
|
core_win.set_focus().unwrap();
|
||||||
|
tray_win.hide().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"quit" => std::process::exit(0),
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(app: &AppHandle, path: String) {
|
pub fn open(app: &AppHandle, path: String) {
|
||||||
tauri::api::shell::open(&app.shell_scope(), path, None).unwrap();
|
tauri::api::shell::open(&app.shell_scope(), path, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,90 +4,90 @@ use tauri::{utils::config::WindowUrl, window::WindowBuilder, App, GlobalShortcut
|
|||||||
use wry::application::accelerator::Accelerator;
|
use wry::application::accelerator::Accelerator;
|
||||||
|
|
||||||
pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
info!("stepup");
|
info!("stepup");
|
||||||
let chat_conf = ChatConfJson::get_chat_conf();
|
let chat_conf = ChatConfJson::get_chat_conf();
|
||||||
let url = chat_conf.origin.to_string();
|
let url = chat_conf.origin.to_string();
|
||||||
let theme = ChatConfJson::theme();
|
let theme = ChatConfJson::theme();
|
||||||
let handle = app.app_handle();
|
let handle = app.app_handle();
|
||||||
|
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
window::tray_window(&handle);
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(v) = chat_conf.global_shortcut {
|
||||||
|
info!("global_shortcut: `{}`", v);
|
||||||
|
match v.parse::<Accelerator>() {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("global_shortcut_register");
|
||||||
|
let handle = app.app_handle();
|
||||||
|
let mut shortcut = app.global_shortcut_manager();
|
||||||
|
shortcut
|
||||||
|
.register(&v, move || {
|
||||||
|
if let Some(w) = handle.get_window("core") {
|
||||||
|
if w.is_visible().unwrap() {
|
||||||
|
w.hide().unwrap();
|
||||||
|
} else {
|
||||||
|
w.show().unwrap();
|
||||||
|
w.set_focus().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
info!("global_shortcut_register_error: {}", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
info!("global_shortcut_parse_error: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("global_shortcut_unregister");
|
||||||
|
};
|
||||||
|
|
||||||
|
if chat_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 {
|
tauri::async_runtime::spawn(async move {
|
||||||
window::tray_window(&handle);
|
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(url.into()))
|
||||||
|
.title("ChatGPT")
|
||||||
|
.resizable(true)
|
||||||
|
.fullscreen(false)
|
||||||
|
.inner_size(800.0, 600.0);
|
||||||
|
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
main_win = main_win.hidden_title(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
main_win
|
||||||
|
.theme(theme)
|
||||||
|
.always_on_top(chat_conf.stay_on_top)
|
||||||
|
.title_bar_style(ChatConfJson::titlebar())
|
||||||
|
.initialization_script(&utils::user_script())
|
||||||
|
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/jspdf.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown.js"))
|
||||||
|
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
||||||
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
|
.initialization_script(include_str!("../scripts/popup.core.js"))
|
||||||
|
.initialization_script(include_str!("../scripts/export.js"))
|
||||||
|
.initialization_script(include_str!("../scripts/markdown.export.js"))
|
||||||
|
.initialization_script(include_str!("../scripts/cmd.js"))
|
||||||
|
.user_agent(&chat_conf.ua_window)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(v) = chat_conf.global_shortcut {
|
// auto_update
|
||||||
info!("global_shortcut: `{}`", v);
|
if chat_conf.auto_update != "Disable" {
|
||||||
match v.parse::<Accelerator>() {
|
info!("stepup::run_check_update");
|
||||||
Ok(_) => {
|
let app = app.handle();
|
||||||
info!("global_shortcut_register");
|
utils::run_check_update(app, chat_conf.auto_update == "Silent", None);
|
||||||
let handle = app.app_handle();
|
}
|
||||||
let mut shortcut = app.global_shortcut_manager();
|
|
||||||
shortcut
|
|
||||||
.register(&v, move || {
|
|
||||||
if let Some(w) = handle.get_window("core") {
|
|
||||||
if w.is_visible().unwrap() {
|
|
||||||
w.hide().unwrap();
|
|
||||||
} else {
|
|
||||||
w.show().unwrap();
|
|
||||||
w.set_focus().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
info!("global_shortcut_register_error: {}", err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
info!("global_shortcut_parse_error: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
info!("global_shortcut_unregister");
|
|
||||||
};
|
|
||||||
|
|
||||||
if chat_conf.hide_dock_icon {
|
Ok(())
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
app.set_activation_policy(tauri::ActivationPolicy::Accessory);
|
|
||||||
} else {
|
|
||||||
let app = app.handle();
|
|
||||||
tauri::async_runtime::spawn(async move {
|
|
||||||
let mut main_win = WindowBuilder::new(&app, "core", WindowUrl::App(url.into()))
|
|
||||||
.title("ChatGPT")
|
|
||||||
.resizable(true)
|
|
||||||
.fullscreen(false)
|
|
||||||
.inner_size(800.0, 600.0);
|
|
||||||
|
|
||||||
if cfg!(target_os = "macos") {
|
|
||||||
main_win = main_win.hidden_title(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
main_win
|
|
||||||
.theme(theme)
|
|
||||||
.always_on_top(chat_conf.stay_on_top)
|
|
||||||
.title_bar_style(ChatConfJson::titlebar())
|
|
||||||
.initialization_script(&utils::user_script())
|
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
|
||||||
.initialization_script(include_str!("../vendors/html2canvas.js"))
|
|
||||||
.initialization_script(include_str!("../vendors/jspdf.js"))
|
|
||||||
.initialization_script(include_str!("../vendors/turndown.js"))
|
|
||||||
.initialization_script(include_str!("../vendors/turndown-plugin-gfm.js"))
|
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
|
||||||
.initialization_script(include_str!("../scripts/export.js"))
|
|
||||||
.initialization_script(include_str!("../scripts/markdown.export.js"))
|
|
||||||
.initialization_script(include_str!("../scripts/cmd.js"))
|
|
||||||
.user_agent(&chat_conf.ua_window)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto_update
|
|
||||||
if chat_conf.auto_update != "Disable" {
|
|
||||||
info!("stepup::run_check_update");
|
|
||||||
let app = app.handle();
|
|
||||||
utils::run_check_update(app, chat_conf.auto_update == "Silent", None);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,104 +4,95 @@ use std::time::SystemTime;
|
|||||||
use tauri::{utils::config::WindowUrl, window::WindowBuilder, Manager};
|
use tauri::{utils::config::WindowUrl, window::WindowBuilder, Manager};
|
||||||
|
|
||||||
pub fn tray_window(handle: &tauri::AppHandle) {
|
pub fn tray_window(handle: &tauri::AppHandle) {
|
||||||
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
let chat_conf = conf::ChatConfJson::get_chat_conf();
|
||||||
let theme = conf::ChatConfJson::theme();
|
let theme = conf::ChatConfJson::theme();
|
||||||
let app = handle.clone();
|
let app = handle.clone();
|
||||||
|
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into()))
|
WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into()))
|
||||||
.title("ChatGPT")
|
.title("ChatGPT")
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.fullscreen(false)
|
.fullscreen(false)
|
||||||
.inner_size(360.0, 540.0)
|
.inner_size(360.0, 540.0)
|
||||||
.decorations(false)
|
.decorations(false)
|
||||||
.always_on_top(true)
|
.always_on_top(true)
|
||||||
.theme(theme)
|
.theme(theme)
|
||||||
.initialization_script(&utils::user_script())
|
.initialization_script(&utils::user_script())
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-core.js"))
|
||||||
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
.initialization_script(include_str!("../vendors/floating-ui-dom.js"))
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
.initialization_script(include_str!("../scripts/cmd.js"))
|
.initialization_script(include_str!("../scripts/cmd.js"))
|
||||||
.initialization_script(include_str!("../scripts/popup.core.js"))
|
.initialization_script(include_str!("../scripts/popup.core.js"))
|
||||||
.user_agent(&chat_conf.ua_tray)
|
.user_agent(&chat_conf.ua_tray)
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.hide()
|
.hide()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dalle2_window(
|
pub fn dalle2_window(handle: &tauri::AppHandle, query: Option<String>, title: Option<String>, is_new: Option<bool>) {
|
||||||
handle: &tauri::AppHandle,
|
info!("dalle2_query: {:?}", query);
|
||||||
query: Option<String>,
|
let theme = conf::ChatConfJson::theme();
|
||||||
title: Option<String>,
|
let app = handle.clone();
|
||||||
is_new: Option<bool>,
|
|
||||||
) {
|
|
||||||
info!("dalle2_query: {:?}", query);
|
|
||||||
let theme = conf::ChatConfJson::theme();
|
|
||||||
let app = handle.clone();
|
|
||||||
|
|
||||||
let query = if query.is_some() {
|
let query = if query.is_some() {
|
||||||
format!(
|
format!(
|
||||||
"window.addEventListener('DOMContentLoaded', function() {{\nwindow.__CHATGPT_QUERY__='{}';\n}})",
|
"window.addEventListener('DOMContentLoaded', function() {{\nwindow.__CHATGPT_QUERY__='{}';\n}})",
|
||||||
query.unwrap()
|
query.unwrap()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let label = if is_new.unwrap_or(true) {
|
let label = if is_new.unwrap_or(true) {
|
||||||
let timestamp = SystemTime::now()
|
let timestamp = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs();
|
.as_secs();
|
||||||
format!("dalle2_{}", timestamp)
|
format!("dalle2_{}", timestamp)
|
||||||
} else {
|
} else {
|
||||||
"dalle2".to_string()
|
"dalle2".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
if app.get_window("dalle2").is_none() {
|
if app.get_window("dalle2").is_none() {
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
WindowBuilder::new(
|
WindowBuilder::new(&app, label, WindowUrl::App("https://labs.openai.com".into()))
|
||||||
&app,
|
.title(title.unwrap_or_else(|| "DALL·E 2".to_string()))
|
||||||
label,
|
.resizable(true)
|
||||||
WindowUrl::App("https://labs.openai.com".into()),
|
.fullscreen(false)
|
||||||
)
|
.inner_size(800.0, 600.0)
|
||||||
.title(title.unwrap_or_else(|| "DALL·E 2".to_string()))
|
.always_on_top(false)
|
||||||
.resizable(true)
|
.theme(theme)
|
||||||
.fullscreen(false)
|
.initialization_script(include_str!("../scripts/core.js"))
|
||||||
.inner_size(800.0, 600.0)
|
.initialization_script(&query)
|
||||||
.always_on_top(false)
|
.initialization_script(include_str!("../scripts/dalle2.js"))
|
||||||
.theme(theme)
|
.build()
|
||||||
.initialization_script(include_str!("../scripts/core.js"))
|
.unwrap();
|
||||||
.initialization_script(&query)
|
});
|
||||||
.initialization_script(include_str!("../scripts/dalle2.js"))
|
} else {
|
||||||
.build()
|
let dalle2_win = app.get_window("dalle2").unwrap();
|
||||||
.unwrap();
|
dalle2_win.show().unwrap();
|
||||||
});
|
dalle2_win.set_focus().unwrap();
|
||||||
} else {
|
}
|
||||||
let dalle2_win = app.get_window("dalle2").unwrap();
|
|
||||||
dalle2_win.show().unwrap();
|
|
||||||
dalle2_win.set_focus().unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn control_window(handle: &tauri::AppHandle) {
|
pub fn control_window(handle: &tauri::AppHandle) {
|
||||||
let app = handle.clone();
|
let app = handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
if app.app_handle().get_window("main").is_none() {
|
if app.app_handle().get_window("main").is_none() {
|
||||||
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into()))
|
||||||
.title("Control Center")
|
.title("Control Center")
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.fullscreen(false)
|
.fullscreen(false)
|
||||||
.inner_size(1000.0, 700.0)
|
.inner_size(1000.0, 700.0)
|
||||||
.min_inner_size(800.0, 600.0)
|
.min_inner_size(800.0, 600.0)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let main_win = app.app_handle().get_window("main").unwrap();
|
let main_win = app.app_handle().get_window("main").unwrap();
|
||||||
main_win.show().unwrap();
|
main_win.show().unwrap();
|
||||||
main_win.set_focus().unwrap();
|
main_win.set_focus().unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ 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";
|
pub const UPDATE_LOG_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/UPDATE_LOG.md";
|
||||||
pub const AWESOME_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/AWESOME.md";
|
pub const AWESOME_URL: &str = "https://github.com/lencx/ChatGPT/blob/main/AWESOME.md";
|
||||||
pub const BUY_COFFEE: &str = "https://www.buymeacoffee.com/lencx";
|
pub const BUY_COFFEE: &str = "https://www.buymeacoffee.com/lencx";
|
||||||
pub const GITHUB_PROMPTS_CSV_URL: &str =
|
pub const GITHUB_PROMPTS_CSV_URL: &str = "https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
||||||
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
|
||||||
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
pub const DEFAULT_CHAT_CONF: &str = r#"{
|
||||||
"stay_on_top": false,
|
"stay_on_top": false,
|
||||||
"auto_update": "Prompt",
|
"auto_update": "Prompt",
|
||||||
@@ -48,153 +47,150 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{
|
|||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct ChatConfJson {
|
pub struct ChatConfJson {
|
||||||
// support macOS only
|
// support macOS only
|
||||||
pub titlebar: bool,
|
pub titlebar: bool,
|
||||||
pub hide_dock_icon: bool,
|
pub hide_dock_icon: bool,
|
||||||
|
|
||||||
// macOS and Windows, Light/Dark/System
|
// macOS and Windows, Light/Dark/System
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
// auto update policy, Prompt/Silent/Disable
|
// auto update policy, Prompt/Silent/Disable
|
||||||
pub auto_update: String,
|
pub auto_update: String,
|
||||||
pub tray: bool,
|
pub tray: bool,
|
||||||
pub popup_search: bool,
|
pub popup_search: bool,
|
||||||
pub stay_on_top: bool,
|
pub stay_on_top: bool,
|
||||||
pub default_origin: String,
|
pub default_origin: String,
|
||||||
pub origin: String,
|
pub origin: String,
|
||||||
pub ua_window: String,
|
pub ua_window: String,
|
||||||
pub ua_tray: String,
|
pub ua_tray: String,
|
||||||
pub global_shortcut: Option<String>,
|
pub global_shortcut: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatConfJson {
|
impl ChatConfJson {
|
||||||
/// init chat.conf.json
|
/// init chat.conf.json
|
||||||
/// path: ~/.chatgpt/chat.conf.json
|
/// path: ~/.chatgpt/chat.conf.json
|
||||||
pub fn init() -> PathBuf {
|
pub fn init() -> PathBuf {
|
||||||
info!("chat_conf_init");
|
info!("chat_conf_init");
|
||||||
let conf_file = ChatConfJson::conf_path();
|
let conf_file = ChatConfJson::conf_path();
|
||||||
let content = if cfg!(target_os = "macos") {
|
let content = if cfg!(target_os = "macos") {
|
||||||
DEFAULT_CHAT_CONF_MAC
|
DEFAULT_CHAT_CONF_MAC
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_CHAT_CONF
|
DEFAULT_CHAT_CONF
|
||||||
};
|
};
|
||||||
|
|
||||||
if !exists(&conf_file) {
|
if !exists(&conf_file) {
|
||||||
create_file(&conf_file).unwrap();
|
create_file(&conf_file).unwrap();
|
||||||
fs::write(&conf_file, content).unwrap();
|
fs::write(&conf_file, content).unwrap();
|
||||||
return conf_file;
|
return conf_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let conf_file = ChatConfJson::conf_path();
|
conf_file
|
||||||
let file_content = fs::read_to_string(&conf_file).unwrap();
|
}
|
||||||
match serde_json::from_str(&file_content) {
|
|
||||||
Ok(v) => v,
|
|
||||||
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 conf_path() -> PathBuf {
|
pub fn get_chat_conf() -> Self {
|
||||||
chat_root().join("chat.conf.json")
|
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
|
||||||
|
};
|
||||||
|
|
||||||
pub fn get_chat_conf() -> Self {
|
match serde_json::from_value(match serde_json::from_str(&file_content) {
|
||||||
let conf_file = ChatConfJson::conf_path();
|
Ok(v) => v,
|
||||||
let file_content = fs::read_to_string(&conf_file).unwrap();
|
Err(_) => {
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_chat_conf() -> Self {
|
|
||||||
let conf_file = ChatConfJson::conf_path();
|
|
||||||
let content = if cfg!(target_os = "macos") {
|
|
||||||
DEFAULT_CHAT_CONF_MAC
|
|
||||||
} else {
|
|
||||||
DEFAULT_CHAT_CONF
|
|
||||||
};
|
|
||||||
fs::write(&conf_file, content).unwrap();
|
fs::write(&conf_file, content).unwrap();
|
||||||
serde_json::from_str(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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_chat_conf() -> Self {
|
||||||
|
let conf_file = ChatConfJson::conf_path();
|
||||||
|
let content = if cfg!(target_os = "macos") {
|
||||||
|
DEFAULT_CHAT_CONF_MAC
|
||||||
|
} else {
|
||||||
|
DEFAULT_CHAT_CONF
|
||||||
|
};
|
||||||
|
fs::write(&conf_file, content).unwrap();
|
||||||
|
serde_json::from_str(content).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://users.rust-lang.org/t/updating-object-fields-given-dynamic-json/39049/3
|
||||||
|
pub fn amend(new_rules: &Value, app: Option<tauri::AppHandle>) -> Result<()> {
|
||||||
|
let config = ChatConfJson::get_chat_conf();
|
||||||
|
let config: Value = serde_json::to_value(&config)?;
|
||||||
|
let mut config: BTreeMap<String, Value> = serde_json::from_value(config)?;
|
||||||
|
let new_rules: BTreeMap<String, Value> = serde_json::from_value(new_rules.clone())?;
|
||||||
|
|
||||||
|
for (k, v) in new_rules {
|
||||||
|
config.insert(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://users.rust-lang.org/t/updating-object-fields-given-dynamic-json/39049/3
|
fs::write(ChatConfJson::conf_path(), serde_json::to_string_pretty(&config)?)?;
|
||||||
pub fn amend(new_rules: &Value, app: Option<tauri::AppHandle>) -> Result<()> {
|
|
||||||
let config = ChatConfJson::get_chat_conf();
|
|
||||||
let config: Value = serde_json::to_value(&config)?;
|
|
||||||
let mut config: BTreeMap<String, Value> = serde_json::from_value(config)?;
|
|
||||||
let new_rules: BTreeMap<String, Value> = serde_json::from_value(new_rules.clone())?;
|
|
||||||
|
|
||||||
for (k, v) in new_rules {
|
if let Some(handle) = app {
|
||||||
config.insert(k, v);
|
tauri::api::process::restart(&handle.env());
|
||||||
}
|
// tauri::api::dialog::ask(
|
||||||
|
// handle.get_window("core").as_ref(),
|
||||||
fs::write(
|
// "ChatGPT Restart",
|
||||||
ChatConfJson::conf_path(),
|
// "Whether to restart immediately?",
|
||||||
serde_json::to_string_pretty(&config)?,
|
// move |is_restart| {
|
||||||
)?;
|
// if is_restart {
|
||||||
|
// }
|
||||||
if let Some(handle) = app {
|
// },
|
||||||
tauri::api::process::restart(&handle.env());
|
// );
|
||||||
// tauri::api::dialog::ask(
|
|
||||||
// handle.get_window("core").as_ref(),
|
|
||||||
// "ChatGPT Restart",
|
|
||||||
// "Whether to restart immediately?",
|
|
||||||
// move |is_restart| {
|
|
||||||
// if is_restart {
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn theme() -> Option<Theme> {
|
Ok(())
|
||||||
let conf = ChatConfJson::get_chat_conf();
|
}
|
||||||
let theme = match conf.theme.as_str() {
|
|
||||||
"System" => match dark_light::detect() {
|
|
||||||
// Dark mode
|
|
||||||
dark_light::Mode::Dark => Theme::Dark,
|
|
||||||
// Light mode
|
|
||||||
dark_light::Mode::Light => Theme::Light,
|
|
||||||
// Unspecified
|
|
||||||
dark_light::Mode::Default => Theme::Light,
|
|
||||||
},
|
|
||||||
"Dark" => Theme::Dark,
|
|
||||||
_ => Theme::Light,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(theme)
|
pub fn theme() -> Option<Theme> {
|
||||||
}
|
let conf = ChatConfJson::get_chat_conf();
|
||||||
|
let theme = match conf.theme.as_str() {
|
||||||
|
"System" => match dark_light::detect() {
|
||||||
|
// Dark mode
|
||||||
|
dark_light::Mode::Dark => Theme::Dark,
|
||||||
|
// Light mode
|
||||||
|
dark_light::Mode::Light => Theme::Light,
|
||||||
|
// Unspecified
|
||||||
|
dark_light::Mode::Default => Theme::Light,
|
||||||
|
},
|
||||||
|
"Dark" => Theme::Dark,
|
||||||
|
_ => Theme::Light,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
Some(theme)
|
||||||
pub fn titlebar() -> TitleBarStyle {
|
}
|
||||||
let conf = ChatConfJson::get_chat_conf();
|
|
||||||
if conf.titlebar {
|
#[cfg(target_os = "macos")]
|
||||||
TitleBarStyle::Transparent
|
pub fn titlebar() -> TitleBarStyle {
|
||||||
} else {
|
let conf = ChatConfJson::get_chat_conf();
|
||||||
TitleBarStyle::Overlay
|
if conf.titlebar {
|
||||||
}
|
TitleBarStyle::Transparent
|
||||||
|
} else {
|
||||||
|
TitleBarStyle::Overlay
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
#![cfg_attr(
|
#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")]
|
||||||
all(not(debug_assertions), target_os = "windows"),
|
|
||||||
windows_subsystem = "windows"
|
|
||||||
)]
|
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod conf;
|
mod conf;
|
||||||
@@ -12,104 +9,101 @@ use conf::ChatConfJson;
|
|||||||
use tauri::api::path;
|
use tauri::api::path;
|
||||||
use tauri_plugin_autostart::MacosLauncher;
|
use tauri_plugin_autostart::MacosLauncher;
|
||||||
use tauri_plugin_log::{
|
use tauri_plugin_log::{
|
||||||
fern::colors::{Color, ColoredLevelConfig},
|
fern::colors::{Color, ColoredLevelConfig},
|
||||||
LogTarget,
|
LogTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
ChatConfJson::init();
|
ChatConfJson::init();
|
||||||
// If the file does not exist, creating the file will block menu synchronization
|
// If the file does not exist, creating the file will block menu synchronization
|
||||||
utils::create_chatgpt_prompts();
|
utils::create_chatgpt_prompts();
|
||||||
let context = tauri::generate_context!();
|
let context = tauri::generate_context!();
|
||||||
let colors = ColoredLevelConfig {
|
let colors = ColoredLevelConfig {
|
||||||
error: Color::Red,
|
error: Color::Red,
|
||||||
warn: Color::Yellow,
|
warn: Color::Yellow,
|
||||||
debug: Color::Blue,
|
debug: Color::Blue,
|
||||||
info: Color::BrightGreen,
|
info: Color::BrightGreen,
|
||||||
trace: Color::Cyan,
|
trace: Color::Cyan,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd::download_list("chat.download.json", "download", None, None);
|
cmd::download_list("chat.download.json", "download", None, None);
|
||||||
cmd::download_list("chat.notes.json", "notes", None, None);
|
cmd::download_list("chat.notes.json", "notes", None, None);
|
||||||
|
|
||||||
let chat_conf = ChatConfJson::get_chat_conf();
|
let chat_conf = ChatConfJson::get_chat_conf();
|
||||||
|
|
||||||
let mut builder = tauri::Builder::default()
|
let mut builder = tauri::Builder::default()
|
||||||
// https://github.com/tauri-apps/tauri/pull/2736
|
// https://github.com/tauri-apps/tauri/pull/2736
|
||||||
.plugin(
|
.plugin(
|
||||||
tauri_plugin_log::Builder::default()
|
tauri_plugin_log::Builder::default()
|
||||||
.targets([
|
.targets([
|
||||||
// LogTarget::LogDir,
|
// LogTarget::LogDir,
|
||||||
// LOG PATH: ~/.chatgpt/ChatGPT.log
|
// LOG PATH: ~/.chatgpt/ChatGPT.log
|
||||||
LogTarget::Folder(path::home_dir().unwrap().join(".chatgpt")),
|
LogTarget::Folder(path::home_dir().unwrap().join(".chatgpt")),
|
||||||
LogTarget::Stdout,
|
LogTarget::Stdout,
|
||||||
LogTarget::Webview,
|
LogTarget::Webview,
|
||||||
])
|
|
||||||
.level(log::LevelFilter::Debug)
|
|
||||||
.with_colors(colors)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.plugin(tauri_plugin_positioner::init())
|
|
||||||
.plugin(tauri_plugin_autostart::init(
|
|
||||||
MacosLauncher::LaunchAgent,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
.invoke_handler(tauri::generate_handler![
|
|
||||||
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_chat_model_cmd,
|
|
||||||
cmd::parse_prompt,
|
|
||||||
cmd::sync_prompts,
|
|
||||||
cmd::sync_user_prompts,
|
|
||||||
cmd::window_reload,
|
|
||||||
cmd::dalle2_window,
|
|
||||||
cmd::cmd_list,
|
|
||||||
cmd::download_list,
|
|
||||||
cmd::get_download_list,
|
|
||||||
fs_extra::metadata,
|
|
||||||
])
|
])
|
||||||
.setup(setup::init)
|
.level(log::LevelFilter::Debug)
|
||||||
.menu(menu::init());
|
.with_colors(colors)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.plugin(tauri_plugin_positioner::init())
|
||||||
|
.plugin(tauri_plugin_autostart::init(MacosLauncher::LaunchAgent, None))
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
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_chat_model_cmd,
|
||||||
|
cmd::parse_prompt,
|
||||||
|
cmd::sync_prompts,
|
||||||
|
cmd::sync_user_prompts,
|
||||||
|
cmd::window_reload,
|
||||||
|
cmd::dalle2_window,
|
||||||
|
cmd::cmd_list,
|
||||||
|
cmd::download_list,
|
||||||
|
cmd::get_download_list,
|
||||||
|
fs_extra::metadata,
|
||||||
|
])
|
||||||
|
.setup(setup::init)
|
||||||
|
.menu(menu::init());
|
||||||
|
|
||||||
if chat_conf.tray {
|
if chat_conf.tray {
|
||||||
builder = builder.system_tray(menu::tray_menu());
|
builder = builder.system_tray(menu::tray_menu());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.on_menu_event(menu::menu_handler)
|
.on_menu_event(menu::menu_handler)
|
||||||
.on_system_tray_event(menu::tray_handler)
|
.on_system_tray_event(menu::tray_handler)
|
||||||
.on_window_event(|event| {
|
.on_window_event(|event| {
|
||||||
// https://github.com/tauri-apps/tauri/discussions/2684
|
// https://github.com/tauri-apps/tauri/discussions/2684
|
||||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
|
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
|
||||||
let win = event.window();
|
let win = event.window();
|
||||||
if win.label() == "core" {
|
if win.label() == "core" {
|
||||||
// TODO: https://github.com/tauri-apps/tauri/issues/3084
|
// TODO: https://github.com/tauri-apps/tauri/issues/3084
|
||||||
// event.window().hide().unwrap();
|
// event.window().hide().unwrap();
|
||||||
// https://github.com/tauri-apps/tao/pull/517
|
// https://github.com/tauri-apps/tao/pull/517
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
event.window().minimize().unwrap();
|
event.window().minimize().unwrap();
|
||||||
|
|
||||||
// fix: https://github.com/lencx/ChatGPT/issues/93
|
// fix: https://github.com/lencx/ChatGPT/issues/93
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
event.window().hide().unwrap();
|
event.window().hide().unwrap();
|
||||||
} else {
|
} else {
|
||||||
win.close().unwrap();
|
win.close().unwrap();
|
||||||
}
|
}
|
||||||
api.prevent_close();
|
api.prevent_close();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.run(context)
|
.run(context)
|
||||||
.expect("error while running ChatGPT application");
|
.expect("error while running ChatGPT application");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,215 +3,180 @@ use log::info;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
use tauri::updater::UpdateResponse;
|
use tauri::updater::UpdateResponse;
|
||||||
use tauri::{utils::config::Config, AppHandle, Manager, Wry};
|
use tauri::{utils::config::Config, AppHandle, Manager, Wry};
|
||||||
|
|
||||||
pub fn chat_root() -> PathBuf {
|
pub fn chat_root() -> PathBuf {
|
||||||
tauri::api::path::home_dir().unwrap().join(".chatgpt")
|
tauri::api::path::home_dir().unwrap().join(".chatgpt")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tauri_conf() -> Option<Config> {
|
pub fn get_tauri_conf() -> Option<Config> {
|
||||||
let config_file = include_str!("../tauri.conf.json");
|
let config_file = include_str!("../tauri.conf.json");
|
||||||
let config: Config =
|
let config: Config = serde_json::from_str(config_file).expect("failed to parse tauri.conf.json");
|
||||||
serde_json::from_str(config_file).expect("failed to parse tauri.conf.json");
|
Some(config)
|
||||||
Some(config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists(path: &Path) -> bool {
|
pub fn exists(path: &Path) -> bool {
|
||||||
Path::new(path).exists()
|
Path::new(path).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_file(path: &Path) -> Result<File> {
|
pub fn create_file(path: &Path) -> Result<File> {
|
||||||
if let Some(p) = path.parent() {
|
if let Some(p) = path.parent() {
|
||||||
fs::create_dir_all(p)?
|
fs::create_dir_all(p)?
|
||||||
}
|
}
|
||||||
File::create(path).map_err(Into::into)
|
File::create(path).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_chatgpt_prompts() {
|
pub fn create_chatgpt_prompts() {
|
||||||
let sync_file = chat_root().join("cache_model").join("chatgpt_prompts.json");
|
let sync_file = chat_root().join("cache_model").join("chatgpt_prompts.json");
|
||||||
if !exists(&sync_file) {
|
if !exists(&sync_file) {
|
||||||
create_file(&sync_file).unwrap();
|
create_file(&sync_file).unwrap();
|
||||||
fs::write(&sync_file, "[]").unwrap();
|
fs::write(&sync_file, "[]").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn script_path() -> PathBuf {
|
pub fn script_path() -> PathBuf {
|
||||||
let script_file = chat_root().join("main.js");
|
let script_file = chat_root().join("main.js");
|
||||||
if !exists(&script_file) {
|
if !exists(&script_file) {
|
||||||
create_file(&script_file).unwrap();
|
create_file(&script_file).unwrap();
|
||||||
fs::write(&script_file, format!("// *** ChatGPT User Script ***\n// @github: https://github.com/lencx/ChatGPT \n// @path: {}\n\nconsole.log('🤩 Hello ChatGPT!!!');", &script_file.to_string_lossy())).unwrap();
|
fs::write(&script_file, format!("// *** ChatGPT User Script ***\n// @github: https://github.com/lencx/ChatGPT \n// @path: {}\n\nconsole.log('🤩 Hello ChatGPT!!!');", &script_file.to_string_lossy())).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
script_file
|
script_file
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_script() -> String {
|
pub fn user_script() -> String {
|
||||||
let user_script_content = fs::read_to_string(script_path()).unwrap_or_else(|_| "".to_string());
|
let user_script_content = fs::read_to_string(script_path()).unwrap_or_else(|_| "".to_string());
|
||||||
format!(
|
format!(
|
||||||
"window.addEventListener('DOMContentLoaded', function() {{\n{}\n}})",
|
"window.addEventListener('DOMContentLoaded', function() {{\n{}\n}})",
|
||||||
user_script_content
|
user_script_content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_file(path: PathBuf) {
|
pub fn open_file(path: PathBuf) {
|
||||||
info!("open_file: {}", path.to_string_lossy());
|
info!("open_file: {}", path.to_string_lossy());
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Command::new("open").arg("-R").arg(path).spawn().unwrap();
|
Command::new("open").arg("-R").arg(path).spawn().unwrap();
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
Command::new("explorer")
|
Command::new("explorer").arg("/select,").arg(path).spawn().unwrap();
|
||||||
.arg("/select,")
|
|
||||||
.arg(path)
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// https://askubuntu.com/a/31071
|
// https://askubuntu.com/a/31071
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
Command::new("xdg-open").arg(path).spawn().unwrap();
|
Command::new("xdg-open").arg(path).spawn().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_conf(app: &tauri::AppHandle) {
|
pub fn clear_conf(app: &tauri::AppHandle) {
|
||||||
let root = chat_root();
|
let root = chat_root();
|
||||||
let app2 = app.clone();
|
let app2 = app.clone();
|
||||||
let msg = format!("Path: {}\nAre you sure to clear all ChatGPT configurations? Please backup in advance if necessary!", root.to_string_lossy());
|
let msg = format!(
|
||||||
tauri::api::dialog::ask(
|
"Path: {}\nAre you sure to clear all ChatGPT configurations? Please backup in advance if necessary!",
|
||||||
app.get_window("core").as_ref(),
|
root.to_string_lossy()
|
||||||
"Clear Config",
|
);
|
||||||
msg,
|
tauri::api::dialog::ask(app.get_window("core").as_ref(), "Clear Config", msg, move |is_ok| {
|
||||||
move |is_ok| {
|
if is_ok {
|
||||||
if is_ok {
|
fs::remove_dir_all(root).unwrap();
|
||||||
fs::remove_dir_all(root).unwrap();
|
tauri::api::process::restart(&app2.env());
|
||||||
tauri::api::process::restart(&app2.env());
|
}
|
||||||
}
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge(v: &Value, fields: &HashMap<String, Value>) -> Value {
|
pub fn merge(v: &Value, fields: &HashMap<String, Value>) -> Value {
|
||||||
match v {
|
match v {
|
||||||
Value::Object(m) => {
|
Value::Object(m) => {
|
||||||
let mut m = m.clone();
|
let mut m = m.clone();
|
||||||
for (k, v) in fields {
|
for (k, v) in fields {
|
||||||
m.insert(k.clone(), v.clone());
|
m.insert(k.clone(), v.clone());
|
||||||
}
|
}
|
||||||
Value::Object(m)
|
Value::Object(m)
|
||||||
}
|
|
||||||
v => v.clone(),
|
|
||||||
}
|
}
|
||||||
|
v => v.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_cmd(name: String) -> String {
|
pub fn gen_cmd(name: String) -> String {
|
||||||
let re = Regex::new(r"[^a-zA-Z0-9]").unwrap();
|
let re = Regex::new(r"[^a-zA-Z0-9]").unwrap();
|
||||||
re.replace_all(&name, "_").to_lowercase()
|
re.replace_all(&name, "_").to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_data(
|
pub async fn get_data(url: &str, app: Option<&tauri::AppHandle>) -> Result<Option<String>, reqwest::Error> {
|
||||||
url: &str,
|
let res = reqwest::get(url).await?;
|
||||||
app: Option<&tauri::AppHandle>,
|
let is_ok = res.status() == 200;
|
||||||
) -> Result<Option<String>, reqwest::Error> {
|
let body = res.text().await?;
|
||||||
let res = reqwest::get(url).await?;
|
|
||||||
let is_ok = res.status() == 200;
|
|
||||||
let body = res.text().await?;
|
|
||||||
|
|
||||||
if is_ok {
|
if is_ok {
|
||||||
Ok(Some(body))
|
Ok(Some(body))
|
||||||
} else {
|
} else {
|
||||||
info!("chatgpt_http_error: {}", body);
|
info!("chatgpt_http_error: {}", body);
|
||||||
if let Some(v) = app {
|
if let Some(v) = app {
|
||||||
tauri::api::dialog::message(v.get_window("core").as_ref(), "ChatGPT HTTP", body);
|
tauri::api::dialog::message(v.get_window("core").as_ref(), "ChatGPT HTTP", body);
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_check_update(app: AppHandle<Wry>, silent: bool, has_msg: Option<bool>) {
|
pub fn run_check_update(app: AppHandle<Wry>, silent: bool, has_msg: Option<bool>) {
|
||||||
info!("run_check_update: silent={} has_msg={:?}", silent, has_msg);
|
info!("run_check_update: silent={} has_msg={:?}", silent, has_msg);
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let result = app.updater().check().await;
|
let result = app.updater().check().await;
|
||||||
let update_resp = result.unwrap();
|
let update_resp = result.unwrap();
|
||||||
if update_resp.is_update_available() {
|
if update_resp.is_update_available() {
|
||||||
if silent {
|
if silent {
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
silent_install(app, update_resp).await.unwrap();
|
silent_install(app, update_resp).await.unwrap();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
prompt_for_install(app, update_resp).await.unwrap();
|
prompt_for_install(app, update_resp).await.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if let Some(v) = has_msg {
|
} else if let Some(v) = has_msg {
|
||||||
if v {
|
if v {
|
||||||
tauri::api::dialog::message(
|
tauri::api::dialog::message(
|
||||||
app.app_handle().get_window("core").as_ref(),
|
app.app_handle().get_window("core").as_ref(),
|
||||||
"ChatGPT",
|
"ChatGPT",
|
||||||
"Your ChatGPT is up to date",
|
"Your ChatGPT is up to date",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy private api in tauri/updater/mod.rs. TODO: refactor to public api
|
// Copy private api in tauri/updater/mod.rs. TODO: refactor to public api
|
||||||
// Prompt a dialog asking if the user want to install the new version
|
// Prompt a dialog asking if the user want to install the new version
|
||||||
// Maybe we should add an option to customize it in future versions.
|
// Maybe we should add an option to customize it in future versions.
|
||||||
pub async fn prompt_for_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
pub async fn prompt_for_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
||||||
info!("prompt_for_install");
|
info!("prompt_for_install");
|
||||||
let windows = app.windows();
|
let windows = app.windows();
|
||||||
let parent_window = windows.values().next();
|
let parent_window = windows.values().next();
|
||||||
let package_info = app.package_info().clone();
|
let package_info = app.package_info().clone();
|
||||||
|
|
||||||
let body = update.body().unwrap();
|
let body = update.body().unwrap();
|
||||||
// todo(lemarier): We should review this and make sure we have
|
// todo(lemarier): We should review this and make sure we have
|
||||||
// something more conventional.
|
// something more conventional.
|
||||||
let should_install = tauri::api::dialog::blocking::ask(
|
let should_install = tauri::api::dialog::blocking::ask(
|
||||||
parent_window,
|
parent_window,
|
||||||
format!(r#"A new version of {} is available! "#, package_info.name),
|
format!(r#"A new version of {} is available! "#, package_info.name),
|
||||||
format!(
|
format!(
|
||||||
r#"{} {} is now available -- you have {}.
|
r#"{} {} is now available -- you have {}.
|
||||||
|
|
||||||
Would you like to install it now?
|
Would you like to install it now?
|
||||||
|
|
||||||
Release Notes:
|
Release Notes:
|
||||||
{}"#,
|
{}"#,
|
||||||
package_info.name,
|
package_info.name,
|
||||||
update.latest_version(),
|
update.latest_version(),
|
||||||
package_info.version,
|
package_info.version,
|
||||||
body
|
body
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if should_install {
|
|
||||||
// Launch updater download process
|
|
||||||
// macOS we display the `Ready to restart dialog` asking to restart
|
|
||||||
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
|
||||||
// Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
|
|
||||||
update.download_and_install().await?;
|
|
||||||
|
|
||||||
// Ask user if we need to restart the application
|
|
||||||
let should_exit = tauri::api::dialog::blocking::ask(
|
|
||||||
parent_window,
|
|
||||||
"Ready to Restart",
|
|
||||||
"The installation was successful, do you want to restart the application now?",
|
|
||||||
);
|
|
||||||
if should_exit {
|
|
||||||
app.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
|
||||||
info!("silent_install");
|
|
||||||
let windows = app.windows();
|
|
||||||
let parent_window = windows.values().next();
|
|
||||||
|
|
||||||
|
if should_install {
|
||||||
// Launch updater download process
|
// Launch updater download process
|
||||||
// macOS we display the `Ready to restart dialog` asking to restart
|
// macOS we display the `Ready to restart dialog` asking to restart
|
||||||
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
||||||
@@ -220,33 +185,54 @@ pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) ->
|
|||||||
|
|
||||||
// Ask user if we need to restart the application
|
// Ask user if we need to restart the application
|
||||||
let should_exit = tauri::api::dialog::blocking::ask(
|
let should_exit = tauri::api::dialog::blocking::ask(
|
||||||
parent_window,
|
parent_window,
|
||||||
"Ready to Restart",
|
"Ready to Restart",
|
||||||
"The silent installation was successful, do you want to restart the application now?",
|
"The installation was successful, do you want to restart the application now?",
|
||||||
);
|
);
|
||||||
if should_exit {
|
if should_exit {
|
||||||
app.restart();
|
app.restart();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn silent_install(app: AppHandle<Wry>, update: UpdateResponse<Wry>) -> Result<()> {
|
||||||
|
info!("silent_install");
|
||||||
|
let windows = app.windows();
|
||||||
|
let parent_window = windows.values().next();
|
||||||
|
|
||||||
|
// Launch updater download process
|
||||||
|
// macOS we display the `Ready to restart dialog` asking to restart
|
||||||
|
// Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
|
||||||
|
// Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
|
||||||
|
update.download_and_install().await?;
|
||||||
|
|
||||||
|
// Ask user if we need to restart the application
|
||||||
|
let should_exit = tauri::api::dialog::blocking::ask(
|
||||||
|
parent_window,
|
||||||
|
"Ready to Restart",
|
||||||
|
"The silent installation was successful, do you want to restart the application now?",
|
||||||
|
);
|
||||||
|
if should_exit {
|
||||||
|
app.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_hidden(entry: &walkdir::DirEntry) -> bool {
|
pub fn is_hidden(entry: &walkdir::DirEntry) -> bool {
|
||||||
entry
|
entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
|
||||||
.file_name()
|
|
||||||
.to_str()
|
|
||||||
.map(|s| s.starts_with('.'))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vec_to_hashmap(
|
pub fn vec_to_hashmap(
|
||||||
vec: impl Iterator<Item = serde_json::Value>,
|
vec: impl Iterator<Item = serde_json::Value>,
|
||||||
key: &str,
|
key: &str,
|
||||||
map: &mut HashMap<String, serde_json::Value>,
|
map: &mut HashMap<String, serde_json::Value>,
|
||||||
) {
|
) {
|
||||||
for v in vec {
|
for v in vec {
|
||||||
if let Some(kval) = v.get(key).and_then(serde_json::Value::as_str) {
|
if let Some(kval) = v.get(key).and_then(serde_json::Value::as_str) {
|
||||||
map.insert(kval.to_string(), v);
|
map.insert(kval.to_string(), v);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/view/awesome/config.tsx
vendored
4
src/view/awesome/config.tsx
vendored
@@ -12,7 +12,7 @@ export const awesomeColumns = () => [
|
|||||||
title: 'URL',
|
title: 'URL',
|
||||||
dataIndex: 'url',
|
dataIndex: 'url',
|
||||||
key: 'url',
|
key: 'url',
|
||||||
width: 120,
|
width: 200,
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title: 'Icon',
|
// title: 'Icon',
|
||||||
@@ -33,7 +33,7 @@ export const awesomeColumns = () => [
|
|||||||
title: 'Category',
|
title: 'Category',
|
||||||
dataIndex: 'category',
|
dataIndex: 'category',
|
||||||
key: 'category',
|
key: 'category',
|
||||||
width: 200,
|
width: 120,
|
||||||
render: (v: string) => <Tag color="geekblue">{v}</Tag>
|
render: (v: string) => <Tag color="geekblue">{v}</Tag>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user