Skip to content

Commit 7e108bd

Browse files
authored
Add custom actions to Switchcraft (#9)
* Add custom actions to Switchcraft * Bump podspec * Add example for custom action usage * Move from callback approach to delegate approach * Bump podspec to show change is breaking * Add new delegate method to README * Remove "Action: " from action labels * Bump podspec up to 1.0.0 * Remove codable and equatable * Use enums for clearer handling * Allow didTapAction to be optional * Make extension public to allow for optional delegate method * Adding documentation for custom actions feature * Fix minor spelling mistake
1 parent 5022c1b commit 7e108bd

8 files changed

Lines changed: 171 additions & 3 deletions

File tree

Example/Pods/Pods.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/Switchcraft/AppDelegate.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ extension Switchcraft {
2727
Endpoint(title: nil, url: URL(string: "http://apple.com")!),
2828
Endpoint(title: "Steamclock", url: URL(string: "http://steamclock.com")!)
2929
],
30+
actions: [
31+
Action(title: "Custom action 1", actionId: Actions.custom1.rawValue),
32+
Action(title: "Custom action 2", actionId: Actions.custom2.rawValue)
33+
],
3034
allowCustom: true
3135
))
3236
}
37+
38+
enum Actions: String {
39+
case custom1
40+
case custom2
41+
}

Example/Switchcraft/ReallySimpleExampleVC.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,18 @@ extension ReallySimpleExampleVC: SwitchcraftDelegate {
3131
currentEndpointLabel.isHidden = endpoint == switchcraft.defaultEndpoint
3232
currentEndpointLabel.text = "Current Endpoint:\n\(endpoint.name)"
3333
}
34+
35+
func switchcraft(_ switchcraft: Switchcraft, didTapAction action: Action) {
36+
guard let action = Actions(rawValue: action.actionId) else {
37+
return
38+
}
39+
40+
switch action {
41+
case .custom1:
42+
print("tapped action 1")
43+
case .custom2:
44+
print("tapped action 2")
45+
}
46+
47+
}
3448
}

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ To get updates whenever an endpoint is selected, you've got two options:
5151
1. Delegation
5252

5353
If you only need to keep track of changes to the current endpoint in a single place, this is probably the way to go.
54-
Classes that want to recieve updates only need to register your `viewController` as a delegate and conform to the `SwitchcraftDelegate` protocol.
54+
Classes that want to receive updates only need to register your `viewController` as a delegate and conform to the `SwitchcraftDelegate` protocol.
5555

5656
```
5757
class MyVC: UIViewController {
@@ -87,6 +87,72 @@ To get updates whenever an endpoint is selected, you've got two options:
8787
// Handle endpoint selected here
8888
}
8989
```
90+
91+
### Custom Actions
92+
93+
1. Add some custom actions to Switchcraft via the `Config`:
94+
```swift
95+
extension Switchcraft {
96+
static let shared = Switchcraft(config: Config(
97+
defaultsKey: ...,
98+
endpoints: ...,
99+
actions: [
100+
Action(title: "Custom action 1", actionId: "customAction1"),
101+
Action(title: "Custom action 2", actionId: "customAction2")
102+
]
103+
))
104+
}
105+
```
106+
107+
2. Add the following to your SwitchCraftDelegate:
108+
```swift
109+
extension MyVC: SwitchcraftDelegate {
110+
...
111+
112+
func switchcraft(_ switchcraft: Switchcraft, didTapAction action: Action)
113+
// Handle custom action selection here
114+
}
115+
}
116+
```
117+
118+
Note: We recommend using Swift enums for the actionId, like the following example:
119+
```swift
120+
enum Actions: String {
121+
case custom1
122+
case custom2
123+
}
124+
125+
extension Switchcraft {
126+
static let shared = Switchcraft(config: Config(
127+
defaultsKey: ...,
128+
endpoints: ...,
129+
actions: [
130+
Action(title: "Custom action 1", actionId: Actions.custom1.rawValue),
131+
Action(title: "Custom action 2", actionId: Actions.custom2.rawValue)
132+
]
133+
))
134+
}
135+
136+
extension MyVC: SwitchcraftDelegate {
137+
...
138+
139+
func switchcraft(_ switchcraft: Switchcraft, didTapAction action: Action) {
140+
guard let action = Actions(rawValue: action.actionId) else {
141+
return
142+
}
143+
144+
switch action {
145+
case .custom1:
146+
// handle the first custom action tapped
147+
...
148+
case .custom2:
149+
// handle the second custom action tapped
150+
...
151+
}
152+
}
153+
}
154+
155+
```
90156

91157
### Getting Fancy
92158

Switchcraft.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'Switchcraft'
3-
s.version = '0.1.2'
3+
s.version = '1.0.0'
44
s.summary = 'Drop and go endpoint selector written in Swift.'
55
s.homepage = 'https://github.com/steamclock/Switchcraft'
66
s.license = { :type => 'MIT', :file => 'LICENSE' }

Switchcraft/Classes/Action.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Actions.swift
3+
// Pods-Switchcraft_Example
4+
//
5+
// Created by Jake on 2018-07-05.
6+
//
7+
8+
import Foundation
9+
10+
/**
11+
* Represents an action that can be tapped using the `Switchcraft` picker.
12+
*/
13+
public struct Action {
14+
/**
15+
* A title to be shown for the action.
16+
*/
17+
public let title: String
18+
19+
/**
20+
* A unique ID for the action.
21+
*/
22+
public let actionId: String
23+
24+
/**
25+
* Create a new action.
26+
*
27+
* - parameter title: The title to show in the endpoint selection menu.
28+
* - parameter actionId: The unique identifier for the action.
29+
*/
30+
public init(title: String, actionId: String) {
31+
self.title = title
32+
self.actionId = actionId
33+
}
34+
}

Switchcraft/Classes/Config.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ public struct Config {
6868
*/
6969
public var endpoints: [Endpoint] = []
7070

71+
/**
72+
* The set of custom actions to be shown in the switcher.
73+
*/
74+
public var actions: [Action] = []
75+
7176
/**
7277
* The index of the default endpoint in `endpoints`.
7378
* Default is `0`.
@@ -82,9 +87,10 @@ public struct Config {
8287
* - parameter endpoints: The set of endpoints to show in the picker.
8388
* - parameter allowCustom: Whether the switcher allows entering custom endpoints.
8489
*/
85-
public init(defaultsKey: String, endpoints: [Endpoint], allowCustom: Bool = false) {
90+
public init(defaultsKey: String, endpoints: [Endpoint], actions: [Action] = [], allowCustom: Bool = false) {
8691
self.defaultsKey = defaultsKey
8792
self.endpoints = endpoints
8893
self.allowCustom = allowCustom
94+
self.actions = actions
8995
}
9096
}

Switchcraft/Classes/Switchcraft.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ public protocol SwitchcraftDelegate: AnyObject {
1414
* Called when an endpoint is selected.
1515
*/
1616
func switchcraft(_ switchcraft: Switchcraft, didSelectEndpoint endpoint: Endpoint)
17+
18+
/**
19+
* Called when an action is tapped.
20+
*/
21+
func switchcraft(_ switchcraft: Switchcraft, didTapAction action: Action)
22+
}
23+
24+
25+
// provides a default extension, so other applications don't have to override the action handling
26+
public extension SwitchcraftDelegate {
27+
func switchcraft(_ switchcraft: Switchcraft, didTapAction action: Action) {
28+
// no-op, allowing this method to be optional
29+
}
1730
}
1831

1932
/**
@@ -191,6 +204,19 @@ public class Switchcraft {
191204
})
192205
}
193206

207+
for action in config.actions {
208+
alertController.addAction(
209+
UIAlertAction(
210+
title: action.title,
211+
style: .default,
212+
handler: { [weak self] _ in
213+
self?.tapped(action: action)
214+
viewController.dismiss(animated: false, completion: nil)
215+
}
216+
)
217+
)
218+
}
219+
194220
alertController.addAction(
195221
UIAlertAction(
196222
title: config.cancelTitle,
@@ -263,6 +289,15 @@ public class Switchcraft {
263289
NotificationCenter.default.post(name: .SwitchcraftDidSelectEndpoint, object: self, userInfo: [Notification.Key.Endpoint: endpoint])
264290
}
265291

292+
/**
293+
* Called when an action is tapped.
294+
*
295+
* - parameter action: The action tapped.
296+
*/
297+
private func tapped(action: Action) {
298+
delegate?.switchcraft(self, didTapAction: action)
299+
}
300+
266301
/**
267302
* Create and return the default UITapGestureRecognizer recognizer to attach to a view.
268303
* The default gesture is a three finger double tap unless built with the simulator,

0 commit comments

Comments
 (0)