diff --git a/src/defaults/mod.rs b/src/defaults/mod.rs index 34b1d6c..3bab370 100644 --- a/src/defaults/mod.rs +++ b/src/defaults/mod.rs @@ -38,7 +38,7 @@ use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::Id; -use crate::foundation::{id, nil, YES, BOOL, NSData, NSInteger, NSString, NSDictionary, NSNumber}; +use crate::foundation::{id, nil, YES, NO, BOOL, NSData, NSString, NSDictionary, NSNumber}; mod value; pub use value::Value; @@ -213,4 +213,49 @@ impl UserDefaults { None } + + /// Returns a boolean value if the object stored for the specified key is managed by an + /// administrator. This is rarely used - mostly in managed environments, e.g a classroom. + /// + /// For managed keys, the application should disable any user interface that allows the + /// user to modify the value of key. + /// + /// ```rust + /// use cacao::defaults::{UserDefaults, Value}; + /// + /// let mut defaults = UserDefaults::standard(); + /// defaults.insert("test", Value::string("value")); + /// + /// let value = defaults.is_forced_for_key("test"); + /// assert_eq!(value, false); + /// ``` + pub fn is_forced_for_key>(&self, key: K) -> bool { + let result: BOOL = unsafe { + let key = NSString::new(key.as_ref()); + msg_send![&*self.0, objectIsForcedForKey:key.into_inner()] + }; + + match result { + YES => true, + NO => false, + _ => unreachable!() + } + } + + /// Blocks for any asynchronous updates to the defaults database and returns. + /// + /// This method is legacy, likely unnecessary and shouldn't be used unless you know exactly why + /// you need it... and even then, you should double check it. + /// ```rust + /// use cacao::defaults::{UserDefaults, Value}; + /// + /// let mut defaults = UserDefaults::standard(); + /// defaults.insert("test", Value::string("value")); + /// defaults.synchronize(); + /// ``` + pub fn synchronize(&self) { + unsafe { + let _: () = msg_send![&*self.0, synchronize]; + } + } } diff --git a/src/defaults/value.rs b/src/defaults/value.rs index d53df96..6ee0f4b 100644 --- a/src/defaults/value.rs +++ b/src/defaults/value.rs @@ -1,9 +1,6 @@ use std::collections::HashMap; -use objc::{class, msg_send, sel, sel_impl}; -use objc_id::Id; - -use crate::foundation::{id, YES, NO, NSData, NSInteger, NSDictionary, NSString}; +use crate::foundation::{id, NSData, NSDictionary, NSString, NSNumber}; /// Represents a Value that can be stored or queried with `UserDefaults`. /// @@ -138,18 +135,12 @@ impl From for id { // These currently work, but may not be exhaustive and should be looked over past the preview // period. fn from(value: Value) -> Self { - unsafe { - match value { - Value::Bool(b) => msg_send![class!(NSNumber), numberWithBool:match b { - true => YES, - false => NO - }], - - Value::String(s) => NSString::new(&s).into_inner(), - Value::Float(f) => msg_send![class!(NSNumber), numberWithDouble:f], - Value::Integer(i) => msg_send![class!(NSNumber), numberWithInteger:i as NSInteger], - Value::Data(data) => NSData::new(data).into_inner() - } + match value { + Value::Bool(b) => NSNumber::bool(b).into_inner(), + Value::String(s) => NSString::new(&s).into_inner(), + Value::Float(f) => NSNumber::float(f).into_inner(), + Value::Integer(i) => NSNumber::integer(i).into_inner(), + Value::Data(data) => NSData::new(data).into_inner() } } } @@ -160,16 +151,13 @@ where { /// Translates a `HashMap` of `Value`s into an `NSDictionary`. fn from(map: HashMap) -> Self { - NSDictionary(unsafe { - let dictionary: id = msg_send![class!(NSMutableDictionary), new]; + let mut dictionary = NSDictionary::new(); - for (key, value) in map.into_iter() { - let k = NSString::new(key.as_ref()); - let v: id = value.into(); - let _: () = msg_send![dictionary, setObject:v forKey:k]; - } + for (key, value) in map.into_iter() { + let k = NSString::new(key.as_ref()); + dictionary.insert(k, value.into()); + } - Id::from_ptr(dictionary) - }) + dictionary } } diff --git a/src/foundation/array.rs b/src/foundation/array.rs index d1e8010..0583c37 100644 --- a/src/foundation/array.rs +++ b/src/foundation/array.rs @@ -1,4 +1,6 @@ -//! A wrapper type for `NSArray`. This is abstracted out as we need to use `NSArray` in a ton of +//! A wrapper type for `NSArray`. +//! +//! This is abstracted out as we need to use `NSArray` in a ton of //! instances in this framework, and down the road I'd like to investigate using `CFArray` instead //! of `NSArray` (i.e, if the ObjC runtime is ever pulled or something - perhaps those types would //! stick around). diff --git a/src/foundation/dictionary.rs b/src/foundation/dictionary.rs index bf6b9b2..6ad3b4a 100644 --- a/src/foundation/dictionary.rs +++ b/src/foundation/dictionary.rs @@ -5,7 +5,7 @@ use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::Id; -use crate::foundation::id; +use crate::foundation::{id, NSString}; /// A wrapper for `NSDictionary`. Behind the scenes we actually wrap `NSMutableDictionary`, and /// rely on Rust doing the usual borrow-checking guards that it does so well. @@ -25,6 +25,12 @@ impl NSDictionary { }) } + pub fn insert(&mut self, key: NSString, object: id) { + unsafe { + let _: () = msg_send![&*self.0, setObject:object forKey:key.into_inner()]; + } + } + pub fn into_inner(mut self) -> id { &mut *self.0 } diff --git a/src/foundation/number.rs b/src/foundation/number.rs index e44ec45..7420b88 100644 --- a/src/foundation/number.rs +++ b/src/foundation/number.rs @@ -21,8 +21,7 @@ impl NSNumber { NSNumber(unsafe { Id::from_ptr(msg_send![class!(NSNumber), numberWithBool:match value { true => YES, - false => NO, - _ => unreachable!() + false => NO }]) }) } diff --git a/src/lib.rs b/src/lib.rs index 2956e15..269d6bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,6 @@ pub use url; #[cfg(feature = "macos")] pub mod macos; -pub mod alert; pub mod button; #[cfg(feature = "cloudkit")] diff --git a/src/alert.rs b/src/macos/alert.rs similarity index 60% rename from src/alert.rs rename to src/macos/alert.rs index 825562f..f481a37 100644 --- a/src/alert.rs +++ b/src/macos/alert.rs @@ -1,5 +1,28 @@ -//! A wrapper for `NSAlert`. Currently doesn't cover everything possible for this class, as it was -//! built primarily for debugging uses. Feel free to extend via pull requests or something. +//! A wrapper for `NSAlert`. +//! +//! This is housed inside `macos` as it's a useful tool for a few cases, but it doesn't match the +//! iOS API, so we make no guarantees about it being a universal control. In general this also +//! doesn't produce an amazing user experience, and you may want to shy away from using it. +//! +//! If you want to show a complex view in an alert-esque fashion, you may consider looking at +//! `Sheet`. +//! +//! ```rust +//! use cacao::macos::{App, AppDelegate, Alert}; +//! +//! #[derive(Default)] +//! struct ExampleApp; +//! +//! impl AppDelegate { +//! fn did_finish_launching(&self) { +//! +//! } +//! } +//! +//! fn main() { +//! App::new("com.alert.example", ExampleApp::default()).run() +//! } +//! ``` use objc_id::Id; use objc::runtime::Object; diff --git a/src/macos/mod.rs b/src/macos/mod.rs index 2f0415d..c715a0a 100644 --- a/src/macos/mod.rs +++ b/src/macos/mod.rs @@ -15,7 +15,12 @@ //! of your app as a cross platform codebase, with the initial 10% being scaffolding code for the //! platform (e.g, NSApplication vs UIApplication lifecycle). -pub mod app; +mod alert; +pub use alert::Alert; + +mod app; +pub use app::*; + pub mod menu; pub mod printing; pub mod toolbar;