This commit is contained in:
lencx
2022-12-07 18:22:18 +08:00
parent 2f9f201c8b
commit 386a58a499
34 changed files with 4177 additions and 0 deletions

31
src-tauri/src/core.js Normal file
View File

@@ -0,0 +1,31 @@
// *** Core Script ***
document.addEventListener('DOMContentLoaded', async () => {
const topStyleDom = document.createElement("style");
topStyleDom.innerHTML = `#chatgpt-app-window-top{position:fixed;top:0;z-index:999999999;width:100%;height:24px;background:transparent;cursor:grab;cursor:-webkit-grab;user-select:none;-webkit-user-select:none;}#chatgpt-app-window-top:active {cursor:grabbing;cursor:-webkit-grabbing;}`;
document.head.appendChild(topStyleDom);
const topDom = document.createElement("div");
topDom.id = "chatgpt-app-window-top";
document.body.appendChild(topDom);
topDom.addEventListener("mousedown", () => __TAURI_INVOKE__("drag_window"));
topDom.addEventListener("touchstart", () => __TAURI_INVOKE__("drag_window"));
topDom.addEventListener("dblclick", () => __TAURI_INVOKE__("fullscreen"));
document.addEventListener("click", (e) => {
const origin = e.target.closest("a");
if (origin && origin.href && origin.target !== '_self') {
origin.target = "_self";
}
});
document.addEventListener('wheel', function(event) {
const deltaX = event.wheelDeltaX;
if (Math.abs(deltaX) >= 50) {
if (deltaX > 0) {
window.history.go(-1);
} else {
window.history.go(1);
}
}
});
})

27
src-tauri/src/main.rs Normal file
View File

@@ -0,0 +1,27 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
mod utils;
mod wa;
use tauri::SystemTray;
use wa::{cmd, menu, setup};
fn main() {
let context = tauri::generate_context!();
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
cmd::drag_window,
cmd::fullscreen,
])
.setup(setup::init)
.menu(menu::init(&context))
.system_tray(SystemTray::new())
.on_menu_event(menu::menu_handler)
.on_system_tray_event(menu::tray_handler)
.run(context)
.expect("error while running ChatGPT application");
}

53
src-tauri/src/utils.rs Normal file
View File

@@ -0,0 +1,53 @@
use anyhow::Result;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use tauri::utils::config::Config;
pub fn get_tauri_conf() -> Option<Config> {
let config_file = include_str!("../tauri.conf.json");
let config: Config =
serde_json::from_str(config_file).expect("failed to parse tauri.conf.json");
Some(config)
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct WaJson {
pub url: String,
pub resizable: bool,
pub theme: tauri::Theme,
pub mode: String,
pub title: String,
pub always_on_top: bool,
pub hidden_title: bool,
pub hide_title_bar: bool,
}
pub fn exists(path: &Path) -> bool {
Path::new(path).exists()
}
pub fn create_file(path: &Path) -> Result<File> {
if let Some(p) = path.parent() {
fs::create_dir_all(p)?
}
File::create(path).map_err(Into::into)
}
pub fn script_path() -> PathBuf {
let root = tauri::api::path::home_dir().unwrap().join(".chatgpt");
let script_file = root.join("main.js");
if !exists(&script_file) {
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();
}
script_file
}
pub fn user_script() -> String {
let user_script_content = fs::read_to_string(script_path()).unwrap_or_else(|_| "".to_string());
format!(
"window.addEventListener('DOMContentLoaded', function() {{\n{}\n}})",
user_script_content
)
}

16
src-tauri/src/wa/cmd.rs Normal file
View File

@@ -0,0 +1,16 @@
use tauri::Manager;
#[tauri::command]
pub fn drag_window(app: tauri::AppHandle) {
app.get_window("core").unwrap().start_dragging().unwrap();
}
#[tauri::command]
pub fn fullscreen(app: tauri::AppHandle) {
let win = app.get_window("core").unwrap();
if win.is_fullscreen().unwrap() {
win.set_fullscreen(false).unwrap();
} else {
win.set_fullscreen(true).unwrap();
}
}

160
src-tauri/src/wa/menu.rs Normal file
View File

@@ -0,0 +1,160 @@
use tauri::{
utils::assets::EmbeddedAssets, AboutMetadata, AppHandle, Context, CustomMenuItem, Manager,
Menu, MenuItem, Submenu, SystemTrayEvent, WindowMenuEvent,
};
use crate::utils;
// --- Menu
pub fn init(context: &Context<EmbeddedAssets>) -> Menu {
let name = &context.package_info().name;
let app_menu = Submenu::new(
name,
Menu::new()
.add_native_item(MenuItem::About(name.into(), AboutMetadata::default()))
.add_native_item(MenuItem::Separator)
.add_item(
CustomMenuItem::new("inject_script".to_string(), "Inject Script")
.accelerator("CmdOrCtrl+J"),
)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Hide)
.add_native_item(MenuItem::HideOthers)
.add_native_item(MenuItem::ShowAll)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Quit),
);
let edit_menu = Submenu::new(
"Edit",
Menu::new()
.add_native_item(MenuItem::Undo)
.add_native_item(MenuItem::Redo)
.add_native_item(MenuItem::Separator)
.add_native_item(MenuItem::Cut)
.add_native_item(MenuItem::Copy)
.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 help_menu = Submenu::new(
"Help",
Menu::new()
.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(edit_menu)
.add_submenu(view_menu)
.add_submenu(help_menu)
}
// --- Menu Event
pub fn menu_handler(event: WindowMenuEvent<tauri::Wry>) {
let win = Some(event.window()).unwrap();
let app = win.app_handle();
match event.menu_item_id() {
// App
"inject_script" => {
tauri::api::shell::open(
&app.shell_scope(),
utils::script_path().to_string_lossy(),
None,
)
.unwrap();
}
// View
"go_back" => {
win.eval("window.history.go(-1)").unwrap();
}
"go_forward" => {
win.eval("window.history.go(1)").unwrap();
}
"scroll_top" => {
win.eval(
r#"window.scroll({
top: 0,
left: 0,
behavior: "smooth"
})"#,
)
.unwrap();
}
"scroll_bottom" => {
win.eval(
r#"window.scroll({
top: document.body.scrollHeight,
left: 0,
behavior: "smooth",
})"#,
)
.unwrap();
}
"reload" => {
win.eval("window.location.reload()").unwrap();
}
// Help
"report_bug" => {
tauri::api::shell::open(
&app.shell_scope(),
"https://github.com/lencx/ChatGPT/issues",
None,
)
.unwrap();
}
"dev_tools" => {
win.open_devtools();
win.close_devtools();
}
_ => (),
}
}
// --- SystemTray Event
pub fn tray_handler(app: &AppHandle, event: SystemTrayEvent) {
if let SystemTrayEvent::LeftClick {
position: _,
size: _,
..
} = event
{
let win = app.get_window("core").unwrap();
if win.is_visible().unwrap() {
win.hide().unwrap();
} else {
win.show().unwrap();
win.set_focus().unwrap();
}
}
}

3
src-tauri/src/wa/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod cmd;
pub mod menu;
pub mod setup;

21
src-tauri/src/wa/setup.rs Normal file
View File

@@ -0,0 +1,21 @@
use tauri::{utils::config::WindowUrl, window::WindowBuilder, App, TitleBarStyle};
use crate::utils;
pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>> {
let conf = utils::get_tauri_conf().unwrap();
let url = conf.build.dev_path.to_string();
WindowBuilder::new(app, "core", WindowUrl::App(url.into()))
.resizable(true)
.fullscreen(false)
.initialization_script(include_str!("../core.js"))
.initialization_script(&utils::user_script())
.title_bar_style(TitleBarStyle::Overlay)
.inner_size(800.0, 600.0)
.hidden_title(true)
.user_agent("5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")
.build()?;
Ok(())
}