@trycourier/courier-react-native 1.0.8 → 2.0.0-beta0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +16 -416
  3. package/android/build.gradle +48 -83
  4. package/android/src/main/AndroidManifest.xml +0 -1
  5. package/android/src/main/AndroidManifestNew.xml +2 -0
  6. package/android/src/main/java/com/courierreactnative/CourierReactNativeActivity.kt +10 -10
  7. package/android/src/main/java/com/courierreactnative/CourierReactNativeModule.kt +146 -139
  8. package/android/src/main/java/com/courierreactnative/CourierReactNativePackage.kt +1 -3
  9. package/android/src/main/java/com/courierreactnative/CourierReactNativeViewManager.kt +43 -0
  10. package/courier-react-native.podspec +12 -4
  11. package/ios/CourierReactNative-Bridging-Header.h +0 -1
  12. package/ios/CourierReactNative.xcodeproj/project.pbxproj +4 -4
  13. package/ios/CourierReactNative.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  14. package/ios/CourierReactNativeModule.m +48 -0
  15. package/ios/{CourierReactNative.swift → CourierReactNativeModule.swift} +167 -48
  16. package/ios/CourierReactNativeViewManager.m +15 -0
  17. package/ios/CourierReactNativeViewManager.swift +348 -0
  18. package/lib/commonjs/index.js +68 -215
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/commonjs/models/CourierInboxListener.js +26 -0
  21. package/lib/commonjs/models/CourierInboxListener.js.map +1 -0
  22. package/lib/commonjs/models/CourierInboxTheme.js +2 -0
  23. package/lib/commonjs/models/CourierInboxTheme.js.map +1 -0
  24. package/lib/commonjs/models/InboxAction.js +2 -0
  25. package/lib/commonjs/models/InboxAction.js.map +1 -0
  26. package/lib/commonjs/models/InboxMessage.js +6 -0
  27. package/lib/commonjs/models/InboxMessage.js.map +1 -0
  28. package/lib/commonjs/views/CourierInboxView.js +53 -0
  29. package/lib/commonjs/views/CourierInboxView.js.map +1 -0
  30. package/lib/module/index.js +62 -214
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/models/CourierInboxListener.js +18 -0
  33. package/lib/module/models/CourierInboxListener.js.map +1 -0
  34. package/lib/module/models/CourierInboxTheme.js +2 -0
  35. package/lib/module/models/CourierInboxTheme.js.map +1 -0
  36. package/lib/module/models/InboxAction.js +2 -0
  37. package/lib/module/models/InboxAction.js.map +1 -0
  38. package/lib/module/models/InboxMessage.js +2 -0
  39. package/lib/module/models/InboxMessage.js.map +1 -0
  40. package/lib/module/views/CourierInboxView.js +45 -0
  41. package/lib/module/views/CourierInboxView.js.map +1 -0
  42. package/lib/typescript/index.d.ts +34 -94
  43. package/lib/typescript/index.d.ts.map +1 -0
  44. package/lib/typescript/models/CourierInboxListener.d.ts +9 -0
  45. package/lib/typescript/models/CourierInboxListener.d.ts.map +1 -0
  46. package/lib/typescript/models/CourierInboxTheme.d.ts +34 -0
  47. package/lib/typescript/models/CourierInboxTheme.d.ts.map +1 -0
  48. package/lib/typescript/models/InboxAction.d.ts +8 -0
  49. package/lib/typescript/models/InboxAction.d.ts.map +1 -0
  50. package/lib/typescript/models/InboxMessage.d.ts +18 -0
  51. package/lib/typescript/models/InboxMessage.d.ts.map +1 -0
  52. package/lib/typescript/views/CourierInboxView.d.ts +16 -0
  53. package/lib/typescript/views/CourierInboxView.d.ts.map +1 -0
  54. package/package.json +61 -44
  55. package/src/index.tsx +188 -0
  56. package/src/models/CourierInboxListener.tsx +25 -0
  57. package/src/models/CourierInboxTheme.tsx +30 -0
  58. package/src/models/InboxAction.tsx +5 -0
  59. package/src/models/InboxMessage.tsx +16 -0
  60. package/src/views/CourierInboxView.tsx +85 -0
  61. package/android/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  62. package/android/.gradle/7.1/dependencies-accessors/gc.properties +0 -0
  63. package/android/.gradle/7.1/executionHistory/executionHistory.lock +0 -0
  64. package/android/.gradle/7.1/fileChanges/last-build.bin +0 -0
  65. package/android/.gradle/7.1/fileHashes/fileHashes.bin +0 -0
  66. package/android/.gradle/7.1/fileHashes/fileHashes.lock +0 -0
  67. package/android/.gradle/7.1/gc.properties +0 -0
  68. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  69. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  70. package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  71. package/android/.gradle/checksums/checksums.lock +0 -0
  72. package/android/.gradle/checksums/md5-checksums.bin +0 -0
  73. package/android/.gradle/checksums/sha1-checksums.bin +0 -0
  74. package/android/.gradle/vcs-1/gc.properties +0 -0
  75. package/android/.idea/compiler.xml +0 -6
  76. package/android/.idea/gradle.xml +0 -17
  77. package/android/.idea/jarRepositories.xml +0 -35
  78. package/android/.idea/misc.xml +0 -10
  79. package/android/.idea/vcs.xml +0 -6
  80. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  81. package/android/gradle/wrapper/gradle-wrapper.properties +0 -5
  82. package/android/gradlew +0 -185
  83. package/android/gradlew.bat +0 -89
  84. package/android/local.properties +0 -8
  85. package/android/src/main/java/com/courierreactnative/NotificationPermissionStatus.kt +0 -6
  86. package/ios/CourierReactNative.m +0 -53
  87. package/ios/CourierReactNativeDelegate.h +0 -20
  88. package/ios/CourierReactNativeDelegate.m +0 -125
  89. package/src/index.ts +0 -341
@@ -1,13 +1,21 @@
1
1
  import Courier_iOS
2
2
 
3
- @objc(CourierReactNative)
4
- class CourierReactNative: RCTEventEmitter {
3
+ @objc(CourierReactNativeModule)
4
+ class CourierReactNativeModule: RCTEventEmitter {
5
5
 
6
6
  private static let COURIER_ERROR_TAG = "Courier iOS SDK Error"
7
7
  internal static let COURIER_PUSH_NOTIFICATION_CLICKED_EVENT = "pushNotificationClicked"
8
8
  internal static let COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT = "pushNotificationDelivered"
9
9
  private static let COURIER_PUSH_NOTIFICATION_DEBUG_LOG_EVENT = "courierDebugEvent"
10
10
 
11
+ class InboxEvents {
12
+ internal static let INITIAL_LOADING = "inboxInitialLoad"
13
+ internal static let ERROR = "inboxError"
14
+ internal static let MESSAGES_CHANGED = "inboxMessagesChanged"
15
+ }
16
+
17
+ private var inboxListeners = [String: CourierInboxListener]()
18
+
11
19
  private var hasListeners = false
12
20
 
13
21
  private var lastClickedMessage: [AnyHashable: Any]? = nil
@@ -35,7 +43,10 @@ class CourierReactNative: RCTEventEmitter {
35
43
 
36
44
  // setup listeners
37
45
  Courier.shared.logListener = { log in
38
- self.sendEvent(withName: CourierReactNative.COURIER_PUSH_NOTIFICATION_DEBUG_LOG_EVENT, body: log)
46
+ self.sendEvent(
47
+ withName: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_DEBUG_LOG_EVENT,
48
+ body: log
49
+ )
39
50
  }
40
51
 
41
52
  }
@@ -52,14 +63,14 @@ class CourierReactNative: RCTEventEmitter {
52
63
  notificationCenter.addObserver(
53
64
  self,
54
65
  selector: #selector(pushNotificationClicked),
55
- name: Notification.Name(rawValue: CourierReactNative.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT),
66
+ name: Notification.Name(rawValue: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT),
56
67
  object: nil
57
68
  )
58
69
 
59
70
  notificationCenter.addObserver(
60
71
  self,
61
72
  selector: #selector(pushNotificationDelivered),
62
- name: Notification.Name(rawValue: CourierReactNative.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT),
73
+ name: Notification.Name(rawValue: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT),
63
74
  object: nil
64
75
  )
65
76
 
@@ -86,7 +97,7 @@ class CourierReactNative: RCTEventEmitter {
86
97
 
87
98
  lastClickedMessage = notification.userInfo
88
99
  sendMessage(
89
- name: CourierReactNative.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
100
+ name: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
90
101
  message: lastClickedMessage
91
102
  )
92
103
 
@@ -95,7 +106,7 @@ class CourierReactNative: RCTEventEmitter {
95
106
  @objc private func pushNotificationDelivered(notification: Notification) {
96
107
 
97
108
  sendMessage(
98
- name: CourierReactNative.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT,
109
+ name: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT,
99
110
  message: notification.userInfo
100
111
  )
101
112
 
@@ -104,28 +115,12 @@ class CourierReactNative: RCTEventEmitter {
104
115
  @objc func registerPushNotificationClickedOnKilledState() {
105
116
 
106
117
  sendMessage(
107
- name: CourierReactNative.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
118
+ name: CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
108
119
  message: lastClickedMessage
109
120
  )
110
121
 
111
122
  }
112
-
113
- @objc(signIn: accessToken: withResolver: withRejecter:)
114
- func signIn(userId: NSString, accessToken: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
115
-
116
- Courier.shared.signIn(
117
- accessToken: accessToken as String,
118
- userId: userId as String,
119
- onSuccess: {
120
- resolve(nil)
121
- },
122
- onFailure: { error in
123
- reject(String(describing: error), CourierReactNative.COURIER_ERROR_TAG, nil)
124
- }
125
- )
126
-
127
- }
128
-
123
+
129
124
  @objc(getNotificationPermissionStatus: withRejecter:)
130
125
  func getNotificationPermissionStatus(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
131
126
 
@@ -144,6 +139,23 @@ class CourierReactNative: RCTEventEmitter {
144
139
 
145
140
  }
146
141
 
142
+ @objc(signIn: withClientKey: withUserId: withResolver: withRejecter:)
143
+ func signIn(accessToken: NSString, clientKey: NSString?, userId: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
144
+
145
+ Courier.shared.signIn(
146
+ accessToken: accessToken as String,
147
+ clientKey: clientKey as? String,
148
+ userId: userId as String,
149
+ onSuccess: {
150
+ resolve(nil)
151
+ },
152
+ onFailure: { error in
153
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
154
+ }
155
+ )
156
+
157
+ }
158
+
147
159
  @objc(signOut: withRejecter:)
148
160
  func signOut(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
149
161
 
@@ -152,7 +164,7 @@ class CourierReactNative: RCTEventEmitter {
152
164
  resolve(nil)
153
165
  },
154
166
  onFailure: { error in
155
- reject(String(describing: error), CourierReactNative.COURIER_ERROR_TAG, nil)
167
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
156
168
  }
157
169
  )
158
170
 
@@ -183,7 +195,7 @@ class CourierReactNative: RCTEventEmitter {
183
195
  resolve(nil)
184
196
  },
185
197
  onFailure: { error in
186
- reject(String(describing: error), CourierReactNative.COURIER_ERROR_TAG, nil)
198
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
187
199
  }
188
200
  )
189
201
 
@@ -197,28 +209,27 @@ class CourierReactNative: RCTEventEmitter {
197
209
 
198
210
  }
199
211
 
200
- @objc(sendPush: withUserId: withTitle: withBody: withProviders: withIsProduction: withResolver: withRejecter:)
201
- func sendPush(authKey: NSString, userId: NSString, title: NSString, body: NSString, providers: NSArray, isProduction: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
212
+ @objc(sendPush: withUserId: withTitle: withBody: withProviders: withResolver: withRejecter:)
213
+ func sendPush(authKey: NSString, userId: NSString, title: NSString, body: NSString, providers: NSArray, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
202
214
 
203
215
  guard let courierProviders = providers as? [String] else {
204
- reject("No provider supported", CourierReactNative.COURIER_ERROR_TAG, nil)
216
+ reject("No provider supported", CourierReactNativeModule.COURIER_ERROR_TAG, nil)
205
217
  return
206
218
  }
207
219
 
208
- Courier.shared.sendPush(
209
- authKey: authKey as String,
210
- userId: userId as String,
211
- title: title as String,
212
- message: body as String,
213
- isProduction: isProduction,
214
- providers: courierProviders,
215
- onSuccess: { requestId in
216
- resolve(requestId)
217
- },
218
- onFailure: { error in
219
- reject(String(describing: error), CourierReactNative.COURIER_ERROR_TAG, nil)
220
- }
221
- )
220
+ // Courier.shared.sendPush(
221
+ // authKey: authKey as String,
222
+ // userId: userId as String,
223
+ // title: title as String,
224
+ // message: body as String,
225
+ // providers: courierProviders,
226
+ // onSuccess: { requestId in
227
+ // resolve(requestId)
228
+ // },
229
+ // onFailure: { error in
230
+ // reject(String(describing: error), CourierReactNative.COURIER_ERROR_TAG, nil)
231
+ // }
232
+ // )
222
233
 
223
234
  }
224
235
 
@@ -235,21 +246,129 @@ class CourierReactNative: RCTEventEmitter {
235
246
  }
236
247
 
237
248
  @objc(setDebugMode: withResolver: withRejecter:)
238
- func setDebugMode(isDebugging: Bool,resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
249
+ func setDebugMode(isDebugging: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
239
250
 
240
251
  Courier.shared.isDebugging = isDebugging
241
252
  resolve(Courier.shared.isDebugging)
242
253
 
243
254
  }
255
+
256
+ @objc(readMessage: withResolver: withRejecter:)
257
+ func readMessage(messageId: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
258
+
259
+ Courier.shared.readMessage(
260
+ messageId: messageId as String,
261
+ onSuccess: {
262
+ resolve(nil)
263
+ },
264
+ onFailure: { error in
265
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
266
+ }
267
+ )
268
+
269
+ }
270
+
271
+ @objc(unreadMessage: withResolver: withRejecter:)
272
+ func unreadMessage(messageId: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
273
+
274
+ Courier.shared.unreadMessage(
275
+ messageId: messageId as String,
276
+ onSuccess: {
277
+ resolve(nil)
278
+ },
279
+ onFailure: { error in
280
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
281
+ }
282
+ )
283
+
284
+ }
285
+
286
+ @objc(readAllInboxMessages: withRejecter:)
287
+ func readAllInboxMessages(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
288
+
289
+ Courier.shared.readAllInboxMessages(
290
+ onSuccess: {
291
+ resolve(nil)
292
+ },
293
+ onFailure: { error in
294
+ reject(String(describing: error), CourierReactNativeModule.COURIER_ERROR_TAG, nil)
295
+ }
296
+ )
297
+
298
+ }
299
+
300
+ @objc(addInboxListener:)
301
+ func addInboxListener(listenerId: NSString?) -> String {
302
+
303
+ let listener = Courier.shared.addInboxListener(
304
+ onInitialLoad: { [weak self] in
305
+ self?.sendEvent(
306
+ withName: CourierReactNativeModule.InboxEvents.INITIAL_LOADING,
307
+ body: nil
308
+ )
309
+ },
310
+ onError: { [weak self] error in
311
+ self?.sendEvent(
312
+ withName: CourierReactNativeModule.InboxEvents.ERROR,
313
+ body: String(describing: error)
314
+ )
315
+ },
316
+ onMessagesChanged: { [weak self] messages, unreadMessageCount, totalMessageCount, canPaginate in
317
+
318
+ let json: [String: Any] = [
319
+ "messages": messages.map { $0.toDictionary() },
320
+ "unreadMessageCount": unreadMessageCount,
321
+ "totalMessageCount": totalMessageCount,
322
+ "canPaginate": canPaginate
323
+ ]
324
+
325
+ self?.sendEvent(
326
+ withName: CourierReactNativeModule.InboxEvents.MESSAGES_CHANGED,
327
+ body: json
328
+ )
329
+
330
+ }
331
+ )
332
+
333
+ // Create an id and add the listener to the dictionary
334
+ let id = UUID().uuidString
335
+ inboxListeners[id] = listener
336
+
337
+ return id
338
+
339
+ }
340
+
341
+ @objc(removeInboxListener:)
342
+ func removeInboxListener(listenerId: NSString) -> String {
343
+
344
+ let id = listenerId as String
345
+
346
+ // Remove the listener
347
+ let listener = inboxListeners[id]
348
+ listener?.remove()
349
+
350
+ // Remove from dictionary
351
+ inboxListeners.removeValue(forKey: id)
352
+
353
+ return id
354
+
355
+ }
244
356
 
245
357
  override func supportedEvents() -> [String]! {
246
358
  return [
247
- CourierReactNative.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
248
- CourierReactNative.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT,
249
- CourierReactNative.COURIER_PUSH_NOTIFICATION_DEBUG_LOG_EVENT
359
+ CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_CLICKED_EVENT,
360
+ CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_DELIVERED_EVENT,
361
+ CourierReactNativeModule.COURIER_PUSH_NOTIFICATION_DEBUG_LOG_EVENT,
362
+ CourierReactNativeModule.InboxEvents.INITIAL_LOADING,
363
+ CourierReactNativeModule.InboxEvents.ERROR,
364
+ CourierReactNativeModule.InboxEvents.MESSAGES_CHANGED
250
365
  ]
251
366
  }
252
367
 
368
+ @objc override static func requiresMainQueueSetup() -> Bool {
369
+ return true
370
+ }
371
+
253
372
  }
254
373
 
255
374
  extension [AnyHashable: Any] {
@@ -0,0 +1,15 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ @interface RCT_EXTERN_MODULE(CourierReactNativeViewManager, RCTViewManager)
4
+
5
+ RCT_EXPORT_VIEW_PROPERTY(lightTheme, NSDictionary)
6
+
7
+ RCT_EXPORT_VIEW_PROPERTY(darkTheme, NSDictionary)
8
+
9
+ RCT_EXPORT_VIEW_PROPERTY(onClickInboxMessageAtIndex, RCTBubblingEventBlock)
10
+
11
+ RCT_EXPORT_VIEW_PROPERTY(onClickInboxActionForMessageAtIndex, RCTBubblingEventBlock)
12
+
13
+ RCT_EXPORT_VIEW_PROPERTY(onScrollInbox, RCTBubblingEventBlock)
14
+
15
+ @end
@@ -0,0 +1,348 @@
1
+ import Courier_iOS
2
+
3
+ @objc(CourierReactNativeViewManager)
4
+ class CourierReactNativeViewManager: RCTViewManager {
5
+
6
+ override func view() -> (CourierReactNativeView) {
7
+ return CourierReactNativeView()
8
+ }
9
+
10
+ @objc override static func requiresMainQueueSetup() -> Bool {
11
+ return true
12
+ }
13
+
14
+ }
15
+
16
+ class CourierReactNativeView : UIView {
17
+
18
+ @objc var lightTheme: NSDictionary? = [:] {
19
+ didSet {
20
+ refreshInbox()
21
+ }
22
+ }
23
+
24
+ @objc var darkTheme: NSDictionary? = [:] {
25
+ didSet {
26
+ refreshInbox()
27
+ }
28
+ }
29
+
30
+ @objc var onClickInboxMessageAtIndex: RCTBubblingEventBlock? = nil
31
+
32
+ @objc var onClickInboxActionForMessageAtIndex: RCTBubblingEventBlock? = nil
33
+
34
+ @objc var onScrollInbox: RCTBubblingEventBlock? = nil
35
+
36
+ override init(frame: CGRect) {
37
+ super.init(frame: frame)
38
+ refreshInbox()
39
+ }
40
+
41
+ required init?(coder: NSCoder) {
42
+ super.init(coder: coder)
43
+ refreshInbox()
44
+ }
45
+
46
+ private func refreshInbox() {
47
+
48
+ subviews.forEach { $0.removeFromSuperview() }
49
+
50
+ // Create the view
51
+ let courierInbox = CourierInbox(
52
+ lightTheme: dictionaryToTheme(dictionary: lightTheme) ?? .defaultLight,
53
+ darkTheme: dictionaryToTheme(dictionary: darkTheme) ?? .defaultDark,
54
+ didClickInboxMessageAtIndex: { [weak self] message, index in
55
+ self?.onClickInboxMessageAtIndex?([
56
+ "message" : message.toDictionary(),
57
+ "index" : index
58
+ ])
59
+ },
60
+ didClickInboxActionForMessageAtIndex: { [weak self] action, message, index in
61
+ self?.onClickInboxActionForMessageAtIndex?([
62
+ "action" : action.toDictionary(),
63
+ "message" : message.toDictionary(),
64
+ "index" : index
65
+ ])
66
+ },
67
+ didScrollInbox: { [weak self] scrollView in
68
+ self?.onScrollInbox?([
69
+ "contentOffset" : [
70
+ "y": scrollView.contentOffset.y,
71
+ "x": scrollView.contentOffset.x
72
+ ]
73
+ ])
74
+ }
75
+ )
76
+
77
+ // Add the view to your UI
78
+ courierInbox.translatesAutoresizingMaskIntoConstraints = false
79
+ addSubview(courierInbox)
80
+
81
+ // Constrain the view how you'd like
82
+ NSLayoutConstraint.activate([
83
+ courierInbox.topAnchor.constraint(equalTo: topAnchor),
84
+ courierInbox.bottomAnchor.constraint(equalTo: bottomAnchor),
85
+ courierInbox.leadingAnchor.constraint(equalTo: leadingAnchor),
86
+ courierInbox.trailingAnchor.constraint(equalTo: trailingAnchor),
87
+ ])
88
+
89
+ }
90
+
91
+ func dictionaryToTheme(dictionary: NSDictionary?) -> CourierInboxTheme? {
92
+
93
+ guard let dict = dictionary else {
94
+ return nil
95
+ }
96
+
97
+ // iOS Theme
98
+ let iOS = dict["iOS"] as? [String : Any]
99
+ let messageAnimationStyle = iOS?["messageAnimationStyle"] as? String
100
+ let cellStyles = iOS?["cellStyles"] as? [String : Any]
101
+
102
+ // Unread
103
+ let unreadIndicatorBarColor = dict["unreadIndicatorBarColor"] as? String
104
+
105
+ // Loading
106
+ let loadingIndicatorColor = dict["loadingIndicatorColor"] as? String
107
+
108
+ // Title
109
+ let titleFont = dict["titleFont"] as? [String : Any]
110
+
111
+ // Time
112
+ let timeFont = dict["timeFont"] as? [String : Any]
113
+
114
+ // Body
115
+ let bodyFont = dict["bodyFont"] as? [String : Any]
116
+
117
+ // Detail
118
+ let detailTitleFont = dict["detailTitleFont"] as? [String : Any]
119
+
120
+ // Detail
121
+ let buttonStyles = dict["buttonStyles"] as? [String : Any]
122
+
123
+ return CourierInboxTheme(
124
+ messageAnimationStyle: messageAnimationStyle?.toRowAnimation() ?? .left,
125
+ unreadIndicatorBarColor: unreadIndicatorBarColor?.toColor(),
126
+ loadingIndicatorColor: loadingIndicatorColor?.toColor(),
127
+ titleFont: dictionaryToFont(
128
+ dictionary: titleFont,
129
+ defaultFont: UIFont.boldSystemFont(ofSize: UIFont.labelFontSize),
130
+ defaultColor: .label
131
+ ),
132
+ timeFont: dictionaryToFont(
133
+ dictionary: timeFont,
134
+ defaultFont: UIFont.systemFont(ofSize: UIFont.labelFontSize),
135
+ defaultColor: .placeholderText
136
+ ),
137
+ bodyFont: dictionaryToFont(
138
+ dictionary: bodyFont,
139
+ defaultFont: UIFont.systemFont(ofSize: UIFont.labelFontSize),
140
+ defaultColor: .label
141
+ ),
142
+ detailTitleFont: dictionaryToFont(
143
+ dictionary: detailTitleFont,
144
+ defaultFont: UIFont.systemFont(ofSize: UIFont.labelFontSize),
145
+ defaultColor: .label
146
+ ),
147
+ buttonStyles: dictionaryToButtonStyles(
148
+ dictionary: buttonStyles
149
+ ),
150
+ cellStyles: dictionaryToCellStyles(
151
+ dictionary: cellStyles
152
+ )
153
+ )
154
+
155
+ }
156
+
157
+ func dictionaryToFont(dictionary: [String : Any]?, defaultFont: UIFont, defaultColor: UIColor) -> CourierInboxFont {
158
+
159
+ guard let dict = dictionary else {
160
+ return CourierInboxFont(
161
+ font: defaultFont,
162
+ color: defaultColor
163
+ )
164
+ }
165
+
166
+ let family = dict["family"] as? String ?? defaultFont.familyName
167
+ let size = dict["size"] as? CGFloat ?? defaultFont.pointSize
168
+ let color = dict["color"] as? String
169
+
170
+ return CourierInboxFont(
171
+ font: UIFont(name: family, size: size) ?? defaultFont,
172
+ color: color?.toColor() ?? defaultColor
173
+ )
174
+
175
+ }
176
+
177
+ func dictionaryToButtonStyles(dictionary: [String : Any]?) -> CourierInboxButtonStyles {
178
+
179
+ guard let dict = dictionary else {
180
+ return CourierInboxButtonStyles()
181
+ }
182
+
183
+ let font = dict["font"] as? [String : Any]
184
+ let backgroundColor = dict["backgroundColor"] as? String
185
+ let cornerRadius = dict["cornerRadius"] as? CGFloat
186
+
187
+ return CourierInboxButtonStyles(
188
+ font: dictionaryToFont(
189
+ dictionary: font,
190
+ defaultFont: UIFont.systemFont(ofSize: UIFont.labelFontSize),
191
+ defaultColor: .white
192
+ ),
193
+ backgroundColor: backgroundColor?.toColor(),
194
+ cornerRadius: cornerRadius ?? 8
195
+ )
196
+
197
+ }
198
+
199
+ func dictionaryToCellStyles(dictionary: [String : Any]?) -> CourierInboxCellStyles {
200
+
201
+ guard let dict = dictionary else {
202
+ return CourierInboxCellStyles()
203
+ }
204
+
205
+ let separatorStyle = dict["separatorStyle"] as? String
206
+ let separatorColor = dict["separatorColor"] as? String
207
+ let selectionStyle = dict["selectionStyle"] as? String
208
+
209
+ let insets = dict["separatorInsets"] as? [String : Any]
210
+ let top = insets?["top"] as? CGFloat
211
+ let left = insets?["left"] as? CGFloat
212
+ let right = insets?["right"] as? CGFloat
213
+ let bottom = insets?["bottom"] as? CGFloat
214
+ let separatorInsets = UIEdgeInsets(top: top ?? 0, left: left ?? 0, bottom: bottom ?? 0, right: right ?? 0)
215
+
216
+ return CourierInboxCellStyles(
217
+ separatorStyle: separatorStyle?.toSeparatorStyle() ?? .singleLine,
218
+ separatorInsets: separatorInsets,
219
+ separatorColor: separatorColor?.toColor(),
220
+ selectionStyle: selectionStyle?.toSelectionStyle() ?? .default
221
+ )
222
+
223
+ }
224
+
225
+ }
226
+
227
+ internal extension InboxMessage {
228
+
229
+ @objc func toDictionary() -> NSDictionary {
230
+
231
+ let dictionary: [String: Any?] = [
232
+ "messageId": messageId,
233
+ "title": title,
234
+ "body": body,
235
+ "preview": preview,
236
+ "created": created,
237
+ "actions": actions?.map { $0.toDictionary() },
238
+ "data": data,
239
+ "read": isRead,
240
+ "opened": isOpened,
241
+ "archived": isArchived
242
+ ]
243
+
244
+ let mutableDictionary = NSMutableDictionary()
245
+ for (key, value) in dictionary {
246
+ if let unwrappedValue = value {
247
+ mutableDictionary[key] = unwrappedValue
248
+ }
249
+ }
250
+
251
+ return mutableDictionary
252
+
253
+ }
254
+
255
+ }
256
+
257
+ internal extension InboxAction {
258
+
259
+ @objc func toDictionary() -> NSDictionary {
260
+
261
+ let dictionary: [String: Any?] = [
262
+ "content": content,
263
+ "href": href,
264
+ "data": data
265
+ ]
266
+
267
+ let mutableDictionary = NSMutableDictionary()
268
+ for (key, value) in dictionary {
269
+ if let unwrappedValue = value {
270
+ mutableDictionary[key] = unwrappedValue
271
+ }
272
+ }
273
+
274
+ return mutableDictionary
275
+
276
+ }
277
+
278
+ }
279
+
280
+ internal extension String {
281
+
282
+ func toRowAnimation() -> UITableView.RowAnimation {
283
+
284
+ switch self.lowercased() {
285
+ case "fade": return .fade
286
+ case "right": return .right
287
+ case "left": return .left
288
+ case "top": return .top
289
+ case "bottom": return .bottom
290
+ case "none": return .none
291
+ case "middle": return .middle
292
+ case "automatic":
293
+ if #available(iOS 11.0, *) {
294
+ return .automatic
295
+ } else {
296
+ return .fade
297
+ }
298
+ default: return .fade
299
+ }
300
+
301
+ }
302
+
303
+ func toSeparatorStyle() -> UITableViewCell.SeparatorStyle {
304
+
305
+ switch self.lowercased() {
306
+ case "none": return .none
307
+ case "singleLine": return .singleLine
308
+ case "singleLineEtched": return .singleLineEtched
309
+ default: return .singleLine
310
+ }
311
+
312
+ }
313
+
314
+ func toSelectionStyle() -> UITableViewCell.SelectionStyle? {
315
+
316
+ switch self.lowercased() {
317
+ case "none": return .none
318
+ case "blue": return .blue
319
+ case "gray": return .gray
320
+ case "default": return .default
321
+ default: return .default
322
+ }
323
+
324
+ }
325
+
326
+ func toColor() -> UIColor? {
327
+
328
+ var hexSanitized = trimmingCharacters(in: .whitespacesAndNewlines)
329
+ hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
330
+
331
+ var rgb: UInt64 = 0
332
+
333
+ Scanner(string: hexSanitized).scanHexInt64(&rgb)
334
+
335
+ guard hexSanitized.count == 6 else {
336
+ return nil
337
+ }
338
+
339
+ return UIColor(
340
+ red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
341
+ green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
342
+ blue: CGFloat(rgb & 0x0000FF) / 255.0,
343
+ alpha: 1.0
344
+ )
345
+
346
+ }
347
+
348
+ }