expo-dev-menu-interface 1.8.4 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/expo/interfaces/devmenu/DevMenuManagerInterface.kt +0 -31
  3. package/android/src/main/java/expo/interfaces/devmenu/ReactHostWrapper.kt +7 -1
  4. package/ios/expo-dev-menu-interface.podspec +3 -9
  5. package/package.json +2 -2
  6. package/android/src/main/java/expo/interfaces/devmenu/DevMenuExtensionInterface.kt +0 -32
  7. package/android/src/main/java/expo/interfaces/devmenu/DevMenuManagerProviderInterface.kt +0 -9
  8. package/android/src/main/java/expo/interfaces/devmenu/annotations/ContainsDevMenuExtension.kt +0 -5
  9. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuDataSource.kt +0 -22
  10. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuExportedCallable.kt +0 -34
  11. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuItemImportance.kt +0 -12
  12. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuItems.kt +0 -182
  13. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuItemsContainer.kt +0 -53
  14. package/android/src/main/java/expo/interfaces/devmenu/items/DevMenuItemsContainerInterface.kt +0 -30
  15. package/ios/DevMenuExtensionProtocol.swift +0 -39
  16. package/ios/EXDevExtensions.swift +0 -10
  17. package/ios/MenuItems/DevMenuAction.swift +0 -105
  18. package/ios/MenuItems/DevMenuDataSource.swift +0 -33
  19. package/ios/MenuItems/DevMenuExportedCallable.swift +0 -64
  20. package/ios/MenuItems/DevMenuGroup.swift +0 -37
  21. package/ios/MenuItems/DevMenuItem.swift +0 -29
  22. package/ios/MenuItems/DevMenuItemsContainer.swift +0 -32
  23. package/ios/MenuItems/DevMenuItemsContainerProtocol.swift +0 -12
  24. package/ios/MenuItems/DevMenuLink.swift +0 -28
  25. package/ios/MenuItems/DevMenuScreen.swift +0 -37
  26. package/ios/MenuItems/DevMenuScreenItem.swift +0 -26
  27. package/ios/MenuItems/DevMenuSelectionList.swift +0 -91
  28. package/ios/Tests/DevMenuActionTest.swift +0 -42
  29. package/ios/Tests/DevMenuItemsContainerTest.swift +0 -63
  30. package/ios/Tests/DevMenuLinkTest.swift +0 -20
  31. package/ios/Tests/DevMenuScreenTest.swift +0 -17
  32. package/ios/Tests/DevMenuSelectionListTest.swift +0 -17
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'host.exp.exponent'
4
- version = '1.8.4'
4
+ version = '1.9.1'
5
5
 
6
6
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
7
  apply from: expoModulesCorePlugin
@@ -13,7 +13,7 @@ android {
13
13
  namespace "expo.interfaces.devmenu"
14
14
  defaultConfig {
15
15
  versionCode 6
16
- versionName '1.8.4'
16
+ versionName '1.9.1'
17
17
  }
18
18
  }
19
19
 
@@ -1,11 +1,8 @@
1
1
  package expo.interfaces.devmenu
2
2
 
3
3
  import android.app.Activity
4
- import android.os.Bundle
5
4
  import android.view.KeyEvent
6
5
  import android.view.MotionEvent
7
- import com.facebook.react.bridge.ReadableMap
8
- import expo.interfaces.devmenu.items.DevMenuDataSourceItem
9
6
  import kotlinx.coroutines.CoroutineScope
10
7
 
11
8
  interface DevMenuManagerInterface {
@@ -51,27 +48,6 @@ interface DevMenuManagerInterface {
51
48
  */
52
49
  fun initializeWithReactHost(reactHost: ReactHostWrapper)
53
50
 
54
- /**
55
- * Finds and dispatches action with provided [actionId].
56
- * If such action doesn't exist, ignore it.
57
- */
58
- fun dispatchCallable(actionId: String, args: ReadableMap?)
59
-
60
- /**
61
- * Registers an extra [DevMenuExtensionInterface] to the manager.
62
- */
63
- fun registerExtensionInterface(extensionInterface: DevMenuExtensionInterface)
64
-
65
- /**
66
- * @return a list of dev menu items serialized to the [Bundle].
67
- */
68
- fun serializedItems(): List<Bundle>
69
-
70
- /**
71
- * @return a list of dev menu screens serialized to the [Bundle].
72
- */
73
- fun serializedScreens(): List<Bundle>
74
-
75
51
  /**
76
52
  * @return a instance of [DevMenuPreferencesInterface] that keeps all settings for current dev menu delegate,
77
53
  * or `null` if delegate wasn't provided.
@@ -88,11 +64,6 @@ interface DevMenuManagerInterface {
88
64
  */
89
65
  fun synchronizeDelegate()
90
66
 
91
- /**
92
- * Set the current screen on which all action will be dispatched.
93
- */
94
- fun setCurrentScreen(screen: String?)
95
-
96
67
  /**
97
68
  * Sends an event to the delegate's bridge if exists.
98
69
  */
@@ -108,7 +79,5 @@ interface DevMenuManagerInterface {
108
79
  */
109
80
  fun setCanLaunchDevMenuOnStart(shouldAutoLaunch: Boolean)
110
81
 
111
- suspend fun fetchDataSource(id: String): List<DevMenuDataSourceItem>
112
-
113
82
  val coroutineScope: CoroutineScope
114
83
  }
@@ -11,6 +11,7 @@ import com.facebook.react.common.LifecycleState
11
11
  import com.facebook.react.config.ReactFeatureFlags
12
12
  import com.facebook.react.devsupport.interfaces.DevSupportManager
13
13
  import com.facebook.react.runtime.ReactHostImpl
14
+ import java.lang.reflect.Field
14
15
 
15
16
  /**
16
17
  * An abstract wrapper to host [ReactNativeHost] and [ReactHost],
@@ -68,7 +69,12 @@ class ReactHostWrapper(reactNativeHost: ReactNativeHost, reactHostProvider: () -
68
69
  val jsExecutorName: String
69
70
  get() {
70
71
  if (isBridgelessMode) {
71
- return if (reactHost.jsEngineResolutionAlgorithm == JSEngineResolutionAlgorithm.JSC) {
72
+ // Access private field using reflection
73
+ val jsEngineResolutionAlgorithmField: Field = reactHost::class.java.getDeclaredField("mJSEngineResolutionAlgorithm")
74
+ jsEngineResolutionAlgorithmField.isAccessible = true
75
+ val jsEngineResolutionAlgorithm = jsEngineResolutionAlgorithmField.get(reactHost) as? JSEngineResolutionAlgorithm
76
+
77
+ return if (jsEngineResolutionAlgorithm == JSEngineResolutionAlgorithm.JSC) {
72
78
  "JSC"
73
79
  } else {
74
80
  "Hermes"
@@ -10,13 +10,14 @@ Pod::Spec.new do |s|
10
10
  s.license = package['license']
11
11
  s.author = package['author']
12
12
  s.homepage = package['homepage']
13
- s.platform = :ios, '13.4'
13
+ s.platforms = {
14
+ :ios => '15.1'
15
+ }
14
16
  s.swift_version = '5.2'
15
17
  s.source = { git: 'https://github.com/expo/expo.git' }
16
18
  s.static_framework = true
17
19
  s.source_files = '**/*.{h,m,swift}'
18
20
  s.preserve_paths = '**/*.{h,m,swift}'
19
- s.exclude_files = 'Tests/**/*.{h,m,swift}'
20
21
  s.requires_arc = true
21
22
  s.header_dir = 'EXDevMenuInterface'
22
23
 
@@ -26,11 +27,4 @@ Pod::Spec.new do |s|
26
27
 
27
28
  # Swift/Objective-C compatibility
28
29
  s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
29
-
30
- s.test_spec 'Tests' do |test_spec|
31
- test_spec.platform = :ios, '13.4'
32
- test_spec.source_files = 'Tests/**/*.{h,m,swift}'
33
- test_spec.dependency 'Quick'
34
- test_spec.dependency 'Nimble'
35
- end
36
30
  end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-dev-menu-interface",
3
- "version": "1.8.4",
3
+ "version": "1.9.1",
4
4
  "description": "Interface for expo-dev-menu",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -25,5 +25,5 @@
25
25
  "peerDependencies": {
26
26
  "expo": "*"
27
27
  },
28
- "gitHead": "6583b7c637a965a9a9872efee9905b11ea806e28"
28
+ "gitHead": "c0899e56c5be08b0142f06f05aa7bac8d6bc18b8"
29
29
  }
@@ -1,32 +0,0 @@
1
- package expo.interfaces.devmenu
2
-
3
- import expo.interfaces.devmenu.items.DevMenuDataSourceInterface
4
- import expo.interfaces.devmenu.items.DevMenuItemsContainerInterface
5
- import expo.interfaces.devmenu.items.DevMenuScreen
6
-
7
- interface DevMenuExtensionSettingsInterface {
8
- fun wasRunOnDevelopmentBridge(): Boolean
9
- val manager: DevMenuManagerInterface
10
- }
11
-
12
- /**
13
- * A native extension to provide extra dev-menu items.
14
- * The implementation should call [DevMenuManagerInterface.registerExtensionInterface]
15
- * to register its instance to the manager.
16
- */
17
- interface DevMenuExtensionInterface {
18
- /**
19
- * Returns a name of the module and the extension. Also required by [com.facebook.react.bridge.ReactContextBaseJavaModule].
20
- */
21
- fun getName(): String
22
-
23
- /**
24
- * Returns a `DevMenuItemsContainer` that contains the dev menu items to show on the main screen.
25
- * It's called only once for the extension instance — results are being cached on first dev menu launch.
26
- */
27
- fun devMenuItems(settings: DevMenuExtensionSettingsInterface): DevMenuItemsContainerInterface?
28
-
29
- fun devMenuScreens(settings: DevMenuExtensionSettingsInterface): List<DevMenuScreen>? = null
30
-
31
- fun devMenuDataSources(settings: DevMenuExtensionSettingsInterface): List<DevMenuDataSourceInterface>? = null
32
- }
@@ -1,9 +0,0 @@
1
- package expo.interfaces.devmenu
2
-
3
- @FunctionalInterface
4
- interface DevMenuManagerProviderInterface {
5
- /**
6
- * Provides access to the object implementing the [DevMenuManagerInterface] interface.
7
- */
8
- fun getDevMenuManager(): DevMenuManagerInterface
9
- }
@@ -1,5 +0,0 @@
1
- package expo.interfaces.devmenu.annotations
2
-
3
- @Target(AnnotationTarget.CLASS)
4
- @Retention(AnnotationRetention.RUNTIME)
5
- annotation class ContainsDevMenuExtension
@@ -1,22 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- import android.os.Bundle
4
-
5
- interface DevMenuDataSourceItem {
6
- fun serialize(): Bundle
7
- }
8
-
9
- interface DevMenuDataSourceInterface {
10
- val id: String
11
-
12
- suspend fun fetchData(): List<DevMenuDataSourceItem>
13
- }
14
-
15
- class DevMenuListDataSource(
16
- override val id: String,
17
- val dataFetcher: suspend () -> List<DevMenuSelectionList.Item>
18
- ) : DevMenuDataSourceInterface {
19
- override suspend fun fetchData(): List<DevMenuDataSourceItem> {
20
- return dataFetcher()
21
- }
22
- }
@@ -1,34 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- import com.facebook.react.bridge.ReadableMap
4
-
5
- interface DevMenuCallableProvider {
6
- fun registerCallable(): DevMenuExportedCallable?
7
- }
8
-
9
- sealed class DevMenuExportedCallable(val id: String)
10
-
11
- class DevMenuExportedFunction(
12
- id: String,
13
- val function: (ReadableMap?) -> Unit
14
- ) : DevMenuExportedCallable(id) {
15
- fun call(args: ReadableMap?) {
16
- function(args)
17
- }
18
- }
19
-
20
- class DevMenuExportedAction(
21
- id: String,
22
- val action: () -> Unit
23
- ) : DevMenuExportedCallable(id) {
24
- var keyCommand: KeyCommand? = null
25
- var isAvailable = { true }
26
-
27
- fun registerKeyCommand(keyCommand: KeyCommand?) {
28
- this.keyCommand = keyCommand
29
- }
30
-
31
- fun call() {
32
- action()
33
- }
34
- }
@@ -1,12 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- /**
4
- * Tells how important the dev menu item is. To use it with [DevMenuItem], you need to pass its [value].
5
- */
6
- enum class DevMenuItemImportance(val value: Int) {
7
- LOWEST(-200),
8
- LOW(-100),
9
- MEDIUM(0),
10
- HIGH(100),
11
- HIGHEST(200)
12
- }
@@ -1,182 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- import android.os.Bundle
4
- import android.view.KeyCharacterMap
5
- import com.facebook.react.bridge.ReadableMap
6
-
7
- val keyCharacterMap: KeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD)
8
-
9
- // Android virtual keyboard only supports `SHIFT` as a modifier.
10
- data class KeyCommand(val code: Int, val withShift: Boolean = false)
11
-
12
- /**
13
- * An abstract representation of the single dev menu item.
14
- */
15
- sealed class DevMenuItem {
16
- /**
17
- * Represent how this item will be treated by the js.
18
- * 1 - [DevMenuAction]
19
- * 2 - [DevMenuGroup]
20
- * 3 - [DevMenuScreen]
21
- * 4 - [DevMenuLink]
22
- * 5 - [DevMenuSelectionList]
23
- */
24
- abstract fun getExportedType(): Int
25
-
26
- open fun serialize() = Bundle().apply {
27
- putInt("type", getExportedType())
28
- }
29
- }
30
-
31
- abstract class DevMenuScreenItem : DevMenuItem() {
32
- var importance = DevMenuItemImportance.MEDIUM.value
33
- }
34
-
35
- class DevMenuScreen(
36
- val screenName: String,
37
- itemsContainer: DevMenuDSLItemsContainerInterface = DevMenuItemsContainer()
38
- ) : DevMenuItem(), DevMenuDSLItemsContainerInterface by itemsContainer {
39
- override fun getExportedType() = 3
40
-
41
- override fun serialize() = super.serialize().apply {
42
- putString("screenName", screenName)
43
- putParcelableArray("items", serializeItems())
44
- }
45
- }
46
-
47
- class DevMenuGroup(
48
- itemsContainer: DevMenuDSLItemsContainerInterface = DevMenuItemsContainer()
49
- ) : DevMenuScreenItem(), DevMenuDSLItemsContainerInterface by itemsContainer {
50
- override fun getExportedType() = 2
51
-
52
- override fun serialize() = super.serialize().apply {
53
- putParcelableArray("items", serializeItems())
54
- }
55
- }
56
-
57
- class DevMenuAction(
58
- actionId: String,
59
- action: () -> Unit
60
- ) : DevMenuScreenItem(), DevMenuCallableProvider {
61
- val callable = DevMenuExportedAction(actionId, action)
62
- var isAvailable: () -> Boolean
63
- get() = callable.isAvailable
64
- set(value) {
65
- callable.isAvailable = value
66
- }
67
- var isEnabled = { false }
68
- var label = { "" }
69
- var detail = { "" }
70
- var glyphName = { "" }
71
-
72
- var keyCommand: KeyCommand?
73
- get() = callable.keyCommand
74
- set(value) {
75
- callable.registerKeyCommand(value)
76
- }
77
-
78
- override fun getExportedType() = 1
79
-
80
- override fun serialize() = super.serialize().apply {
81
- putString("actionId", callable.id)
82
- putBoolean("isAvailable", isAvailable())
83
- putBoolean("isEnabled", isEnabled())
84
- putString("label", label())
85
- putString("detail", detail())
86
- putString("glyphName", glyphName())
87
-
88
- putBundle(
89
- "keyCommand",
90
- keyCommand?.let { keyCommand ->
91
- Bundle().apply {
92
- putString("input", keyCharacterMap.getDisplayLabel(keyCommand.code).toString())
93
- putInt("modifiers", exportKeyCommandModifiers())
94
- }
95
- }
96
- )
97
- }
98
-
99
- private fun exportKeyCommandModifiers(): Int {
100
- if (keyCommand?.withShift == true) {
101
- return 1 shl 3
102
- }
103
- return 0
104
- }
105
-
106
- override fun registerCallable(): DevMenuExportedCallable {
107
- return callable
108
- }
109
- }
110
-
111
- class DevMenuLink(private val target: String) : DevMenuScreenItem() {
112
- var label = { "" }
113
- var glyphName = { "" }
114
-
115
- override fun getExportedType() = 4
116
-
117
- override fun serialize() = super.serialize().apply {
118
- putString("target", target)
119
- putString("label", label())
120
- putString("glyphName", glyphName())
121
- }
122
- }
123
-
124
- class DevMenuSelectionList : DevMenuScreenItem(), DevMenuCallableProvider {
125
- class Item : DevMenuDataSourceItem {
126
- class Tag {
127
- var glyphName = { "" }
128
- var text = { "" }
129
-
130
- internal fun serialize() = Bundle().apply {
131
- putString("text", text())
132
- putString("glyphName", glyphName())
133
- }
134
- }
135
-
136
- var title = { "" }
137
- var tags: () -> List<Tag> = { emptyList() }
138
- var warning: () -> String? = { null }
139
- var isChecked = { false }
140
- var onClickData: () -> Bundle? = { null }
141
-
142
- override fun serialize() = Bundle().apply {
143
- putString("title", title())
144
- putString("warning", warning())
145
- putBoolean("isChecked", isChecked())
146
- putBundle("onClickData", onClickData())
147
- putParcelableArray("tags", tags().map { it.serialize() }.toTypedArray())
148
- }
149
- }
150
-
151
- private var items = ArrayList<Item>()
152
- private var callable: DevMenuExportedFunction? = null
153
- var dataSourceId: () -> String? = { null }
154
-
155
- fun addOnClick(handler: (ReadableMap?) -> Unit) {
156
- callable = DevMenuExportedFunction("expo-dev-menu.selection-list.#${ActionID++}", handler)
157
- }
158
-
159
- fun addItem(item: Item) {
160
- items.add(item)
161
- }
162
-
163
- override fun getExportedType(): Int {
164
- return 5
165
- }
166
-
167
- override fun serialize() = super.serialize().apply {
168
- callable?.let {
169
- putString("actionId", it.id)
170
- }
171
- putString("dataSourceId", dataSourceId())
172
- putParcelableArray("items", items.map { it.serialize() }.toTypedArray())
173
- }
174
-
175
- companion object {
176
- private var ActionID = 0
177
- }
178
-
179
- override fun registerCallable(): DevMenuExportedCallable? {
180
- return callable
181
- }
182
- }
@@ -1,53 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- import java.util.*
4
-
5
- open class DevMenuItemsContainer : DevMenuDSLItemsContainerInterface {
6
- private val items = mutableListOf<DevMenuScreenItem>()
7
-
8
- override fun getRootItems(): List<DevMenuScreenItem> {
9
- items.sortedWith(compareBy { it.importance })
10
- return items
11
- }
12
-
13
- override fun getAllItems(): List<DevMenuScreenItem> {
14
- val result = LinkedList<DevMenuScreenItem>()
15
-
16
- items.forEach {
17
- result.add(it)
18
-
19
- if (it is DevMenuItemsContainerInterface) {
20
- result.addAll(it.getAllItems())
21
- }
22
- }
23
- return result
24
- }
25
-
26
- private fun addItem(item: DevMenuScreenItem) {
27
- items.add(item)
28
- }
29
-
30
- override fun group(init: DevMenuGroup.() -> Unit) = addItem(DevMenuGroup(), init)
31
-
32
- override fun action(actionId: String, action: () -> Unit, init: DevMenuAction.() -> Unit) =
33
- addItem(DevMenuAction(actionId, action), init)
34
-
35
- override fun link(target: String, init: DevMenuLink.() -> Unit) = addItem(DevMenuLink(target), init)
36
-
37
- override fun selectionList(init: DevMenuSelectionList.() -> Unit) = addItem(DevMenuSelectionList(), init)
38
-
39
- private fun <T : DevMenuScreenItem> addItem(item: T, init: T.() -> Unit): T {
40
- item.init()
41
- addItem(item)
42
- return item
43
- }
44
-
45
- companion object {
46
- @JvmStatic
47
- fun export(init: DevMenuDSLItemsContainerInterface.() -> Unit): DevMenuItemsContainer {
48
- val container = DevMenuItemsContainer()
49
- container.init()
50
- return container
51
- }
52
- }
53
- }
@@ -1,30 +0,0 @@
1
- package expo.interfaces.devmenu.items
2
-
3
- import android.os.Bundle
4
-
5
- interface DevMenuItemsContainerInterface {
6
- fun getRootItems(): List<DevMenuScreenItem>
7
- fun getAllItems(): List<DevMenuScreenItem>
8
- }
9
-
10
- fun DevMenuItemsContainerInterface.serializeItems(): Array<Bundle> =
11
- getRootItems()
12
- .map { it.serialize() }
13
- .toTypedArray()
14
-
15
- inline fun <reified T> DevMenuItemsContainerInterface.getItemsOfType(): List<T> {
16
- return getAllItems().filterIsInstance<T>()
17
- }
18
-
19
- interface DevMenuDSLItemsContainerInterface : DevMenuItemsContainerInterface {
20
- fun group(init: DevMenuGroup.() -> Unit): DevMenuGroup
21
- fun action(actionId: String, action: () -> Unit, init: DevMenuAction.() -> Unit): DevMenuAction
22
- fun link(target: String, init: DevMenuLink.() -> Unit): DevMenuLink
23
- fun selectionList(init: DevMenuSelectionList.() -> Unit): DevMenuSelectionList
24
- }
25
-
26
- fun screen(name: String, init: DevMenuScreen.() -> Unit): DevMenuScreen {
27
- val screen = DevMenuScreen(name)
28
- screen.init()
29
- return screen
30
- }
@@ -1,39 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public protocol DevMenuExtensionSettingsProtocol {
7
- func wasRunOnDevelopmentBridge() -> Bool
8
- }
9
-
10
- /**
11
- A protocol for React Native bridge modules that want to provide their own dev menu actions.
12
- */
13
- @objc
14
- public protocol DevMenuExtensionProtocol {
15
- /**
16
- Returns a name of the module and the extension. Required by `RCTBridgeModule`.
17
- This function is optional because otherwise we end up with linker warning:
18
- `method '+moduleName' in category from /.../expo-dev-menu/libexpo-dev-menu.a(DevMenuExtensions-....o)
19
- overrides method from class in /.../expo-dev-menu/libexpo-dev-menu.a(DevMenuExtensions-....o`
20
-
21
- So we assume that this method will be implemented by `RCTBridgeModule`.
22
- In theory we can remove it. However, we leave it to get easy access to the module name.
23
- */
24
- @objc
25
- optional static func moduleName() -> String!
26
-
27
- /**
28
- Returns an array of the dev menu items to show.
29
- It's called only once for the extension instance — results are being cached on first dev menu launch.
30
- */
31
- @objc
32
- optional func devMenuItems(_ settings: DevMenuExtensionSettingsProtocol) -> DevMenuItemsContainerProtocol?
33
-
34
- @objc
35
- optional func devMenuScreens(_ settings: DevMenuExtensionSettingsProtocol) -> [DevMenuScreen]?
36
-
37
- @objc
38
- optional func devMenuDataSources(_ settings: DevMenuExtensionSettingsProtocol) -> [DevMenuDataSourceProtocol]?
39
- }
@@ -1,10 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- // A protocol for determining if a given bridge module is a "DevExtension"
6
- // DevExtensions are passed through to the dev-menu and dev-launcher JS runtimes
7
- // This protocol has no fields on it as of yet but could be extended if additional functionality is needed in the future
8
-
9
- @objc
10
- public protocol EXDevExtensionProtocol {}
@@ -1,105 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
- import UIKit
5
-
6
- @objc
7
- open class DevMenuAction: DevMenuScreenItem, DevMenuCallableProvider {
8
- @objc
9
- public var callable: DevMenuExportedAction
10
-
11
- @objc
12
- public var action: () -> Void {
13
- get { return self.callable.action }
14
- set { self.callable.action = newValue }
15
- }
16
-
17
- @objc
18
- open var isAvailable: () -> Bool {
19
- get {
20
- return self.callable.isAvailable
21
- }
22
- set {
23
- self.callable.isAvailable = newValue
24
- }
25
- }
26
-
27
- @objc
28
- open var isEnabled: () -> Bool = { false }
29
-
30
- @objc
31
- open var label: () -> String = { "" }
32
-
33
- @objc
34
- open var detail: () -> String = { "" }
35
-
36
- @objc
37
- open var glyphName: () -> String = { "" }
38
-
39
- @objc
40
- public init(withId id: String) {
41
- self.callable = DevMenuExportedAction(withId: id, withAction: {})
42
- super.init(type: .Action)
43
- }
44
-
45
- @objc
46
- public convenience init(withId id: String, action: @escaping () -> Void) {
47
- self.init(withId: id)
48
- self.callable.action = action
49
- }
50
-
51
- @objc
52
- public convenience init(withId id: String, _ action: @escaping () -> Void) {
53
- self.init(withId: id, action: action)
54
- }
55
-
56
- public func registerCallable() -> DevMenuExportedCallable? {
57
- return self.callable
58
- }
59
-
60
- @objc
61
- open func registerKeyCommand(input: String, modifiers: UIKeyModifierFlags) {
62
- self.callable.registerKeyCommand(input: input, modifiers: modifiers)
63
- }
64
-
65
- @objc
66
- open override func serialize() -> [String: Any] {
67
- var dict = super.serialize()
68
- dict["actionId"] = self.callable.id
69
- dict["keyCommand"] = self.callable.keyCommand == nil ? nil : [
70
- "input": self.callable.keyCommand!.input!,
71
- "modifiers": exportKeyCommandModifiers()
72
- ]
73
-
74
- dict["isAvailable"] = isAvailable()
75
- dict["isEnabled"] = isAvailable()
76
- dict["label"] = label()
77
- dict["detail"] = detail()
78
- dict["glyphName"] = glyphName()
79
-
80
- return dict
81
- }
82
-
83
- private func exportKeyCommandModifiers() -> Int {
84
- var exportedValue = 0
85
- let keyCommand = self.callable.keyCommand!
86
-
87
- if keyCommand.modifierFlags.contains(.control) {
88
- exportedValue += 1 << 0
89
- }
90
-
91
- if keyCommand.modifierFlags.contains(.alternate) {
92
- exportedValue += 1 << 1
93
- }
94
-
95
- if keyCommand.modifierFlags.contains(.command) {
96
- exportedValue += 1 << 2
97
- }
98
-
99
- if keyCommand.modifierFlags.contains(.shift) {
100
- exportedValue += 1 << 3
101
- }
102
-
103
- return exportedValue
104
- }
105
- }
@@ -1,33 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public protocol DevMenuDataSourceItem {
7
- @objc
8
- func serialize() -> [String: Any]
9
- }
10
-
11
- public typealias DevMenuDataSourceResolver = ([DevMenuDataSourceItem]) -> Void
12
-
13
- @objc
14
- public protocol DevMenuDataSourceProtocol {
15
- var id: String { get }
16
-
17
- func fetchData(resolve: @escaping DevMenuDataSourceResolver)
18
- }
19
-
20
- @objc
21
- public class DevMenuListDataSource: NSObject, DevMenuDataSourceProtocol {
22
- public var id: String
23
- private var dataFetcher: (@escaping ([DevMenuSelectionList.Item]) -> Void) -> Void
24
-
25
- public init(id: String, dataFetcher: @escaping (@escaping ([DevMenuSelectionList.Item]) -> Void) -> Void) {
26
- self.id = id
27
- self.dataFetcher = dataFetcher
28
- }
29
-
30
- public func fetchData(resolve: @escaping ([DevMenuDataSourceItem]) -> Void) {
31
- dataFetcher(resolve)
32
- }
33
- }
@@ -1,64 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
- import UIKit
5
-
6
- @objc
7
- public protocol DevMenuCallableProvider {
8
- @objc
9
- optional func registerCallable() -> DevMenuExportedCallable?
10
- }
11
-
12
- @objc
13
- public class DevMenuExportedCallable: NSObject {
14
- @objc
15
- public let id: String
16
-
17
- @objc
18
- init(withId id: String) {
19
- self.id = id
20
- }
21
- }
22
-
23
- @objc
24
- public class DevMenuExportedFunction: DevMenuExportedCallable {
25
- @objc
26
- public var function: ([String: Any]?) -> Void
27
-
28
- @objc
29
- public init(withId id: String, withFunction function: @escaping ([String: Any]?) -> Void) {
30
- self.function = function
31
- super.init(withId: id)
32
- }
33
-
34
- public func call(args: [String: Any]?) {
35
- function(args)
36
- }
37
- }
38
-
39
- @objc
40
- public class DevMenuExportedAction: DevMenuExportedCallable {
41
- @objc
42
- public var action: () -> Void
43
-
44
- @objc
45
- public private(set) var keyCommand: UIKeyCommand?
46
-
47
- @objc
48
- public var isAvailable: () -> Bool = { true }
49
-
50
- @objc
51
- public init(withId id: String, withAction action: @escaping () -> Void) {
52
- self.action = action
53
- super.init(withId: id)
54
- }
55
-
56
- public func call() {
57
- action()
58
- }
59
-
60
- @objc
61
- public func registerKeyCommand(input: String, modifiers: UIKeyModifierFlags) {
62
- keyCommand = UIKeyCommand(input: input, modifierFlags: modifiers, action: #selector(DevMenuUIResponderExtensionProtocol.EXDevMenu_handleKeyCommand(_:)))
63
- }
64
- }
@@ -1,37 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- open class DevMenuGroup: DevMenuScreenItem, DevMenuItemsContainerProtocol {
7
- let container = DevMenuItemsContainer()
8
-
9
- @objc
10
- public init() {
11
- super.init(type: .Group)
12
- }
13
-
14
- @objc
15
- public func addItem(_ item: DevMenuScreenItem) {
16
- container.addItem(item)
17
- }
18
-
19
- public func getRootItems() -> [DevMenuScreenItem] {
20
- return container.getRootItems()
21
- }
22
-
23
- public func getAllItems() -> [DevMenuScreenItem] {
24
- return container.getAllItems()
25
- }
26
-
27
- public func serializeItems() -> [[String: Any]] {
28
- return container.serializeItems()
29
- }
30
-
31
- @objc
32
- public override func serialize() -> [String: Any] {
33
- var dict = super.serialize()
34
- dict["items"] = serializeItems()
35
- return dict
36
- }
37
- }
@@ -1,29 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- open class DevMenuItem: NSObject {
7
- @objc(DevMenuItemType)
8
- public enum ItemType: Int {
9
- case Action = 1
10
- case Group = 2
11
- case Screen = 3
12
- case Link = 4
13
- case SelectionList = 5
14
- }
15
-
16
- @objc
17
- public let type: ItemType
18
-
19
- init(type: ItemType) {
20
- self.type = type
21
- }
22
-
23
- @objc
24
- open func serialize() -> [String: Any] {
25
- return [
26
- "type": type.rawValue
27
- ]
28
- }
29
- }
@@ -1,32 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public class DevMenuItemsContainer: NSObject, DevMenuItemsContainerProtocol {
7
- private var items: [DevMenuScreenItem] = []
8
-
9
- public func getRootItems() -> [DevMenuScreenItem] {
10
- return items.sorted { $0.importance > $1.importance }
11
- }
12
-
13
- public func getAllItems() -> [DevMenuScreenItem] {
14
- var result: [DevMenuScreenItem] = []
15
- for item in items {
16
- result.append(item)
17
- if let container = item as? DevMenuItemsContainerProtocol {
18
- result.append(contentsOf: container.getAllItems())
19
- }
20
- }
21
- return result.sorted { $0.importance > $1.importance }
22
- }
23
-
24
- @objc
25
- public func addItem(_ item: DevMenuScreenItem) {
26
- items.append(item)
27
- }
28
-
29
- func serializeItems() -> [[String: Any]] {
30
- return getRootItems().map({ $0.serialize() })
31
- }
32
- }
@@ -1,12 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public protocol DevMenuItemsContainerProtocol {
7
- @objc
8
- func getRootItems() -> [DevMenuScreenItem]
9
-
10
- @objc
11
- func getAllItems() -> [DevMenuScreenItem]
12
- }
@@ -1,28 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public class DevMenuLink: DevMenuScreenItem {
7
- var target: String
8
-
9
- @objc
10
- open var label: () -> String = { "" }
11
-
12
- @objc
13
- open var glyphName: () -> String = { "" }
14
-
15
- public init(withTarget target: String) {
16
- self.target = target
17
- super.init(type: .Link)
18
- }
19
-
20
- @objc
21
- open override func serialize() -> [String: Any] {
22
- var dict = super.serialize()
23
- dict["target"] = target
24
- dict["label"] = label()
25
- dict["glyphName"] = glyphName()
26
- return dict
27
- }
28
- }
@@ -1,37 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- public class DevMenuScreen: DevMenuItem, DevMenuItemsContainerProtocol {
7
- let container = DevMenuItemsContainer()
8
- public private(set) var screenName: String
9
-
10
- public func getRootItems() -> [DevMenuScreenItem] {
11
- return container.getRootItems()
12
- }
13
-
14
- public func getAllItems() -> [DevMenuScreenItem] {
15
- return container.getAllItems()
16
- }
17
-
18
- public func addItem(_ item: DevMenuScreenItem) {
19
- container.addItem(item)
20
- }
21
-
22
- func serializeItems() -> [[String: Any]] {
23
- return container.serializeItems()
24
- }
25
-
26
- public init(_ screenName: String) {
27
- self.screenName = screenName
28
- super.init(type: .Screen)
29
- }
30
-
31
- public override func serialize() -> [String: Any] {
32
- var dict = super.serialize()
33
- dict["screenName"] = screenName
34
- dict["items"] = serializeItems()
35
- return dict
36
- }
37
- }
@@ -1,26 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc
6
- open class DevMenuScreenItem: DevMenuItem {
7
- // Static members fit better than enum as we allow any other number.
8
- static public let ImportanceLowest = -200
9
- static public let ImportanceLow = -100
10
- static public let ImportanceMedium = 0
11
- static public let ImportanceHigh = 100
12
- static public let ImportanceHighest = 200
13
-
14
- // This enum is just for Objective-C compatibility, where values are automatically casted to integers.
15
- @objc(DevMenuItemImportance)
16
- public enum ItemImportance: Int {
17
- case Lowest = -200
18
- case Low = -100
19
- case Medium = 0
20
- case High = 100
21
- case Highest = 200
22
- }
23
-
24
- @objc
25
- open var importance: Int = ItemImportance.Medium.rawValue
26
- }
@@ -1,91 +0,0 @@
1
- // Copyright 2015-present 650 Industries. All rights reserved.
2
-
3
- import Foundation
4
-
5
- @objc(EXDevMenuSelectionList)
6
- public class DevMenuSelectionList: DevMenuScreenItem, DevMenuCallableProvider {
7
- @objc(EXDevMenuItem)
8
- public class Item: NSObject, DevMenuDataSourceItem {
9
- @objc(EXDevMenuTag)
10
- public class Tag: NSObject {
11
- @objc
12
- public var text: () -> String = { "" }
13
-
14
- @objc
15
- public var glyphName: () -> String? = { nil }
16
-
17
- fileprivate func serialize() -> [String: Any] {
18
- return [
19
- "text": text(),
20
- "glyphName": glyphName() ?? NSNull()
21
- ]
22
- }
23
- }
24
-
25
- @objc
26
- public var onClickData: () -> [String: Any]? = { nil }
27
-
28
- @objc
29
- public var title: () -> String = { "" }
30
-
31
- @objc
32
- public var warning: () -> String? = { nil }
33
-
34
- @objc
35
- public var isChecked: () -> Bool = { false }
36
-
37
- @objc
38
- public var tags: () -> [Tag] = { [] }
39
-
40
- public func serialize() -> [String: Any] {
41
- return [
42
- "title": title(),
43
- "warning": warning() ?? NSNull(),
44
- "isChecked": isChecked(),
45
- "tags": tags().map { $0.serialize() },
46
- "onClickData": onClickData() ?? NSNull()
47
- ]
48
- }
49
- }
50
-
51
- public static var ActionID = 1
52
- private let callable: DevMenuExportedFunction
53
- private var items: [Item] = []
54
- private let dataSourceId: String?
55
-
56
- @objc
57
- public func addItem(_ item: Item) {
58
- items.append(item)
59
- }
60
-
61
- @objc
62
- public convenience init() {
63
- self.init(dataSourceId: nil)
64
- }
65
-
66
- @objc
67
- public init(dataSourceId: String?) {
68
- self.dataSourceId = dataSourceId
69
- self.callable = DevMenuExportedFunction(withId: "expo-dev-menu.selection-list.#\(DevMenuSelectionList.ActionID)", withFunction: { _ in })
70
- DevMenuSelectionList.ActionID += 1
71
- super.init(type: .SelectionList)
72
- }
73
-
74
- @objc
75
- public override func serialize() -> [String: Any] {
76
- var dict = super.serialize()
77
- dict["items"] = items.map { $0.serialize() }
78
- dict["dataSourceId"] = dataSourceId ?? NSNull()
79
- dict["actionId"] = self.callable.id
80
- return dict
81
- }
82
-
83
- @objc
84
- public func addOnClick(hander: @escaping ([String: Any]?) -> Void) {
85
- self.callable.function = hander
86
- }
87
-
88
- public func registerCallable() -> DevMenuExportedCallable? {
89
- return self.callable
90
- }
91
- }
@@ -1,42 +0,0 @@
1
- import Quick
2
- import Nimble
3
-
4
- @testable import EXDevMenuInterface
5
-
6
- class DevMenuActionTest: QuickSpec {
7
- override class func spec() {
8
- it("Action should be serializable") {
9
- let action = DevMenuAction(withId: "action-1", {})
10
- action.isAvailable = { true }
11
- action.isEnabled = { true }
12
- action.label = { "action-1-label" }
13
- action.detail = { "action-1-details" }
14
- action.glyphName = { "action-1-glyphname" }
15
- action.registerKeyCommand(input: "r", modifiers: .command)
16
-
17
- let serilizedData = action.serialize()
18
-
19
- expect(serilizedData["type"] as? Int).to(equal(ItemType.action.rawValue))
20
- expect(serilizedData["actionId"] as? String).to(equal("action-1"))
21
- expect(serilizedData["isAvailable"] as? Bool).to(beTrue())
22
- expect(serilizedData["isEnabled"] as? Bool).to(beTrue())
23
- expect(serilizedData["label"] as? String).to(equal("action-1-label"))
24
- expect(serilizedData["detail"] as? String).to(equal("action-1-details"))
25
- expect(serilizedData["glyphName"] as? String).to(equal("action-1-glyphname"))
26
-
27
- let keyCommand = serilizedData["keyCommand"] as! [String: Any]
28
-
29
- expect(keyCommand["input"] as? String).to(equal("r"))
30
- expect(keyCommand["modifiers"] as? Int).to(equal(1 << 2))
31
- }
32
-
33
- it("Action callable should be contain passed action") {
34
- var wasCalled = false
35
- let action = DevMenuAction(withId: "action-1", { wasCalled = true })
36
-
37
- action.callable.call()
38
-
39
- expect(wasCalled).to(beTrue())
40
- }
41
- }
42
- }
@@ -1,63 +0,0 @@
1
- import Quick
2
- import Nimble
3
-
4
- @testable import EXDevMenuInterface
5
-
6
- class DevMenuItemsContainerTest: QuickSpec {
7
- override class func spec() {
8
- it("should respect importance") {
9
- let container = DevMenuItemsContainer()
10
-
11
- let seeder = [("action-1", ItemImportance.lowest), ("action-2", ItemImportance.medium), ("action-3", ItemImportance.highest)]
12
-
13
- seeder.forEach { actionDate in
14
- let action = DevMenuAction(withId: actionDate.0)
15
- action.label = { actionDate.0 }
16
- action.importance = actionDate.1.rawValue
17
-
18
- container.addItem(action)
19
- }
20
- let items = container.getRootItems()
21
-
22
- expect(items.count).to(equal(3))
23
- expect((items[0] as! DevMenuAction).label()).to(equal("action-3"))
24
- expect((items[1] as! DevMenuAction).label()).to(equal("action-2"))
25
- expect((items[2] as! DevMenuAction).label()).to(equal("action-1"))
26
- }
27
-
28
- it("should unwrap other containers") {
29
- let container = DevMenuItemsContainer()
30
- container.addItem(DevMenuAction(withId: "action-1"))
31
- let innerContainer = DevMenuGroup()
32
- innerContainer.addItem(DevMenuAction(withId: "action-2"))
33
- container.addItem(innerContainer)
34
-
35
- let items = container.getAllItems()
36
-
37
- expect(items.count).to(equal(3))
38
- expect(items[0] as? DevMenuAction).toNot(beNil())
39
- expect(items[1] as? DevMenuGroup).toNot(beNil())
40
- expect(items[2] as? DevMenuAction).toNot(beNil())
41
- }
42
-
43
- it("should serilize items") {
44
- let container = DevMenuItemsContainer()
45
- container.addItem(DevMenuAction(withId: "action-1"))
46
- let innerContainer = DevMenuGroup()
47
- innerContainer.addItem(DevMenuAction(withId: "action-2"))
48
- container.addItem(innerContainer)
49
-
50
- let items = container.serializeItems()
51
-
52
- expect(items.count).to(equal(2))
53
- expect(items[0]["type"] as? Int).to(equal(ItemType.action.rawValue))
54
- expect(items[0]["actionId"] as? String).to(equal("action-1"))
55
-
56
- expect(items[1]["type"] as? Int).to(equal(ItemType.group.rawValue))
57
-
58
- let innerItem = (items[1]["items"] as! [[String: Any]])[0]
59
- expect(innerItem["type"] as? Int).to(equal(ItemType.action.rawValue))
60
- expect(innerItem["actionId"] as? String).to(equal("action-2"))
61
- }
62
- }
63
- }
@@ -1,20 +0,0 @@
1
- import Quick
2
- import Nimble
3
-
4
- @testable import EXDevMenuInterface
5
-
6
- class DevMenuLinkTest: QuickSpec {
7
- override class func spec() {
8
- it("Link should be serializable") {
9
- let link = DevMenuLink(withTarget: "target-1")
10
- link.glyphName = { "link-1-glyph" }
11
- link.label = { "link-1-label" }
12
-
13
- let serilizedData = link.serialize()
14
-
15
- expect(serilizedData["type"] as? Int).to(equal(ItemType.link.rawValue))
16
- expect(serilizedData["label"] as? String).to(equal("link-1-label"))
17
- expect(serilizedData["glyphName"] as? String).to(equal("link-1-glyph"))
18
- }
19
- }
20
- }
@@ -1,17 +0,0 @@
1
- import Quick
2
- import Nimble
3
-
4
- @testable import EXDevMenuInterface
5
-
6
- class DevMenuScreenTest: QuickSpec {
7
- override class func spec() {
8
- it("Screen should be serializable") {
9
- let screen = DevMenuScreen("screen-1")
10
-
11
- let serilizedData = screen.serialize()
12
-
13
- expect(serilizedData["type"] as? Int).to(equal(ItemType.screen.rawValue))
14
- expect(serilizedData["screenName"] as? String).to(equal("screen-1"))
15
- }
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import Quick
2
- import Nimble
3
-
4
- @testable import EXDevMenuInterface
5
-
6
- class DevMenuSelectionListTest: QuickSpec {
7
- override class func spec() {
8
- it("List should be serializable") {
9
- let list = DevMenuSelectionList()
10
-
11
- let serilizedData = list.serialize()
12
-
13
- expect(serilizedData["type"] as? Int).to(equal(ItemType.selectionList.rawValue))
14
- expect(serilizedData["actionId"] as? String).toNot(beNil())
15
- }
16
- }
17
- }