Setup base eframe application + serialization + arg parsing and configuration
This commit is contained in:
+59
@@ -0,0 +1,59 @@
|
||||
use std::time::Duration;
|
||||
use eframe::{egui, Frame, Storage, CreationContext};
|
||||
use eframe::egui::{Context, Ui};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Application {
|
||||
settings: AppSettings,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
struct AppSettings {
|
||||
serialization_test_string: String,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
pub fn new(cc: &CreationContext) -> Self {
|
||||
let mut settings = AppSettings::default();
|
||||
if let Some(storage) = cc.storage {
|
||||
if let Some(stored_str) = storage.get_string("app_settings") {
|
||||
if let Ok(parsed) = serde_json::from_str(&stored_str) {
|
||||
settings = parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { settings }
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for Application {
|
||||
|
||||
fn logic(&mut self, ctx: &Context, frame: &mut Frame) {
|
||||
|
||||
}
|
||||
|
||||
fn ui(&mut self, ui: &mut Ui, frame: &mut Frame) {
|
||||
egui::CentralPanel::default().show(ui, |ui| {
|
||||
ui.heading("Hello!");
|
||||
ui.text_edit_singleline(&mut self.settings.serialization_test_string);
|
||||
});
|
||||
}
|
||||
|
||||
fn save(&mut self, _storage: &mut dyn Storage) {
|
||||
if let Ok(serialized) = serde_json::to_string(&self.settings) {
|
||||
_storage.set_string("app_settings", serialized);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_exit(&mut self) {
|
||||
|
||||
}
|
||||
|
||||
fn auto_save_interval(&self) -> Duration {
|
||||
Duration::from_secs(5)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
use clap::Parser;
|
||||
use crate::{args};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub(crate) struct Args {
|
||||
/// Override the state file location
|
||||
pub(crate) state: Option<String>,
|
||||
/// Override the default data dir
|
||||
#[clap(short, long)]
|
||||
pub(crate) data_dir: Option<String>,
|
||||
/// Enable verbose logging
|
||||
#[clap(short, long)]
|
||||
pub(crate) verbose: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArgsConfig {
|
||||
pub(crate) state: String,
|
||||
pub(crate) data_dir: String,
|
||||
pub(crate) verbose: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_args() -> ArgsConfig {
|
||||
let args = args::Args::parse();
|
||||
let mut args_config = args::ArgsConfig {
|
||||
state: "".to_string(),
|
||||
data_dir: "".to_string(),
|
||||
verbose: false,
|
||||
};
|
||||
|
||||
if args.data_dir.is_none() {
|
||||
let data_dir = dirs::data_dir().unwrap_or_else(|| "./".into());
|
||||
args_config.data_dir = format!("{}/yt-offline", data_dir.into_string().expect("Failed to convert data directory into string"));
|
||||
}
|
||||
// TODO: add a check in case the passed in data dir as a / at the end
|
||||
|
||||
if args.state.is_some() {
|
||||
args_config.state = format!("{}/{}", args_config.data_dir, args.state.expect("Failed to unwrap config arg"));
|
||||
} else {
|
||||
args_config.state = format!("{}/state.json", args_config.data_dir);
|
||||
}
|
||||
args_config
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
use tracing::log::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing::debug;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn init(is_verbose: bool) {
|
||||
let lvl_filter;
|
||||
let directive;
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
lvl_filter = LevelFilter::Info;
|
||||
directive = "yt_offline=DEBUG";
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
if is_verbose{
|
||||
lvl_filter = LevelFilter::Info;
|
||||
directive = "yt_offline=INFO";
|
||||
} else {
|
||||
lvl_filter = LevelFilter::Warn;
|
||||
directive = "yt_offline=WARN";
|
||||
}
|
||||
}
|
||||
|
||||
let filter = EnvFilter::builder()
|
||||
.with_default_directive(lvl_filter.as_str().parse().expect("Failed to parse lvl_filter into directive"))
|
||||
.from_env().expect("Failed to parse env filter")
|
||||
.add_directive(directive.parse().expect("Failed to parse directive"));
|
||||
tracing_subscriber::fmt().with_env_filter(filter).compact().init();
|
||||
debug!("Successfully setup tracing subscriber.");
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use tracing::{debug, error};
|
||||
mod logging;
|
||||
mod args;
|
||||
mod app;
|
||||
|
||||
fn main() {
|
||||
let args = args::parse_args();
|
||||
logging::init(args.verbose);
|
||||
debug!("Using args: \n{:#?}\n", args);
|
||||
let data_dir_path = PathBuf::from(&args.data_dir);
|
||||
if data_dir_path.is_file() {
|
||||
error!("data_dir is a file... If you have set the data_dir manually, please pass in a directory. If you didn't pass in a path at all, please report this.");
|
||||
error!("{:#?}", args);
|
||||
exit(1);
|
||||
}
|
||||
if !data_dir_path.exists() {
|
||||
if let Err(e) = fs::create_dir(data_dir_path.as_path()) {
|
||||
error!("Failed to create data_dir path with fs error: {}", e);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
let mut options = eframe::NativeOptions::default();
|
||||
options.persistence_path = Some(args.state.parse().expect("Failed to parse state config file path into path"));
|
||||
eframe::run_native(
|
||||
"yt-offline",
|
||||
options,
|
||||
Box::new(|cc| {
|
||||
Ok(Box::new(app::Application::new(cc)))
|
||||
})).expect("TODO: panic message");
|
||||
}
|
||||
Reference in New Issue
Block a user