1 // Copyright 2015-present 650 Industries. All rights reserved.
2 
3 import React
4 
5 class DevMenuDevOptionsDelegate {
6   internal private(set) weak var bridge: RCTBridge?
7   internal private(set) weak var devSettings: RCTDevSettings?
8 
9   #if DEBUG
10   internal private(set) weak var perfMonitor: RCTPerfMonitor?
11   #endif
12 
13   internal init(forBridge bridge: RCTBridge) {
14     self.bridge = bridge
15     devSettings = bridge.module(forName: "DevSettings") as? RCTDevSettings
16 
17     #if DEBUG
18     perfMonitor = bridge.module(forName: "PerfMonitor") as? RCTPerfMonitor
19     #endif
20   }
21 
22   internal func reload() {
23     // Without this the `expo-splash-screen` will reject
24     // No native splash screen registered for given view controller. Call 'SplashScreen.show' for given view controller first.
25     DevMenuManager.shared.hideMenu()
26 
27     bridge?.requestReload()
28   }
29 
30   internal func toggleElementInsector() {
31     devSettings?.toggleElementInspector()
32   }
33 
34   internal func openJSInspector() {
35     guard let bundleURL = bridge?.bundleURL else {
36       return
37     }
38     let port = bundleURL.port ?? Int(RCT_METRO_PORT)
39     let host = bundleURL.host ?? "localhost"
40     let openURL = "http://\(host):\(port)/inspector?applicationId=\(Bundle.main.bundleIdentifier ?? "")"
41     guard let url = URL(string: openURL) else {
42       NSLog("[DevMenu] Invalid openJSInspector URL: $@", openURL)
43       return
44     }
45     let request = NSMutableURLRequest(url: url)
46     request.httpMethod = "PUT"
47     URLSession.shared.dataTask(with: request as URLRequest).resume()
48   }
49 
50   internal func toggleRemoteDebugging() {
51     guard let devSettings = devSettings else {
52       return
53     }
54 
55     DevMenuManager.shared.hideMenu()
56 
57     DispatchQueue.main.async {
58       devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely
59       (DevMenuManager.shared.window?.rootViewController as? DevMenuViewController)?.updateProps() // We have to force props to reflect changes on the UI
60     }
61   }
62 
63   internal func togglePerformanceMonitor() {
64     #if DEBUG
65     guard let perfMonitor = perfMonitor else {
66       return
67     }
68 
69     guard let devSettings = devSettings else {
70       return
71     }
72 
73     DispatchQueue.main.async {
74       devSettings.isPerfMonitorShown ? perfMonitor.hide() : perfMonitor.show()
75       devSettings.isPerfMonitorShown = !devSettings.isPerfMonitorShown
76     }
77     #endif
78   }
79 
80   internal func toggleFastRefresh() {
81     guard let devSettings = devSettings else {
82       return
83     }
84 
85     devSettings.isHotLoadingEnabled = !devSettings.isHotLoadingEnabled
86   }
87 }
88