Platform specific cfgs and including all the questions in the build as to allow for mobile

master
Wynd 2025-06-16 02:22:25 +03:00
parent 41d1ac5389
commit 59fba4a13c
5 changed files with 87 additions and 46 deletions

2
.gitignore vendored
View File

@ -6,4 +6,4 @@
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
questions*.toml /questions

20
Cargo.lock generated
View File

@ -1405,6 +1405,7 @@ name = "flashcards"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dioxus", "dioxus",
"include_dir",
"rand 0.9.1", "rand 0.9.1",
"serde", "serde",
"tokio", "tokio",
@ -2207,6 +2208,25 @@ dependencies = [
"icu_properties", "icu_properties",
] ]
[[package]]
name = "include_dir"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd"
dependencies = [
"include_dir_macros",
]
[[package]]
name = "include_dir_macros"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
dependencies = [
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.3" version = "1.9.3"

View File

@ -7,11 +7,12 @@ edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dioxus = { version = "0.6.3", features = [] } dioxus = { version = "0.6", features = [] }
toml = { version = "0.8" } toml = { version = "0.8" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
rand = { version = "0.9" } rand = { version = "0.9" }
tokio = { version = "1.45" } tokio = { version = "1.45" }
include_dir = { version = "0.7" }
[features] [features]
default = ["desktop"] default = ["desktop"]

View File

@ -1,15 +1,17 @@
use std::{env, sync::OnceLock, time::Duration}; use std::{sync::OnceLock, time::Duration};
use dioxus::{ #[cfg(feature = "desktop")]
desktop::{Config, LogicalSize, WindowBuilder}, use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
prelude::*, use dioxus::prelude::*;
}; use include_dir::{Dir, include_dir};
use models::{Question, Questions}; use models::{Question, Questions};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
#[cfg(feature = "desktop")]
use std::env;
mod models; mod models;
const DEFAULT_FILE: &str = "questions.toml"; const QUESTIONS_DIR: Dir = include_dir!("./questions");
const MAIN_CSS: Asset = asset!("/assets/main.css"); const MAIN_CSS: Asset = asset!("/assets/main.css");
pub static QUESTIONS: OnceLock<Questions> = OnceLock::new(); pub static QUESTIONS: OnceLock<Questions> = OnceLock::new();
@ -17,30 +19,36 @@ pub static QUESTIONS: OnceLock<Questions> = OnceLock::new();
fn get_questions() -> Questions { fn get_questions() -> Questions {
QUESTIONS QUESTIONS
.get_or_init(|| { .get_or_init(|| {
let args: Vec<String> = env::args().collect(); let mut questions = Questions::default();
let file_name = args.get(1).map(|x| x.as_str()).unwrap_or(DEFAULT_FILE);
let questions_str = std::fs::read_to_string(file_name) for entry in QUESTIONS_DIR.files() {
.unwrap_or_else(|_| panic!("Could not read from file {file_name}")); if let Some(content) = entry.contents_utf8() {
let mut questions: Questions = if let Ok(other_questions) = toml::from_str(content) {
toml::from_str(&questions_str).expect("Could not decode the given file as TOML"); questions += other_questions;
}
}
}
if args.len() > 2 { #[cfg(feature = "desktop")]
for i in 2..args.len() { {
let file_name = args.get(i).map(|x| x.as_str()); let args: Vec<String> = env::args().collect();
let Some(file_name) = file_name else { if args.len() > 1 {
continue; for i in 1..args.len() {
}; let file_name = args.get(i).map(|x| x.as_str());
let Some(file_name) = file_name else {
continue;
};
let Ok(questions_str) = std::fs::read_to_string(file_name) else { let Ok(questions_str) = std::fs::read_to_string(file_name) else {
continue; continue;
}; };
let Ok(other_questions) = toml::from_str(&questions_str) else { let Ok(other_questions) = toml::from_str(&questions_str) else {
continue; continue;
}; };
questions += other_questions; questions += other_questions;
}
} }
} }
@ -65,29 +73,41 @@ fn get_rand_questions() -> Vec<Question> {
} }
fn main() { fn main() {
dioxus::LaunchBuilder::new() #[cfg(feature = "desktop")]
.with_cfg( {
Config::default().with_menu(None).with_window( dioxus::LaunchBuilder::new()
WindowBuilder::new() .with_cfg(
.with_min_inner_size(LogicalSize::new(640, 540)) Config::default().with_menu(None).with_window(
.with_maximized(true) WindowBuilder::new()
.with_title("Flashcards"), .with_min_inner_size(LogicalSize::new(640, 540))
), .with_maximized(true)
) .with_title("Flashcards"),
.launch(App) ),
} )
.launch(App)
}
#[component] #[cfg(feature = "mobile")]
fn App() -> Element { {
rsx! { dioxus::launch(App);
document::Link { rel: "stylesheet", href: MAIN_CSS }
QuestionForm {}
} }
} }
#[component] #[component]
pub fn QuestionForm() -> Element { fn App() -> Element {
let mut questions = use_signal(get_rand_questions); let questions = get_rand_questions();
rsx! {
document::Link { rel: "stylesheet", href: MAIN_CSS }
if !questions.is_empty() {
QuestionForm { questions }
}
}
}
#[component]
pub fn QuestionForm(questions: Vec<Question>) -> Element {
let mut questions = use_signal(|| questions);
let mut current = use_signal(move || questions.remove(0)); let mut current = use_signal(move || questions.remove(0));
let total_correct = use_memo(move || { let total_correct = use_memo(move || {

View File

@ -2,7 +2,7 @@ use std::ops::{AddAssign, Deref, DerefMut};
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Default, Clone, Deserialize)]
pub struct Questions { pub struct Questions {
pub questions: Vec<Question>, pub questions: Vec<Question>,
} }