@@ -57,29 +57,19 @@ struct ContentView: View {
57
57
58
58
func applicationBroughtToForeground( viewModel: ChatViewModel )
59
59
{
60
- // Subscribe
61
- viewModel. pubnub? . subscribe ( to: [ groupChatChannel] , withPresence: true )
60
+ // TUTORIAL: STEP 2B CODE GOES HERE (1/2)
61
+
62
+ // TUTORIAL: STEP 2D CODE IS ALREADY PRESENT HERE AS CONTAINS GLUE CODE
62
63
63
- // Applications receive various types of information from PubNub through a 'listener'
64
- // This application dynamically registers an listener when it is in the foreground
65
64
viewModel. listener = SubscriptionListener ( )
66
65
viewModel. listener? . didReceiveSubscription = {
67
66
event in
68
67
switch event {
69
68
case let . messageReceived( message) :
69
+
70
+ // TUTORIAL: STEP 2E CODE GOES HERE
70
71
71
- let messageText : String = message. payload. stringOptional ?? " "
72
- let sender : String = message. publisher ?? " "
73
-
74
- var newMsg = Message ( message: messageText, senderDeviceId: sender, timetoken: String ( message. published) )
75
- let dateFormatter = DateFormatter ( )
76
- dateFormatter. timeStyle = DateFormatter . Style. medium
77
- dateFormatter. dateStyle = DateFormatter . Style. medium
78
- dateFormatter. timeZone = . current
79
- let secsSince1970 : Double = message. published. timetokenDate. timeIntervalSince1970
80
- newMsg. humanReadableTime = dateFormatter. string ( from: Date ( timeIntervalSince1970: secsSince1970) )
81
-
82
- viewModel. messages. append ( newMsg)
72
+ break ;
83
73
84
74
// Status events are commonly used to notify the application that a previous PubNub call has succeeded
85
75
// Not all PubNub calls return their status in this manner but is used in this app to ensure
@@ -101,69 +91,18 @@ struct ContentView: View {
101
91
}
102
92
}
103
93
104
- // When the application is first loaded, it is common to load any recent chat messages
105
- // so the user can get caught up with conversations they missed.
106
- // Every application will handle this differently but here we just load the most recent
107
- // messages
108
- viewModel. pubnub? . fetchMessageHistory ( for: [ groupChatChannel] , includeMeta: true , includeUUID: true , page: PubNubBoundedPageBase ( limit: 8 ) ) { result in
109
- switch result {
110
- case let . success( response) :
111
- if let myChannelMessages = response. messagesByChannel [ groupChatChannel] {
112
- myChannelMessages. forEach { historicalMessage in
113
- // Recreate the message and add it to the viewModel for display.
114
- var newMsg = Message ( )
115
- newMsg. message = historicalMessage. payload. stringOptional ?? " Not found "
116
- newMsg. senderDeviceId = historicalMessage. publisher? . stringOptional ?? " Unknown "
117
- newMsg. timetoken = String ( historicalMessage. published)
118
- let dateFormatter = DateFormatter ( )
119
- dateFormatter. timeStyle = DateFormatter . Style. medium
120
- dateFormatter. dateStyle = DateFormatter . Style. medium
121
- dateFormatter. timeZone = . current
122
- let secsSince1970 : Double = historicalMessage. published. timetokenDate. timeIntervalSince1970
123
- newMsg. humanReadableTime = dateFormatter. string ( from: Date ( timeIntervalSince1970: secsSince1970) )
124
- viewModel. messages. append ( newMsg)
125
-
126
- lookupMemberName ( deviceId: newMsg. senderDeviceId)
127
- }
128
- }
129
- case let . failure( error) :
130
- print ( " Failed to retrieve history: \( error. localizedDescription) " )
131
- }
132
- }
94
+ // TUTORIAL: STEP 2G CODE GOES HERE
95
+
133
96
}
134
97
135
98
// Be notified that a 'presence' event has occurred. I.e. somebody has left or joined
136
99
// the channel. This is similar to the earlier hereNow call but this API will only be
137
100
// invoked when presence information changes, meaning you do NOT have to call hereNow
138
101
// periodically. More info: https://www.pubnub.com/docs/sdks/swift/api-reference/presence
139
102
case let . presenceChanged( presence) :
140
- // A note about ANNOUNCE_MAX:
141
- // There is a server setting, ANNOUNCE_MAX, that you can configure on your keyset. This
142
- // defaults to 20 users and after this number of attendees join each channel, presence
143
- // events are only sent periodically every x seconds, where x is also configured on the keyset.
144
- // More info: https://www.pubnub.com/docs/presence/presence-events#interval-mode
145
- // Since this application needs to know which UUIDs have joined or left since the last update,
146
- // YOU NEED TO SET 'Presence Deltas' to true on the keyset, if you have more than ANNOUNCE_MAX
147
- // users, using this app.
148
- for action in presence. actions {
149
- switch action {
150
- case let . join( uuids) :
151
- uuids. forEach { deviceId in
152
- addMember ( deviceId: deviceId)
153
- }
154
- break ;
155
- case let . leave( uuids) :
156
- uuids. forEach { deviceId in
157
- removeMember ( deviceId: deviceId)
158
- }
159
- break ;
160
- case . timeout( _) :
161
- print ( " Presence - timeout " )
162
- break ;
163
- case let . stateChange( uuid, state) :
164
- print ( " \( uuid) changed their presence state to \( state) at \( presence. timetoken) " )
165
- }
166
- }
103
+
104
+ // TUTORIAL: STEP 2F CODE GOES HERE (1/2)
105
+ break ;
167
106
case let . subscribeError( error) :
168
107
print ( " Subscription Error \( error) " )
169
108
default :
@@ -185,19 +124,9 @@ struct ContentView: View {
185
124
viewModel. objectsListener? . didReceiveObjectMetadataEvent = { event in
186
125
switch event {
187
126
case . setUUID( let metadata) :
188
- let changedId : String = metadata. metadataId;
189
- for change in metadata. changes {
190
- switch change {
191
- case let . stringOptional( _, value) :
192
- let changedValue : String = value? . stringOptional ?? changedId
193
- replaceMemberName (
194
- deviceId: changedId, newName: changedValue
195
- )
196
- case . customOptional( _, _) :
197
- // No action
198
- break ;
199
- }
200
- }
127
+
128
+ // TUTORIAL: STEP 2I CODE GOES HERE (2/2)
129
+
201
130
break ;
202
131
default :
203
132
break
@@ -216,24 +145,7 @@ struct ContentView: View {
216
145
// I am definitely here(!)
217
146
addMember ( deviceId: viewModel. deviceId ?? " defaultId " )
218
147
219
- // PubNub has an API to determine who is in the room. Use this call sparingly since
220
- // you are only ever likely to need to know EVERYONE in the room when the UI is first
221
- // created.
222
- viewModel. pubnub? . hereNow ( on: [ groupChatChannel] , includeUUIDs: true ) { result in
223
- switch result {
224
- case let . success( presenceByChannel) :
225
- if let myChannelPresence = presenceByChannel [ groupChatChannel] {
226
- // The API will return an array of occupants in the channel, defined by
227
- // their ID. This application will need to look up the friendly name
228
- // defined for each of these IDs (later)
229
- myChannelPresence. occupants. forEach { member in
230
- addMember ( deviceId: member)
231
- }
232
- }
233
- case let . failure( error) :
234
- print ( " Failed hereNow Response: \( error) " )
235
- }
236
- }
148
+ // TUTORIAL: STEP 2F CODE GOES HERE (2/2)
237
149
238
150
}
239
151
@@ -243,7 +155,9 @@ struct ContentView: View {
243
155
// when the app goes into the background. This is good to show the principles
244
156
// of presence but you don't need to do this in a production app if it
245
157
// does not fit your use case.
246
- viewModel. pubnub? . unsubscribe ( from: [ groupChatChannel] ) ;
158
+
159
+ // TUTORIAL: STEP 2B CODE GOES HERE (2/2)
160
+
247
161
viewModel. listener? . cancel ( )
248
162
viewModel. objectsListener? . cancel ( )
249
163
}
@@ -263,20 +177,8 @@ struct ContentView: View {
263
177
return ;
264
178
}
265
179
266
- // Create a device-specific DeviceId to represent this device and user, so PubNub
267
- // knows who is connecting.
268
- // More info: https://support.pubnub.com/hc/en-us/articles/360051496532-How-do-I-set-the-UUID-
269
- // All iOS IDs are user-resettable but are still appropriate for use here.
270
- let deviceId = UIDevice . current. identifierForVendor? . uuidString ?? " defaultId "
271
-
272
- // Create a PubNub configuration and instantiate the PubNub object, used to
273
- // communicate with PubNub
274
- let config = PubNubConfiguration (
275
- publishKey: publish_key, subscribeKey: subscribe_key, userId: deviceId
276
- )
180
+ // TUTORIAL: STEP 2A CODE GOES HERE
277
181
278
- // Application state
279
- viewModel. pubnub = PubNub ( configuration: config)
280
182
viewModel. deviceId = deviceId
281
183
viewModel. channel = groupChatChannel
282
184
viewModel. friendlyName = deviceId
@@ -317,21 +219,9 @@ struct ContentView: View {
317
219
// We already know the member name, take no action
318
220
}
319
221
else {
320
- // Resolve the friendly name of the deviceId
321
- viewModel. pubnub? . fetch ( uuid: deviceId) { result in
322
- switch result {
323
- case let . success( uuidMetadata) :
324
- // Add the user's name to the memberNames dictionary (part of the viewModel, so
325
- // the UI will update accordingly)
326
- viewModel. memberNames [ deviceId] = uuidMetadata. name
327
- // Set our own friendly name (stored separately to make the UI logic easier)
328
- if ( deviceId == viewModel. deviceId) {
329
- viewModel. friendlyName = uuidMetadata. name ?? " default name "
330
- }
331
- case . failure( _) :
332
- print ( " Could not find friendly name for device: " + deviceId)
333
- }
334
- }
222
+
223
+ // TUTORIAL: STEP 2I CODE GOES HERE (1/2)
224
+
335
225
}
336
226
}
337
227
0 commit comments