Newer
Older
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
import Integration
import DependencyInjection
public final class PushHandler: PushHandling {
private enum Constants {
static let appGroup = "group.elixxir.messenger"
static let usernamesSetting = "isShowingUsernames"
}
@KeyObject(.pushNotifications, defaultValue: false) var isPushEnabled: Bool
let requestAuth: RequestAuth
public static let defaultRequestAuth = UNUserNotificationCenter.current().requestAuthorization
public typealias RequestAuth = (UNAuthorizationOptions, @escaping (Bool, Error?) -> Void) -> Void
public var pushExtractor: PushExtractor
public var contentsBuilder: ContentsBuilder
public var applicationState: () -> UIApplication.State
public init(
requestAuth: @escaping RequestAuth = defaultRequestAuth,
pushExtractor: PushExtractor = .live,
contentsBuilder: ContentsBuilder = .live,
applicationState: @escaping () -> UIApplication.State = { UIApplication.shared.applicationState }
) {
self.requestAuth = requestAuth
self.pushExtractor = pushExtractor
self.contentsBuilder = contentsBuilder
self.applicationState = applicationState
}
public func registerToken(_ token: Data) {
do {
let session = try DependencyInjection.Container.shared.resolve() as SessionType
try session.registerNotifications(token)
} catch {
isPushEnabled = false
}
}
public func requestAuthorization(
_ completion: @escaping (Result<Bool, Error>) -> Void
) {
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
requestAuth(options) { granted, error in
guard let error = error else {
completion(.success(granted))
return
}
completion(.failure(error))
}
}
public func handlePush(
_ userInfo: [AnyHashable: Any],
_ completion: @escaping (UIBackgroundFetchResult) -> Void
) {
do {
guard
let pushes = try pushExtractor.extractFrom(userInfo).get(),
applicationState() == .background,
pushes.isEmpty == false
else {
completion(.noData)
return
}
let content = contentsBuilder.build("New Messages Available", pushes.first!)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: Bundle.main.bundleIdentifier!, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if error == nil {
completion(.newData)
} else {
completion(.failed)
}
}
} catch {
completion(.failed)
}
}
public func handlePush(
_ request: UNNotificationRequest,
_ completion: @escaping (UNNotificationContent) -> Void
) {
guard let pushes = try? pushExtractor.extractFrom(request.content.userInfo).get(), !pushes.isEmpty,
let defaults = UserDefaults(suiteName: Constants.appGroup) else {
return
}
guard let showSender = defaults.value(forKey: Constants.usernamesSetting) as? Bool, showSender == true else {
pushes.map { ($0.type.unknownSenderContent!, $0) }
.map(contentsBuilder.build)
.forEach { completion($0) }
return
}
let dbPath = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")!
.appendingPathComponent("xxm_database")
.appendingPathExtension("sqlite").path
let dbManager = try? Database.onDisk(path: dbPath),
let contact = try? dbManager.fetchContacts(.init(id: [userId])).first else {

Bruno Muniz
committed
if contact.isBlocked || contact.isBanned {
return nil
}
let name = (contact.nickname ?? contact.username) ?? ""
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
return ($0.type.knownSenderContent(name)!, $0)
}
tuples
.map(contentsBuilder.build)
.forEach { completion($0) }
}
public func handleAction(
_ router: PushRouter,
_ userInfo: [AnyHashable : Any],
_ completion: @escaping () -> Void
) {
guard let typeString = userInfo["type"] as? String,
let type = PushType(rawValue: typeString) else {
completion()
return
}
let route: PushRouter.Route
switch type {
case .e2e:
guard let source = userInfo["source"] as? Data else {
completion()
return
}
route = .contactChat(id: source)
case .group:
guard let source = userInfo["source"] as? Data else {
completion()
return
}
route = .groupChat(id: source)
case .request, .groupRq:
route = .requests
case .silent, .`default`:
fatalError("Silent/Default push types should be filtered at this point")
case .reset, .endFT, .confirm:
route = .requests
}
router.navigateTo(route, completion)
}
}