From be2d942e2d0cb98cb5178b23bed0ce320b68f59f Mon Sep 17 00:00:00 2001 From: Kee Jefferys Date: Tue, 17 Aug 2021 12:00:40 +1000 Subject: [PATCH 01/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d6092a32..40038b0d0 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,6 @@ Copyright 2011 Whisper Systems Copyright 2013-2017 Open Whisper Systems -Copyright 2019-2021 The Loki Project +Copyright 2019-2021 The Oxen Project Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html From cb2fb4497d047be903a525b1647761d3dc7aed60 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 19 Aug 2021 15:57:44 +1000 Subject: [PATCH 02/24] Update version number --- Session.xcodeproj/project.pbxproj | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index bf7584f33..190a90dcd 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5038,7 +5038,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5063,7 +5063,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5111,7 +5111,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5141,7 +5141,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5177,7 +5177,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5200,7 +5200,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5251,7 +5251,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5279,7 +5279,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6187,7 +6187,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6226,7 +6226,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6258,7 +6258,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 288; + CURRENT_PROJECT_VERSION = 289; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6297,7 +6297,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.13; + MARKETING_VERSION = 1.11.14; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 7a354fe220a180a8511949d840acd507c0db7ac9 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 20 Aug 2021 10:01:25 +1000 Subject: [PATCH 03/24] potentially fix the closed group not receiving messages issue --- .../Sending & Receiving/Pollers/ClosedGroupPoller.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index 6a4fb2c92..df74e3f08 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -40,8 +40,11 @@ public final class ClosedGroupPoller : NSObject { public func startPolling(for groupPublicKey: String) { guard !isPolling(for: groupPublicKey) else { return } - setUpPolling(for: groupPublicKey) + // Might be a race condition that the setUpPolling finishes too soon, + // and the timer is not created, if we mark the group as is polling + // after setUpPolling. So the poller may not work, thus misses messages. isPolling[groupPublicKey] = true + setUpPolling(for: groupPublicKey) } @objc public func stop() { @@ -51,8 +54,8 @@ public final class ClosedGroupPoller : NSObject { } public func stopPolling(for groupPublicKey: String) { - timers[groupPublicKey]?.invalidate() isPolling[groupPublicKey] = false + timers[groupPublicKey]?.invalidate() } // MARK: Private API From fff117e6339150812088420699a3eb8f7f163630 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 20 Aug 2021 10:20:23 +1000 Subject: [PATCH 04/24] Update build number --- Session.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 190a90dcd..a571a67d2 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -6187,7 +6187,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 290; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6258,7 +6258,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 290; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From d6f15530501a9ac3d29dc2b3cf316af37a008a8b Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 20 Aug 2021 10:31:15 +1000 Subject: [PATCH 05/24] Update build number --- Session.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index a571a67d2..689b72b5b 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5038,7 +5038,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 291; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5111,7 +5111,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 291; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5177,7 +5177,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 291; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5251,7 +5251,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 289; + CURRENT_PROJECT_VERSION = 291; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6187,7 +6187,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 290; + CURRENT_PROJECT_VERSION = 291; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6258,7 +6258,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 290; + CURRENT_PROJECT_VERSION = 291; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 132ff0416f2f6dcf30ac0d538067ee9c5a8755fd Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 23 Aug 2021 11:10:22 +1000 Subject: [PATCH 06/24] set server timestamp as open group message's sent timestamp --- .../Messages/Signal/TSOutgoingMessage.h | 3 +++ .../Messages/Signal/TSOutgoingMessage.m | 6 ++++++ .../Sending & Receiving/MessageSender.swift | 13 +++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h index f38a173f7..b61bada56 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h @@ -159,6 +159,9 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { #pragma mark - Update With... Methods +- (void)updateOpenGroupServerID:(uint64_t)openGroupServerID + serverTimeStamp:(uint64_t)timestamp; + // This method is used to record a successful send to one recipient. - (void)updateWithSentRecipient:(NSString *)recipientId wasSentByUD:(BOOL)wasSentByUD diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m index 0e9fee8a7..f2985104d 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m @@ -450,6 +450,12 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt #pragma mark - Update With... Methods +- (void)updateOpenGroupServerID:(uint64_t)openGroupServerID serverTimeStamp:(uint64_t)timestamp +{ + self.openGroupServerMessageID = openGroupServerID; + [super updateTimestamp:timestamp]; +} + - (void)updateWithSendingError:(NSError *)error transaction:(YapDatabaseReadWriteTransaction *)transaction { [self applyChangeToSelfAndLatestCopy:transaction diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index a1f16f751..d32b07681 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -317,7 +317,7 @@ public final class MessageSender : NSObject { OpenGroupAPIV2.send(openGroupMessage, to: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in message.openGroupServerMessageID = given(openGroupMessage.serverID) { UInt64($0) } storage.write(with: { transaction in - MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) + MessageSender.handleSuccessfulMessageSend(message, to: destination, serverTimestamp: openGroupMessage.sentTimestamp, using: transaction) seal.fulfill(()) }, completion: { }) }.catch(on: DispatchQueue.global(qos: .userInitiated)) { error in @@ -330,7 +330,7 @@ public final class MessageSender : NSObject { } // MARK: Success & Failure Handling - public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, isSyncMessage: Bool = false, using transaction: Any) { + public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, serverTimestamp: UInt64? = nil, isSyncMessage: Bool = false, using transaction: Any) { let transaction = transaction as! YapDatabaseReadWriteTransaction // Get the visible message if possible if let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) { @@ -338,8 +338,13 @@ public final class MessageSender : NSObject { // will be replaced by the hash value of the sync message. Since the hash value of the // real message has no use when we delete a message. It is OK to let it be. tsMessage.serverHash = message.serverHash - // Track the open group server message ID - tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 + // Track the open group server message ID and update server timestamp + if let openGroupServerMessageID = message.openGroupServerMessageID, let timestamp = serverTimestamp { + // Use server timestamp for open group messages + // Otherwise the quote messages may not be able + // to be found by the timestamp on other devices + tsMessage.updateOpenGroupServerID(openGroupServerMessageID, serverTimeStamp: timestamp) + } // Mark the message as sent var recipients = [ message.recipient! ] if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point From da335a8401d99d97fd55496fbb3aaf2af99632df Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 23 Aug 2021 11:10:45 +1000 Subject: [PATCH 07/24] clean --- Session/Conversations/ConversationViewModel.m | 4 +-- .../Messages/Signal/TSIncomingMessage.h | 2 -- .../Messages/Signal/TSInteraction.h | 5 ++-- .../Messages/Signal/TSInteraction.m | 25 ++++++------------- .../Pollers/OpenGroupPollerV2.swift | 1 - 5 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Session/Conversations/ConversationViewModel.m b/Session/Conversations/ConversationViewModel.m index efcd2cee8..2d63d03b0 100644 --- a/Session/Conversations/ConversationViewModel.m +++ b/Session/Conversations/ConversationViewModel.m @@ -1158,7 +1158,7 @@ NS_ASSUME_NONNULL_BEGIN break; } - uint64_t viewItemTimestamp = viewItem.interaction.timestampForUI; + uint64_t viewItemTimestamp = viewItem.interaction.timestamp; OWSAssertDebug(viewItemTimestamp > 0); BOOL shouldShowDate = NO; @@ -1225,7 +1225,7 @@ NS_ASSUME_NONNULL_BEGIN NSAttributedString *_Nullable senderName = nil; OWSInteractionType interactionType = viewItem.interaction.interactionType; - NSString *timestampText = [DateUtil formatTimestampShort:viewItem.interaction.timestampForUI]; + NSString *timestampText = [DateUtil formatTimestampShort:viewItem.interaction.timestamp]; if (interactionType == OWSInteractionType_OutgoingMessage) { TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction; diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h index 59c11e6fe..762d0b60d 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h @@ -12,8 +12,6 @@ NS_ASSUME_NONNULL_BEGIN @interface TSIncomingMessage : TSMessage -@property (nonatomic, readonly, nullable) NSNumber *serverTimestamp; - @property (nonatomic, readonly) BOOL wasReceivedByUD; @property (nonatomic, readonly) BOOL isUserMentioned; diff --git a/SessionMessagingKit/Messages/Signal/TSInteraction.h b/SessionMessagingKit/Messages/Signal/TSInteraction.h index 4af4ce1cf..e6b77faf3 100644 --- a/SessionMessagingKit/Messages/Signal/TSInteraction.h +++ b/SessionMessagingKit/Messages/Signal/TSInteraction.h @@ -38,9 +38,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value); @property (nonatomic, readonly) uint64_t timestamp; @property (nonatomic, readonly) uint64_t sortId; @property (nonatomic, readonly) uint64_t receivedAtTimestamp; -@property (nonatomic, readonly) BOOL shouldUseServerTime; - -- (uint64_t)timestampForUI; - (NSDate *)dateForUI; @@ -80,6 +77,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value); - (void)saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(saveNextSortId(transaction:)); +- (void)updateTimestamp:(uint64_t)timestamp; + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Messages/Signal/TSInteraction.m b/SessionMessagingKit/Messages/Signal/TSInteraction.m index e6d1a6a93..f3522712d 100644 --- a/SessionMessagingKit/Messages/Signal/TSInteraction.m +++ b/SessionMessagingKit/Messages/Signal/TSInteraction.m @@ -165,17 +165,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) #pragma mark Date operations -- (uint64_t)timestampForUI -{ - // We always want to show the sent timestamp. In the case of one-on-one, closed group and V2 open group messages we get - // this from the protobuf. In the case of V1 open group messages we get it from the envelope in which the message is - // wrapped, which gets parsed to `serverTimestamp` in that case. - if ([self isKindOfClass:TSIncomingMessage.class] && ((TSIncomingMessage *)self).isOpenGroupMessage && ((TSIncomingMessage *)self).serverTimestamp != nil) { - return ((TSIncomingMessage *)self).serverTimestamp.unsignedLongLongValue; - } - return _timestamp; -} - - (uint64_t)timestampForLegacySorting { return self.timestamp; @@ -183,7 +172,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (NSDate *)dateForUI { - return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForUI]; + return [NSDate ows_dateWithMillisecondsSince1970:self.timestamp]; } - (NSDate *)receivedAtDate @@ -229,12 +218,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) - (uint64_t)sortId { - // We always want to sort on the sent timestamp. In the case of one-on-one, closed group and V2 open group messages we get - // this from the protobuf. In the case of V1 open group messages we get it from the envelope in which the message is - // wrapped, which gets parsed to `serverTimestamp` in that case. - if ([self isKindOfClass:TSIncomingMessage.class] && ((TSIncomingMessage *)self).isOpenGroupMessage && ((TSIncomingMessage *)self).serverTimestamp != nil) { - return ((TSIncomingMessage *)self).serverTimestamp.unsignedLongLongValue; - } return self.timestamp; } @@ -280,6 +263,12 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) [self saveWithTransaction:transaction]; } +- (void)updateTimestamp:(uint64_t)timestamp +{ + _timestamp = timestamp; +} + + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift index 946a564d7..d5eee9ad1 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift @@ -73,7 +73,6 @@ public final class OpenGroupPollerV2 : NSObject { let envelope = SNProtoEnvelope.builder(type: .sessionMessage, timestamp: message.sentTimestamp) envelope.setContent(data) envelope.setSource(message.sender!) // Safe because messages with a nil sender are filtered out - envelope.setServerTimestamp(message.sentTimestamp) do { let data = try envelope.buildSerializedData() let (message, proto) = try MessageReceiver.parse(data, openGroupMessageServerID: UInt64(message.serverID!), isRetry: false, using: transaction) From d319840c045e666f4ac0bafd75d1ac0010124b53 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 23 Aug 2021 11:15:05 +1000 Subject: [PATCH 08/24] clean unused server timestamp --- .../Messages/Signal/TSIncomingMessage+Conversion.swift | 1 - SessionMessagingKit/Messages/Signal/TSIncomingMessage.h | 1 - SessionMessagingKit/Messages/Signal/TSIncomingMessage.m | 4 ---- 3 files changed, 6 deletions(-) diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift index 81e60ab3d..6849fd50c 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage+Conversion.swift @@ -19,7 +19,6 @@ public extension TSIncomingMessage { expiresInSeconds: !isOpenGroupMessage ? expiration : 0, // Ensure we don't ever expire open group messages quotedMessage: quotedMessage, linkPreview: linkPreview, - serverTimestamp: visibleMessage.openGroupServerTimestamp as NSNumber?, wasReceivedByUD: true, openGroupInvitationName: visibleMessage.openGroupInvitation?.name, openGroupInvitationURL: visibleMessage.openGroupInvitation?.url, diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h index 762d0b60d..b4a0edb0e 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h @@ -59,7 +59,6 @@ NS_ASSUME_NONNULL_BEGIN expiresInSeconds:(uint32_t)expiresInSeconds quotedMessage:(nullable TSQuotedMessage *)quotedMessage linkPreview:(nullable OWSLinkPreview *)linkPreview - serverTimestamp:(nullable NSNumber *)serverTimestamp wasReceivedByUD:(BOOL)wasReceivedByUD openGroupInvitationName:(nullable NSString *)openGroupInvitationName openGroupInvitationURL:(nullable NSString *)openGroupInvitationURL diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m index 90d893b9f..ecfc9168f 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m @@ -21,8 +21,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, getter=wasRead) BOOL read; -@property (nonatomic, nullable) NSNumber *serverTimestamp; - @end #pragma mark - @@ -52,7 +50,6 @@ NS_ASSUME_NONNULL_BEGIN expiresInSeconds:(uint32_t)expiresInSeconds quotedMessage:(nullable TSQuotedMessage *)quotedMessage linkPreview:(nullable OWSLinkPreview *)linkPreview - serverTimestamp:(nullable NSNumber *)serverTimestamp wasReceivedByUD:(BOOL)wasReceivedByUD openGroupInvitationName:(nullable NSString *)openGroupInvitationName openGroupInvitationURL:(nullable NSString *)openGroupInvitationURL @@ -77,7 +74,6 @@ NS_ASSUME_NONNULL_BEGIN _authorId = authorId; _sourceDeviceId = sourceDeviceId; _read = NO; - _serverTimestamp = serverTimestamp; _wasReceivedByUD = wasReceivedByUD; _notificationIdentifier = nil; From a5369701b02c90eeb5fc98ea5cf44d61fe9bbd24 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 24 Aug 2021 10:27:57 +1000 Subject: [PATCH 09/24] Fix the crash when seleting photos --- .../PhotoLibrary.swift | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Session/Media Viewing & Editing/PhotoLibrary.swift b/Session/Media Viewing & Editing/PhotoLibrary.swift index b5e011da2..164c8b542 100644 --- a/Session/Media Viewing & Editing/PhotoLibrary.swift +++ b/Session/Media Viewing & Editing/PhotoLibrary.swift @@ -221,6 +221,10 @@ class PhotoCollectionContents { class PhotoCollection { private let collection: PHAssetCollection + + // The user never sees this collection, but we use it for a null object pattern + // when the user has denied photos access. + static let empty = PhotoCollection(collection: PHAssetCollection()) init(collection: PHAssetCollection) { self.collection = collection @@ -275,11 +279,30 @@ class PhotoLibrary: NSObject, PHPhotoLibraryChangeObserver { deinit { PHPhotoLibrary.shared().unregisterChangeObserver(self) } + + private lazy var fetchOptions: PHFetchOptions = { + let fetchOptions = PHFetchOptions() + fetchOptions.sortDescriptors = [NSSortDescriptor(key: "endDate", ascending: true)] + return fetchOptions + }() func defaultPhotoCollection() -> PhotoCollection { - guard let photoCollection = allPhotoCollections().first else { - owsFail("Could not locate Camera Roll.") + var fetchedCollection: PhotoCollection? + PHAssetCollection.fetchAssetCollections( + with: .smartAlbum, + subtype: .smartAlbumUserLibrary, + options: fetchOptions + ).enumerateObjects { collection, _, stop in + fetchedCollection = PhotoCollection(collection: collection) + stop.pointee = true } + + guard let photoCollection = fetchedCollection else { + Logger.info("Using empty photo collection.") + assert(PHPhotoLibrary.authorizationStatus() == .denied) + return PhotoCollection.empty + } + return photoCollection } From d6d041a74fcd48659faebac03a576f22d07697ff Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 24 Aug 2021 14:58:27 +1000 Subject: [PATCH 10/24] fix closed group threading issue --- .../Sending & Receiving/Pollers/ClosedGroupPoller.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index df74e3f08..00148075a 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -5,6 +5,7 @@ import PromiseKit public final class ClosedGroupPoller : NSObject { private var isPolling: [String:Bool] = [:] private var timers: [String:Timer] = [:] + private let internalQueue: DispatchQueue = DispatchQueue(label:"isPollingQueue") // MARK: Settings private static let minPollInterval: Double = 2 @@ -137,6 +138,6 @@ public final class ClosedGroupPoller : NSObject { // MARK: Convenience private func isPolling(for groupPublicKey: String) -> Bool { - return isPolling[groupPublicKey] ?? false + return internalQueue.sync{ isPolling[groupPublicKey] ?? false } } } From d60475be99bc97891a4282aedd8427a06ff4b44d Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 25 Aug 2021 11:54:41 +1000 Subject: [PATCH 11/24] add accessibility to send button and voice message button --- Session/Conversations/Input View/InputView.swift | 8 +++++++- Session/Conversations/Input View/InputViewButton.swift | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/Input View/InputView.swift b/Session/Conversations/Input View/InputView.swift index af84dec92..599af7599 100644 --- a/Session/Conversations/Input View/InputView.swift +++ b/Session/Conversations/Input View/InputView.swift @@ -22,11 +22,17 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, // MARK: UI Components private lazy var attachmentsButton = ExpandingAttachmentsButton(delegate: delegate) - private lazy var voiceMessageButton = InputViewButton(icon: #imageLiteral(resourceName: "Microphone"), delegate: self) + private lazy var voiceMessageButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "Microphone"), delegate: self) + result.accessibilityLabel = NSLocalizedString("VOICE_MESSAGE_TOO_SHORT_ALERT_TITLE", comment: "") + result.accessibilityHint = NSLocalizedString("VOICE_MESSAGE_TOO_SHORT_ALERT_MESSAGE", comment: "") + return result + }() private lazy var sendButton: InputViewButton = { let result = InputViewButton(icon: #imageLiteral(resourceName: "ArrowUp"), isSendButton: true, delegate: self) result.isHidden = true + result.accessibilityLabel = NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", comment: "") return result }() private lazy var voiceMessageButtonContainer = container(for: voiceMessageButton) diff --git a/Session/Conversations/Input View/InputViewButton.swift b/Session/Conversations/Input View/InputViewButton.swift index 92707c7fc..082442faa 100644 --- a/Session/Conversations/Input View/InputViewButton.swift +++ b/Session/Conversations/Input View/InputViewButton.swift @@ -25,6 +25,7 @@ final class InputViewButton : UIView { self.hasOpaqueBackground = hasOpaqueBackground super.init(frame: CGRect.zero) setUpViewHierarchy() + self.isAccessibilityElement = true } override init(frame: CGRect) { From b7289e72a3295499ee98aaf5d0c89e8b55df9b5f Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 25 Aug 2021 12:18:06 +1000 Subject: [PATCH 12/24] add accessibility to attachment buttons --- .../ExpandingAttachmentsButton.swift | 32 ++++++++++++++++--- .../Translations/de.lproj/Localizable.strings | 6 ++++ .../Translations/en.lproj/Localizable.strings | 6 ++++ .../Translations/es.lproj/Localizable.strings | 6 ++++ .../Translations/fa.lproj/Localizable.strings | 6 ++++ .../Translations/fi.lproj/Localizable.strings | 6 ++++ .../Translations/fr.lproj/Localizable.strings | 6 ++++ .../Translations/hi.lproj/Localizable.strings | 6 ++++ .../Translations/hr.lproj/Localizable.strings | 6 ++++ .../id-ID.lproj/Localizable.strings | 6 ++++ .../Translations/it.lproj/Localizable.strings | 6 ++++ .../Translations/ja.lproj/Localizable.strings | 6 ++++ .../Translations/nl.lproj/Localizable.strings | 6 ++++ .../Translations/pl.lproj/Localizable.strings | 6 ++++ .../pt_BR.lproj/Localizable.strings | 6 ++++ .../Translations/ru.lproj/Localizable.strings | 6 ++++ .../Translations/sk.lproj/Localizable.strings | 6 ++++ .../Translations/sv.lproj/Localizable.strings | 6 ++++ .../Translations/th.lproj/Localizable.strings | 6 ++++ .../vi-VN.lproj/Localizable.strings | 6 ++++ .../zh-Hant.lproj/Localizable.strings | 6 ++++ .../zh_CN.lproj/Localizable.strings | 6 ++++ .../Jobs/AttachmentDownloadJob.swift | 10 ++++++ .../NotificationServiceExtension.swift | 2 +- 24 files changed, 164 insertions(+), 6 deletions(-) diff --git a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift index a42f4488e..8652d57c6 100644 --- a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift +++ b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift @@ -10,15 +10,35 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { private lazy var cameraButtonContainerBottomConstraint = cameraButtonContainer.pin(.bottom, to: .bottom, of: self) // MARK: UI Components - lazy var gifButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self, hasOpaqueBackground: true) + lazy var gifButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self, hasOpaqueBackground: true) + result.accessibilityLabel = NSLocalizedString("accessibility_gif_button", comment: "") + return result + }() lazy var gifButtonContainer = container(for: gifButton) - lazy var documentButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true) + lazy var documentButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true) + result.accessibilityLabel = NSLocalizedString("accessibility_document_button", comment: "") + return result + }() lazy var documentButtonContainer = container(for: documentButton) - lazy var libraryButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true) + lazy var libraryButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true) + result.accessibilityLabel = NSLocalizedString("accessibility_library_button", comment: "") + return result + }() lazy var libraryButtonContainer = container(for: libraryButton) - lazy var cameraButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true) + lazy var cameraButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true) + result.accessibilityLabel = NSLocalizedString("accessibility_camera_button", comment: "") + return result + }() lazy var cameraButtonContainer = container(for: cameraButton) - lazy var mainButton = InputViewButton(icon: #imageLiteral(resourceName: "ic_plus_24"), delegate: self) + lazy var mainButton: InputViewButton = { + let result = InputViewButton(icon: #imageLiteral(resourceName: "ic_plus_24"), delegate: self) + result.accessibilityLabel = NSLocalizedString("accessibility_expanding_attachments_button", comment: "") + return result + }() lazy var mainButtonContainer = container(for: mainButton) // MARK: Lifecycle @@ -66,6 +86,7 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { // MARK: Animation private func expandOrCollapse() { if isExpanded { + mainButton.accessibilityLabel = NSLocalizedString("accessibility_main_button_collapse", comment: "") let expandedButtonSize = InputViewButton.expandedSize let spacing: CGFloat = 4 cameraButtonContainerBottomConstraint.constant = -1 * (expandedButtonSize + spacing) @@ -79,6 +100,7 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { self.layoutIfNeeded() } } else { + mainButton.accessibilityLabel = NSLocalizedString("accessibility_expanding_attachments_button", comment: "") [ gifButtonContainerBottomConstraint, documentButtonContainerBottomConstraint, libraryButtonContainerBottomConstraint, cameraButtonContainerBottomConstraint ].forEach { $0.constant = 0 } diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 5ca82d5a0..3db0bf36c 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 430e5c044..7de331a6d 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -557,4 +557,10 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 4f3111a6b..34dce14f6 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 1021d569f..8cb43a537 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index ef67453b8..c68cc6d28 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index f97d407c7..d91844903 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index 204731d63..f750e97f4 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 860a546a3..9d32a4823 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index af4f39234..b3ec9fb89 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index f8018c99c..c2301da20 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index b43619cd7..4c6af761a 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index df6a8d106..61311680a 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 204ba918b..487c99a88 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 583e81ff9..7248083fa 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index b851e2a59..d5fcd1c2d 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 129b79ad4..ec5306e3e 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index dd4b04329..311db3616 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 30f4a0ae2..c10829003 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 2ee0add3b..665f93fd8 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 117376ddb..1f25b7e6d 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index aab0afae7..e11098fae 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -557,3 +557,9 @@ "context_menu_save" = "Save"; "context_menu_ban_user" = "Ban User"; "context_menu_ban_and_delete_all" = "Ban and Delete All"; +"accessibility_expanding_attachments_button" = "Add attachments"; +"accessibility_gif_button" = "Gif"; +"accessibility_document_button" = "Document"; +"accessibility_library_button" = "Photo library"; +"accessibility_camera_button" = "Camera"; +"accessibility_main_button_collapse" = "Collapse attachment options"; diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index f7a281b20..1ddb1b65c 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -60,6 +60,10 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Running public func execute() { + execute(completion: nil) + } + + public func execute(completion: (() -> Void)?) { if let id = id { JobQueue.currentlyExecutingJobs.insert(id) } @@ -67,9 +71,11 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject if TSAttachment.fetch(uniqueId: attachmentID) is TSAttachmentStream { // FIXME: It's not clear * how * this happens, but apparently we can get to this point // from time to time with an already downloaded attachment. + completion?() return handleSuccess() } guard let pointer = TSAttachment.fetch(uniqueId: attachmentID) as? TSAttachmentPointer else { + completion?() return handleFailure(error: Error.noAttachment) } let storage = SNMessagingKitConfiguration.shared.storage @@ -92,8 +98,10 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsMessageID, using: transaction) }, completion: { }) // This usually indicates a file that has expired on the server, so there's no need to retry. + completion?() self.handlePermanentFailure(error: error) } else { + completion?() self.handleFailure(error: error) } } @@ -103,6 +111,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject } OpenGroupAPIV2.download(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) + completion?() }.catch(on: DispatchQueue.global()) { error in handleFailure(error) } @@ -113,6 +122,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject let useOldServer = pointer.downloadURL.contains(FileServerAPIV2.oldServer) FileServerAPIV2.download(file, useOldServer: useOldServer).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) + completion?() }.catch(on: DispatchQueue.global()) { error in handleFailure(error) } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index bc40de1f7..3b1818124 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -48,7 +48,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension case let visibleMessage as VisibleMessage: let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, isBackgroundPoll: false, using: transaction) guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { - return self.handleFailure(for: notificationContent) + return self.completeSilenty() } let thread = tsIncomingMessage.thread(with: transaction) if thread.isMuted { From f99fa58acc76386a257684cccb184e58365ffa75 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 25 Aug 2021 14:12:47 +1000 Subject: [PATCH 13/24] add accessibility for input text view --- Session/Conversations/Input View/InputTextView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Session/Conversations/Input View/InputTextView.swift b/Session/Conversations/Input View/InputTextView.swift index 1c8fb3595..57546e407 100644 --- a/Session/Conversations/Input View/InputTextView.swift +++ b/Session/Conversations/Input View/InputTextView.swift @@ -26,6 +26,8 @@ public final class InputTextView : UITextView, UITextViewDelegate { super.init(frame: CGRect.zero, textContainer: nil) setUpViewHierarchy() self.delegate = self + self.isAccessibilityElement = true + self.accessibilityLabel = NSLocalizedString("vc_conversation_input_prompt", comment: "") } public override init(frame: CGRect, textContainer: NSTextContainer?) { From 70e38e11d8040c4272086d3d55f1299ec48b4fff Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 25 Aug 2021 16:39:30 +1000 Subject: [PATCH 14/24] clean attachment download job --- SessionMessagingKit/Jobs/AttachmentDownloadJob.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 1ddb1b65c..164f422a9 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -60,10 +60,6 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Running public func execute() { - execute(completion: nil) - } - - public func execute(completion: (() -> Void)?) { if let id = id { JobQueue.currentlyExecutingJobs.insert(id) } @@ -71,11 +67,9 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject if TSAttachment.fetch(uniqueId: attachmentID) is TSAttachmentStream { // FIXME: It's not clear * how * this happens, but apparently we can get to this point // from time to time with an already downloaded attachment. - completion?() return handleSuccess() } guard let pointer = TSAttachment.fetch(uniqueId: attachmentID) as? TSAttachmentPointer else { - completion?() return handleFailure(error: Error.noAttachment) } let storage = SNMessagingKitConfiguration.shared.storage @@ -98,10 +92,8 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject storage.setAttachmentState(to: .failed, for: pointer, associatedWith: self.tsMessageID, using: transaction) }, completion: { }) // This usually indicates a file that has expired on the server, so there's no need to retry. - completion?() self.handlePermanentFailure(error: error) } else { - completion?() self.handleFailure(error: error) } } @@ -111,7 +103,6 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject } OpenGroupAPIV2.download(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) - completion?() }.catch(on: DispatchQueue.global()) { error in handleFailure(error) } @@ -122,7 +113,6 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject let useOldServer = pointer.downloadURL.contains(FileServerAPIV2.oldServer) FileServerAPIV2.download(file, useOldServer: useOldServer).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) - completion?() }.catch(on: DispatchQueue.global()) { error in handleFailure(error) } @@ -172,4 +162,3 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject delegate?.handleJobFailed(self, with: error) } } - From 6fd5bbeab1a4646745aa12cfe85457d3633883d0 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 26 Aug 2021 10:49:55 +1000 Subject: [PATCH 15/24] WIP: download attachments in NSE --- Podfile | 1 + .../Database/Storage+Jobs.swift | 14 ++++++++ .../Jobs/AttachmentDownloadJob.swift | 32 ++++++++++++++++--- SessionMessagingKit/Storage.swift | 1 + .../NotificationServiceExtension.swift | 21 +++++++++++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Podfile b/Podfile index 5452d4e81..2374b76a3 100644 --- a/Podfile +++ b/Podfile @@ -32,6 +32,7 @@ target 'SessionNotificationServiceExtension' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true + pod 'PromiseKit', :inhibit_warnings => true end target 'SignalUtilitiesKit' do diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index fe3f31615..e504fee0e 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -73,6 +73,20 @@ extension Storage { return result.first } + public func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? { + var result: [AttachmentDownloadJob] = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in + guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } + result.append(job) + } + } + #if DEBUG + assert(result.isEmpty || result.count == 1) + #endif + return result.first + } + public func getAttachmentDownloadJobs(for threadID: String) -> [AttachmentDownloadJob] { var result: [AttachmentDownloadJob] = [] Storage.read { transaction in diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 164f422a9..72b04e4ca 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -2,6 +2,7 @@ import Foundation import SessionUtilitiesKit import SessionSnodeKit import SignalCoreKit +import PromiseKit public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let attachmentID: String @@ -60,17 +61,29 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Running public func execute() { + executeAsync().retainUntilComplete() + } + + public func executeAsync() -> Promise { + let (promise, seal) = Promise.pending() if let id = id { JobQueue.currentlyExecutingJobs.insert(id) } - guard !isDeferred else { return } + guard !isDeferred else { + seal.fulfill(()) + return promise + } if TSAttachment.fetch(uniqueId: attachmentID) is TSAttachmentStream { // FIXME: It's not clear * how * this happens, but apparently we can get to this point // from time to time with an already downloaded attachment. - return handleSuccess() + handleSuccess() + seal.fulfill(()) + return promise } guard let pointer = TSAttachment.fetch(uniqueId: attachmentID) as? TSAttachmentPointer else { - return handleFailure(error: Error.noAttachment) + handleFailure(error: Error.noAttachment) + seal.reject(Error.noAttachment) + return promise } let storage = SNMessagingKitConfiguration.shared.storage storage.write(with: { transaction in @@ -99,24 +112,33 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject } if let tsMessage = TSMessage.fetch(uniqueId: tsMessageID), let v2OpenGroup = storage.getV2OpenGroup(for: tsMessage.uniqueThreadId) { guard let fileAsString = pointer.downloadURL.split(separator: "/").last, let file = UInt64(fileAsString) else { - return handleFailure(Error.invalidURL) + handleFailure(Error.invalidURL) + seal.reject(Error.invalidURL) + return promise } OpenGroupAPIV2.download(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) + seal.fulfill(()) }.catch(on: DispatchQueue.global()) { error in handleFailure(error) + seal.reject(error) } } else { guard let fileAsString = pointer.downloadURL.split(separator: "/").last, let file = UInt64(fileAsString) else { - return handleFailure(Error.invalidURL) + handleFailure(Error.invalidURL) + seal.reject(Error.invalidURL) + return promise } let useOldServer = pointer.downloadURL.contains(FileServerAPIV2.oldServer) FileServerAPIV2.download(file, useOldServer: useOldServer).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) + seal.fulfill(()) }.catch(on: DispatchQueue.global()) { error in handleFailure(error) + seal.reject(error) } } + return promise } private func handleDownloadedAttachment(data: Data, temporaryFilePath: URL, pointer: TSAttachmentPointer, failureHandler: (Swift.Error) -> Void) { diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 4444307d3..75df638df 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -33,6 +33,7 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? + func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) func isJobCanceled(_ job: Job) -> Bool diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 3b1818124..d904dd902 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -1,6 +1,7 @@ import UserNotifications import SessionMessagingKit import SignalUtilitiesKit +import PromiseKit public final class NotificationServiceExtension : UNNotificationServiceExtension { private var didPerformSetup = false @@ -35,6 +36,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } Storage.write { transaction in // Intentionally capture self do { + var attachmentDownloadJobs: [AttachmentDownloadJob] = [] let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) let senderPublicKey = message.sender! if (senderPublicKey == userPublicKey) { @@ -69,6 +71,14 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } // Store the notification ID for unsend requests to later cancel this notification tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction) + let storage = SNMessagingKitConfiguration.shared.storage + let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0) as? TSAttachmentPointer } + let attachmentsToDownload = attachments.filter { !$0.isDownloaded } + attachmentsToDownload.forEach { attachment in + if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID) { + attachmentDownloadJobs.append(job) + } + } case let unsendRequest as UnsendRequest: MessageReceiver.handleUnsendRequest(unsendRequest, using: transaction) return self.completeSilenty() @@ -96,7 +106,16 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension notificationContent.body = "You've got a new message" default: break } - self.handleSuccess(for: notificationContent) + if attachmentDownloadJobs.isEmpty { + self.handleSuccess(for: notificationContent) + } else { + let promises = attachmentDownloadJobs.map { $0.executeAsync() } + when(fulfilled: promises).map { attachments in + self.handleSuccess(for: notificationContent) + }.catch { error in + self.handleSuccess(for: notificationContent) + }.retainUntilComplete() + } } catch { self.handleFailure(for: notificationContent) } From 7295c14e17ba314b9336bf1e2a96cc32279ae0df Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 27 Aug 2021 13:32:31 +1000 Subject: [PATCH 16/24] WIP: make the attachment download work in NSE --- Podfile.lock | 2 +- .../Database/Storage+Jobs.swift | 10 +++---- .../Notifications/PushNotificationAPI.swift | 2 +- SessionMessagingKit/Storage.swift | 3 +- .../NotificationServiceExtension.swift | 28 ++++++++++--------- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 804a148c7..1b4e85988 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -208,6 +208,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 50e6a35c838ba28d2ee02bc6018fdd297c04e55f +PODFILE CHECKSUM: 71474628a9c2c3e57bdb0992668809a4369452f1 COCOAPODS: 1.10.1 diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index e504fee0e..1cb71172d 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -73,13 +73,11 @@ extension Storage { return result.first } - public func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? { + public func getAttachmentDownloadJob(for attachmentID: String, with transaction: YapDatabaseReadTransaction) -> AttachmentDownloadJob? { var result: [AttachmentDownloadJob] = [] - Storage.read { transaction in - transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in - guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } - result.append(job) - } + transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in + guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } + result.append(job) } #if DEBUG assert(result.isEmpty || result.count == 1) diff --git a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index 8fccb96ec..c44649c60 100644 --- a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -5,7 +5,7 @@ import PromiseKit public final class PushNotificationAPI : NSObject { // MARK: Settings - public static let server = "https://live.apns.getsession.org" + public static let server = "https://dev.apns.getsession.org" public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049" private static let maxRetryCount: UInt = 4 private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60 diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 75df638df..f523f34e8 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -1,5 +1,6 @@ import PromiseKit import Sodium +import YapDatabase public protocol SessionMessagingKitStorageProtocol { @@ -33,7 +34,7 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? - func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? + func getAttachmentDownloadJob(for attachmentID: String, with transaction: YapDatabaseReadTransaction) -> AttachmentDownloadJob? func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) func isJobCanceled(_ job: Job) -> Bool diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index d904dd902..06a5d1de2 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -34,9 +34,9 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension let envelope = try? MessageWrapper.unwrap(data: data), let envelopeAsData = try? envelope.serializedData() else { return self.handleFailure(for: notificationContent) } + var attachmentDownloadJobs: [AttachmentDownloadJob] = [] Storage.write { transaction in // Intentionally capture self do { - var attachmentDownloadJobs: [AttachmentDownloadJob] = [] let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) let senderPublicKey = message.sender! if (senderPublicKey == userPublicKey) { @@ -72,10 +72,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension // Store the notification ID for unsend requests to later cancel this notification tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction) let storage = SNMessagingKitConfiguration.shared.storage - let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0) as? TSAttachmentPointer } + let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0, transaction: transaction) as? TSAttachmentPointer } let attachmentsToDownload = attachments.filter { !$0.isDownloaded } attachmentsToDownload.forEach { attachment in - if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID) { + if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID, with: transaction) { attachmentDownloadJobs.append(job) } } @@ -106,20 +106,21 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension notificationContent.body = "You've got a new message" default: break } - if attachmentDownloadJobs.isEmpty { - self.handleSuccess(for: notificationContent) - } else { - let promises = attachmentDownloadJobs.map { $0.executeAsync() } - when(fulfilled: promises).map { attachments in - self.handleSuccess(for: notificationContent) - }.catch { error in - self.handleSuccess(for: notificationContent) - }.retainUntilComplete() - } } catch { self.handleFailure(for: notificationContent) } } + +// if attachmentDownloadJobs.isEmpty { +// self.handleSuccess(for: notificationContent) +// } else { +// let promises = attachmentDownloadJobs.map { $0.executeAsync() } +// when(fulfilled: promises).map { attachments in +// self.handleSuccess(for: notificationContent) +// }.catch { error in +// self.handleSuccess(for: notificationContent) +// }.retainUntilComplete() +// } } } @@ -163,6 +164,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension override public func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + print("serviceExtensionTimeWillExpire") let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] let notificationContent = self.notificationContent! notificationContent.userInfo = userInfo From 454003c02799ee07c4b904bc3af4a91d462a9da8 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 30 Aug 2021 10:00:04 +1000 Subject: [PATCH 17/24] Revert "WIP: make the attachment download work in NSE" This reverts commit 7295c14e17ba314b9336bf1e2a96cc32279ae0df. --- Podfile.lock | 2 +- .../Database/Storage+Jobs.swift | 10 ++++--- .../Notifications/PushNotificationAPI.swift | 2 +- SessionMessagingKit/Storage.swift | 3 +- .../NotificationServiceExtension.swift | 28 +++++++++---------- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 1b4e85988..804a148c7 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -208,6 +208,6 @@ SPEC CHECKSUMS: YYImage: 6db68da66f20d9f169ceb94dfb9947c3867b9665 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 71474628a9c2c3e57bdb0992668809a4369452f1 +PODFILE CHECKSUM: 50e6a35c838ba28d2ee02bc6018fdd297c04e55f COCOAPODS: 1.10.1 diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index 1cb71172d..e504fee0e 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -73,11 +73,13 @@ extension Storage { return result.first } - public func getAttachmentDownloadJob(for attachmentID: String, with transaction: YapDatabaseReadTransaction) -> AttachmentDownloadJob? { + public func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? { var result: [AttachmentDownloadJob] = [] - transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in - guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } - result.append(job) + Storage.read { transaction in + transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in + guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } + result.append(job) + } } #if DEBUG assert(result.isEmpty || result.count == 1) diff --git a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift index c44649c60..8fccb96ec 100644 --- a/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift +++ b/SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift @@ -5,7 +5,7 @@ import PromiseKit public final class PushNotificationAPI : NSObject { // MARK: Settings - public static let server = "https://dev.apns.getsession.org" + public static let server = "https://live.apns.getsession.org" public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049" private static let maxRetryCount: UInt = 4 private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60 diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index f523f34e8..75df638df 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -1,6 +1,5 @@ import PromiseKit import Sodium -import YapDatabase public protocol SessionMessagingKitStorageProtocol { @@ -34,7 +33,7 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? - func getAttachmentDownloadJob(for attachmentID: String, with transaction: YapDatabaseReadTransaction) -> AttachmentDownloadJob? + func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) func isJobCanceled(_ job: Job) -> Bool diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 06a5d1de2..d904dd902 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -34,9 +34,9 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension let envelope = try? MessageWrapper.unwrap(data: data), let envelopeAsData = try? envelope.serializedData() else { return self.handleFailure(for: notificationContent) } - var attachmentDownloadJobs: [AttachmentDownloadJob] = [] Storage.write { transaction in // Intentionally capture self do { + var attachmentDownloadJobs: [AttachmentDownloadJob] = [] let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) let senderPublicKey = message.sender! if (senderPublicKey == userPublicKey) { @@ -72,10 +72,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension // Store the notification ID for unsend requests to later cancel this notification tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction) let storage = SNMessagingKitConfiguration.shared.storage - let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0, transaction: transaction) as? TSAttachmentPointer } + let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0) as? TSAttachmentPointer } let attachmentsToDownload = attachments.filter { !$0.isDownloaded } attachmentsToDownload.forEach { attachment in - if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID, with: transaction) { + if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID) { attachmentDownloadJobs.append(job) } } @@ -106,21 +106,20 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension notificationContent.body = "You've got a new message" default: break } + if attachmentDownloadJobs.isEmpty { + self.handleSuccess(for: notificationContent) + } else { + let promises = attachmentDownloadJobs.map { $0.executeAsync() } + when(fulfilled: promises).map { attachments in + self.handleSuccess(for: notificationContent) + }.catch { error in + self.handleSuccess(for: notificationContent) + }.retainUntilComplete() + } } catch { self.handleFailure(for: notificationContent) } } - -// if attachmentDownloadJobs.isEmpty { -// self.handleSuccess(for: notificationContent) -// } else { -// let promises = attachmentDownloadJobs.map { $0.executeAsync() } -// when(fulfilled: promises).map { attachments in -// self.handleSuccess(for: notificationContent) -// }.catch { error in -// self.handleSuccess(for: notificationContent) -// }.retainUntilComplete() -// } } } @@ -164,7 +163,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension override public func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. - print("serviceExtensionTimeWillExpire") let userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] let notificationContent = self.notificationContent! notificationContent.userInfo = userInfo From e0458080705d1e852d69a04a7858b42825ad06d5 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 30 Aug 2021 10:00:19 +1000 Subject: [PATCH 18/24] Revert "WIP: download attachments in NSE" This reverts commit 6fd5bbeab1a4646745aa12cfe85457d3633883d0. --- Podfile | 1 - .../Database/Storage+Jobs.swift | 14 -------- .../Jobs/AttachmentDownloadJob.swift | 32 +++---------------- SessionMessagingKit/Storage.swift | 1 - .../NotificationServiceExtension.swift | 21 +----------- 5 files changed, 6 insertions(+), 63 deletions(-) diff --git a/Podfile b/Podfile index 2374b76a3..5452d4e81 100644 --- a/Podfile +++ b/Podfile @@ -32,7 +32,6 @@ target 'SessionNotificationServiceExtension' do pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit.git', :inhibit_warnings => true pod 'SignalCoreKit', git: 'https://github.com/signalapp/SignalCoreKit.git', :inhibit_warnings => true pod 'YapDatabase/SQLCipher', :git => 'https://github.com/loki-project/session-ios-yap-database.git', branch: 'signal-release', :inhibit_warnings => true - pod 'PromiseKit', :inhibit_warnings => true end target 'SignalUtilitiesKit' do diff --git a/SessionMessagingKit/Database/Storage+Jobs.swift b/SessionMessagingKit/Database/Storage+Jobs.swift index e504fee0e..fe3f31615 100644 --- a/SessionMessagingKit/Database/Storage+Jobs.swift +++ b/SessionMessagingKit/Database/Storage+Jobs.swift @@ -73,20 +73,6 @@ extension Storage { return result.first } - public func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? { - var result: [AttachmentDownloadJob] = [] - Storage.read { transaction in - transaction.enumerateRows(inCollection: AttachmentDownloadJob.collection) { _, object, _, _ in - guard let job = object as? AttachmentDownloadJob, job.attachmentID == attachmentID else { return } - result.append(job) - } - } - #if DEBUG - assert(result.isEmpty || result.count == 1) - #endif - return result.first - } - public func getAttachmentDownloadJobs(for threadID: String) -> [AttachmentDownloadJob] { var result: [AttachmentDownloadJob] = [] Storage.read { transaction in diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift index 72b04e4ca..164f422a9 100644 --- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift @@ -2,7 +2,6 @@ import Foundation import SessionUtilitiesKit import SessionSnodeKit import SignalCoreKit -import PromiseKit public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility public let attachmentID: String @@ -61,29 +60,17 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject // MARK: Running public func execute() { - executeAsync().retainUntilComplete() - } - - public func executeAsync() -> Promise { - let (promise, seal) = Promise.pending() if let id = id { JobQueue.currentlyExecutingJobs.insert(id) } - guard !isDeferred else { - seal.fulfill(()) - return promise - } + guard !isDeferred else { return } if TSAttachment.fetch(uniqueId: attachmentID) is TSAttachmentStream { // FIXME: It's not clear * how * this happens, but apparently we can get to this point // from time to time with an already downloaded attachment. - handleSuccess() - seal.fulfill(()) - return promise + return handleSuccess() } guard let pointer = TSAttachment.fetch(uniqueId: attachmentID) as? TSAttachmentPointer else { - handleFailure(error: Error.noAttachment) - seal.reject(Error.noAttachment) - return promise + return handleFailure(error: Error.noAttachment) } let storage = SNMessagingKitConfiguration.shared.storage storage.write(with: { transaction in @@ -112,33 +99,24 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject } if let tsMessage = TSMessage.fetch(uniqueId: tsMessageID), let v2OpenGroup = storage.getV2OpenGroup(for: tsMessage.uniqueThreadId) { guard let fileAsString = pointer.downloadURL.split(separator: "/").last, let file = UInt64(fileAsString) else { - handleFailure(Error.invalidURL) - seal.reject(Error.invalidURL) - return promise + return handleFailure(Error.invalidURL) } OpenGroupAPIV2.download(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) - seal.fulfill(()) }.catch(on: DispatchQueue.global()) { error in handleFailure(error) - seal.reject(error) } } else { guard let fileAsString = pointer.downloadURL.split(separator: "/").last, let file = UInt64(fileAsString) else { - handleFailure(Error.invalidURL) - seal.reject(Error.invalidURL) - return promise + return handleFailure(Error.invalidURL) } let useOldServer = pointer.downloadURL.contains(FileServerAPIV2.oldServer) FileServerAPIV2.download(file, useOldServer: useOldServer).done(on: DispatchQueue.global(qos: .userInitiated)) { data in self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) - seal.fulfill(()) }.catch(on: DispatchQueue.global()) { error in handleFailure(error) - seal.reject(error) } } - return promise } private func handleDownloadedAttachment(data: Data, temporaryFilePath: URL, pointer: TSAttachmentPointer, failureHandler: (Swift.Error) -> Void) { diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 75df638df..4444307d3 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -33,7 +33,6 @@ public protocol SessionMessagingKitStorageProtocol { func markJobAsFailed(_ job: Job, using transaction: Any) func getAllPendingJobs(of type: Job.Type) -> [Job] func getAttachmentUploadJob(for attachmentID: String) -> AttachmentUploadJob? - func getAttachmentDownloadJob(for attachmentID: String) -> AttachmentDownloadJob? func getMessageSendJob(for messageSendJobID: String) -> MessageSendJob? func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) func isJobCanceled(_ job: Job) -> Bool diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index d904dd902..3b1818124 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -1,7 +1,6 @@ import UserNotifications import SessionMessagingKit import SignalUtilitiesKit -import PromiseKit public final class NotificationServiceExtension : UNNotificationServiceExtension { private var didPerformSetup = false @@ -36,7 +35,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } Storage.write { transaction in // Intentionally capture self do { - var attachmentDownloadJobs: [AttachmentDownloadJob] = [] let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) let senderPublicKey = message.sender! if (senderPublicKey == userPublicKey) { @@ -71,14 +69,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } // Store the notification ID for unsend requests to later cancel this notification tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction) - let storage = SNMessagingKitConfiguration.shared.storage - let attachments = visibleMessage.attachmentIDs.compactMap { TSAttachment.fetch(uniqueId: $0) as? TSAttachmentPointer } - let attachmentsToDownload = attachments.filter { !$0.isDownloaded } - attachmentsToDownload.forEach { attachment in - if let attachmentID = attachment.uniqueId, let job = storage.getAttachmentDownloadJob(for: attachmentID) { - attachmentDownloadJobs.append(job) - } - } case let unsendRequest as UnsendRequest: MessageReceiver.handleUnsendRequest(unsendRequest, using: transaction) return self.completeSilenty() @@ -106,16 +96,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension notificationContent.body = "You've got a new message" default: break } - if attachmentDownloadJobs.isEmpty { - self.handleSuccess(for: notificationContent) - } else { - let promises = attachmentDownloadJobs.map { $0.executeAsync() } - when(fulfilled: promises).map { attachments in - self.handleSuccess(for: notificationContent) - }.catch { error in - self.handleSuccess(for: notificationContent) - }.retainUntilComplete() - } + self.handleSuccess(for: notificationContent) } catch { self.handleFailure(for: notificationContent) } From 42d4e07724d0f4e2361de9187a40cc6ad9a872fe Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 30 Aug 2021 13:22:40 +1000 Subject: [PATCH 19/24] add @ symbol when there is mention in unread messages --- Session/Shared/ConversationCell.swift | 27 ++++++++++++++++++- SessionMessagingKit/Threads/TSThread.h | 3 +++ SessionMessagingKit/Threads/TSThread.m | 26 ++++++++++++++++++ .../Messaging/ThreadViewModel.swift | 2 ++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 3b1d8ca6a..32ae0d4bd 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -1,4 +1,5 @@ import UIKit +import SessionUIKit final class ConversationCell : UITableViewCell { var threadViewModel: ThreadViewModel! { didSet { update() } } @@ -37,6 +38,26 @@ final class ConversationCell : UITableViewCell { return result }() + private lazy var hasMentionView: UIView = { + let result = UIView() + result.backgroundColor = Colors.accent + let size = ConversationCell.unreadCountViewSize + result.set(.width, to: size) + result.set(.height, to: size) + result.layer.masksToBounds = true + result.layer.cornerRadius = size / 2 + return result + }() + + private lazy var hasMentionLabel: UILabel = { + let result = UILabel() + result.font = .boldSystemFont(ofSize: Values.verySmallFontSize) + result.textColor = Colors.text + result.text = "@" + result.textAlignment = .center + return result + }() + private lazy var timestampLabel: UILabel = { let result = UILabel() result.font = .systemFont(ofSize: Values.smallFontSize) @@ -98,9 +119,12 @@ final class ConversationCell : UITableViewCell { // Unread count view unreadCountView.addSubview(unreadCountLabel) unreadCountLabel.pin(to: unreadCountView) + // Has mention view + hasMentionView.addSubview(hasMentionLabel) + hasMentionLabel.pin(to: hasMentionView) // Label stack view let topLabelSpacer = UIView.hStretchingSpacer() - let topLabelStackView = UIStackView(arrangedSubviews: [ displayNameLabel, unreadCountView, topLabelSpacer, timestampLabel ]) + let topLabelStackView = UIStackView(arrangedSubviews: [ displayNameLabel, unreadCountView, hasMentionView, topLabelSpacer, timestampLabel ]) topLabelStackView.axis = .horizontal topLabelStackView.alignment = .center topLabelStackView.spacing = Values.smallSpacing / 2 // Effectively Values.smallSpacing because there'll be spacing before and after the invisible spacer @@ -176,6 +200,7 @@ final class ConversationCell : UITableViewCell { unreadCountLabel.text = unreadCount < 100 ? "\(unreadCount)" : "99+" let fontSize = (unreadCount < 100) ? Values.verySmallFontSize : 8 unreadCountLabel.font = .boldSystemFont(ofSize: fontSize) + hasMentionView.isHidden = !threadViewModel.hasUnreadMentions profilePictureView.update(for: thread) displayNameLabel.text = getDisplayName() timestampLabel.text = DateUtil.formatDate(forDisplay: threadViewModel.lastMessageDate) diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index 82f556d57..7ed517919 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -57,6 +57,9 @@ BOOL IsNoteToSelfEnabled(void); - (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(unreadMessageCount(transaction:)); +- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction + NS_SWIFT_NAME(hasUnreadMentionMessage(transaction:)); + - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; /** diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 14b16ed09..dbfa1ecd4 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -264,6 +264,32 @@ BOOL IsNoteToSelfEnabled(void) return count; } +- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + __block BOOL hasUnreadMention = false; + + YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName]; + [unreadMessages enumerateKeysAndObjectsInGroup:self.uniqueId + usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { + if (![object isKindOfClass:[TSIncomingMessage class]]) { + return; + } + TSIncomingMessage* unreadMessage = (TSIncomingMessage*)object; + if (unreadMessage.read) { + NSLog(@"Found an already read message in the * unread * messages list."); + return; + } + + if (unreadMessage.isUserMentioned) { + hasUnreadMention = true; + *stop = YES; + } + }]; + + return hasUnreadMention; + +} + - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { for (id message in [self unseenMessagesWithTransaction:transaction]) { diff --git a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift index 30177ec11..0162b873f 100644 --- a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift +++ b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift @@ -15,6 +15,7 @@ public class ThreadViewModel: NSObject { @objc public let name: String @objc public let isMuted: Bool @objc public let isOnlyNotifyingForMentions: Bool + @objc public let hasUnreadMentions: Bool var isContactThread: Bool { return !isGroupThread @@ -49,6 +50,7 @@ public class ThreadViewModel: NSObject { self.unreadCount = thread.unreadMessageCount(transaction: transaction) self.hasUnreadMessages = unreadCount > 0 + self.hasUnreadMentions = thread.hasUnreadMentionMessage(transaction: transaction) } @objc From a7e960683347e49c31b47e05002e35be8fe50dc1 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 31 Aug 2021 10:28:45 +1000 Subject: [PATCH 20/24] add copy link option when clicking a link --- .../ConversationVC+Interaction.swift | 42 ++++++++++++------- .../Translations/de.lproj/Localizable.strings | 1 + .../Translations/en.lproj/Localizable.strings | 1 + .../Translations/es.lproj/Localizable.strings | 1 + .../Translations/fa.lproj/Localizable.strings | 1 + .../Translations/fi.lproj/Localizable.strings | 1 + .../Translations/fr.lproj/Localizable.strings | 1 + .../Translations/hi.lproj/Localizable.strings | 1 + .../Translations/hr.lproj/Localizable.strings | 1 + .../id-ID.lproj/Localizable.strings | 1 + .../Translations/it.lproj/Localizable.strings | 1 + .../Translations/ja.lproj/Localizable.strings | 1 + .../Translations/nl.lproj/Localizable.strings | 1 + .../Translations/pl.lproj/Localizable.strings | 1 + .../pt_BR.lproj/Localizable.strings | 1 + .../Translations/ru.lproj/Localizable.strings | 1 + .../Translations/sk.lproj/Localizable.strings | 1 + .../Translations/sv.lproj/Localizable.strings | 1 + .../Translations/th.lproj/Localizable.strings | 1 + .../vi-VN.lproj/Localizable.strings | 1 + .../zh-Hant.lproj/Localizable.strings | 1 + .../zh_CN.lproj/Localizable.strings | 1 + 22 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 2a1bf39bc..4be698a05 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -359,6 +359,13 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc snInputView.hideMentionsUI() self.oldText = newText } + + func showInputAccessoryView() { + UIView.animate(withDuration: 0.25, animations: { + self.inputAccessoryView?.isHidden = false + self.inputAccessoryView?.alpha = 1 + }) + } // MARK: View Item Interaction func handleViewItemLongPressed(_ viewItem: ConversationViewItem) { @@ -560,19 +567,12 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc return } - func showInputAccessoryView() { - UIView.animate(withDuration: 0.25, animations: { - self.inputAccessoryView?.isHidden = false - self.inputAccessoryView?.alpha = 1 - }) - } - if viewItem.interaction.interactionType() == .outgoingMessage, let message = viewItem.interaction as? TSMessage, message.serverHash != nil { let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) let deleteLocallyAction = UIAlertAction.init(title: NSLocalizedString("delete_message_for_me", comment: ""), style: .destructive) { _ in self.deleteLocally(viewItem) - showInputAccessoryView() + self.showInputAccessoryView() } alertVC.addAction(deleteLocallyAction) @@ -582,12 +582,12 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } let deleteRemotelyAction = UIAlertAction.init(title: title, style: .destructive) { _ in self.deleteForEveryone(viewItem) - showInputAccessoryView() + self.showInputAccessoryView() } alertVC.addAction(deleteRemotelyAction) let cancelAction = UIAlertAction.init(title: NSLocalizedString("TXT_CANCEL_TITLE", comment: ""), style: .cancel) {_ in - showInputAccessoryView() + self.showInputAccessoryView() } alertVC.addAction(cancelAction) @@ -674,10 +674,24 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc func openURL(_ url: URL) { // URLs can be unsafe, so always ask the user whether they want to open one - let urlModal = URLModal(url: url) - urlModal.modalPresentationStyle = .overFullScreen - urlModal.modalTransitionStyle = .crossDissolve - present(urlModal, animated: true, completion: nil) + let title = NSLocalizedString("modal_open_url_title", comment: "") + let message = String(format: NSLocalizedString("modal_open_url_explanation", comment: ""), url.absoluteString) + let alertVC = UIAlertController.init(title: title, message: message, preferredStyle: .actionSheet) + let openAction = UIAlertAction.init(title: NSLocalizedString("modal_open_url_button_title", comment: ""), style: .default) { _ in + UIApplication.shared.open(url, options: [:], completionHandler: nil) + self.showInputAccessoryView() + } + alertVC.addAction(openAction) + let copyAction = UIAlertAction.init(title: NSLocalizedString("modal_copy_url_button_title", comment: ""), style: .default) { _ in + UIPasteboard.general.string = url.absoluteString + self.showInputAccessoryView() + } + alertVC.addAction(copyAction) + let cancelAction = UIAlertAction.init(title: NSLocalizedString("cancel", comment: ""), style: .cancel) {_ in + self.showInputAccessoryView() + } + alertVC.addAction(cancelAction) + self.presentAlert(alertVC) } func joinOpenGroup(name: String, url: String) { diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 3db0bf36c..e63e229d4 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "URL öffnen?"; "modal_open_url_explanation" = "Möchten Sie %@ wirklich öffnen?"; "modal_open_url_button_title" = "Öffnen"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "%@ entsperren?"; "modal_blocked_explanation" = "Sind Sie sicher, dass Sie %@ entsperren möchten?"; "modal_blocked_button_title" = "Entsperren"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 7de331a6d..fafe02bc9 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Open URL?"; "modal_open_url_explanation" = "Are you sure you want to open %@?"; "modal_open_url_button_title" = "Open"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Unblock %@?"; "modal_blocked_explanation" = "Are you sure you want to unblock %@?"; "modal_blocked_button_title" = "Unblock"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 34dce14f6..4a291409e 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "¿Abrir URL?"; "modal_open_url_explanation" = "¿Estás seguro de que quieres abrir %@?"; "modal_open_url_button_title" = "Abrir"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "¿Desbloquear a %@?"; "modal_blocked_explanation" = "¿Estás seguro de que quieres desbloquear a %@?"; "modal_blocked_button_title" = "Desbloquear"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 8cb43a537..8980aea86 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "URL باز شود؟"; "modal_open_url_explanation" = "آیا مطمئن هستید که میخواهید %@ را باز کنید؟"; "modal_open_url_button_title" = "باز کن"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Unblock %@?"; "modal_blocked_explanation" = "Are you sure you want to unblock %@?"; "modal_blocked_button_title" = "رفع مسدودی"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index c68cc6d28..b0e6e5e63 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Avataanko URL?"; "modal_open_url_explanation" = "Oletko varma, että haluat avata linkin %@?"; "modal_open_url_button_title" = "Avaa"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Poista esto henkilöltä %@?"; "modal_blocked_explanation" = "Oletko varma, että haluat poistaa eston henkilöltä %@?"; "modal_blocked_button_title" = "Poista esto"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index d91844903..f060c6e28 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Ouvrir l'URL?"; "modal_open_url_explanation" = "Êtes-vous sûr de vouloir ouvrir %@?"; "modal_open_url_button_title" = "Ouvrir"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Débloquer %@ ?"; "modal_blocked_explanation" = "Confirmez-vous le déblocage de %@ ?"; "modal_blocked_button_title" = "Débloquer"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index f750e97f4..db6d2cfab 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "यूआरएल खोलें"; "modal_open_url_explanation" = "क्या आप वाकई %@ खोलना चाहते हैं?"; "modal_open_url_button_title" = "खोलें"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "%@ अनब्लॉक करें?"; "modal_blocked_explanation" = "क्या आप वाकई %@ को अनब्लॉक करना चाहते हैं?"; "modal_blocked_button_title" = "अनब्लॉक करें"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 9d32a4823..437d90817 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Otvori poveznicu?"; "modal_open_url_explanation" = "Jeste li sigurni da želite otvoriti %@?"; "modal_open_url_button_title" = "Otvori"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Deblokiraj %@?"; "modal_blocked_explanation" = "Jeste li sigurni da želite deblokirati %@?"; "modal_blocked_button_title" = "Deblokiraj"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index b3ec9fb89..b09799f22 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Open URL?"; "modal_open_url_explanation" = "Are you sure you want to open %@?"; "modal_open_url_button_title" = "Open"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Unblock %@?"; "modal_blocked_explanation" = "Are you sure you want to unblock %@?"; "modal_blocked_button_title" = "Unblock"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index c2301da20..fe374ac9c 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Aprire URL?"; "modal_open_url_explanation" = "Sei sicuro di voler aprire %@?"; "modal_open_url_button_title" = "Apri"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Sbloccare %@?"; "modal_blocked_explanation" = "Sei sicuro di voler sbloccare %@?"; "modal_blocked_button_title" = "Sblocca"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 4c6af761a..ffade96b2 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "URLを開きますか?"; "modal_open_url_explanation" = "%@を本当に開いてもよろしいですか?"; "modal_open_url_button_title" = "開く"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "%@のブロックを解除しますか?"; "modal_blocked_explanation" = "%@のブロックを解除してもよろしいですか?"; "modal_blocked_button_title" = "ブロックを解除する"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 61311680a..ef1eb532e 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "URL openen?"; "modal_open_url_explanation" = "Weet u zeker dat u %@ wilt openen?"; "modal_open_url_button_title" = "Openen"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Blokkering opheffen voor %@?"; "modal_blocked_explanation" = "Weet je zeker dat je %@ weer wilt toelaten?"; "modal_blocked_button_title" = "Deblokkeren"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 487c99a88..2c4c8d9e6 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Otworzyć URL?"; "modal_open_url_explanation" = "Czy na pewno chcesz otworzyć %@?"; "modal_open_url_button_title" = "Otwórz"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Odblokować %@?"; "modal_blocked_explanation" = "Czy na pewno chcesz odblokować %@?"; "modal_blocked_button_title" = "Odblokuj"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 7248083fa..07d303ece 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Abrir URL?"; "modal_open_url_explanation" = "Você tem certeza que deseja abrir %@/?"; "modal_open_url_button_title" = "Abrir"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Desbloquear %@?"; "modal_blocked_explanation" = "Você tem certeza que deseja desbloquear %@?"; "modal_blocked_button_title" = "Desbloquear"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index d5fcd1c2d..b51f0d475 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Открыть ссылку?"; "modal_open_url_explanation" = "Вы уверены, что хотите открыть %@?"; "modal_open_url_button_title" = "Открыть"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Разблокировать %@?"; "modal_blocked_explanation" = "Вы уверены, что хотите разблокировать %@?"; "modal_blocked_button_title" = "Разблокировать"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index ec5306e3e..8e905f1e9 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Otvoriť URL?"; "modal_open_url_explanation" = "Ste si istý, že chcete otvoriť %@?"; "modal_open_url_button_title" = "Otvoriť"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Odblokovať %@?"; "modal_blocked_explanation" = "Ste si istý/á, že chcete odblokovať %@?"; "modal_blocked_button_title" = "Odblokovať"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 311db3616..9035c2970 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Öppna URL?"; "modal_open_url_explanation" = "Är du säker på att du vill öppna %@?"; "modal_open_url_button_title" = "Öppna"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Avblockera %@?"; "modal_blocked_explanation" = "Är du säker på att du vill avblockera %@?"; "modal_blocked_button_title" = "Avblockera"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index c10829003..d6b2137f6 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "เปิดลิงค์ URL ไหม"; "modal_open_url_explanation" = "แน่ใจไหมว่าคุณต้องกาเปิดดู %@"; "modal_open_url_button_title" = "เปิด"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "เลิกบล็อก %@ ไหม"; "modal_blocked_explanation" = "แน่ใจไหมว่าคุณต้องการเลิกบล็อก %@"; "modal_blocked_button_title" = "เลิกบล็อก"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 665f93fd8..af2ab31c3 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "Open URL?"; "modal_open_url_explanation" = "Are you sure you want to open %@?"; "modal_open_url_button_title" = "Open"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "Unblock %@?"; "modal_blocked_explanation" = "Are you sure you want to unblock %@?"; "modal_blocked_button_title" = "Unblock"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 1f25b7e6d..0e8cb4773 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "打開連結?"; "modal_open_url_explanation" = "您確定要打開 %@ 嗎?"; "modal_open_url_button_title" = "打開"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "解除封鎖 %@ 嗎?"; "modal_blocked_explanation" = "您確定要解除封鎖 %@ 嗎?"; "modal_blocked_button_title" = "解除封鎖"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index e11098fae..a7a52671f 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -531,6 +531,7 @@ "modal_open_url_title" = "打开链接?"; "modal_open_url_explanation" = "确定要打开 %@ 吗?"; "modal_open_url_button_title" = "打开"; +"modal_copy_url_button_title" = "Copy Link"; "modal_blocked_title" = "从黑名单中移除 %@ 吗?"; "modal_blocked_explanation" = "确定解除屏蔽%@吗?"; "modal_blocked_button_title" = "解除屏蔽"; From e0288f2bb36e3377bda92a76f3e5806ae9a3c25c Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 1 Sep 2021 10:23:31 +1000 Subject: [PATCH 21/24] clean draft after deleting it --- Session/Conversations/ConversationVC.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index bee500a68..cc4445e25 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -258,10 +258,8 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) let text = snInputView.text - if !text.isEmpty { - Storage.write { transaction in - self.thread.setDraft(text, transaction: transaction) - } + Storage.write { transaction in + self.thread.setDraft(text, transaction: transaction) } inputAccessoryView?.resignFirstResponder() } From 7c11285dfb7b54ab2d2a6de4ce3e5f498ff3101d Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 1 Sep 2021 15:11:59 +1000 Subject: [PATCH 22/24] fix a crash when scanning false QR code to link a device --- Session/Meta/Translations/en.lproj/Localizable.strings | 1 + Session/Onboarding/LinkDeviceVC.swift | 8 ++++++++ Session/Shared/ScanQRCodeWrapperVC.swift | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index fafe02bc9..77a6a7650 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -564,4 +564,5 @@ "accessibility_library_button" = "Photo library"; "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; +"invalid_recovery_phrase" = "Invalid Recovery Phrase"; diff --git a/Session/Onboarding/LinkDeviceVC.swift b/Session/Onboarding/LinkDeviceVC.swift index f88f00659..e346bc325 100644 --- a/Session/Onboarding/LinkDeviceVC.swift +++ b/Session/Onboarding/LinkDeviceVC.swift @@ -122,6 +122,14 @@ final class LinkDeviceVC : BaseVC, UIPageViewControllerDataSource, UIPageViewCon } func continueWithSeed(_ seed: Data) { + if (seed.count != 16) { + let alert = UIAlertController(title: NSLocalizedString("invalid_recovery_phrase", comment: ""), message: NSLocalizedString("Please check the Recovery Phrase and try again.", comment: ""), preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: { _ in + self.scanQRCodeWrapperVC.startCapture() + })) + presentAlert(alert) + return + } let (ed25519KeyPair, x25519KeyPair) = KeyPairUtilities.generate(from: seed) Onboarding.Flow.link.preregister(with: seed, ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair) TSAccountManager.sharedInstance().didRegister() diff --git a/Session/Shared/ScanQRCodeWrapperVC.swift b/Session/Shared/ScanQRCodeWrapperVC.swift index 57b0eefd8..e3a8c07e2 100644 --- a/Session/Shared/ScanQRCodeWrapperVC.swift +++ b/Session/Shared/ScanQRCodeWrapperVC.swift @@ -71,4 +71,10 @@ final class ScanQRCodeWrapperVC : BaseVC { @objc private func close() { presentingViewController?.dismiss(animated: true, completion: nil) } + + public func startCapture() { + DispatchQueue.main.async { [weak self] in + self?.scanQRCodeVC.startCapture() + } + } } From a25ef77f9a1684b99bda76b6ed4c87f718d68410 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 2 Sep 2021 11:38:00 +1000 Subject: [PATCH 23/24] update version number --- Session.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 689b72b5b..f75e264e5 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -6187,7 +6187,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 292; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6226,7 +6226,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6258,7 +6258,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 292; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6297,7 +6297,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From d60bbdb31546746d5cce16f54608ab314917d6e2 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 3 Sep 2021 11:03:16 +1000 Subject: [PATCH 24/24] update build number --- Session.xcodeproj/project.pbxproj | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index f75e264e5..45da8a58d 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5038,7 +5038,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 294; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5063,7 +5063,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5111,7 +5111,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 294; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5141,7 +5141,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5177,7 +5177,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 294; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5200,7 +5200,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5251,7 +5251,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 291; + CURRENT_PROJECT_VERSION = 294; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5279,7 +5279,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.11.14; + MARKETING_VERSION = 1.11.15; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6187,7 +6187,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 292; + CURRENT_PROJECT_VERSION = 294; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6258,7 +6258,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 292; + CURRENT_PROJECT_VERSION = 294; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)",