add configuration with hot reload
This commit is contained in:
parent
b0d82ea050
commit
56f7e1f11b
|
@ -315,6 +315,7 @@ dependencies = [
|
|||
"env_logger",
|
||||
"image",
|
||||
"log",
|
||||
"notify",
|
||||
"rand 0.8.5",
|
||||
"ray_format",
|
||||
"serde",
|
||||
|
@ -322,6 +323,7 @@ dependencies = [
|
|||
"tauri",
|
||||
"tauri-build",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -963,6 +965,15 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futf"
|
||||
version = "0.1.5"
|
||||
|
@ -1513,6 +1524,26 @@ dependencies = [
|
|||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
@ -1643,6 +1674,26 @@ dependencies = [
|
|||
"treediff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue-sys"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchiki"
|
||||
version = "0.8.1"
|
||||
|
@ -1922,6 +1973,24 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
|
|
|
@ -42,6 +42,8 @@ rand = "0.8.5"
|
|||
tokio = { version = "1.21.0", features = ["full"] }
|
||||
image = "0.24.3"
|
||||
base64-url = "1.4.13"
|
||||
toml = "0.5.9"
|
||||
notify = "5.0.0"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use log::{debug, error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::api::path::config_dir;
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
pub background_color: BGColor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum BGColor {
|
||||
Transparent,
|
||||
Green,
|
||||
Blue,
|
||||
Pink,
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl Default for BGColor {
|
||||
fn default() -> Self {
|
||||
Self::Transparent
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BGColor {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Custom(c) => {
|
||||
write!(f, "{}", c)
|
||||
}
|
||||
_ => {
|
||||
write!(f, "{}", self.to_string().to_lowercase())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_config() -> Config {
|
||||
if let Some(d) = config_dir() {
|
||||
use std::fs;
|
||||
let path = d.join("cathode");
|
||||
if !path.exists() {
|
||||
if let Err(e) = fs::create_dir_all(&path) {
|
||||
debug!("{:?}", e);
|
||||
error!("Failed to create config directory");
|
||||
error!("{}", e);
|
||||
} else {
|
||||
debug!("Created config dir at {}", path.display())
|
||||
}
|
||||
Config::default()
|
||||
} else {
|
||||
let raw = fs::read_to_string(path.join("config.toml")).unwrap_or_else(|f| {
|
||||
error!("Failed to load config file: {}", f);
|
||||
String::new()
|
||||
});
|
||||
toml::from_str::<Config>(&raw).unwrap_or_default()
|
||||
}
|
||||
} else {
|
||||
Config::default()
|
||||
}
|
||||
}
|
|
@ -4,18 +4,24 @@
|
|||
)]
|
||||
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
path::Path,
|
||||
sync::{Arc, Mutex},
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use audio::monitor;
|
||||
use log::{debug, trace, warn};
|
||||
use log::{debug, error, trace, warn};
|
||||
use serde_json::Value;
|
||||
use tauri::{api::path::cache_dir, Manager, State};
|
||||
use tauri::{
|
||||
api::path::{cache_dir, config_dir},
|
||||
Manager, State,
|
||||
};
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
mod audio;
|
||||
mod config;
|
||||
mod fs;
|
||||
|
||||
const MIC_THRESHOLD: f32 = 0.5f32;
|
||||
|
@ -23,6 +29,7 @@ const MIC_THRESHOLD: f32 = 0.5f32;
|
|||
struct MicThreshold(Arc<Mutex<f32>>);
|
||||
struct AudioLevel(Arc<Mutex<f32>>);
|
||||
struct BlinkInterval(Arc<Mutex<u64>>);
|
||||
struct CurrentConfig(Arc<Mutex<Config>>);
|
||||
|
||||
// struct LastImage(Option<Arc<Path>>);
|
||||
// struct LastRay(Arc<Mutex<Path>>);
|
||||
|
@ -42,10 +49,17 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
// Create the config directory if needed
|
||||
let config = config::load_config();
|
||||
|
||||
let current_conf = Arc::new(Mutex::new(config));
|
||||
|
||||
let config = current_conf.clone();
|
||||
tauri::Builder::default()
|
||||
.manage(MicThreshold(threshold.clone()))
|
||||
.manage(AudioLevel(level.clone()))
|
||||
.manage(BlinkInterval(blink_interval.clone()))
|
||||
.manage(CurrentConfig(current_conf.clone()))
|
||||
.setup(|app| {
|
||||
let window = app.get_window("main").unwrap();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
|
@ -66,6 +80,34 @@ fn main() {
|
|||
}
|
||||
});
|
||||
|
||||
let window = app.get_window("main").unwrap();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
use notify::{event::AccessKind, Event, EventKind, RecursiveMode, Result, Watcher};
|
||||
if let Some(path) = config_dir() {
|
||||
// let window = app.get_window("main").unwrap();
|
||||
let mut watcher =
|
||||
notify::recommended_watcher(move |res: Result<Event>| match res {
|
||||
Ok(event) => {
|
||||
if let EventKind::Access(AccessKind::Close(_)) = event.kind {
|
||||
*config.lock().unwrap() = config::load_config();
|
||||
window.emit("reload-config", "").unwrap();
|
||||
}
|
||||
}
|
||||
Err(e) => error!("error watching filesystem {:?}", e),
|
||||
})
|
||||
.unwrap();
|
||||
watcher
|
||||
.watch(
|
||||
&path.join("cathode").join("config.toml"),
|
||||
RecursiveMode::NonRecursive,
|
||||
)
|
||||
.unwrap();
|
||||
loop {
|
||||
sleep(Duration::from_millis(5000));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Ok(matches) = app.get_cli_matches() {
|
||||
if let Some(arg) = matches.args.get("file") {
|
||||
if let Value::String(path) = arg.value.clone() {
|
||||
|
@ -96,6 +138,7 @@ fn main() {
|
|||
set_mic_threshold,
|
||||
get_mic_threshold,
|
||||
get_audio_level,
|
||||
get_config,
|
||||
fs::open_image,
|
||||
fs::save_ray,
|
||||
fs::open_ray,
|
||||
|
@ -123,3 +166,8 @@ fn get_mic_threshold(current: State<'_, MicThreshold>) -> f32 {
|
|||
fn get_audio_level(level: State<'_, AudioLevel>) -> f32 {
|
||||
*level.0.lock().unwrap()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_config(current: State<'_, CurrentConfig>) -> Config {
|
||||
current.0.lock().unwrap().clone()
|
||||
}
|
||||
|
|
|
@ -1,25 +1,44 @@
|
|||
<script lang="ts">
|
||||
import MainView from "./views/main.svelte";
|
||||
|
||||
//TODO: load config
|
||||
<script lang="ts" context="module">
|
||||
type Config = {
|
||||
background_color: "transparent" | "blue" | "green" | "pink" | {custom: string};
|
||||
}
|
||||
</script>
|
||||
|
||||
<main style:background-color="lightblue">
|
||||
<MainView />
|
||||
<script lang="ts">
|
||||
import MainView from "./views/main.svelte";
|
||||
import {appWindow} from "@tauri-apps/api/window";
|
||||
import {invoke} from "@tauri-apps/api";
|
||||
import {onMount} from "svelte";
|
||||
|
||||
let config: Config = {background_color: "transparent"};
|
||||
$: transparent = config.background_color == "transparent";
|
||||
$: color = typeof config.background_color == "object" ? config.background_color.custom : config.background_color;
|
||||
|
||||
|
||||
|
||||
onMount(async () => {
|
||||
config = await invoke("get_config") as Config;
|
||||
await appWindow.listen("reload-config", async () => {
|
||||
config = await invoke("get_config") as Config;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<MainView --active-color={transparent ? 'lightblue' : color} --inactive-color={color}/>
|
||||
</main>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
:global(*) {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
:global(body) {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
:global(body) {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
}}
|
||||
class="buttons"
|
||||
>
|
||||
<div on:click={saveRay}><span>Save</span></div>
|
||||
<div on:click={saveRay}>Save</div>
|
||||
<div on:click={loadRay}>Load</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -174,10 +174,6 @@
|
|||
<svelte:body on:contextmenu|preventDefault />
|
||||
|
||||
<style lang="scss">
|
||||
div {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: absolute;
|
||||
top: 2vh;
|
||||
|
@ -222,23 +218,23 @@
|
|||
|
||||
@keyframes fade-out {
|
||||
0% {
|
||||
background-color: inherit;
|
||||
background-color: var(--active-color);
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
background-color: var(--inactive-color);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
background-color: transparent;
|
||||
background-color: var(--inactive-color);
|
||||
}
|
||||
100% {
|
||||
background-color: inherit;
|
||||
background-color: var(--active-color);
|
||||
}
|
||||
}
|
||||
.container {
|
||||
background-color: inherit;
|
||||
background-color: var(--active-color);
|
||||
animation-name: fade-in;
|
||||
animation-duration: 0.2s;
|
||||
}
|
||||
|
@ -246,6 +242,6 @@
|
|||
.container.transparent {
|
||||
animation-name: fade-out;
|
||||
animation-duration: 0.2s;
|
||||
background-color: transparent;
|
||||
background-color: var(--inactive-color);
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue