use std::collections::HashMap; use cacao::defaults::{UserDefaults, Value}; use objc::runtime::Object; const EXAMPLE: &str = "exampleSetting"; /// A very basic wrapper around UserDefaults. If I wind up implementing Serde support for /// UserDefaults, then much of this could be removed or simplified - but I'm not sold on that yet, /// so this exists for now. #[derive(Debug)] pub struct Defaults; impl Defaults { /// Registers the default settings for our application. Note that just because this is run at /// application start does _not_ mean it's always the defaults; this is effectively "on first /// run, set these defaults". Updates will persist and overwrite these accordingly. pub fn register() { let mut defaults = UserDefaults::standard(); defaults.register({ let mut map = HashMap::new(); map.insert(EXAMPLE, Value::Bool(true)); map }); } /// Toggles the example setting. pub fn toggle_should_whatever(_object: *const Object) { toggle_bool(EXAMPLE); } /// Returns whether the example setting is currently true or false. pub fn should_whatever() -> bool { load_bool(EXAMPLE) } } /// A helper method for toggling a boolean value held at the specified key. If the value cannot /// be pulled as a bool, then this panics. /// /// Note that choosing to panic here is a personal design decision; this is core functionality that /// should work, and I'd rather it crash with a meaningful message rather than `unwrap()` issues. fn toggle_bool(key: &str) { let mut defaults = UserDefaults::standard(); if let Some(value) = defaults.get(key) { if let Some(value) = value.as_bool() { defaults.insert(key, Value::Bool(!value)); return; } panic!("Attempting to toggle a boolean value for {}, but it's not a boolean.", key); } panic!( "Attempting to toggle a boolean value for {}, but this key does not exist.", key ); } /// A helper method for loading a boolean value held at the specified key. If the value cannot /// be pulled as a bool, then this panics. /// /// Note that choosing to panic here is a personal design decision; this is core functionality that /// should work, and I'd rather it crash with a meaningful message rather than `unwrap()` issues. fn load_bool(key: &str) -> bool { let defaults = UserDefaults::standard(); if let Some(value) = defaults.get(key) { if let Some(value) = value.as_bool() { return value; } panic!("Attempting to load a boolean value for {}, but it's not a boolean.", key); } panic!("Attempting to load a boolean value for {}, but this key does not exist.", key); }