-
Notifications
You must be signed in to change notification settings - Fork 872
/
Copy pathMessagesViewController.swift
191 lines (149 loc) · 7.52 KB
/
MessagesViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
Abstract:
The root view controller shown by the Messages app.
*/
import UIKit
import Messages
class MessagesViewController: MSMessagesAppViewController {
// MARK: Properties
override func willBecomeActive(with conversation: MSConversation) {
super.willBecomeActive(with: conversation)
// Present the view controller appropriate for the conversation and presentation style.
presentViewController(for: conversation, with: presentationStyle)
}
// MARK: MSMessagesAppViewController
override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
guard let conversation = activeConversation else { fatalError("Expected an active converstation") }
// Present the view controller appropriate for the conversation and presentation style.
presentViewController(for: conversation, with: presentationStyle)
}
// MARK: Child view controller presentation
private func presentViewController(for conversation: MSConversation, with presentationStyle: MSMessagesAppPresentationStyle) {
// Determine the controller to present.
let controller: UIViewController
if presentationStyle == .compact {
// Show a list of previously created ice creams.
controller = instantiateIceCreamsController()
}
else {
/*
Parse an `IceCream` from the conversation's `selectedMessage` or
create a new `IceCream` if there isn't one associated with the message.
*/
let iceCream = IceCream(message: conversation.selectedMessage) ?? IceCream()
if iceCream.isComplete {
controller = instantiateCompletedIceCreamController(with: iceCream)
}
else {
controller = instantiateBuildIceCreamController(with: iceCream)
}
}
// Remove any existing child controllers.
for child in childViewControllers {
child.willMove(toParentViewController: nil)
child.view.removeFromSuperview()
child.removeFromParentViewController()
}
// Embed the new controller.
addChildViewController(controller)
controller.view.frame = view.bounds
controller.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(controller.view)
controller.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
controller.view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
controller.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
controller.didMove(toParentViewController: self)
}
private func instantiateIceCreamsController() -> UIViewController {
// Instantiate a `IceCreamsViewController` and present it.
guard let controller = storyboard?.instantiateViewController(withIdentifier: IceCreamsViewController.storyboardIdentifier) as? IceCreamsViewController else { fatalError("Unable to instantiate an IceCreamsViewController from the storyboard") }
controller.delegate = self
return controller
}
private func instantiateBuildIceCreamController(with iceCream: IceCream) -> UIViewController {
// Instantiate a `BuildIceCreamViewController` and present it.
guard let controller = storyboard?.instantiateViewController(withIdentifier: BuildIceCreamViewController.storyboardIdentifier) as? BuildIceCreamViewController else { fatalError("Unable to instantiate a BuildIceCreamViewController from the storyboard") }
controller.iceCream = iceCream
controller.delegate = self
return controller
}
private func instantiateCompletedIceCreamController(with iceCream: IceCream) -> UIViewController {
// Instantiate a `BuildIceCreamViewController` and present it.
guard let controller = storyboard?.instantiateViewController(withIdentifier: CompletedIceCreamViewController.storyboardIdentifier) as? CompletedIceCreamViewController else { fatalError("Unable to instantiate a CompletedIceCreamViewController from the storyboard") }
controller.iceCream = iceCream
return controller
}
// MARK: Convenience
fileprivate func composeMessage(with iceCream: IceCream, caption: String, session: MSSession? = nil) -> MSMessage {
var components = URLComponents()
components.queryItems = iceCream.queryItems
let layout = MSMessageTemplateLayout()
layout.image = iceCream.renderSticker(opaque: true)
layout.caption = caption
let message = MSMessage(session: session ?? MSSession())
message.url = components.url!
message.layout = layout
return message
}
}
/**
Extends `MessagesViewController` to conform to the `IceCreamsViewControllerDelegate`
protocol.
*/
extension MessagesViewController: IceCreamsViewControllerDelegate {
func iceCreamsViewControllerDidSelectAdd(_ controller: IceCreamsViewController) {
/*
The user tapped the silhouette to start creating a new ice cream.
Change the presentation style to `.expanded`.
*/
requestPresentationStyle(.expanded)
}
}
/**
Extends `MessagesViewController` to conform to the `BuildIceCreamViewControllerDelegate`
protocol.
*/
extension MessagesViewController: BuildIceCreamViewControllerDelegate {
func buildIceCreamViewController(_ controller: BuildIceCreamViewController, didSelect iceCreamPart: IceCreamPart) {
guard let conversation = activeConversation else { fatalError("Expected a conversation") }
guard var iceCream = controller.iceCream else { fatalError("Expected the controller to be displaying an ice cream") }
/*
Update the ice cream with the selected body part and determine a caption
and description of the change.
*/
var messageCaption: String
if let base = iceCreamPart as? Base {
iceCream.base = base
messageCaption = NSLocalizedString("Let's build an ice cream", comment: "")
}
else if let scoops = iceCreamPart as? Scoops {
iceCream.scoops = scoops
messageCaption = NSLocalizedString("I added some scoops", comment: "")
}
else if let topping = iceCreamPart as? Topping {
iceCream.topping = topping
messageCaption = NSLocalizedString("Our finished ice cream", comment: "")
}
else {
fatalError("Unexpected type of ice cream part selected.")
}
// Create a new message with the same session as any currently selected message.
let message = composeMessage(with: iceCream, caption: messageCaption, session: conversation.selectedMessage?.session)
// Add the message to the conversation.
conversation.insert(message) { error in
if let error = error {
print(error)
}
}
// If the ice cream is complete, save it in the history.
if iceCream.isComplete {
var history = IceCreamHistory.load()
history.append(iceCream)
history.save()
}
dismiss()
}
}