mirror of
https://github.com/flutter/packages.git
synced 2025-07-02 08:34:31 +08:00
[quick_actions] convert to pigeon (#5159)
Converts from direct use of method channels to using Pigeon. Part of https://github.com/flutter/flutter/issues/117844 fixes https://github.com/flutter/flutter/issues/117913 fixes https://github.com/flutter/flutter/issues/117112
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
|
## 1.0.8
|
||||||
|
|
||||||
|
* Changes method channels to pigeon.
|
||||||
|
|
||||||
## 1.0.7
|
## 1.0.7
|
||||||
|
|
||||||
* Adds pub topics to package metadata.
|
* Adds pub topics to package metadata.
|
||||||
|
@ -16,12 +16,9 @@
|
|||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
E092A7ED28D10802005C7F67 /* MockMethodChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */; };
|
|
||||||
E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */; };
|
E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */; };
|
||||||
E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */; };
|
E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */; };
|
||||||
E092A7F428D110B3005C7F67 /* DefaultShortcutItemParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */; };
|
|
||||||
E092A7F628D128EB005C7F67 /* RunnerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F528D128EB005C7F67 /* RunnerUITests.swift */; };
|
E092A7F628D128EB005C7F67 /* RunnerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E092A7F528D128EB005C7F67 /* RunnerUITests.swift */; };
|
||||||
E0A075D529147FE200329BAE /* MockShortcutItemParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -78,12 +75,9 @@
|
|||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
9D27FE1F0F21D4D47DDA16DE /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
9D27FE1F0F21D4D47DDA16DE /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
C35AD3650AB6BF850E016715 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
C35AD3650AB6BF850E016715 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockMethodChannel.swift; sourceTree = "<group>"; };
|
|
||||||
E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionsPluginTests.swift; sourceTree = "<group>"; };
|
E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuickActionsPluginTests.swift; sourceTree = "<group>"; };
|
||||||
E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemProvider.swift; sourceTree = "<group>"; };
|
E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemProvider.swift; sourceTree = "<group>"; };
|
||||||
E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultShortcutItemParserTests.swift; sourceTree = "<group>"; };
|
|
||||||
E092A7F528D128EB005C7F67 /* RunnerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerUITests.swift; sourceTree = "<group>"; };
|
E092A7F528D128EB005C7F67 /* RunnerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerUITests.swift; sourceTree = "<group>"; };
|
||||||
E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShortcutItemParser.swift; sourceTree = "<group>"; };
|
|
||||||
F0609304FBCAEC2289164BD5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
F0609304FBCAEC2289164BD5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -120,7 +114,6 @@
|
|||||||
E092A7F228D10908005C7F67 /* Mocks */,
|
E092A7F228D10908005C7F67 /* Mocks */,
|
||||||
33E20B3626EFCDFC00A4A191 /* Info.plist */,
|
33E20B3626EFCDFC00A4A191 /* Info.plist */,
|
||||||
E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */,
|
E092A7EB28D10802005C7F67 /* QuickActionsPluginTests.swift */,
|
||||||
E092A7F328D110B3005C7F67 /* DefaultShortcutItemParserTests.swift */,
|
|
||||||
);
|
);
|
||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -215,9 +208,7 @@
|
|||||||
E092A7F228D10908005C7F67 /* Mocks */ = {
|
E092A7F228D10908005C7F67 /* Mocks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E092A7EA28D10801005C7F67 /* MockMethodChannel.swift */,
|
|
||||||
E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */,
|
E092A7F028D10890005C7F67 /* MockShortcutItemProvider.swift */,
|
||||||
E0A075D429147FE200329BAE /* MockShortcutItemParser.swift */,
|
|
||||||
);
|
);
|
||||||
path = Mocks;
|
path = Mocks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -289,7 +280,7 @@
|
|||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1300;
|
LastUpgradeCheck = 1430;
|
||||||
ORGANIZATIONNAME = "The Flutter Authors";
|
ORGANIZATIONNAME = "The Flutter Authors";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
33E20B3126EFCDFC00A4A191 = {
|
33E20B3126EFCDFC00A4A191 = {
|
||||||
@ -364,6 +355,7 @@
|
|||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
);
|
);
|
||||||
name = "Thin Binary";
|
name = "Thin Binary";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
@ -435,10 +427,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */,
|
E092A7EE28D10802005C7F67 /* QuickActionsPluginTests.swift in Sources */,
|
||||||
E092A7ED28D10802005C7F67 /* MockMethodChannel.swift in Sources */,
|
|
||||||
E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */,
|
E092A7F128D10890005C7F67 /* MockShortcutItemProvider.swift in Sources */,
|
||||||
E0A075D529147FE200329BAE /* MockShortcutItemParser.swift in Sources */,
|
|
||||||
E092A7F428D110B3005C7F67 /* DefaultShortcutItemParserTests.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1300"
|
LastUpgradeVersion = "1430"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import Flutter
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
@testable import quick_actions_ios
|
|
||||||
|
|
||||||
class DefaultShortcutItemParserTests: XCTestCase {
|
|
||||||
|
|
||||||
func testParseShortcutItems() {
|
|
||||||
let rawItem = [
|
|
||||||
"type": "SearchTheThing",
|
|
||||||
"localizedTitle": "Search the thing",
|
|
||||||
"icon": "search_the_thing.png",
|
|
||||||
]
|
|
||||||
|
|
||||||
let expectedItem = UIApplicationShortcutItem(
|
|
||||||
type: "SearchTheThing",
|
|
||||||
localizedTitle: "Search the thing",
|
|
||||||
localizedSubtitle: nil,
|
|
||||||
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
|
||||||
userInfo: nil)
|
|
||||||
|
|
||||||
let parser = DefaultShortcutItemParser()
|
|
||||||
XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testParseShortcutItems_noIcon() {
|
|
||||||
let rawItem: [String: Any] = [
|
|
||||||
"type": "SearchTheThing",
|
|
||||||
"localizedTitle": "Search the thing",
|
|
||||||
"icon": NSNull(),
|
|
||||||
]
|
|
||||||
|
|
||||||
let expectedItem = UIApplicationShortcutItem(
|
|
||||||
type: "SearchTheThing",
|
|
||||||
localizedTitle: "Search the thing",
|
|
||||||
localizedSubtitle: nil,
|
|
||||||
icon: nil,
|
|
||||||
userInfo: nil)
|
|
||||||
|
|
||||||
let parser = DefaultShortcutItemParser()
|
|
||||||
XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testParseShortcutItems_noType() {
|
|
||||||
let rawItem = [
|
|
||||||
"localizedTitle": "Search the thing",
|
|
||||||
"icon": "search_the_thing.png",
|
|
||||||
]
|
|
||||||
|
|
||||||
let parser = DefaultShortcutItemParser()
|
|
||||||
XCTAssertEqual(parser.parseShortcutItems([rawItem]), [])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testParseShortcutItems_noLocalizedTitle() {
|
|
||||||
let rawItem = [
|
|
||||||
"type": "SearchTheThing",
|
|
||||||
"icon": "search_the_thing.png",
|
|
||||||
]
|
|
||||||
|
|
||||||
let parser = DefaultShortcutItemParser()
|
|
||||||
XCTAssertEqual(parser.parseShortcutItems([rawItem]), [])
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@testable import quick_actions_ios
|
|
||||||
|
|
||||||
final class MockMethodChannel: MethodChannel {
|
|
||||||
var invokeMethodStub: ((_ methods: String, _ arguments: Any?) -> Void)? = nil
|
|
||||||
func invokeMethod(_ method: String, arguments: Any?) {
|
|
||||||
invokeMethodStub?(method, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@testable import quick_actions_ios
|
|
||||||
|
|
||||||
final class MockShortcutItemParser: ShortcutItemParser {
|
|
||||||
|
|
||||||
var parseShortcutItemsStub: ((_ items: [[String: Any]]) -> [UIApplicationShortcutItem])? = nil
|
|
||||||
|
|
||||||
func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] {
|
|
||||||
return parseShortcutItemsStub?(items) ?? []
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,14 +7,27 @@ import XCTest
|
|||||||
|
|
||||||
@testable import quick_actions_ios
|
@testable import quick_actions_ios
|
||||||
|
|
||||||
|
class MockFlutterApi: IOSQuickActionsFlutterApiProtocol {
|
||||||
|
/// Method to allow for async testing.
|
||||||
|
var launchActionCallback: ((String) -> Void)? = nil
|
||||||
|
|
||||||
|
func launchAction(
|
||||||
|
action actionArg: String, completion: @escaping (Result<Void, FlutterError>) -> Void
|
||||||
|
) {
|
||||||
|
self.launchActionCallback?(actionArg)
|
||||||
|
completion(.success(Void()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class QuickActionsPluginTests: XCTestCase {
|
class QuickActionsPluginTests: XCTestCase {
|
||||||
|
|
||||||
func testHandleMethodCall_setShortcutItems() {
|
func testHandleMethodCall_setShortcutItems() {
|
||||||
let rawItem = [
|
let rawItem = ShortcutItemMessage(
|
||||||
"type": "SearchTheThing",
|
type: "SearchTheThing",
|
||||||
"localizedTitle": "Search the thing",
|
localizedTitle: "Search the thing",
|
||||||
"icon": "search_the_thing.png",
|
icon: "search_the_thing.png"
|
||||||
]
|
)
|
||||||
|
|
||||||
let item = UIApplicationShortcutItem(
|
let item = UIApplicationShortcutItem(
|
||||||
type: "SearchTheThing",
|
type: "SearchTheThing",
|
||||||
localizedTitle: "Search the thing",
|
localizedTitle: "Search the thing",
|
||||||
@ -22,32 +35,15 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
||||||
userInfo: nil)
|
userInfo: nil)
|
||||||
|
|
||||||
let call = FlutterMethodCall(methodName: "setShortcutItems", arguments: [rawItem])
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
|
|
||||||
let mockChannel = MockMethodChannel()
|
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let parseShortcutItemsExpectation = expectation(
|
plugin.setShortcutItems(itemsList: [rawItem])
|
||||||
description: "parseShortcutItems must be called.")
|
|
||||||
mockShortcutItemParser.parseShortcutItemsStub = { items in
|
|
||||||
XCTAssertEqual(items as? [[String: String]], [rawItem])
|
|
||||||
parseShortcutItemsExpectation.fulfill()
|
|
||||||
return [item]
|
|
||||||
}
|
|
||||||
|
|
||||||
let resultExpectation = expectation(description: "result block must be called.")
|
|
||||||
plugin.handle(call) { result in
|
|
||||||
XCTAssertNil(result, "result block must be called with nil.")
|
|
||||||
resultExpectation.fulfill()
|
|
||||||
}
|
|
||||||
XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [item], "Must set shortcut items.")
|
XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [item], "Must set shortcut items.")
|
||||||
waitForExpectations(timeout: 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHandleMethodCall_clearShortcutItems() {
|
func testHandleMethodCall_clearShortcutItems() {
|
||||||
@ -58,82 +54,28 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
||||||
userInfo: nil)
|
userInfo: nil)
|
||||||
|
|
||||||
let call = FlutterMethodCall(methodName: "clearShortcutItems", arguments: nil)
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockChannel = MockMethodChannel()
|
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
let plugin = QuickActionsPlugin(
|
||||||
|
flutterApi: flutterApi,
|
||||||
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
|
|
||||||
mockShortcutItemProvider.shortcutItems = [item]
|
mockShortcutItemProvider.shortcutItems = [item]
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
plugin.clearShortcutItems()
|
||||||
channel: mockChannel,
|
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let resultExpectation = expectation(description: "result block must be called.")
|
|
||||||
plugin.handle(call) { result in
|
|
||||||
XCTAssertNil(result, "result block must be called with nil.")
|
|
||||||
resultExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [], "Must clear shortcut items.")
|
XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [], "Must clear shortcut items.")
|
||||||
waitForExpectations(timeout: 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHandleMethodCall_getLaunchAction() {
|
|
||||||
let call = FlutterMethodCall(methodName: "getLaunchAction", arguments: nil)
|
|
||||||
|
|
||||||
let mockChannel = MockMethodChannel()
|
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
|
||||||
channel: mockChannel,
|
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let resultExpectation = expectation(description: "result block must be called.")
|
|
||||||
plugin.handle(call) { result in
|
|
||||||
XCTAssertNil(result, "result block must be called with nil.")
|
|
||||||
resultExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForExpectations(timeout: 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHandleMethodCall_nonExistMethods() {
|
|
||||||
let call = FlutterMethodCall(methodName: "nonExist", arguments: nil)
|
|
||||||
|
|
||||||
let mockChannel = MockMethodChannel()
|
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
|
||||||
channel: mockChannel,
|
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let resultExpectation = expectation(description: "result block must be called.")
|
|
||||||
|
|
||||||
plugin.handle(call) { result in
|
|
||||||
XCTAssertEqual(
|
|
||||||
result as? NSObject, FlutterMethodNotImplemented,
|
|
||||||
"result block must be called with FlutterMethodNotImplemented")
|
|
||||||
resultExpectation.fulfill()
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForExpectations(timeout: 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testApplicationPerformActionForShortcutItem() {
|
func testApplicationPerformActionForShortcutItem() {
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let item = UIApplicationShortcutItem(
|
let item = UIApplicationShortcutItem(
|
||||||
type: "SearchTheThing",
|
type: "SearchTheThing",
|
||||||
@ -143,30 +85,29 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
userInfo: nil)
|
userInfo: nil)
|
||||||
|
|
||||||
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
||||||
mockChannel.invokeMethodStub = { method, arguments in
|
flutterApi.launchActionCallback = { aString in
|
||||||
XCTAssertEqual(method, "launch")
|
XCTAssertEqual(aString, item.type)
|
||||||
XCTAssertEqual(arguments as? String, item.type)
|
|
||||||
invokeMethodExpectation.fulfill()
|
invokeMethodExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
let actionResult = plugin.application(
|
let actionResult = plugin.application(
|
||||||
UIApplication.shared,
|
UIApplication.shared,
|
||||||
performActionFor: item
|
performActionFor: item
|
||||||
) { success in /* no-op */ }
|
) { success in
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
XCTAssert(actionResult, "performActionForShortcutItem must return true.")
|
XCTAssert(actionResult, "performActionForShortcutItem must return true.")
|
||||||
waitForExpectations(timeout: 1)
|
waitForExpectations(timeout: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testApplicationDidFinishLaunchingWithOptions_launchWithShortcut() {
|
func testApplicationDidFinishLaunchingWithOptions_launchWithShortcut() {
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let item = UIApplicationShortcutItem(
|
let item = UIApplicationShortcutItem(
|
||||||
type: "SearchTheThing",
|
type: "SearchTheThing",
|
||||||
@ -183,14 +124,12 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testApplicationDidFinishLaunchingWithOptions_launchWithoutShortcut() {
|
func testApplicationDidFinishLaunchingWithOptions_launchWithoutShortcut() {
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
|
let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
|
||||||
XCTAssert(
|
XCTAssert(
|
||||||
@ -198,18 +137,12 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testApplicationDidBecomeActive_launchWithoutShortcut() {
|
func testApplicationDidBecomeActive_launchWithoutShortcut() {
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
mockChannel.invokeMethodStub = { _, _ in
|
|
||||||
XCTFail("invokeMethod should not be called if launch without shortcut.")
|
|
||||||
}
|
|
||||||
|
|
||||||
let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
|
let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
|
||||||
XCTAssert(
|
XCTAssert(
|
||||||
@ -226,19 +159,16 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
||||||
userInfo: nil)
|
userInfo: nil)
|
||||||
|
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
||||||
mockChannel.invokeMethodStub = { method, arguments in
|
flutterApi.launchActionCallback = { aString in
|
||||||
XCTAssertEqual(method, "launch")
|
XCTAssertEqual(aString, item.type)
|
||||||
XCTAssertEqual(arguments as? String, item.type)
|
|
||||||
invokeMethodExpectation.fulfill()
|
invokeMethodExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,20 +191,19 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
|
||||||
userInfo: nil)
|
userInfo: nil)
|
||||||
|
|
||||||
let mockChannel = MockMethodChannel()
|
let flutterApi: MockFlutterApi = MockFlutterApi()
|
||||||
let mockShortcutItemProvider = MockShortcutItemProvider()
|
let mockShortcutItemProvider = MockShortcutItemProvider()
|
||||||
let mockShortcutItemParser = MockShortcutItemParser()
|
|
||||||
|
|
||||||
let plugin = QuickActionsPlugin(
|
let plugin = QuickActionsPlugin(
|
||||||
channel: mockChannel,
|
flutterApi: flutterApi,
|
||||||
shortcutItemProvider: mockShortcutItemProvider,
|
shortcutItemProvider: mockShortcutItemProvider)
|
||||||
shortcutItemParser: mockShortcutItemParser)
|
|
||||||
|
|
||||||
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
|
||||||
|
|
||||||
var invokeMehtodCount = 0
|
var invokeMethodCount = 0
|
||||||
mockChannel.invokeMethodStub = { method, arguments in
|
flutterApi.launchActionCallback = { aString in
|
||||||
invokeMehtodCount += 1
|
XCTAssertEqual(aString, item.type)
|
||||||
|
invokeMethodCount += 1
|
||||||
invokeMethodExpectation.fulfill()
|
invokeMethodExpectation.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +217,6 @@ class QuickActionsPluginTests: XCTestCase {
|
|||||||
plugin.applicationDidBecomeActive(UIApplication.shared)
|
plugin.applicationDidBecomeActive(UIApplication.shared)
|
||||||
waitForExpectations(timeout: 1)
|
waitForExpectations(timeout: 1)
|
||||||
|
|
||||||
XCTAssertEqual(invokeMehtodCount, 1, "shortcut should only be handled once per launch.")
|
XCTAssertEqual(invokeMethodCount, 1, "shortcut should only be handled once per launch.")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import Flutter
|
|
||||||
|
|
||||||
/// A channel for platform code to communicate with the Dart code.
|
|
||||||
protocol MethodChannel {
|
|
||||||
/// Invokes a method in Dart code.
|
|
||||||
/// - Parameter method the method name.
|
|
||||||
/// - Parameter arguments the method arguments.
|
|
||||||
func invokeMethod(_ method: String, arguments: Any?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A default implementation of the `MethodChannel` protocol.
|
|
||||||
extension FlutterMethodChannel: MethodChannel {}
|
|
@ -4,48 +4,36 @@
|
|||||||
|
|
||||||
import Flutter
|
import Flutter
|
||||||
|
|
||||||
public final class QuickActionsPlugin: NSObject, FlutterPlugin {
|
public final class QuickActionsPlugin: NSObject, FlutterPlugin, IOSQuickActionsApi {
|
||||||
|
|
||||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
let channel = FlutterMethodChannel(
|
let messenger = registrar.messenger()
|
||||||
name: "plugins.flutter.io/quick_actions_ios",
|
let flutterApi = IOSQuickActionsFlutterApi(binaryMessenger: messenger)
|
||||||
binaryMessenger: registrar.messenger())
|
let instance = QuickActionsPlugin(flutterApi: flutterApi)
|
||||||
let instance = QuickActionsPlugin(channel: channel)
|
IOSQuickActionsApiSetup.setUp(binaryMessenger: messenger, api: instance)
|
||||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
|
||||||
registrar.addApplicationDelegate(instance)
|
registrar.addApplicationDelegate(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let channel: MethodChannel
|
|
||||||
private let shortcutItemProvider: ShortcutItemProviding
|
private let shortcutItemProvider: ShortcutItemProviding
|
||||||
private let shortcutItemParser: ShortcutItemParser
|
private let flutterApi: IOSQuickActionsFlutterApiProtocol
|
||||||
/// The type of the shortcut item selected when launching the app.
|
/// The type of the shortcut item selected when launching the app.
|
||||||
private var launchingShortcutType: String? = nil
|
private var launchingShortcutType: String? = nil
|
||||||
|
|
||||||
init(
|
init(
|
||||||
channel: MethodChannel,
|
flutterApi: IOSQuickActionsFlutterApiProtocol,
|
||||||
shortcutItemProvider: ShortcutItemProviding = UIApplication.shared,
|
shortcutItemProvider: ShortcutItemProviding = UIApplication.shared
|
||||||
shortcutItemParser: ShortcutItemParser = DefaultShortcutItemParser()
|
|
||||||
) {
|
) {
|
||||||
self.channel = channel
|
self.flutterApi = flutterApi
|
||||||
self.shortcutItemProvider = shortcutItemProvider
|
self.shortcutItemProvider = shortcutItemProvider
|
||||||
self.shortcutItemParser = shortcutItemParser
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
func setShortcutItems(itemsList: [ShortcutItemMessage]) {
|
||||||
switch call.method {
|
shortcutItemProvider.shortcutItems =
|
||||||
case "setShortcutItems":
|
convertShortcutItemMessageListToUIApplicationShortcutItemList(itemsList)
|
||||||
// `arguments` must be an array of dictionaries
|
|
||||||
let items = call.arguments as! [[String: Any]]
|
|
||||||
shortcutItemProvider.shortcutItems = shortcutItemParser.parseShortcutItems(items)
|
|
||||||
result(nil)
|
|
||||||
case "clearShortcutItems":
|
|
||||||
shortcutItemProvider.shortcutItems = []
|
|
||||||
result(nil)
|
|
||||||
case "getLaunchAction":
|
|
||||||
result(nil)
|
|
||||||
case _:
|
|
||||||
result(FlutterMethodNotImplemented)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearShortcutItems() {
|
||||||
|
shortcutItemProvider.shortcutItems = []
|
||||||
}
|
}
|
||||||
|
|
||||||
public func application(
|
public func application(
|
||||||
@ -84,8 +72,37 @@ public final class QuickActionsPlugin: NSObject, FlutterPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleShortcut(_ shortcut: String) {
|
func handleShortcut(_ shortcut: String) {
|
||||||
channel.invokeMethod("launch", arguments: shortcut)
|
flutterApi.launchAction(action: shortcut) { _ in
|
||||||
|
// noop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func convertShortcutItemMessageListToUIApplicationShortcutItemList(
|
||||||
|
_ items: [ShortcutItemMessage]
|
||||||
|
) -> [UIApplicationShortcutItem] {
|
||||||
|
return items.compactMap { convertShortcutItemMessageToUIApplicationShortcutItem(with: $0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func convertShortcutItemMessageToUIApplicationShortcutItem(
|
||||||
|
with shortcut: ShortcutItemMessage
|
||||||
|
)
|
||||||
|
-> UIApplicationShortcutItem?
|
||||||
|
{
|
||||||
|
|
||||||
|
let type = shortcut.type
|
||||||
|
let localizedTitle = shortcut.localizedTitle
|
||||||
|
|
||||||
|
let icon = (shortcut.icon).map {
|
||||||
|
UIApplicationShortcutIcon(templateImageName: $0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// type and localizedTitle are required.
|
||||||
|
return UIApplicationShortcutItem(
|
||||||
|
type: type,
|
||||||
|
localizedTitle: localizedTitle,
|
||||||
|
localizedSubtitle: nil,
|
||||||
|
icon: icon,
|
||||||
|
userInfo: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// A parser that parses an array of raw shortcut items.
|
|
||||||
protocol ShortcutItemParser {
|
|
||||||
|
|
||||||
/// Parses an array of raw shortcut items into an array of UIApplicationShortcutItems
|
|
||||||
///
|
|
||||||
/// - Parameter items an array of raw shortcut items to be parsed.
|
|
||||||
/// - Returns an array of parsed shortcut items to be set.
|
|
||||||
///
|
|
||||||
func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A default implementation of the `ShortcutItemParser` protocol.
|
|
||||||
final class DefaultShortcutItemParser: ShortcutItemParser {
|
|
||||||
|
|
||||||
func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] {
|
|
||||||
return items.compactMap { deserializeShortcutItem(with: $0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func deserializeShortcutItem(with serialized: [String: Any]) -> UIApplicationShortcutItem?
|
|
||||||
{
|
|
||||||
guard
|
|
||||||
let type = serialized["type"] as? String,
|
|
||||||
let localizedTitle = serialized["localizedTitle"] as? String
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon = (serialized["icon"] as? String).map {
|
|
||||||
UIApplicationShortcutIcon(templateImageName: $0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// type and localizedTitle are required.
|
|
||||||
return UIApplicationShortcutItem(
|
|
||||||
type: type,
|
|
||||||
localizedTitle: localizedTitle,
|
|
||||||
localizedSubtitle: nil,
|
|
||||||
icon: icon,
|
|
||||||
userInfo: nil)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
// Autogenerated from Pigeon (v12.0.1), do not edit directly.
|
||||||
|
// See also: https://pub.dev/packages/pigeon
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
#if os(iOS)
|
||||||
|
import Flutter
|
||||||
|
#elseif os(macOS)
|
||||||
|
import FlutterMacOS
|
||||||
|
#else
|
||||||
|
#error("Unsupported platform.")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extension FlutterError: Error {}
|
||||||
|
|
||||||
|
private func isNullish(_ value: Any?) -> Bool {
|
||||||
|
return value is NSNull || value == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func wrapResult(_ result: Any?) -> [Any?] {
|
||||||
|
return [result]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func wrapError(_ error: Any) -> [Any?] {
|
||||||
|
if let flutterError = error as? FlutterError {
|
||||||
|
return [
|
||||||
|
flutterError.code,
|
||||||
|
flutterError.message,
|
||||||
|
flutterError.details
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
"\(error)",
|
||||||
|
"\(type(of: error))",
|
||||||
|
"Stacktrace: \(Thread.callStackSymbols)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func nilOrValue<T>(_ value: Any?) -> T? {
|
||||||
|
if value is NSNull { return nil }
|
||||||
|
return value as! T?
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Home screen quick-action shortcut item.
|
||||||
|
///
|
||||||
|
/// Generated class from Pigeon that represents data sent in messages.
|
||||||
|
struct ShortcutItemMessage {
|
||||||
|
/// The identifier of this item; should be unique within the app.
|
||||||
|
var type: String
|
||||||
|
/// Localized title of the item.
|
||||||
|
var localizedTitle: String
|
||||||
|
/// Name of native resource to be displayed as the icon for this item.
|
||||||
|
var icon: String? = nil
|
||||||
|
|
||||||
|
static func fromList(_ list: [Any?]) -> ShortcutItemMessage? {
|
||||||
|
let type = list[0] as! String
|
||||||
|
let localizedTitle = list[1] as! String
|
||||||
|
let icon: String? = nilOrValue(list[2])
|
||||||
|
|
||||||
|
return ShortcutItemMessage(
|
||||||
|
type: type,
|
||||||
|
localizedTitle: localizedTitle,
|
||||||
|
icon: icon
|
||||||
|
)
|
||||||
|
}
|
||||||
|
func toList() -> [Any?] {
|
||||||
|
return [
|
||||||
|
type,
|
||||||
|
localizedTitle,
|
||||||
|
icon,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private class IOSQuickActionsApiCodecReader: FlutterStandardReader {
|
||||||
|
override func readValue(ofType type: UInt8) -> Any? {
|
||||||
|
switch type {
|
||||||
|
case 128:
|
||||||
|
return ShortcutItemMessage.fromList(self.readValue() as! [Any?])
|
||||||
|
default:
|
||||||
|
return super.readValue(ofType: type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IOSQuickActionsApiCodecWriter: FlutterStandardWriter {
|
||||||
|
override func writeValue(_ value: Any) {
|
||||||
|
if let value = value as? ShortcutItemMessage {
|
||||||
|
super.writeByte(128)
|
||||||
|
super.writeValue(value.toList())
|
||||||
|
} else {
|
||||||
|
super.writeValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IOSQuickActionsApiCodecReaderWriter: FlutterStandardReaderWriter {
|
||||||
|
override func reader(with data: Data) -> FlutterStandardReader {
|
||||||
|
return IOSQuickActionsApiCodecReader(data: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func writer(with data: NSMutableData) -> FlutterStandardWriter {
|
||||||
|
return IOSQuickActionsApiCodecWriter(data: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IOSQuickActionsApiCodec: FlutterStandardMessageCodec {
|
||||||
|
static let shared = IOSQuickActionsApiCodec(readerWriter: IOSQuickActionsApiCodecReaderWriter())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
|
||||||
|
protocol IOSQuickActionsApi {
|
||||||
|
/// Sets the dynamic shortcuts for the app.
|
||||||
|
func setShortcutItems(itemsList: [ShortcutItemMessage]) throws
|
||||||
|
/// Removes all dynamic shortcuts.
|
||||||
|
func clearShortcutItems() throws
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
||||||
|
class IOSQuickActionsApiSetup {
|
||||||
|
/// The codec used by IOSQuickActionsApi.
|
||||||
|
static var codec: FlutterStandardMessageCodec { IOSQuickActionsApiCodec.shared }
|
||||||
|
/// Sets up an instance of `IOSQuickActionsApi` to handle messages through the `binaryMessenger`.
|
||||||
|
static func setUp(binaryMessenger: FlutterBinaryMessenger, api: IOSQuickActionsApi?) {
|
||||||
|
/// Sets the dynamic shortcuts for the app.
|
||||||
|
let setShortcutItemsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsApi.setShortcutItems", binaryMessenger: binaryMessenger, codec: codec)
|
||||||
|
if let api = api {
|
||||||
|
setShortcutItemsChannel.setMessageHandler { message, reply in
|
||||||
|
let args = message as! [Any?]
|
||||||
|
let itemsListArg = args[0] as! [ShortcutItemMessage]
|
||||||
|
do {
|
||||||
|
try api.setShortcutItems(itemsList: itemsListArg)
|
||||||
|
reply(wrapResult(nil))
|
||||||
|
} catch {
|
||||||
|
reply(wrapError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setShortcutItemsChannel.setMessageHandler(nil)
|
||||||
|
}
|
||||||
|
/// Removes all dynamic shortcuts.
|
||||||
|
let clearShortcutItemsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsApi.clearShortcutItems", binaryMessenger: binaryMessenger, codec: codec)
|
||||||
|
if let api = api {
|
||||||
|
clearShortcutItemsChannel.setMessageHandler { _, reply in
|
||||||
|
do {
|
||||||
|
try api.clearShortcutItems()
|
||||||
|
reply(wrapResult(nil))
|
||||||
|
} catch {
|
||||||
|
reply(wrapError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearShortcutItemsChannel.setMessageHandler(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
|
||||||
|
protocol IOSQuickActionsFlutterApiProtocol {
|
||||||
|
/// Sends a string representing a shortcut from the native platform to the app.
|
||||||
|
func launchAction(action actionArg: String, completion: @escaping (Result<Void, FlutterError>) -> Void)
|
||||||
|
}
|
||||||
|
class IOSQuickActionsFlutterApi: IOSQuickActionsFlutterApiProtocol {
|
||||||
|
private let binaryMessenger: FlutterBinaryMessenger
|
||||||
|
init(binaryMessenger: FlutterBinaryMessenger){
|
||||||
|
self.binaryMessenger = binaryMessenger
|
||||||
|
}
|
||||||
|
/// Sends a string representing a shortcut from the native platform to the app.
|
||||||
|
func launchAction(action actionArg: String, completion: @escaping (Result<Void, FlutterError>) -> Void) {
|
||||||
|
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsFlutterApi.launchAction", binaryMessenger: binaryMessenger)
|
||||||
|
channel.sendMessage([actionArg] as [Any?]) { _ in
|
||||||
|
completion(.success(Void()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
packages/quick_actions/quick_actions_ios/lib/messages.g.dart
Normal file
178
packages/quick_actions/quick_actions_ios/lib/messages.g.dart
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
// Autogenerated from Pigeon (v12.0.1), do not edit directly.
|
||||||
|
// See also: https://pub.dev/packages/pigeon
|
||||||
|
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
List<Object?> wrapResponse(
|
||||||
|
{Object? result, PlatformException? error, bool empty = false}) {
|
||||||
|
if (empty) {
|
||||||
|
return <Object?>[];
|
||||||
|
}
|
||||||
|
if (error == null) {
|
||||||
|
return <Object?>[result];
|
||||||
|
}
|
||||||
|
return <Object?>[error.code, error.message, error.details];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Home screen quick-action shortcut item.
|
||||||
|
class ShortcutItemMessage {
|
||||||
|
ShortcutItemMessage({
|
||||||
|
required this.type,
|
||||||
|
required this.localizedTitle,
|
||||||
|
this.icon,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The identifier of this item; should be unique within the app.
|
||||||
|
String type;
|
||||||
|
|
||||||
|
/// Localized title of the item.
|
||||||
|
String localizedTitle;
|
||||||
|
|
||||||
|
/// Name of native resource to be displayed as the icon for this item.
|
||||||
|
String? icon;
|
||||||
|
|
||||||
|
Object encode() {
|
||||||
|
return <Object?>[
|
||||||
|
type,
|
||||||
|
localizedTitle,
|
||||||
|
icon,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static ShortcutItemMessage decode(Object result) {
|
||||||
|
result as List<Object?>;
|
||||||
|
return ShortcutItemMessage(
|
||||||
|
type: result[0]! as String,
|
||||||
|
localizedTitle: result[1]! as String,
|
||||||
|
icon: result[2] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _IOSQuickActionsApiCodec extends StandardMessageCodec {
|
||||||
|
const _IOSQuickActionsApiCodec();
|
||||||
|
@override
|
||||||
|
void writeValue(WriteBuffer buffer, Object? value) {
|
||||||
|
if (value is ShortcutItemMessage) {
|
||||||
|
buffer.putUint8(128);
|
||||||
|
writeValue(buffer, value.encode());
|
||||||
|
} else {
|
||||||
|
super.writeValue(buffer, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||||
|
switch (type) {
|
||||||
|
case 128:
|
||||||
|
return ShortcutItemMessage.decode(readValue(buffer)!);
|
||||||
|
default:
|
||||||
|
return super.readValueOfType(type, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IOSQuickActionsApi {
|
||||||
|
/// Constructor for [IOSQuickActionsApi]. The [binaryMessenger] named argument is
|
||||||
|
/// available for dependency injection. If it is left null, the default
|
||||||
|
/// BinaryMessenger will be used which routes to the host platform.
|
||||||
|
IOSQuickActionsApi({BinaryMessenger? binaryMessenger})
|
||||||
|
: _binaryMessenger = binaryMessenger;
|
||||||
|
final BinaryMessenger? _binaryMessenger;
|
||||||
|
|
||||||
|
static const MessageCodec<Object?> codec = _IOSQuickActionsApiCodec();
|
||||||
|
|
||||||
|
/// Sets the dynamic shortcuts for the app.
|
||||||
|
Future<void> setShortcutItems(
|
||||||
|
List<ShortcutItemMessage?> arg_itemsList) async {
|
||||||
|
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||||
|
'dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsApi.setShortcutItems',
|
||||||
|
codec,
|
||||||
|
binaryMessenger: _binaryMessenger);
|
||||||
|
final List<Object?>? replyList =
|
||||||
|
await channel.send(<Object?>[arg_itemsList]) as List<Object?>?;
|
||||||
|
if (replyList == null) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'channel-error',
|
||||||
|
message: 'Unable to establish connection on channel.',
|
||||||
|
);
|
||||||
|
} else if (replyList.length > 1) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: replyList[0]! as String,
|
||||||
|
message: replyList[1] as String?,
|
||||||
|
details: replyList[2],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes all dynamic shortcuts.
|
||||||
|
Future<void> clearShortcutItems() async {
|
||||||
|
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||||
|
'dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsApi.clearShortcutItems',
|
||||||
|
codec,
|
||||||
|
binaryMessenger: _binaryMessenger);
|
||||||
|
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
||||||
|
if (replyList == null) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'channel-error',
|
||||||
|
message: 'Unable to establish connection on channel.',
|
||||||
|
);
|
||||||
|
} else if (replyList.length > 1) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: replyList[0]! as String,
|
||||||
|
message: replyList[1] as String?,
|
||||||
|
details: replyList[2],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class IOSQuickActionsFlutterApi {
|
||||||
|
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||||
|
|
||||||
|
/// Sends a string representing a shortcut from the native platform to the app.
|
||||||
|
void launchAction(String action);
|
||||||
|
|
||||||
|
static void setup(IOSQuickActionsFlutterApi? api,
|
||||||
|
{BinaryMessenger? binaryMessenger}) {
|
||||||
|
{
|
||||||
|
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||||
|
'dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsFlutterApi.launchAction',
|
||||||
|
codec,
|
||||||
|
binaryMessenger: binaryMessenger);
|
||||||
|
if (api == null) {
|
||||||
|
channel.setMessageHandler(null);
|
||||||
|
} else {
|
||||||
|
channel.setMessageHandler((Object? message) async {
|
||||||
|
assert(message != null,
|
||||||
|
'Argument for dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsFlutterApi.launchAction was null.');
|
||||||
|
final List<Object?> args = (message as List<Object?>?)!;
|
||||||
|
final String? arg_action = (args[0] as String?);
|
||||||
|
assert(arg_action != null,
|
||||||
|
'Argument for dev.flutter.pigeon.quick_actions_ios.IOSQuickActionsFlutterApi.launchAction was null, expected non-null String.');
|
||||||
|
try {
|
||||||
|
api.launchAction(arg_action!);
|
||||||
|
return wrapResponse(empty: true);
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
return wrapResponse(error: e);
|
||||||
|
} catch (e) {
|
||||||
|
return wrapResponse(
|
||||||
|
error: PlatformException(code: 'error', message: e.toString()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,54 +3,58 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:quick_actions_platform_interface/quick_actions_platform_interface.dart';
|
import 'package:quick_actions_platform_interface/quick_actions_platform_interface.dart';
|
||||||
|
|
||||||
|
import 'messages.g.dart';
|
||||||
|
|
||||||
export 'package:quick_actions_platform_interface/types/types.dart';
|
export 'package:quick_actions_platform_interface/types/types.dart';
|
||||||
|
|
||||||
const MethodChannel _channel =
|
late QuickActionHandler _handler;
|
||||||
MethodChannel('plugins.flutter.io/quick_actions_ios');
|
|
||||||
|
|
||||||
/// An implementation of [QuickActionsPlatform] for iOS.
|
/// An implementation of [QuickActionsPlatform] for iOS.
|
||||||
class QuickActionsIos extends QuickActionsPlatform {
|
class QuickActionsIos extends QuickActionsPlatform {
|
||||||
|
/// Creates a new plugin implementation instance.
|
||||||
|
QuickActionsIos({
|
||||||
|
@visibleForTesting IOSQuickActionsApi? api,
|
||||||
|
}) : _hostApi = api ?? IOSQuickActionsApi();
|
||||||
|
|
||||||
|
final IOSQuickActionsApi _hostApi;
|
||||||
|
|
||||||
/// Registers this class as the default instance of [QuickActionsPlatform].
|
/// Registers this class as the default instance of [QuickActionsPlatform].
|
||||||
static void registerWith() {
|
static void registerWith() {
|
||||||
QuickActionsPlatform.instance = QuickActionsIos();
|
QuickActionsPlatform.instance = QuickActionsIos();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The MethodChannel that is being used by this implementation of the plugin.
|
|
||||||
@visibleForTesting
|
|
||||||
MethodChannel get channel => _channel;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> initialize(QuickActionHandler handler) async {
|
Future<void> initialize(QuickActionHandler handler) async {
|
||||||
channel.setMethodCallHandler((MethodCall call) async {
|
final _QuickActionHandlerApi quickActionsHandlerApi =
|
||||||
assert(call.method == 'launch');
|
_QuickActionHandlerApi();
|
||||||
handler(call.arguments as String);
|
IOSQuickActionsFlutterApi.setup(quickActionsHandlerApi);
|
||||||
});
|
_handler = handler;
|
||||||
final String? action =
|
|
||||||
await channel.invokeMethod<String?>('getLaunchAction');
|
|
||||||
if (action != null) {
|
|
||||||
handler(action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setShortcutItems(List<ShortcutItem> items) async {
|
Future<void> setShortcutItems(List<ShortcutItem> items) async {
|
||||||
final List<Map<String, String?>> itemsList =
|
await _hostApi.setShortcutItems(
|
||||||
items.map(_serializeItem).toList();
|
items.map(_shortcutItemToShortcutItemMessage).toList(),
|
||||||
await channel.invokeMethod<void>('setShortcutItems', itemsList);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> clearShortcutItems() =>
|
Future<void> clearShortcutItems() => _hostApi.clearShortcutItems();
|
||||||
channel.invokeMethod<void>('clearShortcutItems');
|
|
||||||
|
|
||||||
Map<String, String?> _serializeItem(ShortcutItem item) {
|
ShortcutItemMessage _shortcutItemToShortcutItemMessage(ShortcutItem item) {
|
||||||
return <String, String?>{
|
return ShortcutItemMessage(
|
||||||
'type': item.type,
|
type: item.type,
|
||||||
'localizedTitle': item.localizedTitle,
|
localizedTitle: item.localizedTitle,
|
||||||
'icon': item.icon,
|
icon: item.icon,
|
||||||
};
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _QuickActionHandlerApi extends IOSQuickActionsFlutterApi {
|
||||||
|
@override
|
||||||
|
void launchAction(String action) {
|
||||||
|
_handler(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
Use of this source code is governed by a BSD-style license that can be
|
||||||
|
found in the LICENSE file.
|
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:pigeon/pigeon.dart';
|
||||||
|
|
||||||
|
@ConfigurePigeon(PigeonOptions(
|
||||||
|
dartOut: 'lib/messages.g.dart',
|
||||||
|
swiftOut: 'ios/Classes/messages.g.swift',
|
||||||
|
copyrightHeader: 'pigeons/copyright.txt',
|
||||||
|
))
|
||||||
|
|
||||||
|
/// Home screen quick-action shortcut item.
|
||||||
|
class ShortcutItemMessage {
|
||||||
|
ShortcutItemMessage(
|
||||||
|
this.type,
|
||||||
|
this.localizedTitle,
|
||||||
|
this.icon,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// The identifier of this item; should be unique within the app.
|
||||||
|
String type;
|
||||||
|
|
||||||
|
/// Localized title of the item.
|
||||||
|
String localizedTitle;
|
||||||
|
|
||||||
|
/// Name of native resource to be displayed as the icon for this item.
|
||||||
|
String? icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostApi()
|
||||||
|
abstract class IOSQuickActionsApi {
|
||||||
|
/// Sets the dynamic shortcuts for the app.
|
||||||
|
void setShortcutItems(List<ShortcutItemMessage> itemsList);
|
||||||
|
|
||||||
|
/// Removes all dynamic shortcuts.
|
||||||
|
void clearShortcutItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FlutterApi()
|
||||||
|
abstract class IOSQuickActionsFlutterApi {
|
||||||
|
/// Sends a string representing a shortcut from the native platform to the app.
|
||||||
|
void launchAction(String action);
|
||||||
|
}
|
@ -2,7 +2,7 @@ name: quick_actions_ios
|
|||||||
description: An implementation for the iOS platform of the Flutter `quick_actions` plugin.
|
description: An implementation for the iOS platform of the Flutter `quick_actions` plugin.
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/quick_actions/quick_actions_ios
|
repository: https://github.com/flutter/packages/tree/main/packages/quick_actions/quick_actions_ios
|
||||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
|
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
|
||||||
version: 1.0.7
|
version: 1.0.8
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.19.0 <4.0.0"
|
sdk: ">=2.19.0 <4.0.0"
|
||||||
@ -26,6 +26,7 @@ dev_dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
integration_test:
|
integration_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
pigeon: ^12.0.1
|
||||||
plugin_platform_interface: ^2.1.2
|
plugin_platform_interface: ^2.1.2
|
||||||
|
|
||||||
topics:
|
topics:
|
||||||
|
@ -2,35 +2,18 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:quick_actions_ios/messages.g.dart';
|
||||||
import 'package:quick_actions_ios/quick_actions_ios.dart';
|
import 'package:quick_actions_ios/quick_actions_ios.dart';
|
||||||
import 'package:quick_actions_platform_interface/quick_actions_platform_interface.dart';
|
import 'package:quick_actions_platform_interface/quick_actions_platform_interface.dart';
|
||||||
|
|
||||||
|
const String LAUNCH_ACTION_STRING = 'aString';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('$QuickActionsIos', () {
|
final _FakeQuickActionsApi api = _FakeQuickActionsApi();
|
||||||
late List<MethodCall> log;
|
final QuickActionsIos quickActions = QuickActionsIos(api: api);
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
log = <MethodCall>[];
|
|
||||||
});
|
|
||||||
|
|
||||||
QuickActionsIos buildQuickActionsPlugin() {
|
|
||||||
final QuickActionsIos quickActions = QuickActionsIos();
|
|
||||||
_ambiguate(TestDefaultBinaryMessengerBinding.instance)!
|
|
||||||
.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(quickActions.channel,
|
|
||||||
(MethodCall methodCall) async {
|
|
||||||
log.add(methodCall);
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
return quickActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
test('registerWith() registers correct instance', () {
|
test('registerWith() registers correct instance', () {
|
||||||
QuickActionsIos.registerWith();
|
QuickActionsIos.registerWith();
|
||||||
@ -38,118 +21,32 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('#initialize', () {
|
group('#initialize', () {
|
||||||
test('passes getLaunchAction on launch method', () {
|
test('initialize', () {
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
expect(quickActions.initialize((_) {}), completes);
|
||||||
quickActions.initialize((String type) {});
|
});
|
||||||
|
});
|
||||||
expect(
|
|
||||||
log,
|
test('setShortcutItems', () async {
|
||||||
<Matcher>[
|
await quickActions.initialize((String type) {});
|
||||||
isMethodCall('getLaunchAction', arguments: null),
|
const ShortcutItem item =
|
||||||
],
|
ShortcutItem(type: 'test', localizedTitle: 'title', icon: 'icon.svg');
|
||||||
);
|
await quickActions.setShortcutItems(<ShortcutItem>[item]);
|
||||||
});
|
|
||||||
|
expect(api.items.first.type, item.type);
|
||||||
test('initialize', () async {
|
expect(api.items.first.localizedTitle, item.localizedTitle);
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
expect(api.items.first.icon, item.icon);
|
||||||
final Completer<bool> quickActionsHandler = Completer<bool>();
|
});
|
||||||
await quickActions
|
|
||||||
.initialize((_) => quickActionsHandler.complete(true));
|
test('clearShortCutItems', () {
|
||||||
expect(
|
|
||||||
log,
|
|
||||||
<Matcher>[
|
|
||||||
isMethodCall('getLaunchAction', arguments: null),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
log.clear();
|
|
||||||
|
|
||||||
expect(quickActionsHandler.future, completion(isTrue));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group('#setShortCutItems', () {
|
|
||||||
test('passes shortcutItem through channel', () {
|
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
|
||||||
quickActions.initialize((String type) {});
|
|
||||||
quickActions.setShortcutItems(<ShortcutItem>[
|
|
||||||
const ShortcutItem(
|
|
||||||
type: 'test', localizedTitle: 'title', icon: 'icon.svg')
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
log,
|
|
||||||
<Matcher>[
|
|
||||||
isMethodCall('getLaunchAction', arguments: null),
|
|
||||||
isMethodCall('setShortcutItems', arguments: <Map<String, String>>[
|
|
||||||
<String, String>{
|
|
||||||
'type': 'test',
|
|
||||||
'localizedTitle': 'title',
|
|
||||||
'icon': 'icon.svg',
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('setShortcutItems with demo data', () async {
|
|
||||||
const String type = 'type';
|
|
||||||
const String localizedTitle = 'localizedTitle';
|
|
||||||
const String icon = 'icon';
|
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
|
||||||
await quickActions.setShortcutItems(
|
|
||||||
const <ShortcutItem>[
|
|
||||||
ShortcutItem(type: type, localizedTitle: localizedTitle, icon: icon)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
log,
|
|
||||||
<Matcher>[
|
|
||||||
isMethodCall(
|
|
||||||
'setShortcutItems',
|
|
||||||
arguments: <Map<String, String>>[
|
|
||||||
<String, String>{
|
|
||||||
'type': type,
|
|
||||||
'localizedTitle': localizedTitle,
|
|
||||||
'icon': icon,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
log.clear();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group('#clearShortCutItems', () {
|
|
||||||
test('send clearShortcutItems through channel', () {
|
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
|
||||||
quickActions.initialize((String type) {});
|
quickActions.initialize((String type) {});
|
||||||
|
const ShortcutItem item =
|
||||||
|
ShortcutItem(type: 'test', localizedTitle: 'title', icon: 'icon.svg');
|
||||||
|
quickActions.setShortcutItems(<ShortcutItem>[item]);
|
||||||
quickActions.clearShortcutItems();
|
quickActions.clearShortcutItems();
|
||||||
|
|
||||||
expect(
|
expect(api.items.isEmpty, true);
|
||||||
log,
|
|
||||||
<Matcher>[
|
|
||||||
isMethodCall('getLaunchAction', arguments: null),
|
|
||||||
isMethodCall('clearShortcutItems', arguments: null),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('clearShortcutItems', () {
|
|
||||||
final QuickActionsIos quickActions = buildQuickActionsPlugin();
|
|
||||||
quickActions.clearShortcutItems();
|
|
||||||
expect(
|
|
||||||
log,
|
|
||||||
<Matcher>[
|
|
||||||
isMethodCall('clearShortcutItems', arguments: null),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
log.clear();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group('$ShortcutItem', () {
|
|
||||||
test('Shortcut item can be constructed', () {
|
test('Shortcut item can be constructed', () {
|
||||||
const String type = 'type';
|
const String type = 'type';
|
||||||
const String localizedTitle = 'title';
|
const String localizedTitle = 'title';
|
||||||
@ -162,11 +59,32 @@ void main() {
|
|||||||
expect(item.localizedTitle, localizedTitle);
|
expect(item.localizedTitle, localizedTitle);
|
||||||
expect(item.icon, icon);
|
expect(item.icon, icon);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This allows a value of type T or T? to be treated as a value of type T?.
|
class _FakeQuickActionsApi implements IOSQuickActionsApi {
|
||||||
///
|
List<ShortcutItem> items = <ShortcutItem>[];
|
||||||
/// We use this so that APIs that have become non-nullable can still be used
|
bool getLaunchActionCalled = false;
|
||||||
/// with `!` and `?` on the stable branch.
|
|
||||||
T? _ambiguate<T>(T? value) => value;
|
@override
|
||||||
|
Future<void> clearShortcutItems() async {
|
||||||
|
items = <ShortcutItem>[];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setShortcutItems(List<ShortcutItemMessage?> itemsList) async {
|
||||||
|
await clearShortcutItems();
|
||||||
|
for (final ShortcutItemMessage? element in itemsList) {
|
||||||
|
items.add(shortcutItemMessageToShortcutItem(element!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conversion tool to change [ShortcutItemMessage] back to [ShortcutItem]
|
||||||
|
ShortcutItem shortcutItemMessageToShortcutItem(ShortcutItemMessage item) {
|
||||||
|
return ShortcutItem(
|
||||||
|
type: item.type,
|
||||||
|
localizedTitle: item.localizedTitle,
|
||||||
|
icon: item.icon,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user