From 4f237fb9aecaf574a5d31bca4dc3990cd1e1cadb Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 25 Sep 2019 09:09:25 -0700 Subject: [PATCH 01/21] Fix missed subclass when plumbing transaction through message building fixup to 2063f84e6 --- SignalServiceKit/src/Devices/OWSBlockedPhoneNumbersMessage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Devices/OWSBlockedPhoneNumbersMessage.m b/SignalServiceKit/src/Devices/OWSBlockedPhoneNumbersMessage.m index 0ef7d08ba0..78cd801526 100644 --- a/SignalServiceKit/src/Devices/OWSBlockedPhoneNumbersMessage.m +++ b/SignalServiceKit/src/Devices/OWSBlockedPhoneNumbersMessage.m @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder +- (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilderWithTransaction:(SDSAnyReadTransaction *)transaction { SSKProtoSyncMessageBlockedBuilder *blockedBuilder = [SSKProtoSyncMessageBlocked builder]; [blockedBuilder setNumbers:_phoneNumbers]; From 3868a56b63b32492f5c6ca6647d80dd3de3f5bdc Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 25 Sep 2019 18:34:08 -0700 Subject: [PATCH 02/21] update tags_to_ignore --- Scripts/reverse_integration_check.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/reverse_integration_check.py b/Scripts/reverse_integration_check.py index 2221481bf4..ecfc162464 100755 --- a/Scripts/reverse_integration_check.py +++ b/Scripts/reverse_integration_check.py @@ -81,7 +81,9 @@ def main(): # Looks like this tag was erroneously applied before rebasing. # After rebasing, HEAD was retagged with 2.41.0.2 '2.41.0.1', - # + # internal builds, not marked as such + '2.44.0.0', + '2.44.0.3' ] tags_of_concern = [tag for tag in tags_of_concern if tag not in tags_to_ignore] From fbeb5eb4a71b1fcd6c2d25d7ceafbcbf4647f98c Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 25 Sep 2019 21:13:03 -0700 Subject: [PATCH 03/21] "Bump build to 2.44.0.4." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 11f1614e1a..5de5b0c64f 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 2.44.0.0 + 2.44.0.4 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 23a77d3dc7..554fa5b23c 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.44.0 CFBundleVersion - 2.44.0.0 + 2.44.0.4 ITSAppUsesNonExemptEncryption NSAppTransportSecurity From 3df2f56fc902793241191f1e7e1ae11953dc32ba Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 12:29:55 -0300 Subject: [PATCH 04/21] Improve handling of data source value. --- .../ConversationViewController.m | 8 ++++-- .../ViewControllers/DebugUI/DebugUIMessages.m | 17 +++++++++++++ .../src/Messages/OWSMessageManager.m | 25 ++++++++++--------- SignalServiceKit/src/Util/DataSource.m | 7 +++++- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index c3c536a8e8..846927a62d 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3529,9 +3529,13 @@ typedef enum : NSUInteger { [groupThread fireAvatarChangedNotification]; + NSData *_Nullable groupAvatarData; if (newGroupModel.groupImage) { - NSData *data = UIImagePNGRepresentation(newGroupModel.groupImage); - _Nullable id dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; + groupAvatarData = UIImagePNGRepresentation(newGroupModel.groupImage); + OWSAssertDebug(groupAvatarData.length > 0); + } + if (groupAvatarData.length > 0) { + _Nullable id dataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message // which causes this code to be called. Once we're more aggressive about durable sending retry, // we could get rid of this "retryable tappable error message". diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index 919582f27a..d029f49756 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -329,6 +329,10 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIMessages sendMessages:1 toAllMembersOfGroup:groupThread]; }]]; + [items addObject:[OWSTableItem itemWithTitle:@"Send Group Info Request" + actionBlock:^{ + [DebugUIMessages requestGroupInfoForGroupThread:groupThread]; + }]]; } return [OWSTableSection sectionWithTitle:self.name items:items]; @@ -4933,6 +4937,19 @@ typedef OWSContact * (^OWSContactBlock)(SDSAnyWriteTransaction *transaction); }]; } ++ (void)requestGroupInfoForGroupThread:(TSGroupThread *)groupThread +{ + [self writeWithBlock:^(SDSAnyWriteTransaction *_Nonnull transaction) { + for (SignalServiceAddress *address in groupThread.groupModel.groupMembers) { + TSThread *thread = [TSContactThread getOrCreateThreadWithContactAddress:address transaction:transaction]; + OWSLogInfo(@"Requesting group info for group thread from: %@", address); + OWSSyncGroupsRequestMessage *syncGroupsRequestMessage = + [[OWSSyncGroupsRequestMessage alloc] initWithThread:thread groupId:groupThread.groupModel.groupId]; + [self.messageSenderJobQueue addMessage:syncGroupsRequestMessage.asPreparer transaction:transaction]; + } + }]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 454506121a..48c6f93a22 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1223,19 +1223,20 @@ NS_ASSUME_NONNULL_BEGIN // Only send this group update to the requester. [message updateWithSendingToSingleGroupRecipient:envelope.sourceAddress transaction:transaction]; + NSData *_Nullable groupAvatarData; if (gThread.groupModel.groupImage) { - NSData *_Nullable data = UIImagePNGRepresentation(gThread.groupModel.groupImage); - OWSAssertDebug(data); - if (data) { - _Nullable id dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; - [self.messageSenderJobQueue addMediaMessage:message - dataSource:dataSource - contentType:OWSMimeTypeImagePng - sourceFilename:nil - caption:nil - albumMessageId:nil - isTemporaryAttachment:YES]; - } + groupAvatarData = UIImagePNGRepresentation(gThread.groupModel.groupImage); + OWSAssertDebug(groupAvatarData.length > 0); + } + if (groupAvatarData.length > 0) { + _Nullable id dataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; + [self.messageSenderJobQueue addMediaMessage:message + dataSource:dataSource + contentType:OWSMimeTypeImagePng + sourceFilename:nil + caption:nil + albumMessageId:nil + isTemporaryAttachment:YES]; } else { [self.messageSenderJobQueue addMessage:message.asPreparer transaction:transaction]; } diff --git a/SignalServiceKit/src/Util/DataSource.m b/SignalServiceKit/src/Util/DataSource.m index 0c80a391fd..3938c9461c 100755 --- a/SignalServiceKit/src/Util/DataSource.m +++ b/SignalServiceKit/src/Util/DataSource.m @@ -179,7 +179,12 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(self->_cachedFileUrl != nil); } - NSURL *srcUrl = self.dataUrl; + NSURL *_Nullable srcUrl = self.dataUrl; + if (srcUrl == nil) { + *error = OWSErrorMakeAssertionError(@"Missing data URL."); + success = NO; + return; + } self.isConsumed = YES; success = [NSFileManager.defaultManager moveItemAtURL:srcUrl toURL:dstUrl From d8872f9e6adee36ed859a91f57709fa00aabc6b2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 12:57:46 -0300 Subject: [PATCH 05/21] Respond to CR. --- .../ConversationView/ConversationViewController.m | 7 +++++-- SignalServiceKit/src/Messages/OWSMessageManager.m | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 846927a62d..142e35ee65 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3534,12 +3534,15 @@ typedef enum : NSUInteger { groupAvatarData = UIImagePNGRepresentation(newGroupModel.groupImage); OWSAssertDebug(groupAvatarData.length > 0); } + _Nullable id groupAvatarDataSource; if (groupAvatarData.length > 0) { - _Nullable id dataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; + groupAvatarDataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; + } + if (groupAvatarDataSource != nil) { // DURABLE CLEANUP - currently one caller uses the completion handler to delete the tappable error message // which causes this code to be called. Once we're more aggressive about durable sending retry, // we could get rid of this "retryable tappable error message". - [self.messageSender sendTemporaryAttachment:dataSource + [self.messageSender sendTemporaryAttachment:groupAvatarDataSource contentType:OWSMimeTypeImagePng inMessage:message success:^{ diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 48c6f93a22..fe364282c1 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1228,10 +1228,13 @@ NS_ASSUME_NONNULL_BEGIN groupAvatarData = UIImagePNGRepresentation(gThread.groupModel.groupImage); OWSAssertDebug(groupAvatarData.length > 0); } + _Nullable id groupAvatarDataSource; if (groupAvatarData.length > 0) { - _Nullable id dataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; + groupAvatarDataSource = [DataSourceValue dataSourceWithData:groupAvatarData fileExtension:@"png"]; + } + if (groupAvatarDataSource != nil) { [self.messageSenderJobQueue addMediaMessage:message - dataSource:dataSource + dataSource:groupAvatarDataSource contentType:OWSMimeTypeImagePng sourceFilename:nil caption:nil From 0fb818a8f590dac389a41d7dbbf43bdc92b071d0 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 12:58:54 -0300 Subject: [PATCH 06/21] "Bump build to 2.43.2.0." --- Signal/Signal-Info.plist | 4 ++-- SignalShareExtension/Info.plist | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index ab8eeec264..939a29f5d9 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.43.1 + 2.43.2 CFBundleSignature ???? CFBundleURLTypes @@ -47,7 +47,7 @@ CFBundleVersion - 2.43.1.6 + 2.43.2.0 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 9c54979fb6..e816da260e 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 2.43.1 + 2.43.2 CFBundleVersion - 2.43.1.6 + 2.43.2.0 ITSAppUsesNonExemptEncryption NSAppTransportSecurity From a48deb06e1ba2d22898b4dc6fbdd3207a6e95588 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 20 Sep 2019 21:18:17 -0300 Subject: [PATCH 07/21] Set feature flags to production. --- SignalServiceKit/src/Util/FeatureFlags.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Util/FeatureFlags.swift b/SignalServiceKit/src/Util/FeatureFlags.swift index 35c462be58..5bf4b7082f 100644 --- a/SignalServiceKit/src/Util/FeatureFlags.swift +++ b/SignalServiceKit/src/Util/FeatureFlags.swift @@ -18,7 +18,7 @@ extension FeatureBuild { } } -let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .beta +let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .production // MARK: - From 833e5437e7b9d707343f40ebe9b6b0b240512c8a Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 13:00:21 -0300 Subject: [PATCH 08/21] "Bump build to 2.43.2.1." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 939a29f5d9..8381aa3129 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 2.43.2.0 + 2.43.2.1 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index e816da260e..284243580a 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.43.2 CFBundleVersion - 2.43.2.0 + 2.43.2.1 ITSAppUsesNonExemptEncryption NSAppTransportSecurity From 5b05369f026ae1df7087f9180a76e9789a0e5553 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 20 Sep 2019 21:17:56 -0300 Subject: [PATCH 09/21] Set feature flags to beta. --- SignalServiceKit/src/Util/FeatureFlags.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Util/FeatureFlags.swift b/SignalServiceKit/src/Util/FeatureFlags.swift index 5bf4b7082f..35c462be58 100644 --- a/SignalServiceKit/src/Util/FeatureFlags.swift +++ b/SignalServiceKit/src/Util/FeatureFlags.swift @@ -18,7 +18,7 @@ extension FeatureBuild { } } -let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .production +let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .beta // MARK: - From 48ed98af494b62c388bc69e1ecfedc505d015448 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 13:00:34 -0300 Subject: [PATCH 10/21] "Bump build to 2.43.2.2." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 8381aa3129..0d9622b300 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 2.43.2.1 + 2.43.2.2 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 284243580a..60e485c7e2 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.43.2 CFBundleVersion - 2.43.2.1 + 2.43.2.2 ITSAppUsesNonExemptEncryption NSAppTransportSecurity From bf323049c055a61982d8b6d9fe82a48fd2f2aa10 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 24 Sep 2019 17:04:06 -0300 Subject: [PATCH 11/21] Log how long it takes to open the database file. --- .../src/Storage/Database/SDSDatabaseStorage.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift index 4efbe25b1e..072304c1d9 100644 --- a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift +++ b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift @@ -155,7 +155,11 @@ public class SDSDatabaseStorage: SDSTransactable { // crash if we can't read the DB. do { - return try GRDBDatabaseStorageAdapter(baseDir: type(of: self).baseDir()) + let startDate = Date() + Logger.verbose("Creating GRDB storage.") + let result = try GRDBDatabaseStorageAdapter(baseDir: type(of: self).baseDir()) + Logger.verbose("Elapsed: \(abs(startDate.timeIntervalSinceNow)).") + return result } catch { owsFail("\(error)") } @@ -188,8 +192,12 @@ public class SDSDatabaseStorage: SDSTransactable { } } + let startDate = Date() + Logger.verbose("Creating YDB storage.") let yapPrimaryStorage = OWSPrimaryStorage() - return YAPDBStorageAdapter(storage: yapPrimaryStorage) + let result = YAPDBStorageAdapter(storage: yapPrimaryStorage) + Logger.verbose("Elapsed: \(abs(startDate.timeIntervalSinceNow)).") + return result } // MARK: - From a2c4d728fa83f4b06eb2a42f0188d757a5c2b6bf Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 14:12:08 -0300 Subject: [PATCH 12/21] Respond to CR. --- .../Storage/Database/SDSDatabaseStorage.swift | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift index 072304c1d9..804078ef96 100644 --- a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift +++ b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift @@ -155,11 +155,9 @@ public class SDSDatabaseStorage: SDSTransactable { // crash if we can't read the DB. do { - let startDate = Date() - Logger.verbose("Creating GRDB storage.") - let result = try GRDBDatabaseStorageAdapter(baseDir: type(of: self).baseDir()) - Logger.verbose("Elapsed: \(abs(startDate.timeIntervalSinceNow)).") - return result + return try Bench(title: "Creating GRDB storage") { + return try GRDBDatabaseStorageAdapter(baseDir: type(of: self).baseDir()) + } } catch { owsFail("\(error)") } @@ -192,12 +190,9 @@ public class SDSDatabaseStorage: SDSTransactable { } } - let startDate = Date() - Logger.verbose("Creating YDB storage.") - let yapPrimaryStorage = OWSPrimaryStorage() - let result = YAPDBStorageAdapter(storage: yapPrimaryStorage) - Logger.verbose("Elapsed: \(abs(startDate.timeIntervalSinceNow)).") - return result + return Bench(title: "Creating YDB storage") { + return YAPDBStorageAdapter(storage: yapPrimaryStorage) + } } // MARK: - From 20c39a4f3677b69ee3f958b32362c21ac4ab5d99 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 26 Sep 2019 08:47:41 -0700 Subject: [PATCH 13/21] view-once video proto --- SignalServiceKit/protobuf/SignalService.proto | 9 +++++---- SignalServiceKit/src/Protos/Generated/SSKProto.swift | 3 +++ .../src/Protos/Generated/SignalService.pb.swift | 8 ++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index 42df452e9a..cba7d4895b 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -225,10 +225,11 @@ message DataMessage { enum ProtocolVersion { option allow_alias = true; - INITIAL = 0; - MESSAGE_TIMERS = 1; - VIEW_ONCE = 2; - CURRENT = 2; + INITIAL = 0; + MESSAGE_TIMERS = 1; + VIEW_ONCE = 2; + VIEW_ONCE_VIDEO = 3; + CURRENT = 3; } optional string body = 1; diff --git a/SignalServiceKit/src/Protos/Generated/SSKProto.swift b/SignalServiceKit/src/Protos/Generated/SSKProto.swift index 8f94b6c046..8acbf59052 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProto.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProto.swift @@ -3573,6 +3573,7 @@ extension SSKProtoDataMessageSticker.SSKProtoDataMessageStickerBuilder { case initial = 0 case messageTimers = 1 case viewOnce = 2 + case viewOnceVideo = 3 } private class func SSKProtoDataMessageProtocolVersionWrap(_ value: SignalServiceProtos_DataMessage.ProtocolVersion) -> SSKProtoDataMessageProtocolVersion { @@ -3580,6 +3581,7 @@ extension SSKProtoDataMessageSticker.SSKProtoDataMessageStickerBuilder { case .initial: return .initial case .messageTimers: return .messageTimers case .viewOnce: return .viewOnce + case .viewOnceVideo: return .viewOnceVideo } } @@ -3588,6 +3590,7 @@ extension SSKProtoDataMessageSticker.SSKProtoDataMessageStickerBuilder { case .initial: return .initial case .messageTimers: return .messageTimers case .viewOnce: return .viewOnce + case .viewOnceVideo: return .viewOnceVideo } } diff --git a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift index 76b286ec0b..93fa3184eb 100644 --- a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift +++ b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift @@ -710,7 +710,8 @@ struct SignalServiceProtos_DataMessage { case initial // = 0 case messageTimers // = 1 case viewOnce // = 2 - static let current = viewOnce + case viewOnceVideo // = 3 + static let current = viewOnceVideo init() { self = .initial @@ -721,6 +722,7 @@ struct SignalServiceProtos_DataMessage { case 0: self = .initial case 1: self = .messageTimers case 2: self = .viewOnce + case 3: self = .viewOnceVideo default: return nil } } @@ -730,6 +732,7 @@ struct SignalServiceProtos_DataMessage { case .initial: return 0 case .messageTimers: return 1 case .viewOnce: return 2 + case .viewOnceVideo: return 3 } } @@ -3452,7 +3455,8 @@ extension SignalServiceProtos_DataMessage.ProtocolVersion: SwiftProtobuf._ProtoN static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 0: .same(proto: "INITIAL"), 1: .same(proto: "MESSAGE_TIMERS"), - 2: .aliased(proto: "VIEW_ONCE", aliases: ["CURRENT"]), + 2: .same(proto: "VIEW_ONCE"), + 3: .aliased(proto: "VIEW_ONCE_VIDEO", aliases: ["CURRENT"]), ] } From ac48db41db89bc9d4881509e4d1ca9172cea6dc2 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 26 Sep 2019 09:02:52 -0700 Subject: [PATCH 14/21] don't manually wrap generated code except where necessary --- .../OWSOutgoingSentMessageTranscript.m | 2 +- .../Messages/Interactions/TSOutgoingMessage.m | 4 ++-- .../src/Protos/Generated/SSKProtos.swift | 17 ++--------------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m index bfb3b3a5c9..c0e2122e13 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m @@ -101,7 +101,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(SSKFeatureFlags.viewOnceSending); [dataBuilder setIsViewOnce:YES]; - [dataBuilder setRequiredProtocolVersion:(uint32_t)SSKProtos.viewOnceMessagesProtocolVersion]; + [dataBuilder setRequiredProtocolVersion:(uint32_t)SSKProtoDataMessageProtocolVersionViewOnceVideo]; NSError *error; dataMessage = [dataBuilder buildAndReturnError:&error]; diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 25d8cf2a8c..32fe152396 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -1070,12 +1070,12 @@ NSUInteger const TSOutgoingMessageSchemaVersion = 1; SSKProtoDataMessageBuilder *builder = [SSKProtoDataMessage builder]; [builder setTimestamp:self.timestamp]; - NSUInteger requiredProtocolVersion = SSKProtos.initialProtocolVersion; + NSUInteger requiredProtocolVersion = SSKProtoDataMessageProtocolVersionInitial; if (self.isViewOnceMessage) { if (SSKFeatureFlags.viewOnceSending) { [builder setIsViewOnce:YES]; - requiredProtocolVersion = SSKProtos.viewOnceMessagesProtocolVersion; + requiredProtocolVersion = SSKProtoDataMessageProtocolVersionViewOnceVideo; } else { OWSFailDebug(@"Feature flag not set."); } diff --git a/SignalServiceKit/src/Protos/Generated/SSKProtos.swift b/SignalServiceKit/src/Protos/Generated/SSKProtos.swift index f77d810f96..5c9f973d8c 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProtos.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProtos.swift @@ -9,23 +9,10 @@ public class SSKProtos: NSObject { private override init() {} - @objc - public class var initialProtocolVersion: Int { - return SignalServiceProtos_DataMessage.ProtocolVersion.initial.rawValue - } - - @objc - public class var perMessageExpirationProtocolVersion: Int { - return SignalServiceProtos_DataMessage.ProtocolVersion.messageTimers.rawValue - } - - @objc - public class var viewOnceMessagesProtocolVersion: Int { - return SignalServiceProtos_DataMessage.ProtocolVersion.viewOnce.rawValue - } - @objc public class var currentProtocolVersion: Int { + // Our proto wrappers don't handle enum aliases, so we have one non-generated + // wrapper for the "current" protocol version. return SignalServiceProtos_DataMessage.ProtocolVersion.current.rawValue } } From f6747076df40fad4b1d886c864a84e1c806a3349 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 26 Sep 2019 11:53:52 -0700 Subject: [PATCH 15/21] View Once Video --- .../Cells/OWSMessageViewOnceView.m | 44 ++++++++- .../ConversationView/ConversationViewItem.m | 3 +- .../ViewOnceMessageViewController.swift | 97 ++++++++++++++++--- .../translations/en.lproj/Localizable.strings | 7 +- .../AttachmentApprovalViewController.swift | 3 +- SignalMessaging/Views/CommonStrings.swift | 6 ++ SignalMessaging/Views/VideoPlayerView.swift | 2 +- .../attachments/OWSVideoPlayer.swift | 23 ++++- .../Messages/Interactions/TSOutgoingMessage.m | 2 +- 9 files changed, 155 insertions(+), 32 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m index 68bb6c5a3d..0cab44296c 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m @@ -15,6 +15,12 @@ NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, ViewOnceMessageType) { + ViewOnceMessageType_Unknown = 0, + ViewOnceMessageType_Photo, + ViewOnceMessageType_Video, +}; + @interface OWSMessageViewOnceView () @property (nonatomic) OWSBubbleView *bubbleView; @@ -82,7 +88,7 @@ NS_ASSUME_NONNULL_BEGIN self.senderNameContainer = [UIView new]; self.senderNameContainer.layoutMargins = UIEdgeInsetsMake(0, 0, self.senderNameBottomSpacing, 0); [self.senderNameContainer addSubview:self.senderNameLabel]; - [self.senderNameLabel ows_autoPinToSuperviewMargins]; + [self.senderNameLabel autoPinEdgesToSuperviewMargins]; self.iconView = [UIImageView new]; [self.iconView setContentHuggingHigh]; @@ -406,6 +412,27 @@ NS_ASSUME_NONNULL_BEGIN // Do nothing. } +- (ViewOnceMessageType)viewOnceMessageType +{ + if (self.viewItem.attachmentStream == nil) { + // The attachment doesn't exist for outgoing + // messages so we'd need to store the content type if + // we wanted to distinguish between photo and video + + // For incoming messages viewed messages, it doesn't matter + // because we show generic "View" text, regardless of the + // content type + return ViewOnceMessageType_Unknown + } + + if (self.viewItem.attachmentStream.isVideo) { + return ViewOnceMessageType_Video; + } else { + OWSAssertDebug(self.viewItem.attachmentStream.isImage || self.viewItem.attachmentStream.isAnimated); + return ViewOnceMessageType_Photo; + } +} + #pragma mark - Subviews - (void)configureLabel @@ -436,9 +463,18 @@ NS_ASSUME_NONNULL_BEGIN self.label.text = CommonStrings.retryButton; break; case ViewOnceMessageState_IncomingAvailable: - self.label.text = NSLocalizedString(@"PER_MESSAGE_EXPIRATION_TAP_TO_VIEW", - @"Label for view-once messages indicating that " - @"user can tap to view the message's contents."); + switch (self.viewOnceMessageType) { + case ViewOnceMessageType_Photo: + self.label.text = MessageStrings.viewOnceViewPhoto; + break; + case ViewOnceMessageType_Video: + self.label.text = MessageStrings.viewOnceViewVideo; + break; + case ViewOnceMessageType_Unknown: + OWSFailDebug(@"unexpected viewOnceMessageType for IncomingFailed."); + self.label.text = MessageStrings.viewOnceViewPhoto; + break; + } break; case ViewOnceMessageState_OutgoingFailed: self.label.text = CommonStrings.retryButton; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index 5477c172f6..6cbfc7623c 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -990,7 +990,8 @@ NSString *NSStringForViewOnceMessageState(ViewOnceMessageState cellType) return; } else if ([mediaAttachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachmentStream *attachmentStream = (TSAttachmentStream *)mediaAttachment; - if (attachmentStream.isValidVisualMedia && (attachmentStream.isImage || attachmentStream.isAnimated)) { + if (attachmentStream.isValidVisualMedia + && (attachmentStream.isImage || attachmentStream.isAnimated || attachmentStream.isVideo)) { self.messageCellType = OWSMessageCellType_ViewOnce; self.viewOnceMessageState = ViewOnceMessageState_IncomingAvailable; self.attachmentStream = attachmentStream; diff --git a/Signal/src/ViewControllers/ViewOnceMessageViewController.swift b/Signal/src/ViewControllers/ViewOnceMessageViewController.swift index b328d3d2eb..0050c349f9 100644 --- a/Signal/src/ViewControllers/ViewOnceMessageViewController.swift +++ b/Signal/src/ViewControllers/ViewOnceMessageViewController.swift @@ -9,19 +9,18 @@ import UIKit class ViewOnceMessageViewController: OWSViewController { class Content { + enum ContentType { + case stillImage, animatedImage, video + } + let messageId: String let filePath: String - // The content is an animated image (GIF or WEBP) - // if true, a still image otherwise. - // TODO: We could eventually support video. - let isAnimated: Bool + let type: ContentType - init(messageId: String, - filePath: String, - isAnimated: Bool) { + init(messageId: String, filePath: String, type: ContentType) { self.messageId = messageId self.filePath = filePath - self.isAnimated = isAnimated + self.type = type } deinit { @@ -132,11 +131,14 @@ class ViewOnceMessageViewController: OWSViewController { owsFailDebug("Missing content type.") return } - let isAnimated: Bool + + let viewOnceType: Content.ContentType if attachmentStream.isAnimated || contentType == OWSMimeTypeImageWebp { - isAnimated = true + viewOnceType = .animatedImage } else if attachmentStream.isImage { - isAnimated = false + viewOnceType = .stillImage + } else if attachmentStream.isVideo { + viewOnceType = .video } else { owsFailDebug("Unexpected content type.") return @@ -214,9 +216,7 @@ class ViewOnceMessageViewController: OWSViewController { return } - content = Content(messageId: messageId, - filePath: tempFilePath, - isAnimated: isAnimated) + content = Content(messageId: messageId, filePath: tempFilePath, type: viewOnceType) } return content } @@ -270,7 +270,8 @@ class ViewOnceMessageViewController: OWSViewController { private func buildMediaView() -> UIView? { let filePath = content.filePath - if content.isAnimated { + switch content.type { + case .animatedImage: guard let image = YYImage(contentsOfFile: filePath) else { owsFailDebug("Could not load attachment.") return nil @@ -291,7 +292,7 @@ class ViewOnceMessageViewController: OWSViewController { animatedImageView.layer.allowsEdgeAntialiasing = true animatedImageView.image = image return animatedImageView - } else { + case .stillImage: guard let image = UIImage(contentsOfFile: filePath) else { owsFailDebug("Could not load attachment.") return nil @@ -313,9 +314,66 @@ class ViewOnceMessageViewController: OWSViewController { imageView.layer.allowsEdgeAntialiasing = true imageView.image = image return imageView + case .video: + let videoContainer = UIView() + + let videoUrl = URL(fileURLWithPath: content.filePath) + let player = OWSVideoPlayer(url: videoUrl, shouldLoop: true) + self.videoPlayer = player + player.delegate = self + + let playerView = VideoPlayerView() + playerView.player = player.avPlayer + + videoContainer.addSubview(playerView) + playerView.autoPinEdgesToSuperviewEdges() + + let label = UILabel() + label.textColor = Theme.darkThemePrimaryColor + label.font = UIFont.ows_dynamicTypeBody.ows_monospaced() + label.setShadow() + + videoContainer.addSubview(label) + label.autoPinEdge(toSuperviewMargin: .top, withInset: 16) + label.autoPinEdge(toSuperviewMargin: .trailing, withInset: 16) + + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .positional + formatter.allowedUnits = [.minute, .second ] + formatter.zeroFormattingBehavior = [ .pad ] + + let avPlayer = player.avPlayer + self.videoPlayerProgressObserver = avPlayer.addPeriodicTimeObserver(forInterval: CMTime(seconds: 0.1, preferredTimescale: 100), queue: nil) { [weak self] (_) in + + guard let item = avPlayer.currentItem else { + owsFailDebug("item was unexpectedly nil") + label.text = "0:00" + return + } + + let position = avPlayer.currentTime() + let duration: CMTime = item.asset.duration + let remainingTime = duration - position + let remainingSeconds = CMTimeGetSeconds(remainingTime) + + guard let remainingString = formatter.string(from: remainingSeconds) else { + owsFailDebug("unable to format time remaining") + label.text = "0:00" + return + } + + label.text = remainingString + } + + return videoContainer } } + // MARK: Video + + var videoPlayerProgressObserver: Any? + var videoPlayer: OWSVideoPlayer? + func setupDatabaseObservation() { databaseStorage.add(databaseStorageObserver: self) @@ -339,6 +397,7 @@ class ViewOnceMessageViewController: OWSViewController { super.viewDidAppear(animated) self.becomeFirstResponder() + self.videoPlayer?.play() } public override var preferredStatusBarStyle: UIStatusBarStyle { @@ -419,3 +478,9 @@ extension ViewOnceMessageViewController: SDSDatabaseStorageObserver { dismissIfRemoved() } } + +extension ViewOnceMessageViewController: OWSVideoPlayerDelegate { + func videoPlayerDidPlayToCompletion(_ videoPlayer: OWSVideoPlayer) { + // no-op + } +} diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index cd7ba46ac7..209b6ccbed 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1773,10 +1773,13 @@ "PER_MESSAGE_EXPIRATION_NOTIFICATION" = "Disappearing Photo"; /* Label for outgoing view-once messages. */ -"PER_MESSAGE_EXPIRATION_OUTGOING_MESSAGE" = "Photo"; +"PER_MESSAGE_EXPIRATION_OUTGOING_MESSAGE" = "Media"; /* Label for view-once messages indicating that user can tap to view the message's contents. */ -"PER_MESSAGE_EXPIRATION_TAP_TO_VIEW" = "View Photo"; +"PER_MESSAGE_EXPIRATION_VIEW_PHOTO" = "View Photo"; + +/* Label for view-once messages indicating that user can tap to view the message's contents. */ +"PER_MESSAGE_EXPIRATION_VIEW_VIDEO" = "View Video"; /* Label for view-once messages indicating that the local user has viewed the message's contents. */ "PER_MESSAGE_EXPIRATION_VIEWED" = "Viewed"; diff --git a/SignalMessaging/ViewControllers/AttachmentApproval/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApproval/AttachmentApprovalViewController.swift index 775b752807..507594ab35 100644 --- a/SignalMessaging/ViewControllers/AttachmentApproval/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApproval/AttachmentApprovalViewController.swift @@ -69,11 +69,10 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC private var options: AttachmentApprovalViewControllerOptions { var options = receivedOptions - // For now, only still images can be sent as view-once messages. if FeatureFlags.viewOnceSending, attachmentApprovalItemCollection.attachmentApprovalItems.count == 1, let firstItem = attachmentApprovalItemCollection.attachmentApprovalItems.first, - firstItem.attachment.isValidImage { + firstItem.attachment.isValidImage || firstItem.attachment.isValidVideo { options.insert(.canToggleViewOnce) } diff --git a/SignalMessaging/Views/CommonStrings.swift b/SignalMessaging/Views/CommonStrings.swift index 192fe2f1aa..b172197a79 100644 --- a/SignalMessaging/Views/CommonStrings.swift +++ b/SignalMessaging/Views/CommonStrings.swift @@ -64,6 +64,12 @@ public class MessageStrings: NSObject { @objc static public let noteToSelf = NSLocalizedString("NOTE_TO_SELF", comment: "Label for 1:1 conversation with yourself.") + + @objc + static public let viewOnceViewPhoto = NSLocalizedString("PER_MESSAGE_EXPIRATION_VIEW_PHOTO", comment: "Label for view-once messages indicating that user can tap to view the message's contents.") + + @objc + static public let viewOnceViewVideo = NSLocalizedString("PER_MESSAGE_EXPIRATION_VIEW_VIDEO", comment: "Label for view-once messages indicating that user can tap to view the message's contents.") } @objc diff --git a/SignalMessaging/Views/VideoPlayerView.swift b/SignalMessaging/Views/VideoPlayerView.swift index 213c2fe396..ff4e5637b1 100644 --- a/SignalMessaging/Views/VideoPlayerView.swift +++ b/SignalMessaging/Views/VideoPlayerView.swift @@ -8,7 +8,7 @@ import AVFoundation @objc public class VideoPlayerView: UIView { @objc - var player: AVPlayer? { + public var player: AVPlayer? { get { return playerLayer.player } diff --git a/SignalMessaging/attachments/OWSVideoPlayer.swift b/SignalMessaging/attachments/OWSVideoPlayer.swift index 95532b2a70..361b005d7c 100644 --- a/SignalMessaging/attachments/OWSVideoPlayer.swift +++ b/SignalMessaging/attachments/OWSVideoPlayer.swift @@ -6,7 +6,7 @@ import Foundation import AVFoundation @objc -protocol OWSVideoPlayerDelegate: class { +public protocol OWSVideoPlayerDelegate: class { func videoPlayerDidPlayToCompletion(_ videoPlayer: OWSVideoPlayer) } @@ -14,15 +14,23 @@ protocol OWSVideoPlayerDelegate: class { public class OWSVideoPlayer: NSObject { @objc - let avPlayer: AVPlayer + public let avPlayer: AVPlayer let audioActivity: AudioActivity + let shouldLoop: Bool @objc - weak var delegate: OWSVideoPlayerDelegate? + weak public var delegate: OWSVideoPlayerDelegate? - @objc init(url: URL) { + @objc + convenience public init(url: URL) { + self.init(url: url, shouldLoop: false) + } + + @objc + public init(url: URL, shouldLoop: Bool) { self.avPlayer = AVPlayer(url: url) self.audioActivity = AudioActivity(audioDescription: "[OWSVideoPlayer] url:\(url)", behavior: .playback) + self.shouldLoop = shouldLoop super.init() @@ -81,6 +89,11 @@ public class OWSVideoPlayer: NSObject { @objc private func playerItemDidPlayToCompletion(_ notification: Notification) { self.delegate?.videoPlayerDidPlayToCompletion(self) - audioSession.endAudioActivity(self.audioActivity) + if shouldLoop { + avPlayer.seek(to: CMTime.zero) + avPlayer.play() + } else { + audioSession.endAudioActivity(self.audioActivity) + } } } diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 32fe152396..efffdafed9 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -1069,7 +1069,7 @@ NSUInteger const TSOutgoingMessageSchemaVersion = 1; SSKProtoDataMessageBuilder *builder = [SSKProtoDataMessage builder]; [builder setTimestamp:self.timestamp]; - + NSUInteger requiredProtocolVersion = SSKProtoDataMessageProtocolVersionInitial; if (self.isViewOnceMessage) { From f671bb30bc4f96a3dc84bc6dfd23308652f0340b Mon Sep 17 00:00:00 2001 From: Nora Trapp Date: Thu, 26 Sep 2019 11:56:27 -0700 Subject: [PATCH 16/21] Update play/pause button animation --- Signal.xcodeproj/project.pbxproj | 8 ++++---- Signal/Lottie/playPauseButton.json | 2 +- .../ConversationView/Cells/AudioMessageView.swift | 10 +++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7fd54f2e0f..0169e0716f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -568,6 +568,7 @@ 8809CE8122F534B200D38867 /* CustomKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8809CE8022F534B200D38867 /* CustomKeyboard.swift */; }; 8809CE8722F8FE6D00D38867 /* AttachmentKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8809CE8622F8FE6D00D38867 /* AttachmentKeyboard.swift */; }; 8809CE8A22F93C2200D38867 /* RecentPhotoCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8809CE8922F93C2200D38867 /* RecentPhotoCollectionView.swift */; }; + 880C0FF7233D3F7C00386FB8 /* playPauseButton.json in Resources */ = {isa = PBXBuildFile; fileRef = 880C0FF6233D3F7C00386FB8 /* playPauseButton.json */; }; 8810223722DF9C2300A7C44F /* OnboardingAccountLockedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8810223622DF9C2300A7C44F /* OnboardingAccountLockedViewController.swift */; }; 8811CF842295D8DA00FF6549 /* VolumeButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8811CF832295D8DA00FF6549 /* VolumeButtons.swift */; }; 8813F6E12330082900ADEC6A /* AudioWaveformProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A695BC232C18DF002F7B9B /* AudioWaveformProgressView.swift */; }; @@ -586,7 +587,6 @@ 88A9729222FA5D4B004B4FBF /* AttachmentFormatPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A9729122FA5D4B004B4FBF /* AttachmentFormatPickerView.swift */; }; 88A9729422FB4D02004B4FBF /* LocationPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A9729322FB4D02004B4FBF /* LocationPicker.swift */; }; 88BFD4732335C2B3001797D7 /* waveformLoading.json in Resources */ = {isa = PBXBuildFile; fileRef = 88BFD4722335C2B3001797D7 /* waveformLoading.json */; }; - 88BFD4752335C2DB001797D7 /* playPauseButton.json in Resources */ = {isa = PBXBuildFile; fileRef = 88BFD4742335C2DB001797D7 /* playPauseButton.json */; }; 88D1D40222EBB5A100F472C5 /* MessageRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D1D40122EBB5A100F472C5 /* MessageRequestView.swift */; }; 88D1D40422EF8A9700F472C5 /* ThreadDetailsInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D1D40322EF8A9700F472C5 /* ThreadDetailsInteraction.swift */; }; 88D1D40622EF8F1100F472C5 /* ThreadDetailsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D1D40522EF8F1100F472C5 /* ThreadDetailsCell.swift */; }; @@ -1399,6 +1399,7 @@ 8809CE8422F8DB2D00D38867 /* AttachmentKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentKeyboard.swift; sourceTree = ""; }; 8809CE8622F8FE6D00D38867 /* AttachmentKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentKeyboard.swift; sourceTree = ""; }; 8809CE8922F93C2200D38867 /* RecentPhotoCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentPhotoCollectionView.swift; sourceTree = ""; }; + 880C0FF6233D3F7C00386FB8 /* playPauseButton.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = playPauseButton.json; sourceTree = ""; }; 8810223622DF9C2300A7C44F /* OnboardingAccountLockedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingAccountLockedViewController.swift; sourceTree = ""; }; 8811CF832295D8DA00FF6549 /* VolumeButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VolumeButtons.swift; sourceTree = ""; }; 881677C422DD2B21007BAF49 /* OWSPinReminderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSPinReminderViewController.swift; sourceTree = ""; }; @@ -1418,7 +1419,6 @@ 88A9729122FA5D4B004B4FBF /* AttachmentFormatPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentFormatPickerView.swift; sourceTree = ""; }; 88A9729322FB4D02004B4FBF /* LocationPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPicker.swift; sourceTree = ""; }; 88BFD4722335C2B3001797D7 /* waveformLoading.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = waveformLoading.json; sourceTree = ""; }; - 88BFD4742335C2DB001797D7 /* playPauseButton.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = playPauseButton.json; sourceTree = ""; }; 88D1D40122EBB5A100F472C5 /* MessageRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestView.swift; sourceTree = ""; }; 88D1D40322EF8A9700F472C5 /* ThreadDetailsInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDetailsInteraction.swift; sourceTree = ""; }; 88D1D40522EF8F1100F472C5 /* ThreadDetailsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDetailsCell.swift; sourceTree = ""; }; @@ -2742,7 +2742,7 @@ 88BFD4712335C2A4001797D7 /* Lottie */ = { isa = PBXGroup; children = ( - 88BFD4742335C2DB001797D7 /* playPauseButton.json */, + 880C0FF6233D3F7C00386FB8 /* playPauseButton.json */, 88BFD4722335C2B3001797D7 /* waveformLoading.json */, ); path = Lottie; @@ -3388,6 +3388,7 @@ AD83FF421A73426500B5C81A /* audio_play_button.png in Resources */, 34330A5C1E787A9800DF2FB9 /* dripicons-v2.ttf in Resources */, B633C5C41A1D190B0059AC12 /* mute_on@2x.png in Resources */, + 880C0FF7233D3F7C00386FB8 /* playPauseButton.json in Resources */, B633C5CE1A1D190B0059AC12 /* quit@2x.png in Resources */, AD83FF441A73426500B5C81A /* audio_pause_button.png in Resources */, B6F509971AA53F760068F56A /* Localizable.strings in Resources */, @@ -3397,7 +3398,6 @@ B10C9B611A7049EC00ECA2BF /* play_icon.png in Resources */, AD83FF401A73426500B5C81A /* audio_pause_button_blue@2x.png in Resources */, B66DBF4A19D5BBC8006EA940 /* Images.xcassets in Resources */, - 88BFD4752335C2DB001797D7 /* playPauseButton.json in Resources */, 34CF0788203E6B78005C4D61 /* ringback_tone_ansi.caf in Resources */, 34C3C78F2040A4F70000134C /* sonarping.mp3 in Resources */, AD83FF431A73426500B5C81A /* audio_play_button@2x.png in Resources */, diff --git a/Signal/Lottie/playPauseButton.json b/Signal/Lottie/playPauseButton.json index 9960fe2ae7..a44d0d88a9 100644 --- a/Signal/Lottie/playPauseButton.json +++ b/Signal/Lottie/playPauseButton.json @@ -1 +1 @@ -{"v":"5.5.2","fr":60,"ip":0,"op":30,"w":24,"h":24,"nm":"lottie-assets2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Play Outlines 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":28,"s":[90]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[14,12,0],"to":[-0.333,0,0],"ti":[0.333,0,0]},{"t":28,"s":[12,12,0]}],"ix":2},"a":{"a":0,"k":[7.25,8.25,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-7,-4],[-7,4],[7,4],[6.888,3.936]],"c":true}]},{"t":28,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.969],[-7.984,1.999],[8,1.999],[7.998,-1.997]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[7.25,4.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Play Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":28,"s":[90]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[14,12,0],"to":[-0.333,0,0],"ti":[0.333,0,0]},{"t":28,"s":[12,12,0]}],"ix":2},"a":{"a":0,"k":[7.25,8.25,0],"ix":1},"s":{"a":0,"k":[100,-100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-7,-4],[-7,4],[7,4],[6.888,3.936]],"c":true}]},{"t":28,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.969],[-7.984,1.999],[8,1.999],[7.998,-1.997]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[7.25,4.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} +{"v":"5.5.9","fr":60,"ip":0,"op":30,"w":28,"h":28,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Play 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":28,"s":[90]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[15.111,14,0],"to":[-0.183,0,0],"ti":[0.183,0,0]},{"t":28,"s":[14.011,14,0]}],"ix":2},"a":{"a":0,"k":[0,-5.2,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0.825],[0,0],[0,0],[-0.222,-0.002],[0.093,-0.134],[0.153,-0.057],[0,0],[0,0]],"o":[[-0.716,0.414],[0,0],[0,0],[0,0],[0,0.163],[-0.093,0.134],[0,0],[0,0],[0,0]],"v":[[-7.811,5.035],[-9.111,4.287],[-9.111,-5.168],[-9.111,-5.213],[9.111,-5.211],[8.968,-4.754],[8.589,-4.461],[8.581,-4.456],[8.526,-4.424]],"c":true}]},{"t":28,"s":[{"i":[[0,0],[-0.005,0.388],[0,0.202],[-0.4,0.001],[-0.222,-0.002],[0.005,-0.402],[-0.001,-0.198],[-0.001,-0.09],[0.399,0.003]],"o":[[-0.404,0],[0,0],[-0.005,-0.405],[0,0],[0.404,0.001],[0,0.195],[0,0],[-0.001,0.404],[-0.586,-0.004]],"v":[[-9.41,2.811],[-10.003,2.219],[-10.003,-2.587],[-9.404,-3.19],[9.401,-3.188],[10.004,-2.593],[10.003,2.017],[10.003,2.21],[9.409,2.808]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[99.952,100.017],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Play","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":28,"s":[90]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[15.111,13.987,0],"to":[-0.183,0,0],"ti":[0.183,0,0]},{"t":28,"s":[14.011,13.987,0]}],"ix":2},"a":{"a":0,"k":[0,5.2,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[-0.093,-0.134],[0,-0.163],[0,0],[0,0],[0,0],[-0.716,-0.414],[0,0],[0,0]],"o":[[0.153,0.057],[0.093,0.134],[-0.222,0.002],[0,0],[0,0],[0,-0.825],[0,0],[0,0],[0,0]],"v":[[8.589,4.461],[8.968,4.754],[9.111,5.211],[-9.111,5.213],[-9.111,5.202],[-9.111,-4.287],[-7.811,-5.035],[8.576,4.453],[8.588,4.46]],"c":true}]},{"t":28,"s":[{"i":[[0,0],[-0.001,-0.126],[0.395,0],[0,0],[0,0.392],[0,0],[-0.398,0],[-0.241,0.001],[0,-0.403]],"o":[[0.002,0.152],[0,0.396],[-0.222,0.002],[-0.402,0],[0,-0.1],[0,-0.396],[0,0],[0.397,0],[0.001,0.072]],"v":[[10.01,-1.986],[10.012,2.618],[9.415,3.21],[-9.386,3.208],[-9.987,2.615],[-9.987,-2.191],[-9.389,-2.788],[9.413,-2.788],[10.011,-2.189]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift b/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift index 429d7924a7..7e54ccc770 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift @@ -63,8 +63,12 @@ class AudioMessageView: UIStackView { addArrangedSubview(topLabel) } - // TODO: Adjust the animation speed once we get the final animation - playPauseAnimation.animationSpeed = 2 + // TODO: There is a bug with Lottie where animations lag when there are a lot + // of other things happening on screen. Since this animation generally plays + // when the progress bar / waveform is rendering we speed up the playback to + // address some of the lag issues. Once this is fixed we should update lottie + // and remove this check. https://github.com/airbnb/lottie-ios/issues/1034 + playPauseAnimation.animationSpeed = 3 playPauseAnimation.backgroundBehavior = .forceFinish playPauseAnimation.contentMode = .scaleAspectFit playPauseAnimation.autoSetDimensions(to: CGSize(square: animationSize)) @@ -150,7 +154,7 @@ class AudioMessageView: UIStackView { private static var labelFont: UIFont = .ows_dynamicTypeCaption2 private static var waveformHeight: CGFloat = 35 private static var vMargin: CGFloat = 4 - private var animationSize: CGFloat = 30 + private var animationSize: CGFloat = 28 private var iconSize: CGFloat = 24 private var hMargin: CGFloat = 0 private var hSpacing: CGFloat = 12 From fc9ee2e35715d15150981fc4b14df91b14539fc1 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 17:21:03 -0300 Subject: [PATCH 17/21] Fix break in database storage. --- SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift index 804078ef96..7765830141 100644 --- a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift +++ b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift @@ -191,6 +191,7 @@ public class SDSDatabaseStorage: SDSTransactable { } return Bench(title: "Creating YDB storage") { + let yapPrimaryStorage = OWSPrimaryStorage() return YAPDBStorageAdapter(storage: yapPrimaryStorage) } } From 77fec0f8026c733820834878cd4d9bae4d32b89f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 17:26:51 -0300 Subject: [PATCH 18/21] Fix typo. --- .../ConversationView/Cells/OWSMessageViewOnceView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m index 0cab44296c..f680a65bfb 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageViewOnceView.m @@ -422,7 +422,7 @@ typedef NS_ENUM(NSUInteger, ViewOnceMessageType) { // For incoming messages viewed messages, it doesn't matter // because we show generic "View" text, regardless of the // content type - return ViewOnceMessageType_Unknown + return ViewOnceMessageType_Unknown; } if (self.viewItem.attachmentStream.isVideo) { From 4a168f13851fe405465828ae45d8cf24b916cb8c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 17:40:01 -0300 Subject: [PATCH 19/21] Set feature flags for v2.44.0 release. --- SignalServiceKit/src/Util/FeatureFlags.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SignalServiceKit/src/Util/FeatureFlags.swift b/SignalServiceKit/src/Util/FeatureFlags.swift index d0ed0e6477..c253575b82 100644 --- a/SignalServiceKit/src/Util/FeatureFlags.swift +++ b/SignalServiceKit/src/Util/FeatureFlags.swift @@ -18,7 +18,7 @@ extension FeatureBuild { } } -let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .beta +let build: FeatureBuild = OWSIsDebugBuild() ? .dev : .qa // MARK: - @@ -90,10 +90,7 @@ public class FeatureFlags: NSObject { @objc public static var storageMode: StorageMode { if CurrentAppContext().isRunningTests { - // We should be running the tests using both .ydbTests or .grdbTests. - return .grdbTests - } else if build.includes(.dev) { - return .grdbThrowawayIfMigrating + return .ydbTests } else { return .ydb } From 0e902b4bca96c38ea312374ff30ab57726245a7d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Sep 2019 18:20:36 -0300 Subject: [PATCH 20/21] "Bump build to 2.44.0.5." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 5de5b0c64f..bf3cdf5809 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 2.44.0.4 + 2.44.0.5 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 554fa5b23c..8d6ce2793f 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.44.0 CFBundleVersion - 2.44.0.4 + 2.44.0.5 ITSAppUsesNonExemptEncryption NSAppTransportSecurity From 450354b24864a69a0d5dbcd478162d59ea4706a1 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 24 Sep 2019 13:02:53 -0300 Subject: [PATCH 21/21] Upsert experience upgrades. --- SignalServiceKit/src/Util/ExperienceUpgradeFinder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Util/ExperienceUpgradeFinder.swift b/SignalServiceKit/src/Util/ExperienceUpgradeFinder.swift index 84fe6cf586..7a97714ebe 100644 --- a/SignalServiceKit/src/Util/ExperienceUpgradeFinder.swift +++ b/SignalServiceKit/src/Util/ExperienceUpgradeFinder.swift @@ -65,7 +65,7 @@ public enum ExperienceUpgradeId: String { @objc public func markAsSeen(experienceUpgrade: ExperienceUpgrade, transaction: SDSAnyWriteTransaction) { Logger.info("marking experience upgrade as seen") - experienceUpgrade.anyInsert(transaction: transaction) + experienceUpgrade.anyUpsert(transaction: transaction) } @objc