diff --git a/launchers/macosx/I2PLauncher/Utils/Preferences.swift b/launchers/macosx/I2PLauncher/Utils/Preferences.swift
new file mode 100644
index 0000000000000000000000000000000000000000..1cff8b2e0535776185a5b1d1c87b3b03984fda51
--- /dev/null
+++ b/launchers/macosx/I2PLauncher/Utils/Preferences.swift
@@ -0,0 +1,285 @@
+//
+//  Preferences.swift
+//  I2PLauncher
+//
+//  Created by Mikal Villa on 01/12/2018.
+//  Copyright © 2018 The I2P Project. All rights reserved.
+//
+
+import Foundation
+
+class PreferenceRow {
+  var name: String?
+  var defaultValue: Any?
+  var selectedValue: Any?
+  
+  init(_ name: String, _ value: Any?, _ defaultVal: Any? = "") {
+    self.name = name
+    self.selectedValue = value
+    self.defaultValue = defaultVal
+  }
+  
+  func asRawValue() -> Any {
+    return self.selectedValue ?? self.defaultValue!
+  }
+}
+
+class Preferences  : NSObject {
+  private var prefObject: Dictionary<String,Any> = Dictionary<String,Any>()
+  private var prefDict = Dictionary<String,PreferenceRow>()
+  private var prefDefaultDict: Dictionary<String,Any>?
+  
+  // This makes an read-only property computed from another property
+  // It's usage is mainly in UI Table view, so we want the prefDict size
+  var count: Int {
+    get {
+      return prefDict.count
+    }
+  }
+  
+  // Interface with a string setting in background
+  var showAsIconMode: PreferencesViewController.ShowAsMode {
+    get {
+      var mode = self.prefObject["I2Pref_showAsIconMode"]
+      if (mode == nil) {
+        mode = "bothIcon"
+      }
+      switch (mode as! String) {
+      case "bothIcon":
+        return PreferencesViewController.ShowAsMode.bothIcon
+      case "dockIcon":
+        return PreferencesViewController.ShowAsMode.dockIcon
+      case "menubarIcon":
+        return PreferencesViewController.ShowAsMode.menubarIcon
+      default:
+        return PreferencesViewController.ShowAsMode.bothIcon
+      }
+    }
+    set(newVal) {
+      //
+      var newMode: String = "bothIcon"
+      switch newVal {
+      case .bothIcon:
+        newMode = "bothIcon"
+      case .menubarIcon:
+        newMode = "menubarIcon"
+      case .dockIcon:
+        newMode = "dockIcon"
+      }
+      self.prefObject["I2Pref_showAsIconMode"] = newMode
+      UserDefaults.standard.setPersistentDomain(self.prefObject, forName: APPDOMAIN)
+    }
+  }
+
+  // Lookup by name
+  subscript(prefName:String) -> Any? {
+    get  {
+      return prefObject[prefName]
+    }
+    set(newValue) {
+      prefObject[prefName] = newValue
+      prefDict[prefName] = PreferenceRow(prefName, newValue)
+      UserDefaults.standard.setPersistentDomain(self.prefObject, forName: APPDOMAIN)
+    }
+  }
+  
+  // Lookup by index
+  subscript(index:Int) -> PreferenceRow? {
+    get  {
+      return prefDict[Array(prefDict.keys)[index]]
+    }
+    set(newValue) {
+      let pKey = Array(prefDict.keys)[index]
+      prefDict[pKey] = newValue!
+      prefObject[pKey] = newValue!.asRawValue()
+      UserDefaults.standard.setPersistentDomain(self.prefObject, forName: APPDOMAIN)
+    }
+  }
+  
+  private static var sharedPreferences: Preferences = {
+    let preferences = Preferences()
+    
+    // Setup defaults
+    
+    var home = NSHomeDirectory()
+    // Add default values
+    var defaults = Dictionary<String,Any>()
+    defaults["I2Pref_enableLogging"] = true
+    defaults["I2Pref_enableVerboseLogging"] = true
+    defaults["I2Pref_autoStartRouterAtBoot"] = false
+    defaults["I2Pref_startLauncherAtLogin"] = false
+    defaults["I2Pref_startRouterAtStartup"] = true
+    defaults["I2Pref_stopRouterAtShutdown"] = true
+    defaults["I2Pref_letRouterLiveEvenLauncherDied"] = false
+    defaults["I2Pref_allowAdvancedPreferences"] = false
+    defaults["I2Pref_alsoStartFirefoxOnLaunch"] = true
+    defaults["I2Pref_firefoxBundlePath"] = "/Applications/Firefox.app"
+    defaults["I2Pref_consolePortCheckNum"] = 7657
+    defaults["I2Pref_i2pBaseDirectory"] = NSString(format: "%@/Library/I2P", home)
+    defaults["I2Pref_i2pLogDirectory"] = NSString(format: "%@/Library/Logs/I2P", home)
+    defaults["I2Pref_showAsIconMode"] = "bothIcon"
+    defaults["I2Pref_javaCommandPath"] = "/usr/libexec/java_home -v 1.7+ --exec java "
+    defaults["I2Pref_javaCommandOptions"] = "-Xmx512M -Xms128m"
+    defaults["I2Pref_featureToggleExperimental"] = false
+    preferences.prefDefaultDict = defaults
+    
+    if (preferences.prefDict.isEmpty) {
+      print("Stored new user defaults")
+      preferences.addDictToPrefTable(defaults)
+    }
+    
+    print("User Preferences loaded - Got \(preferences.count) items.")
+    
+    return preferences
+  }()
+  
+  // MARK: -
+  
+  func addDictToPrefTable(_ dict: Dictionary<String,Any>, _ emptyFirst: Bool = true) {
+    if (emptyFirst) {
+      self.prefDict.removeAll()
+    }
+    for (pKey, pVal) in dict {
+      if (pKey.starts(with: "I2P")) {
+        print("Preference -> \(pKey)")
+        prefDict[pKey] = PreferenceRow(pKey, pVal, self.prefDefaultDict![pKey])
+      } else {
+        print("Skipping preference -> \(pKey)")
+      }
+    }
+  }
+  
+  // Initialization
+  
+  private override init() {
+    super.init()
+    self.prefObject = UserDefaults.standard.persistentDomain(forName: APPDOMAIN) ?? Dictionary<String,Any>()
+    print("Preferences size from disk is: \(prefObject.count).")
+    self.addDictToPrefTable(self.prefObject)
+    UserDefaults.standard.setPersistentDomain(self.prefObject, forName: APPDOMAIN)
+  }
+  
+  // TODO: Make menubar icon optional
+  func getMenubarIconStateIsShowing() -> Bool {
+    return true
+  }
+  
+  // MARK: - Accessors
+  
+  class func shared() -> Preferences {
+    return sharedPreferences
+  }
+  
+  func redrawPrefTableItems() {
+    self.addDictToPrefTable(self.prefObject, true)
+  }
+  
+  
+  // MARK: - Accessors for Application Preferences
+  
+  var startRouterOnLauncherStart: Bool {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_startRouterAtStartup"] as! Bool
+      return (self.prefObject["I2Pref_startRouterAtStartup"] as? Bool ?? dfl)
+    }
+    set(newValue) {
+      self.prefObject["I2Pref_startRouterAtStartup"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var stopRouterOnLauncherShutdown: Bool {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_stopRouterAtShutdown"] as! Bool
+      return (self.prefObject["I2Pref_stopRouterAtShutdown"] as? Bool ?? dfl)
+    }
+    set(newValue) {
+      self.prefObject["I2Pref_stopRouterAtShutdown"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var allowAdvancedPreferenceEdit: Bool {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_allowAdvancedPreferences"] as! Bool
+      return (self.prefObject["I2Pref_allowAdvancedPreferences"] as? Bool ?? dfl)
+    }
+    set(newValue) {
+      self.prefObject["I2Pref_allowAdvancedPreferences"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var alsoStartFirefoxOnLaunch: Bool {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_alsoStartFirefoxOnLaunch"] as! Bool
+      return (self.prefObject["I2Pref_alsoStartFirefoxOnLaunch"] as? Bool ?? dfl)
+    }
+    set(newValue) {
+      self.prefObject["I2Pref_alsoStartFirefoxOnLaunch"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var featureToggleExperimental: Bool {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_featureToggleExperimental"] as! Bool
+      return (self.prefObject["I2Pref_featureToggleExperimental"] as? Bool ?? dfl)
+    }
+    set(newValue) {
+      self.prefObject["I2Pref_featureToggleExperimental"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var i2pBaseDirectory: String {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_i2pBaseDirectory"] as! String
+      return (self.prefObject["I2Pref_i2pBaseDirectory"] as? String ?? dfl)
+    }
+    set(newValue) {
+      // TODO: Check if string is a valid directory path, and that it exists.
+      self.prefObject["I2Pref_i2pBaseDirectory"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var i2pLogDirectory: String {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_i2pLogDirectory"] as! String
+      return (self.prefObject["I2Pref_i2pLogDirectory"] as? String ?? dfl)
+    }
+    set(newValue) {
+      // TODO: Check if string is a valid java command path, check if it executes with -version.
+      self.prefObject["I2Pref_i2pLogDirectory"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var javaCommandPath: String {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_javaCommandPath"] as! String
+      return (self.prefObject["I2Pref_javaCommandPath"] as? String ?? dfl)
+    }
+    set(newValue) {
+      // TODO: Check if string is a valid java command path, check if it executes with -version.
+      self.prefObject["I2Pref_javaCommandPath"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  var javaCommandOptions: String {
+    get {
+      let dfl = self.prefDefaultDict?["I2Pref_javaCommandOptions"] as! String
+      return (self.prefObject["I2Pref_javaCommandOptions"] as? String ?? dfl)
+    }
+    set(newValue) {
+      // TODO: Check if string is a valid set of java options
+      self.prefObject["I2Pref_javaCommandOptions"] = newValue
+      UserDefaults.standard.synchronize()
+    }
+  }
+  
+  
+}
+