Shared groundwork: - paths.rs: folders for data, settings and downloads per system (Linux XDG unchanged, Windows %APPDATA%/%LOCALAPPDATA%, Android app folder) - Linux-only parts behind cfg: Wayland on-screen keyboard (osk/wayland.rs), display backend and app id, the vendored winit touch extensions - run_with(event_loop) so that other entry points can start the app Windows (#48): - cross-compiled with MinGW into a portable ink-notes_<version>_x86_64.exe (system DLLs only), no console window in release builds - file picker: user folders and drives; held notebook locks are detected (ERROR_LOCK_VIOLATION) - updater: replaces the running .exe via rename, active at the next start - octotablet panicking without the Tablet PC components no longer crashes the app - release: .exe built in CI and part of the signed checksums - all library tests pass under wine Android (#42): - android_main entry point, winit with android-native-activity, android_logger; octotablet and arboard left out there - cargo check and the cdylib build for aarch64-linux-android pass; the window surface does not follow the activity lifecycle yet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.3 KiB
Rust
75 lines
2.3 KiB
Rust
//! Folders for notebooks, settings and downloads on each platform (Issues #42, #48).
|
|
//!
|
|
//! - Linux: XDG (`~/.local/share/ink-notes`, `~/.config/ink-notes`, `~/.cache/ink-notes`)
|
|
//! - Windows: `%APPDATA%\ink-notes` for data and settings, `%LOCALAPPDATA%\ink-notes` for
|
|
//! downloads
|
|
//! - Android: the app's internal folder, set once at startup with [`set_app_dir`]
|
|
//!
|
|
//! The environment is read on every call, so tests can point the folders elsewhere.
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::OnceLock;
|
|
|
|
/// Fixed app folder (Android: internal storage of the app)
|
|
static APP_DIR: OnceLock<PathBuf> = OnceLock::new();
|
|
|
|
/// Puts data, settings and downloads below `dir` (Android, where there is no XDG or home).
|
|
pub fn set_app_dir(dir: PathBuf) {
|
|
let _ = APP_DIR.set(dir);
|
|
}
|
|
|
|
/// Value of an environment variable, unless empty.
|
|
fn env_dir(key: &str) -> Option<PathBuf> {
|
|
std::env::var_os(key)
|
|
.filter(|v| !v.to_string_lossy().trim().is_empty())
|
|
.map(PathBuf::from)
|
|
}
|
|
|
|
/// Home folder of the user.
|
|
pub fn home_dir() -> Option<PathBuf> {
|
|
if cfg!(windows) {
|
|
env_dir("USERPROFILE").or_else(|| env_dir("HOME"))
|
|
} else {
|
|
env_dir("HOME")
|
|
}
|
|
}
|
|
|
|
/// Folder for notebooks and emergency backups.
|
|
pub fn data_dir() -> Option<PathBuf> {
|
|
if let Some(dir) = APP_DIR.get() {
|
|
return Some(dir.clone());
|
|
}
|
|
if cfg!(windows) {
|
|
return env_dir("APPDATA").map(|d| d.join("ink-notes"));
|
|
}
|
|
env_dir("XDG_DATA_HOME")
|
|
.or_else(|| home_dir().map(|h| h.join(".local").join("share")))
|
|
.map(|d| d.join("ink-notes"))
|
|
}
|
|
|
|
/// Folder for the settings (`ui.json`).
|
|
pub fn config_dir() -> Option<PathBuf> {
|
|
if let Some(dir) = APP_DIR.get() {
|
|
return Some(dir.join("config"));
|
|
}
|
|
if cfg!(windows) {
|
|
return env_dir("APPDATA").map(|d| d.join("ink-notes"));
|
|
}
|
|
env_dir("XDG_CONFIG_HOME")
|
|
.or_else(|| home_dir().map(|h| h.join(".config")))
|
|
.map(|d| d.join("ink-notes"))
|
|
}
|
|
|
|
/// Folder for downloaded updates.
|
|
pub fn cache_dir() -> Option<PathBuf> {
|
|
if let Some(dir) = APP_DIR.get() {
|
|
return Some(dir.join("cache"));
|
|
}
|
|
if cfg!(windows) {
|
|
return env_dir("LOCALAPPDATA").map(|d| d.join("ink-notes"));
|
|
}
|
|
env_dir("XDG_CACHE_HOME")
|
|
.or_else(|| home_dir().map(|h| h.join(".cache")))
|
|
.map(|d| d.join("ink-notes"))
|
|
}
|