Revision fa6e5004
ChatSecure.xcodeproj/project.pbxproj | ||
---|---|---|
530 | 530 |
D9EEEDD31D2739A800B8BC54 /* OTRvCard.h in Headers */ = {isa = PBXBuildFile; fileRef = D9EEEDD11D27388600B8BC54 /* OTRvCard.h */; settings = {ATTRIBUTES = (Public, ); }; }; |
531 | 531 |
D9F3B1AF1FD48DDA00DFC5DA /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9F3B1AE1FD48DDA00DFC5DA /* Account.swift */; }; |
532 | 532 |
D9F8C3C21FBFD2CA00D4B857 /* RoomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9F8C3C11FBFD2CA00D4B857 /* RoomManager.swift */; }; |
533 |
D9FBDDC91FD74A93006F1C6C /* OTRAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9FBDDC81FD74A93006F1C6C /* OTRAppDelegate.swift */; }; |
|
533 | 534 |
D9FD36011EFAFD3C00398CE4 /* FormatterKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9EC476B1EFA03FC00C39B25 /* FormatterKit.framework */; }; |
534 | 535 |
D9FD36021EFAFD3C00398CE4 /* HTMLReader.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9EC476C1EFA03FC00C39B25 /* HTMLReader.framework */; }; |
535 | 536 |
D9FD36031EFAFD3C00398CE4 /* KVOController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9EC476E1EFA03FC00C39B25 /* KVOController.framework */; }; |
... | ... | |
1177 | 1178 |
D9EEEDD11D27388600B8BC54 /* OTRvCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OTRvCard.h; path = "Yap Storage/OTRvCard.h"; sourceTree = "<group>"; }; |
1178 | 1179 |
D9F3B1AE1FD48DDA00DFC5DA /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; }; |
1179 | 1180 |
D9F8C3C11FBFD2CA00D4B857 /* RoomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomManager.swift; sourceTree = "<group>"; }; |
1181 |
D9FBDDC81FD74A93006F1C6C /* OTRAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTRAppDelegate.swift; sourceTree = "<group>"; }; |
|
1180 | 1182 |
DE32B878BAC9A236855EAF6E /* Pods-ChatSecureCorePods-ChatSecure.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatSecureCorePods-ChatSecure.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ChatSecureCorePods-ChatSecure/Pods-ChatSecureCorePods-ChatSecure.debug.xcconfig"; sourceTree = "<group>"; }; |
1181 | 1183 |
/* End PBXFileReference section */ |
1182 | 1184 |
|
... | ... | |
1307 | 1309 |
633105001A16D1A300C17BAE /* Classes */ = { |
1308 | 1310 |
isa = PBXGroup; |
1309 | 1311 |
children = ( |
1312 |
D9FBDDC81FD74A93006F1C6C /* OTRAppDelegate.swift */, |
|
1310 | 1313 |
633105E51A16D1A300C17BAE /* OTRAppDelegate.h */, |
1311 | 1314 |
633105E61A16D1A300C17BAE /* OTRAppDelegate.m */, |
1312 | 1315 |
633105011A16D1A300C17BAE /* Categories */, |
... | ... | |
3187 | 3190 |
632AA72B1D480BFF00F65733 /* OTRSignalSenderKey.m in Sources */, |
3188 | 3191 |
632AA72F1D4819BD00F65733 /* OTRSignalPreKey.m in Sources */, |
3189 | 3192 |
D93DDADE1BA79A2700CD8331 /* OTRXMPPPresenceSubscriptionRequest.m in Sources */, |
3193 |
D9FBDDC91FD74A93006F1C6C /* OTRAppDelegate.swift in Sources */, |
|
3190 | 3194 |
D93DDADF1BA79A2700CD8331 /* OTRYapDatabaseObject.m in Sources */, |
3191 | 3195 |
D94ACBA51DFA206500B8C0F5 /* OTRBuddyCache.m in Sources */, |
3192 | 3196 |
D93DDAE01BA79A2700CD8331 /* OTRCertificatePinning.m in Sources */, |
ChatSecure/Classes/Controllers/XMPP/Storage/MessageStorage.swift | ||
---|---|---|
295 | 295 |
|
296 | 296 |
self.fileTransfer.createAndDownloadItemsIfNeeded(message: message, force: false, transaction: transaction) |
297 | 297 |
UIApplication.shared.showLocalNotification(message, transaction: transaction) |
298 |
|
|
299 |
/// mark as read if on screen |
|
300 |
MessageStorage.markAsReadIfVisible(message: message) |
|
298 | 301 |
} |
299 | 302 |
} |
300 | 303 |
|
... | ... | |
469 | 472 |
// Extract XEP-0359 stanza-id |
470 | 473 |
self.originId = xmppMessage.originId |
471 | 474 |
self.stanzaId = xmppMessage.extractStanzaId(account: account, capabilities: capabilities) |
472 |
|
|
473 |
if let incoming = self as? OTRIncomingMessage { |
|
474 |
// Mark if read if it's on the screen |
|
475 |
// TODO: make this not dependent on global main thread variable |
|
476 |
if let yapKey = OTRAppDelegate.appDelegate.activeThreadYapKey, |
|
477 |
yapKey == incoming.threadId { |
|
478 |
incoming.read = true |
|
479 |
} |
|
480 |
} |
|
481 | 475 |
} |
482 | 476 |
} |
483 | 477 |
|
... | ... | |
488 | 482 |
} |
489 | 483 |
} |
490 | 484 |
|
485 |
public extension MessageStorage { |
|
486 |
@objc public static func markAsReadIfVisible(message: OTRMessageProtocol) { |
|
487 |
guard message.isMessageRead == false, |
|
488 |
let connection = OTRDatabaseManager.shared.readWriteDatabaseConnection else { |
|
489 |
return |
|
490 |
} |
|
491 |
OTRAppDelegate.visibleThread({ (ck) in |
|
492 |
guard let key = ck?.key, |
|
493 |
let collection = ck?.collection, |
|
494 |
key == message.threadId, |
|
495 |
collection == message.threadCollection else { |
|
496 |
return |
|
497 |
} |
|
498 |
connection.asyncReadWrite({ (transaction) in |
|
499 |
if message.isMessageRead == false, let message = message.copyAsSelf() { |
|
500 |
if let incoming = message as? OTRIncomingMessage { |
|
501 |
incoming.read = true |
|
502 |
} else if let roomMessage = message as? OTRXMPPRoomMessage { |
|
503 |
roomMessage.read = true |
|
504 |
} |
|
505 |
message.save(with: transaction) |
|
506 |
} |
|
507 |
}) |
|
508 |
}) |
|
509 |
} |
|
510 |
} |
|
511 |
|
ChatSecure/Classes/Controllers/XMPP/Storage/OTRXMPPMessageYapStorage.m | ||
---|---|---|
140 | 140 |
} |
141 | 141 |
|
142 | 142 |
OTRIncomingMessage *message = [self incomingMessageFromXMPPMessage:xmppMessage buddyId:messageBuddy.uniqueId]; |
143 |
NSString *activeThreadYapKey = [[OTRAppDelegate appDelegate] activeThreadYapKey];
|
|
143 |
NSString *activeThreadYapKey = [[OTRAppDelegate appDelegate] r];
|
|
144 | 144 |
if([activeThreadYapKey isEqualToString:message.threadId]) { |
145 | 145 |
message.read = YES; |
146 | 146 |
} |
ChatSecure/Classes/Controllers/XMPP/Storage/OTRXMPPRoomYapStorage.m | ||
---|---|---|
76 | 76 |
__block OTRXMPPRoomMessage *databaseMessage = nil; |
77 | 77 |
__block OTRXMPPRoom *databaseRoom = nil; |
78 | 78 |
__block OTRXMPPAccount *account = nil; |
79 |
|
|
79 | 80 |
[self.databaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { |
80 | 81 |
account = [OTRXMPPAccount fetchObjectWithUniqueID:accountId transaction:transaction]; |
81 | 82 |
// Sends a response receipt when receiving a delivery receipt request |
... | ... | |
84 | 85 |
// Extract XEP-0359 stanza-id |
85 | 86 |
NSString *stanzaId = [message extractStanzaIdWithAccount:account capabilities:self.capabilities]; |
86 | 87 |
NSString *originId = message.originId; |
87 |
databaseMessage.originId = originId; |
|
88 |
databaseMessage.stanzaId = stanzaId; |
|
89 | 88 |
|
90 | 89 |
if ([self existsMessage:message from:fromJID stanzaId:stanzaId transaction:transaction]) { |
91 | 90 |
// This message already exists and shouldn't be inserted |
... | ... | |
120 | 119 |
databaseMessage.roomUniqueId = databaseRoom.uniqueId; |
121 | 120 |
|
122 | 121 |
databaseRoom.lastRoomMessageId = [databaseMessage uniqueId]; |
123 |
NSString *activeThreadYapKey = [[OTRAppDelegate appDelegate] activeThreadYapKey]; |
|
124 |
if([activeThreadYapKey isEqualToString:databaseMessage.threadId]) { |
|
125 |
databaseMessage.read = YES; |
|
126 |
} else { |
|
127 |
databaseMessage.read = NO; |
|
128 |
} |
|
122 |
databaseMessage.originId = originId; |
|
123 |
databaseMessage.stanzaId = stanzaId; |
|
124 |
databaseMessage.read = NO; |
|
125 |
|
|
129 | 126 |
|
130 | 127 |
[databaseRoom saveWithTransaction:transaction]; |
131 | 128 |
[databaseMessage saveWithTransaction:transaction]; |
132 | 129 |
|
133 |
if(databaseMessage) { |
|
134 |
OTRXMPPManager *xmpp = (OTRXMPPManager*)[OTRProtocolManager.shared protocolForAccount:account]; |
|
135 |
[xmpp.fileTransferManager createAndDownloadItemsIfNeededWithMessage:databaseMessage force:NO transaction:transaction]; |
|
136 |
// If delayedDeliveryDate is set we are retrieving history. Don't show |
|
137 |
// notifications in that case. Also, don't show notifications for archived |
|
138 |
// rooms. |
|
139 |
if (!message.delayedDeliveryDate && !databaseRoom.isArchived) { |
|
140 |
[[UIApplication sharedApplication] showLocalNotification:databaseMessage transaction:transaction]; |
|
141 |
} |
|
130 |
OTRXMPPManager *xmpp = (OTRXMPPManager*)[OTRProtocolManager.shared protocolForAccount:account]; |
|
131 |
[xmpp.fileTransferManager createAndDownloadItemsIfNeededWithMessage:databaseMessage force:NO transaction:transaction]; |
|
132 |
// If delayedDeliveryDate is set we are retrieving history. Don't show |
|
133 |
// notifications in that case. Also, don't show notifications for archived |
|
134 |
// rooms. |
|
135 |
if (!message.delayedDeliveryDate && !databaseRoom.isArchived) { |
|
136 |
[[UIApplication sharedApplication] showLocalNotification:databaseMessage transaction:transaction]; |
|
142 | 137 |
} |
138 |
[MessageStorage markAsReadIfVisibleWithMessage:databaseMessage]; |
|
143 | 139 |
}]; |
144 | 140 |
} |
145 | 141 |
|
ChatSecure/Classes/OTRAppDelegate.h | ||
---|---|---|
35 | 35 |
/** Only used from Database Unlock view. */ |
36 | 36 |
- (void) showConversationViewController; |
37 | 37 |
|
38 |
/** The yap key for the active on-screen OTRThreadOwner. This should be moved */ |
|
39 |
@property (nonatomic, readonly, nullable) NSString *activeThreadYapKey; |
|
40 | 38 |
@property (class, nonatomic, readonly) __kindof OTRAppDelegate *appDelegate; |
41 | 39 |
|
42 | 40 |
#pragma mark Theming |
ChatSecure/Classes/OTRAppDelegate.m | ||
---|---|---|
83 | 83 |
|
84 | 84 |
@implementation OTRAppDelegate |
85 | 85 |
@synthesize window = _window; |
86 |
@dynamic activeThreadYapKey; |
|
87 | 86 |
|
88 | 87 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions |
89 | 88 |
{ |
... | ... | |
258 | 257 |
self.window.rootViewController = [self setupDefaultSplitViewControllerWithLeadingViewController:[[UINavigationController alloc] initWithRootViewController:self.conversationViewController]]; |
259 | 258 |
} |
260 | 259 |
|
261 |
- (NSString *)activeThreadYapKey |
|
262 |
{ |
|
263 |
NSString *threadOwnerYapKey = nil; |
|
264 |
if (self.messagesViewController && [self.messagesViewController otr_isVisible]) { |
|
265 |
threadOwnerYapKey = self.messagesViewController.threadKey; |
|
266 |
} |
|
267 |
return threadOwnerYapKey; |
|
268 |
} |
|
269 |
|
|
270 | 260 |
- (void)applicationWillResignActive:(UIApplication *)application |
271 | 261 |
{ |
272 | 262 |
[OTRProtocolManager sharedInstance].lastInteractionDate = [NSDate date]; |
... | ... | |
517 | 507 |
#pragma mark UNUserNotificationCenterDelegate methods (iOS 10+) |
518 | 508 |
|
519 | 509 |
- (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { |
520 |
if ([notification.request.content.threadIdentifier isEqualToString:[self activeThreadYapKey]]) { |
|
521 |
completionHandler(UNNotificationPresentationOptionNone); |
|
522 |
} else { |
|
523 |
completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert); |
|
524 |
} |
|
510 |
[OTRAppDelegate visibleThread:^(YapCollectionKey * _Nullable ck) { |
|
511 |
if ([ck.key isEqualToString:notification.request.content.threadIdentifier]) { |
|
512 |
completionHandler(UNNotificationPresentationOptionNone); |
|
513 |
} else { |
|
514 |
completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert); |
|
515 |
} |
|
516 |
} completionQueue:nil]; |
|
525 | 517 |
} |
526 | 518 |
|
527 | 519 |
- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { |
ChatSecure/Classes/OTRAppDelegate.swift | ||
---|---|---|
1 |
// |
|
2 |
// OTRAppDelegate.swift |
|
3 |
// ChatSecureCore |
|
4 |
// |
|
5 |
// Created by Chris Ballinger on 12/5/17. |
|
6 |
// Copyright © 2017 Chris Ballinger. All rights reserved. |
|
7 |
// |
|
8 |
|
|
9 |
import Foundation |
|
10 |
import YapDatabase |
|
11 |
|
|
12 |
public extension OTRAppDelegate { |
|
13 |
/// Returns key/collection of visible thread, or nil if not visible or unset |
|
14 |
@objc public static func visibleThread(_ block: @escaping (_ thread: YapCollectionKey?)->(), completionQueue: DispatchQueue? = nil) { |
|
15 |
DispatchQueue.main.async { |
|
16 |
let messagesVC = OTRAppDelegate.appDelegate.messagesViewController |
|
17 |
guard messagesVC.isViewLoaded, |
|
18 |
messagesVC.view.window != nil, |
|
19 |
let key = messagesVC.threadKey, |
|
20 |
let collection = messagesVC.threadCollection else { |
|
21 |
block(nil) |
|
22 |
return |
|
23 |
} |
|
24 |
let ck = YapCollectionKey(collection: collection, key: key) |
|
25 |
if let completionQueue = completionQueue { |
|
26 |
completionQueue.async { |
|
27 |
block(ck) |
|
28 |
} |
|
29 |
} else { |
|
30 |
block(ck) |
|
31 |
} |
|
32 |
} |
|
33 |
} |
|
34 |
} |
Also available in: Unified diff