// Copyright 2015-present 650 Industries. All rights reserved. import ExpoModulesCore let motionGestureEnabledKey = "EXDevMenuMotionGestureEnabled" let touchGestureEnabledKey = "EXDevMenuTouchGestureEnabled" let keyCommandsEnabledKey = "EXDevMenuKeyCommandsEnabled" let showsAtLaunchKey = "EXDevMenuShowsAtLaunch" let isOnboardingFinishedKey = "EXDevMenuIsOnboardingFinished" public class DevMenuPreferences: Module { public func definition() -> ModuleDefinition { Name("DevMenuPreferences") AsyncFunction("getPreferencesAsync") { return DevMenuPreferences.serialize() } AsyncFunction("setPreferencesAsync") { (settings: [String: Any]) in DevMenuPreferences.setSettings(settings) } } /* Initializes dev menu preferences by registering user defaults and applying some preferences to static classes like interceptors. */ static func setup() { #if os(tvOS) UserDefaults.standard.register(defaults: [ motionGestureEnabledKey: false, touchGestureEnabledKey: false, keyCommandsEnabledKey: true, showsAtLaunchKey: false, isOnboardingFinishedKey: true ]) #else UserDefaults.standard.register(defaults: [ motionGestureEnabledKey: true, touchGestureEnabledKey: true, keyCommandsEnabledKey: true, showsAtLaunchKey: false, isOnboardingFinishedKey: false ]) #endif /* We don't want to uninstall `DevMenuMotionInterceptor`, because otherwise, the app on shake gesture will bring up the dev-menu from the RN. So we added `isEnabled` to disable it, but not uninstall. */ DevMenuMotionInterceptor.isInstalled = true DevMenuMotionInterceptor.isEnabled = DevMenuPreferences.motionGestureEnabled DevMenuTouchInterceptor.isInstalled = DevMenuPreferences.touchGestureEnabled DevMenuKeyCommandsInterceptor.isInstalled = DevMenuPreferences.keyCommandsEnabled } /** Whether to enable shake gesture. */ static var motionGestureEnabled: Bool { get { return boolForKey(motionGestureEnabledKey) } set { setBool(newValue, forKey: motionGestureEnabledKey) DevMenuMotionInterceptor.isEnabled = newValue } } /** Whether to enable three-finger long press gesture. */ static var touchGestureEnabled: Bool { get { return boolForKey(touchGestureEnabledKey) } set { setBool(newValue, forKey: touchGestureEnabledKey) DevMenuTouchInterceptor.isInstalled = newValue } } /** Whether to enable key commands. */ static var keyCommandsEnabled: Bool { get { return boolForKey(keyCommandsEnabledKey) } set { setBool(newValue, forKey: keyCommandsEnabledKey) DevMenuKeyCommandsInterceptor.isInstalled = newValue } } /** Whether to automatically show the dev menu once its delegate is set and the bridge is loaded. */ static var showsAtLaunch: Bool { get { return DevMenuTestInterceptorManager.interceptor?.shouldShowAtLaunch ?? boolForKey(showsAtLaunchKey) } set { setBool(newValue, forKey: showsAtLaunchKey) DevMenuManager.shared.updateAutoLaunchObserver() } } /** Returns `true` only if the user finished onboarding, `false` otherwise. This is now public because expo-dev-launcher needs access in order to disable the onboarding popup for certain bundle URLs */ public static var isOnboardingFinished: Bool { get { return DevMenuTestInterceptorManager.interceptor?.isOnboardingFinishedKey ?? boolForKey(isOnboardingFinishedKey) } set { setBool(newValue, forKey: isOnboardingFinishedKey) } } /** Serializes settings into a dictionary so they can be passed through the bridge. */ static func serialize() -> [String: Any] { return [ "motionGestureEnabled": DevMenuPreferences.motionGestureEnabled, "touchGestureEnabled": DevMenuPreferences.touchGestureEnabled, "keyCommandsEnabled": DevMenuPreferences.keyCommandsEnabled, "showsAtLaunch": DevMenuPreferences.showsAtLaunch, "isOnboardingFinished": DevMenuPreferences.isOnboardingFinished ] } static func setSettings(_ settings: [String: Any]) { if let motionGestureEnabled = settings["motionGestureEnabled"] as? Bool { DevMenuPreferences.motionGestureEnabled = motionGestureEnabled } if let touchGestureEnabled = settings["touchGestureEnabled"] as? Bool { DevMenuPreferences.touchGestureEnabled = touchGestureEnabled } if let keyCommandsEnabled = settings["keyCommandsEnabled"] as? Bool { DevMenuPreferences.keyCommandsEnabled = keyCommandsEnabled } if let showsAtLaunch = settings["showsAtLaunch"] as? Bool { DevMenuPreferences.showsAtLaunch = showsAtLaunch } } } private func boolForKey(_ key: String) -> Bool { return UserDefaults.standard.bool(forKey: key) } private func setBool(_ value: Bool, forKey key: String) { UserDefaults.standard.set(value, forKey: key) }