This repository was archived by the owner on Sep 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathRemoteNotificationSettings.swift
More file actions
186 lines (163 loc) · 6.59 KB
/
Copy pathRemoteNotificationSettings.swift
File metadata and controls
186 lines (163 loc) · 6.59 KB
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
import Foundation
/// The goal of this class is to parse Notification Settings data from the backend, and structure it in a
/// meaningful way. Notification Settings come in three different flavors:
///
/// - "Our Own" Blog Settings
/// - "Third Party" Site Settings
/// - WordPress.com Settings
///
/// Each one of the possible channels may post notifications via different streams:
/// Email, Push Notifications, and Timeline.
///
open class RemoteNotificationSettings {
/// Represents the Channel to which the current settings are associated.
///
public let channel: Channel
/// Contains an array of the available Notification Streams.
///
public let streams: [Stream]
/// Represents a communication channel that may post notifications to the user.
///
@frozen public enum Channel: Equatable {
case blog(blogId: Int)
case other
case wordPressCom
}
/// Contains the Notification Settings for a specific communications stream.
///
open class Stream {
open var kind: Kind
open var preferences: [String: Bool]?
/// Enumerates all of the possible Stream Kinds
///
public enum Kind: String {
case Timeline = "timeline"
case Email = "email"
case Device = "device"
static let allValues = [ Timeline, Email, Device ]
}
/// Private Designated Initializer
///
/// - Parameters:
/// - kind: The Kind of stream we're currently dealing with
/// - preferences: Raw remote preferences, retrieved from the backend
///
fileprivate init(kind: Kind, preferences: NSDictionary?) {
self.kind = kind
self.preferences = filterNonBooleanEntries(preferences)
}
/// Helper method that will filter out non boolean entries, and return a native Swift collection.
///
/// - Parameter dictionary: NextStep Dictionary containing raw values
///
/// - Returns: A native Swift dictionary, containing only the Boolean entries
///
private func filterNonBooleanEntries(_ dictionary: NSDictionary?) -> [String: Bool] {
var filtered = [String: Bool]()
if dictionary == nil {
return filtered
}
for (key, value) in dictionary! {
if let stringKey = key as? String,
let boolValue = value as? Bool {
let value = value as AnyObject
// NSNumbers might get converted to Bool anyways
if value === kCFBooleanFalse || value === kCFBooleanTrue {
filtered[stringKey] = boolValue
}
}
}
return filtered
}
/// Parser method that will convert a raw dictionary of stream settings into Swift Native objects.
///
/// - Parameter dictionary: NextStep Dictionary containing raw Stream Preferences
///
/// - Returns: A native Swift array containing Stream entities
///
fileprivate static func fromDictionary(_ dictionary: NSDictionary?) -> [Stream] {
var parsed = [Stream]()
for kind in Kind.allValues {
if let preferences = dictionary?[kind.rawValue] as? NSDictionary {
parsed.append(Stream(kind: kind, preferences: preferences))
}
}
return parsed
}
}
/// Private Designated Initializer
///
/// - Parameters:
/// - channel: The communications channel that uses the current settings
/// - settings: Raw dictionary containing the remote settings response
///
private init(channel: Channel, settings: NSDictionary?) {
self.channel = channel
self.streams = Stream.fromDictionary(settings)
}
/// Private Designated Initializer
///
/// - Parameter wpcomSettings: Dictionary containing the collection of WordPress.com Settings
///
private init(wpcomSettings: NSDictionary?) {
// WordPress.com is a special scenario: It contains just one (unspecified) stream: Email
self.channel = Channel.wordPressCom
self.streams = [ Stream(kind: .Email, preferences: wpcomSettings) ]
}
/// Private Convenience Initializer
///
/// - Parameter blogSettings: Dictionary containing the collection of settings for a single blog
///
private convenience init(blogSettings: NSDictionary?) {
let blogId = blogSettings?["blog_id"] as? Int ?? Int.max
self.init(channel: Channel.blog(blogId: blogId), settings: blogSettings)
}
/// Private Convenience Initializer
///
/// - Parameter otherSettings: Dictionary containing the collection of "Other Settings"
///
private convenience init(otherSettings: NSDictionary?) {
self.init(channel: Channel.other, settings: otherSettings)
}
/// Static Helper that will parse all of the Remote Settings, into a collection of Swift Native
/// RemoteNotificationSettings objects.
///
/// - Parameter dictionary: Dictionary containing the remote Settings response
///
/// - Returns: An array of RemoteNotificationSettings objects
///
public static func fromDictionary(_ dictionary: NSDictionary?) -> [RemoteNotificationSettings] {
var parsed = [RemoteNotificationSettings]()
if let rawBlogs = dictionary?["blogs"] as? [NSDictionary] {
for rawBlog in rawBlogs {
let parsedBlog = RemoteNotificationSettings(blogSettings: rawBlog)
parsed.append(parsedBlog)
}
}
let other = RemoteNotificationSettings(otherSettings: dictionary?["other"] as? NSDictionary)
parsed.append(other)
let wpcom = RemoteNotificationSettings(wpcomSettings: dictionary?["wpcom"] as? NSDictionary)
parsed.append(wpcom)
return parsed
}
}
/// Swift requires this method to be implemented globally. Sorry about that!
///
/// - Parameters:
/// - lhs: Left Hand Side Channel
/// - rhs: Right Hand Side Channel
///
/// - Returns: A boolean indicating whether two channels are equal. Or not!
///
public func ==(lhs: RemoteNotificationSettings.Channel, rhs: RemoteNotificationSettings.Channel) -> Bool {
switch (lhs, rhs) {
case (let .blog(firstBlogId), let .blog(secondBlogId)) where firstBlogId == secondBlogId:
return true
case (.other, .other):
return true
case (.wordPressCom, .wordPressCom):
return true
default:
return false
}
}