1 // Copyright 2015-present 650 Industries. All rights reserved.
2 import ExpoModulesCore
3
4 let motionGestureEnabledKey = "EXDevMenuMotionGestureEnabled"
5 let touchGestureEnabledKey = "EXDevMenuTouchGestureEnabled"
6 let keyCommandsEnabledKey = "EXDevMenuKeyCommandsEnabled"
7 let showsAtLaunchKey = "EXDevMenuShowsAtLaunch"
8 let isOnboardingFinishedKey = "EXDevMenuIsOnboardingFinished"
9
10 public class DevMenuPreferences: Module {
definitionnull11 public func definition() -> ModuleDefinition {
12 Name("DevMenuPreferences")
13
14 AsyncFunction("getPreferencesAsync") {
15 return DevMenuPreferences.serialize()
16 }
17
18 AsyncFunction("setPreferencesAsync") { (settings: [String: Any]) in
19 DevMenuPreferences.setSettings(settings)
20 }
21 }
22
23 /**
24 Initializes dev menu preferences by registering user defaults
25 and applying some preferences to static classes like interceptors.
26 */
setupnull27 static func setup() {
28 UserDefaults.standard.register(defaults: [
29 motionGestureEnabledKey: true,
30 touchGestureEnabledKey: true,
31 keyCommandsEnabledKey: true,
32 showsAtLaunchKey: false,
33 isOnboardingFinishedKey: false
34 ])
35
36 /**
37 We don't want to uninstall `DevMenuMotionInterceptor`, because otherwise, the app on shake gesture will bring up the dev-menu from the RN.
38 So we added `isEnabled` to disable it, but not uninstall.
39 */
40 DevMenuMotionInterceptor.isInstalled = true
41 DevMenuMotionInterceptor.isEnabled = DevMenuPreferences.motionGestureEnabled
42 DevMenuTouchInterceptor.isInstalled = DevMenuPreferences.touchGestureEnabled
43 DevMenuKeyCommandsInterceptor.isInstalled = DevMenuPreferences.keyCommandsEnabled
44 }
45
46 /**
47 Whether to enable shake gesture.
48 */
49 static var motionGestureEnabled: Bool {
50 get {
51 return boolForKey(motionGestureEnabledKey)
52 }
53 set {
54 setBool(newValue, forKey: motionGestureEnabledKey)
55 DevMenuMotionInterceptor.isEnabled = newValue
56 }
57 }
58
59 /**
60 Whether to enable three-finger long press gesture.
61 */
62 static var touchGestureEnabled: Bool {
63 get {
64 return boolForKey(touchGestureEnabledKey)
65 }
66 set {
67 setBool(newValue, forKey: touchGestureEnabledKey)
68 DevMenuTouchInterceptor.isInstalled = newValue
69 }
70 }
71
72 /**
73 Whether to enable key commands.
74 */
75 static var keyCommandsEnabled: Bool {
76 get {
77 return boolForKey(keyCommandsEnabledKey)
78 }
79 set {
80 setBool(newValue, forKey: keyCommandsEnabledKey)
81 DevMenuKeyCommandsInterceptor.isInstalled = newValue
82 }
83 }
84
85 /**
86 Whether to automatically show the dev menu once its delegate is set and the bridge is loaded.
87 */
88 static var showsAtLaunch: Bool {
89 get {
90 return DevMenuTestInterceptorManager.interceptor?.shouldShowAtLaunch ?? boolForKey(showsAtLaunchKey)
91 }
92 set {
93 setBool(newValue, forKey: showsAtLaunchKey)
94 }
95 }
96
97 /**
98 Returns `true` only if the user finished onboarding, `false` otherwise.
99 This is now public because expo-dev-launcher needs access
100 in order to disable the onboarding popup for certain bundle URLs
101 */
102 public static var isOnboardingFinished: Bool {
103 get {
104 return DevMenuTestInterceptorManager.interceptor?.isOnboardingFinishedKey ?? boolForKey(isOnboardingFinishedKey)
105 }
106 set {
107 setBool(newValue, forKey: isOnboardingFinishedKey)
108 }
109 }
110
111 /**
112 Serializes settings into a dictionary so they can be passed through the bridge.
113 */
serializenull114 static func serialize() -> [String: Any] {
115 return [
116 "motionGestureEnabled": DevMenuPreferences.motionGestureEnabled,
117 "touchGestureEnabled": DevMenuPreferences.touchGestureEnabled,
118 "keyCommandsEnabled": DevMenuPreferences.keyCommandsEnabled,
119 "showsAtLaunch": DevMenuPreferences.showsAtLaunch,
120 "isOnboardingFinished": DevMenuPreferences.isOnboardingFinished
121 ]
122 }
123
setSettingsnull124 static func setSettings(_ settings: [String: Any]) {
125 if let motionGestureEnabled = settings["motionGestureEnabled"] as? Bool {
126 DevMenuPreferences.motionGestureEnabled = motionGestureEnabled
127 }
128 if let touchGestureEnabled = settings["touchGestureEnabled"] as? Bool {
129 DevMenuPreferences.touchGestureEnabled = touchGestureEnabled
130 }
131 if let keyCommandsEnabled = settings["keyCommandsEnabled"] as? Bool {
132 DevMenuPreferences.keyCommandsEnabled = keyCommandsEnabled
133 }
134 if let showsAtLaunch = settings["showsAtLaunch"] as? Bool {
135 DevMenuPreferences.showsAtLaunch = showsAtLaunch
136 }
137 }
138 }
139
boolForKeynull140 private func boolForKey(_ key: String) -> Bool {
141 return UserDefaults.standard.bool(forKey: key)
142 }
143
setBoolnull144 private func setBool(_ value: Bool, forKey key: String) {
145 UserDefaults.standard.set(value, forKey: key)
146 }
147