using System; #if __UNIFIED__ using Foundation; #else using MonoTouch.Foundation; #endif using Plugin.Settings.Abstractions; namespace Bit.iOS.Core.Services { /// /// Main implementation for ISettings /// public class Settings : ISettings { private readonly object locker = new object(); private readonly NSUserDefaults _defaults; public Settings(string defaultsName) { _defaults = string.IsNullOrWhiteSpace(defaultsName) ? NSUserDefaults.StandardUserDefaults : new NSUserDefaults(defaultsName, NSUserDefaultsType.SuiteName); } /// /// Gets the current value or the default that you specify. /// /// Vaue of t (bool, int, float, long, string) /// Key for settings /// default value if not set /// Value or default public T GetValueOrDefault(string key, T defaultValue = default(T)) { lock(locker) { var defaults = _defaults; if(defaults.ValueForKey(new NSString(key)) == null) return defaultValue; Type typeOf = typeof(T); if(typeOf.IsGenericType && typeOf.GetGenericTypeDefinition() == typeof(Nullable<>)) { typeOf = Nullable.GetUnderlyingType(typeOf); } object value = null; var typeCode = Type.GetTypeCode(typeOf); switch(typeCode) { case TypeCode.Decimal: var savedDecimal = defaults.StringForKey(key); value = Convert.ToDecimal(savedDecimal, System.Globalization.CultureInfo.InvariantCulture); break; case TypeCode.Boolean: value = defaults.BoolForKey(key); break; case TypeCode.Int64: var savedInt64 = defaults.StringForKey(key); value = Convert.ToInt64(savedInt64, System.Globalization.CultureInfo.InvariantCulture); break; case TypeCode.Double: value = defaults.DoubleForKey(key); break; case TypeCode.String: value = defaults.StringForKey(key); break; case TypeCode.Int32: #if __UNIFIED__ value = (Int32)defaults.IntForKey(key); #else value = defaults.IntForKey(key); #endif break; case TypeCode.Single: #if __UNIFIED__ value = (float)defaults.FloatForKey(key); #else value = defaults.FloatForKey(key); #endif break; case TypeCode.DateTime: var savedTime = defaults.StringForKey(key); if(string.IsNullOrWhiteSpace(savedTime)) { value = defaultValue; } else { var ticks = Convert.ToInt64(savedTime, System.Globalization.CultureInfo.InvariantCulture); if(ticks >= 0) { //Old value, stored before update to UTC values value = new DateTime(ticks); } else { //New value, UTC value = new DateTime(-ticks, DateTimeKind.Utc); } } break; default: if(defaultValue is Guid) { var outGuid = Guid.Empty; var savedGuid = defaults.StringForKey(key); if(string.IsNullOrWhiteSpace(savedGuid)) { value = outGuid; } else { Guid.TryParse(savedGuid, out outGuid); value = outGuid; } } else { throw new ArgumentException(string.Format("Value of type {0} is not supported.", value.GetType().Name)); } break; } return null != value ? (T)value : defaultValue; } } /// /// Adds or updates a value /// /// key to update /// value to set /// True if added or update and you need to save public bool AddOrUpdateValue(string key, T value) { Type typeOf = typeof(T); if(typeOf.IsGenericType && typeOf.GetGenericTypeDefinition() == typeof(Nullable<>)) { typeOf = Nullable.GetUnderlyingType(typeOf); } var typeCode = Type.GetTypeCode(typeOf); return AddOrUpdateValue(key, value, typeCode); } private bool AddOrUpdateValue(string key, object value, TypeCode typeCode) { lock(locker) { var defaults = _defaults; switch(typeCode) { case TypeCode.Decimal: defaults.SetString(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture), key); break; case TypeCode.Boolean: defaults.SetBool(Convert.ToBoolean(value), key); break; case TypeCode.Int64: defaults.SetString(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture), key); break; case TypeCode.Double: defaults.SetDouble(Convert.ToDouble(value, System.Globalization.CultureInfo.InvariantCulture), key); break; case TypeCode.String: defaults.SetString(Convert.ToString(value), key); break; case TypeCode.Int32: defaults.SetInt(Convert.ToInt32(value, System.Globalization.CultureInfo.InvariantCulture), key); break; case TypeCode.Single: defaults.SetFloat(Convert.ToSingle(value, System.Globalization.CultureInfo.InvariantCulture), key); break; case TypeCode.DateTime: defaults.SetString(Convert.ToString(-(Convert.ToDateTime(value)).ToUniversalTime().Ticks), key); break; default: if(value is Guid) { if(value == null) value = Guid.Empty; defaults.SetString(((Guid)value).ToString(), key); } else { throw new ArgumentException(string.Format("Value of type {0} is not supported.", value.GetType().Name)); } break; } try { defaults.Synchronize(); } catch(Exception ex) { Console.WriteLine("Unable to save: " + key, " Message: " + ex.Message); } } return true; } /// /// Removes a desired key from the settings /// /// Key for setting public void Remove(string key) { lock(locker) { var defaults = _defaults; try { var nsString = new NSString(key); if(defaults.ValueForKey(nsString) != null) { defaults.RemoveObject(key); defaults.Synchronize(); } } catch(Exception ex) { Console.WriteLine("Unable to remove: " + key, " Message: " + ex.Message); } } } /// /// Clear all keys from settings /// public void Clear() { lock(locker) { var defaults = _defaults; try { defaults.RemovePersistentDomain(NSBundle.MainBundle.BundleIdentifier); defaults.Synchronize(); } catch(Exception ex) { Console.WriteLine("Unable to clear all defaults. Message: " + ex.Message); } } } /// /// Checks to see if the key has been added. /// /// Key to check /// True if contains key, else false public bool Contains(string key) { lock(locker) { var defaults = _defaults; try { var nsString = new NSString(key); var setting = defaults.ValueForKey(nsString); return setting != null; } catch(Exception ex) { Console.WriteLine("Unable to clear all defaults. Message: " + ex.Message); } return false; } } } }