You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Nothing/src-tauri/src/main.rs

227 lines
6.8 KiB

// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::sync::mpsc::Receiver;
use std::{path::PathBuf, sync::Mutex};
use config::Config;
use crossbeam::channel::Sender;
use notify::PollWatcher;
use overlay::{Event, Overlay};
use plan::{Plan, PlanMetadata};
use poe_data::world_area::WorldAreasMap;
use poe_reader::filter_func;
use poe_reader::{blocking_area_filtered_rx, poe_client_log_receiver};
use simple_logger::SimpleLogger;
use storage::Storage;
use tauri::CustomMenuItem;
use tauri::Manager;
use tauri::SystemTray;
use tauri::SystemTrayEvent;
use tauri::SystemTrayMenu;
use tauri::SystemTrayMenuItem;
use tauri::Window;
use lazy_static::lazy_static;
mod config;
mod overlay;
mod plan;
mod poe_reader;
mod storage;
lazy_static! {
static ref WORLD_AREAS_MAP: WorldAreasMap = poe_data::world_area::load_world_areas_map(
include_str!("../../data/processed_world_areas.json")
);
}
#[tauri::command]
fn set_interactable(interactable: bool, state: tauri::State<Sender<Event>>) {
if interactable {
state.send(overlay::State::Interactable {}.into()).ok();
} else {
state.send(overlay::Event::Return).ok();
}
}
#[tauri::command]
fn load_world_areas() -> WorldAreasMap {
log::info!("Loading world areas");
WORLD_AREAS_MAP.clone()
}
#[tauri::command]
fn load_config(state: tauri::State<Mutex<Storage>>) -> Option<Config> {
Some(state.lock().ok()?.config.clone())
}
#[tauri::command]
fn update_config(config: Config, state: tauri::State<Mutex<Storage>>) {
log::info!("Saved config: {:?}", config);
if let Ok(mut storage) = state.lock() {
storage.config = config.clone();
storage.save_config();
}
}
#[tauri::command]
fn enumerate_stored_plans() -> Vec<PlanMetadata> {
Storage::enumerate_plans()
}
#[tauri::command]
fn load_plan_at_path(
path: PathBuf,
save_local: Option<bool>,
state: tauri::State<Mutex<Storage>>,
) -> Option<Plan> {
if !path.exists() {
return None;
}
let mut storage = match state.lock() {
Ok(storage) => storage,
Err(_) => return None,
};
let save_local = save_local.unwrap_or(true);
storage.last_plan = Some(path.clone());
Storage::load_plan_at_path(path, save_local)
}
#[tauri::command]
fn save_plan_at_path(path: PathBuf, plan: Plan) -> bool {
if let Some(path_string) = path.with_extension("json").to_str() {
return Storage::save_plan_at_path(path_string, plan).is_ok();
}
false
}
#[tauri::command]
fn save_plan_at_store(name: String, plan: Plan) -> Option<PathBuf> {
Storage::save_plan_at_store_path(&name, plan).ok()
}
#[tauri::command]
fn base_plan() -> Plan {
const BASE_PLAN_STRING: &str = include_str!("../../data/base_plan.json");
serde_json::from_str(BASE_PLAN_STRING).expect("could not load base_plan")
}
fn main() {
SimpleLogger::new()
.with_module_level("underlayer", log::LevelFilter::Info)
.with_level(log::LevelFilter::Trace)
.init()
.expect("Could not init logger");
let settings = CustomMenuItem::new("settings".to_string(), "Settings");
let editor = CustomMenuItem::new("editor".to_string(), "Plan Editor");
let force_show = CustomMenuItem::new("force_show".to_string(), "Force show");
let exit = CustomMenuItem::new("exit".to_string(), "Exit");
let tray_menu = SystemTrayMenu::new()
.add_item(settings)
.add_item(editor)
.add_item(force_show)
.add_native_item(SystemTrayMenuItem::Separator)
.add_item(exit);
let system_tray = SystemTray::new().with_menu(tray_menu);
tauri::Builder::default()
.setup(|app| {
let tx = Overlay::initialize(
app.get_window("Overlay")
.expect("Could not get main overlay window"),
"Path of Exile",
);
app.manage(tx);
app.manage(Mutex::new(Storage::default()));
if let Ok(storage) = app.state::<Mutex<Storage>>().lock() {
listen_for_zone_changes(
storage.config.poe_client_log_path.clone(),
app.get_window("Overlay")
.expect("Could not get main overlay window"),
);
}
// app.get_window("Overlay")
// .expect("Could not get main overlay window")
// .open_devtools();
Ok(())
})
.invoke_handler(tauri::generate_handler![
set_interactable,
load_world_areas,
load_config,
update_config,
enumerate_stored_plans,
load_plan_at_path,
save_plan_at_path,
save_plan_at_store,
base_plan,
])
.system_tray(system_tray)
.on_system_tray_event(|app, event| match event {
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
"exit" => {
std::process::exit(0);
}
"editor" | "settings" => {
if let Some(window) = app.get_window("Normal") {
window.show().ok();
window.emit_to("Normal", "loadTab", id).ok();
}
}
"force_show" => {
app.state::<Sender<Event>>()
.send(overlay::State::Interactable {}.into())
.ok();
}
_ => {}
},
_ => {}
})
.on_window_event(|event| match event.event() {
tauri::WindowEvent::CloseRequested { api, .. } => {
event.window().hide().ok();
api.prevent_close();
}
_ => {}
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
fn listen_for_zone_changes(poe_client_log_path: Option<PathBuf>, window: Window) {
std::thread::spawn(move || {
// need _watcher
if let Some((enter_area_receiver, _watcher)) = receiver_from_path(&poe_client_log_path) {
let world_areas: WorldAreasMap = load_world_areas();
for area in blocking_area_filtered_rx(&enter_area_receiver) {
if let Some(area) = filter_func(area) {
if let Some(entered) = world_areas.get(&area) {
window.emit_to("Overlay", "entered", &entered.named_id).ok();
}
}
}
}
});
}
fn receiver_from_path(path: &Option<PathBuf>) -> Option<(Receiver<String>, PollWatcher)> {
if let Some(poe_path) = path {
if poe_path.exists() {
return Some(poe_client_log_receiver(poe_path.clone()));
}
}
None
}