expo-dev-menu-interface 0.3.3 → 0.4.2

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 (31) hide show
  1. package/Info-generated.plist +22 -0
  2. package/README.md +1 -1
  3. package/android/build.gradle +3 -2
  4. package/android/src/main/java/expo/interfaces/devmenu/DevMenuManagerInterface.kt +8 -0
  5. package/expo-dev-menu-interface.podspec +8 -1
  6. package/ios/DevMenuBridgeProtocol.swift +2 -0
  7. package/ios/DevMenuDelegateProtocol.swift +3 -0
  8. package/ios/DevMenuExtensionProtocol.swift +2 -0
  9. package/ios/DevMenuManagerProtocol.swift +2 -0
  10. package/ios/DevMenuManagerProviderProtocol.swift +2 -0
  11. package/ios/DevMenuUIResponderExtensionProtocol.swift +3 -0
  12. package/ios/ExpoApiClient/DevMenuEASUpdates.swift +2 -0
  13. package/ios/ExpoApiClient/DevMenuExpoApiClientProtocol.swift +2 -0
  14. package/ios/MenuItems/DevMenuAction.swift +8 -0
  15. package/ios/MenuItems/DevMenuDataSource.swift +2 -0
  16. package/ios/MenuItems/DevMenuExportedCallable.swift +3 -0
  17. package/ios/MenuItems/DevMenuGroup.swift +2 -0
  18. package/ios/MenuItems/DevMenuItem.swift +2 -0
  19. package/ios/MenuItems/DevMenuItemsContainer.swift +2 -0
  20. package/ios/MenuItems/DevMenuItemsContainerProtocol.swift +2 -0
  21. package/ios/MenuItems/DevMenuLink.swift +2 -0
  22. package/ios/MenuItems/DevMenuScreen.swift +2 -0
  23. package/ios/MenuItems/DevMenuScreenItem.swift +2 -0
  24. package/ios/MenuItems/DevMenuSelectionList.swift +2 -0
  25. package/ios/Tests/DevMenuActionTest.swift +42 -0
  26. package/ios/Tests/DevMenuEASUpdatesTest.swift +86 -0
  27. package/ios/Tests/DevMenuItemsContainerTest.swift +63 -0
  28. package/ios/Tests/DevMenuLinkTest.swift +20 -0
  29. package/ios/Tests/DevMenuScreenTest.swift +17 -0
  30. package/ios/Tests/DevMenuSelectionListTest.swift +17 -0
  31. package/package.json +2 -2
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>expo.dev.menu.interface</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>EXDevMenuInterface</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>0.3.2</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>0</string>
21
+ </dict>
22
+ </plist>
package/README.md CHANGED
@@ -8,7 +8,7 @@ For managed [managed](https://docs.expo.io/versions/latest/introduction/managed-
8
8
 
9
9
  # Installation in bare React Native projects
10
10
 
11
- For bare React Native projects, you must ensure that you have [installed and configured the `react-native-unimodules` package](https://github.com/expo/expo/tree/master/packages/react-native-unimodules) before continuing.
11
+ For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
12
12
 
13
13
  ### Add the package to your npm dependencies
14
14
 
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '0.3.3'
6
+ version = '0.4.2'
7
7
 
8
8
  buildscript {
9
9
  // Simple helper that allows the root project to override versions declared by this library.
@@ -57,7 +57,7 @@ android {
57
57
  minSdkVersion safeExtGet("minSdkVersion", 21)
58
58
  targetSdkVersion safeExtGet("targetSdkVersion", 30)
59
59
  versionCode 6
60
- versionName '0.3.3'
60
+ versionName '0.4.2'
61
61
  }
62
62
  lintOptions {
63
63
  abortOnError false
@@ -71,4 +71,5 @@ dependencies {
71
71
  implementation 'com.squareup.okhttp3:okhttp:3.14.9'
72
72
 
73
73
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
74
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
74
75
  }
@@ -8,6 +8,7 @@ import com.facebook.react.ReactNativeHost
8
8
  import com.facebook.react.bridge.ReadableMap
9
9
  import expo.interfaces.devmenu.expoapi.DevMenuExpoApiClientInterface
10
10
  import expo.interfaces.devmenu.items.DevMenuDataSourceItem
11
+ import kotlinx.coroutines.CoroutineScope
11
12
 
12
13
  interface DevMenuManagerInterface {
13
14
  /**
@@ -110,5 +111,12 @@ interface DevMenuManagerInterface {
110
111
  */
111
112
  fun isInitialized(): Boolean
112
113
 
114
+ /**
115
+ * Whether to automatically show the dev menu on app load. Defaults to true if not set.
116
+ */
117
+ fun setCanLaunchDevMenuOnStart(shouldAutoLaunch: Boolean)
118
+
113
119
  suspend fun fetchDataSource(id: String): List<DevMenuDataSourceItem>
120
+
121
+ val coroutineScope: CoroutineScope
114
122
  }
@@ -13,13 +13,20 @@ Pod::Spec.new do |s|
13
13
  s.platform = :ios, '11.0'
14
14
  s.swift_version = '5.2'
15
15
  s.source = { git: 'https://github.com/expo/expo.git' }
16
+ s.static_framework = true
16
17
  s.source_files = 'ios/**/*.{h,m,swift}'
17
18
  s.preserve_paths = 'ios/**/*.{h,m,swift}'
19
+ s.exclude_files = ['ios/Tests/**/*.{h,m,swift}']
18
20
  s.requires_arc = true
19
21
  s.header_dir = 'EXDevMenuInterface'
20
22
 
21
23
  # Swift/Objective-C compatibility
22
24
  s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
23
25
 
24
- s.dependency 'React'
26
+ s.test_spec 'Tests' do |test_spec|
27
+ test_spec.platform = :ios, '12.0'
28
+ test_spec.source_files = 'ios/Tests/**/*.{h,m,swift}'
29
+ test_spec.dependency 'Quick'
30
+ test_spec.dependency 'Nimble'
31
+ end
25
32
  end
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuBridgeProtocol {
5
7
  @objc
@@ -1,5 +1,8 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+ import UIKit
5
+
3
6
  @objc
4
7
  public protocol DevMenuDelegateProtocol {
5
8
  /**
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuExtensionSettingsProtocol {
5
7
  func wasRunOnDevelopmentBridge() -> Bool
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuManagerProtocol {
5
7
  /**
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuManagerProviderProtocol {
5
7
 
@@ -1,5 +1,8 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+ import UIKit
5
+
3
6
  @objc
4
7
  public protocol DevMenuUIResponderExtensionProtocol {
5
8
 
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuConstructibleFromDictionary {
5
7
  @objc
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  public typealias HTTPCompletionHandler = (Data?, URLResponse?, Error?) -> Void
4
6
 
5
7
  @objc
@@ -1,5 +1,8 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+ import UIKit
5
+
3
6
  @objc
4
7
  open class DevMenuAction: DevMenuScreenItem, DevMenuCallableProvider {
5
8
  @objc
@@ -45,6 +48,11 @@ open class DevMenuAction: DevMenuScreenItem, DevMenuCallableProvider {
45
48
  self.callable.action = action
46
49
  }
47
50
 
51
+ @objc
52
+ public convenience init(withId id: String, _ action: @escaping () -> ()) {
53
+ self.init(withId: id, action: action)
54
+ }
55
+
48
56
  public func registerCallable() -> DevMenuExportedCallable? {
49
57
  return self.callable
50
58
  }
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuDataSourceItem {
5
7
  @objc
@@ -1,5 +1,8 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+ import UIKit
5
+
3
6
  @objc
4
7
  public protocol DevMenuCallableProvider {
5
8
  @objc
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  open class DevMenuGroup: DevMenuScreenItem, DevMenuItemsContainerProtocol {
5
7
  let container = DevMenuItemsContainer()
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  open class DevMenuItem: NSObject {
5
7
  @objc(DevMenuItemType)
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public class DevMenuItemsContainer: NSObject, DevMenuItemsContainerProtocol {
5
7
  private var items: [DevMenuScreenItem] = []
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public protocol DevMenuItemsContainerProtocol {
5
7
  @objc
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public class DevMenuLink: DevMenuScreenItem {
5
7
  var target: String
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public class DevMenuScreen : DevMenuItem, DevMenuItemsContainerProtocol {
5
7
  let container = DevMenuItemsContainer()
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  open class DevMenuScreenItem: DevMenuItem {
5
7
  // Static members fit better than enum as we allow any other number.
@@ -1,5 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ import Foundation
4
+
3
5
  @objc
4
6
  public class DevMenuSelectionList: DevMenuScreenItem, DevMenuCallableProvider {
5
7
  @objc
@@ -0,0 +1,42 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuActionTest: QuickSpec {
7
+ override 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
+ }
@@ -0,0 +1,86 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuEASUpdatesTest: QuickSpec {
7
+ override func spec() {
8
+ it("Channel constructor should populate all fields") {
9
+ let seeder = [
10
+ "id": "1234",
11
+ "name": "channel-1",
12
+ "createdAt": "1635508863",
13
+ "updatedAt": "1635508873"
14
+ ]
15
+
16
+ let channel = DevMenuEASUpdates.Channel(dictionary: seeder)
17
+
18
+ expect(channel.id).to(equal("1234"))
19
+ expect(channel.name).to(equal("channel-1"))
20
+ expect(channel.createdAt).to(equal("1635508863"))
21
+ expect(channel.updatedAt).to(equal("1635508873"))
22
+ }
23
+
24
+ it("Update constructor should populate all fields") {
25
+ let seeder = [
26
+ "id": "1234",
27
+ "message": "update-1",
28
+ "platform": "ios",
29
+ "runtimeVersion": "1",
30
+ "createdAt": "1635508863",
31
+ "updatedAt": "1635508873"
32
+ ]
33
+
34
+ let update = DevMenuEASUpdates.Update(dictionary: seeder)
35
+
36
+ expect(update.id).to(equal("1234"))
37
+ expect(update.message).to(equal("update-1"))
38
+ expect(update.platform).to(equal("ios"))
39
+ expect(update.runtimeVersion).to(equal("1"))
40
+ expect(update.createdAt).to(equal("1635508863"))
41
+ expect(update.updatedAt).to(equal("1635508873"))
42
+ }
43
+
44
+ it("Branch constructor should populate all fields") {
45
+ let seeder = [
46
+ "id": "1",
47
+ "updates": [
48
+ [
49
+ "id": "1234",
50
+ "message": "update-1",
51
+ "platform": "ios",
52
+ "runtimeVersion": "1",
53
+ "createdAt": "1635508863",
54
+ "updatedAt": "1635508873"
55
+ ],
56
+ [
57
+ "id": "9876",
58
+ "message": "update-2",
59
+ "platform": "ios",
60
+ "runtimeVersion": "2",
61
+ "createdAt": "1635508863",
62
+ "updatedAt": "1635508873"
63
+ ]
64
+ ]
65
+ ] as [String : Any]
66
+
67
+ let branch = DevMenuEASUpdates.Branch(dictionary: seeder)
68
+ let update1 = branch.updates[0]
69
+ let update2 = branch.updates[1]
70
+
71
+ expect(branch.id).to(equal("1"))
72
+ expect(update1.id).to(equal("1234"))
73
+ expect(update1.message).to(equal("update-1"))
74
+ expect(update1.platform).to(equal("ios"))
75
+ expect(update1.runtimeVersion).to(equal("1"))
76
+ expect(update1.createdAt).to(equal("1635508863"))
77
+ expect(update1.updatedAt).to(equal("1635508873"))
78
+ expect(update2.id).to(equal("9876"))
79
+ expect(update2.message).to(equal("update-2"))
80
+ expect(update2.platform).to(equal("ios"))
81
+ expect(update2.runtimeVersion).to(equal("2"))
82
+ expect(update2.createdAt).to(equal("1635508863"))
83
+ expect(update2.updatedAt).to(equal("1635508873"))
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,63 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuItemsContainerTest: QuickSpec {
7
+ override 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
+ }
@@ -0,0 +1,20 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuLinkTest: QuickSpec {
7
+ override 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
+ }
@@ -0,0 +1,17 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuScreenTest: QuickSpec {
7
+ override 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
+ }
@@ -0,0 +1,17 @@
1
+ import Quick
2
+ import Nimble
3
+
4
+ @testable import EXDevMenuInterface
5
+
6
+ class DevMenuSelectionListTest: QuickSpec {
7
+ override 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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-dev-menu-interface",
3
- "version": "0.3.3",
3
+ "version": "0.4.2",
4
4
  "description": "Interface for expo-dev-menu",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -22,5 +22,5 @@
22
22
  "author": "650 Industries, Inc.",
23
23
  "license": "MIT",
24
24
  "homepage": "https://docs.expo.io",
25
- "gitHead": "5b7ae72196358c9ded95c2ad578383c08df8684b"
25
+ "gitHead": "7bb3c874946fd9b20e25601b155309080b08b5cb"
26
26
  }