Add default disappearing message timer

This commit is contained in:
Nora Trapp 2021-04-26 12:06:30 -07:00
parent b12120afc5
commit 6783db210e
33 changed files with 371 additions and 58 deletions

View File

@ -845,6 +845,7 @@
88D6E93F254CF712003142D9 /* group_call_leave.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 88D6E93D254CF712003142D9 /* group_call_leave.aiff */; };
88D6E940254CF712003142D9 /* group_call_join.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 88D6E93E254CF712003142D9 /* group_call_join.aiff */; };
88D6E94325535D49003142D9 /* CVTextTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D6E94125535482003142D9 /* CVTextTest.swift */; };
88DBDFB9263731C800C2101C /* DefaultDisappearingMessageTimerInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DBDFB8263731C800C2101C /* DefaultDisappearingMessageTimerInteraction.swift */; };
88E34F2722F269E900966CC2 /* StorageServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E34F2622F269E900966CC2 /* StorageServiceManager.swift */; };
88E34F2922F26CC100966CC2 /* StorageServiceProto+Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E34F2822F26CC100966CC2 /* StorageServiceProto+Sync.swift */; };
88E728FF25F0241100A2E4A4 /* AccountSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E728FE25F0241100A2E4A4 /* AccountSettingsViewController.swift */; };
@ -1980,6 +1981,7 @@
88D6E93D254CF712003142D9 /* group_call_leave.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = group_call_leave.aiff; sourceTree = "<group>"; };
88D6E93E254CF712003142D9 /* group_call_join.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = group_call_join.aiff; sourceTree = "<group>"; };
88D6E94125535482003142D9 /* CVTextTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CVTextTest.swift; sourceTree = "<group>"; };
88DBDFB8263731C800C2101C /* DefaultDisappearingMessageTimerInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultDisappearingMessageTimerInteraction.swift; sourceTree = "<group>"; };
88E34F2622F269E900966CC2 /* StorageServiceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageServiceManager.swift; sourceTree = "<group>"; };
88E34F2822F26CC100966CC2 /* StorageServiceProto+Sync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageServiceProto+Sync.swift"; sourceTree = "<group>"; };
88E728FE25F0241100A2E4A4 /* AccountSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingsViewController.swift; sourceTree = "<group>"; };
@ -2508,6 +2510,7 @@
88D1D40322EF8A9700F472C5 /* ThreadDetailsInteraction.swift */,
34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */,
346CD5C126306578004162D6 /* UnknownThreadWarningInteraction.swift */,
88DBDFB8263731C800C2101C /* DefaultDisappearingMessageTimerInteraction.swift */,
4CFF115223A9C2130007F9D7 /* UnreadIndicatorInteraction.swift */,
);
path = ConversationView;
@ -5465,6 +5468,7 @@
346EAA14250199A400E8AB6F /* MemberRequestView.swift in Sources */,
3426A37A2563F0EA0036407F /* CVComponentBottomButtons.swift in Sources */,
32ECD08824BFBF8000EDDED0 /* HelpViewController.swift in Sources */,
88DBDFB9263731C800C2101C /* DefaultDisappearingMessageTimerInteraction.swift in Sources */,
3497972125DAA86100E99FA4 /* SendPaymentViewController.swift in Sources */,
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */,
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */,

View File

@ -61,7 +61,7 @@ class PrivacySettingsViewController: OWSTableViewController2 {
))
}
if FeatureFlags.phoneNumberDiscoverability {
if FeatureFlags.phoneNumberDiscoverability, tsAccountManager.isPrimaryDevice {
whoCanSection.add(.disclosureItem(
withText: NSLocalizedString(
"SETTINGS_PHONE_NUMBER_DISCOVERABILITY",
@ -108,6 +108,49 @@ class PrivacySettingsViewController: OWSTableViewController2 {
))
contents.addSection(messagingSection)
let disappearingMessagesSection = OWSTableSection()
disappearingMessagesSection.headerTitle = NSLocalizedString(
"SETTINGS_DISAPPEARING_MESSAGES",
comment: "Label for the 'disappearig messages' privacy settings."
)
disappearingMessagesSection.footerTitle = NSLocalizedString(
"SETTINGS_DISAPPEARING_MESSAGES_FOOTER",
comment: "Explanation for the 'disappearig messages' privacy settings."
)
let disappearingMessagesConfiguration = databaseStorage.read { transaction in
OWSDisappearingMessagesConfiguration.fetchOrBuildDefaultUniversalConfiguration(with: transaction)
}
disappearingMessagesSection.add(.init(
customCellBlock: { [weak self] in
guard let self = self else { return UITableViewCell() }
let cell = OWSTableItem.buildIconNameCell(
icon: disappearingMessagesConfiguration.isEnabled
? .settingsTimer
: .settingsTimerDisabled,
itemName: NSLocalizedString(
"SETTINGS_DEFAULT_DISAPPEARING_MESSAGES",
comment: "table cell label in conversation settings"
),
accessoryText: disappearingMessagesConfiguration.isEnabled
? NSString.formatDurationSeconds(disappearingMessagesConfiguration.durationSeconds, useShortFormat: true)
: CommonStrings.switchOff,
accessoryType: .disclosureIndicator,
accessoryImage: nil,
accessibilityIdentifier: UIView.accessibilityIdentifier(in: self, name: "disappearing_messages")
)
return cell
}, actionBlock: { [weak self] in
let vc = DisappearingMessagesTimerSettingsViewController(configuration: disappearingMessagesConfiguration) { configuration in
self?.databaseStorage.write { transaction in
configuration.anyUpsert(transaction: transaction)
}
self?.updateTableContents()
}
self?.presentFormSheet(OWSNavigationController(rootViewController: vc), animated: true)
}
))
contents.addSection(disappearingMessagesSection)
let appSecuritySection = OWSTableSection()
appSecuritySection.headerTitle = NSLocalizedString("SETTINGS_SECURITY_TITLE", comment: "Section header")

View File

@ -302,6 +302,7 @@ public enum CVComponentKey: CustomStringConvertible, CaseIterable {
case threadDetails
case failedOrPendingDownloads
case unknownThreadWarning
case defaultDisappearingMessageTimer
public var description: String {
switch self {
@ -349,6 +350,8 @@ public enum CVComponentKey: CustomStringConvertible, CaseIterable {
return ".failedOrPendingDownloads"
case .sendFailureBadge:
return ".sendFailureBadge"
case .defaultDisappearingMessageTimer:
return ".defaultDisappearingMessageTimer"
}
}

View File

@ -210,6 +210,9 @@ public class CVComponentState: Equatable, Dependencies {
typealias UnknownThreadWarning = CVComponentState.SystemMessage
let unknownThreadWarning: UnknownThreadWarning?
typealias DefaultDisappearingMessageTimer = CVComponentState.SystemMessage
let defaultDisappearingMessageTimer: DefaultDisappearingMessageTimer?
struct BottomButtons: Equatable {
let actions: [CVMessageAction]
}
@ -243,6 +246,7 @@ public class CVComponentState: Equatable, Dependencies {
typingIndicator: TypingIndicator?,
threadDetails: ThreadDetails?,
unknownThreadWarning: UnknownThreadWarning?,
defaultDisappearingMessageTimer: DefaultDisappearingMessageTimer?,
bottomButtons: BottomButtons?,
failedOrPendingDownloads: FailedOrPendingDownloads?,
sendFailureBadge: SendFailureBadge?) {
@ -266,6 +270,7 @@ public class CVComponentState: Equatable, Dependencies {
self.typingIndicator = typingIndicator
self.threadDetails = threadDetails
self.unknownThreadWarning = unknownThreadWarning
self.defaultDisappearingMessageTimer = defaultDisappearingMessageTimer
self.bottomButtons = bottomButtons
self.failedOrPendingDownloads = failedOrPendingDownloads
self.sendFailureBadge = sendFailureBadge
@ -293,6 +298,7 @@ public class CVComponentState: Equatable, Dependencies {
lhs.typingIndicator == rhs.typingIndicator &&
lhs.threadDetails == rhs.threadDetails &&
lhs.unknownThreadWarning == rhs.unknownThreadWarning &&
lhs.defaultDisappearingMessageTimer == rhs.defaultDisappearingMessageTimer &&
lhs.bottomButtons == rhs.bottomButtons &&
lhs.failedOrPendingDownloads == rhs.failedOrPendingDownloads &&
lhs.sendFailureBadge == rhs.sendFailureBadge)
@ -318,6 +324,7 @@ public class CVComponentState: Equatable, Dependencies {
typealias TypingIndicator = CVComponentState.TypingIndicator
typealias ThreadDetails = CVComponentState.ThreadDetails
typealias UnknownThreadWarning = CVComponentState.UnknownThreadWarning
typealias DefaultDisappearingMessageTimer = CVComponentState.DefaultDisappearingMessageTimer
typealias FailedOrPendingDownloads = CVComponentState.FailedOrPendingDownloads
typealias BottomButtons = CVComponentState.BottomButtons
typealias SendFailureBadge = CVComponentState.SendFailureBadge
@ -342,6 +349,7 @@ public class CVComponentState: Equatable, Dependencies {
var typingIndicator: TypingIndicator?
var threadDetails: ThreadDetails?
var unknownThreadWarning: UnknownThreadWarning?
var defaultDisappearingMessageTimer: DefaultDisappearingMessageTimer?
var reactions: Reactions?
var failedOrPendingDownloads: FailedOrPendingDownloads?
var sendFailureBadge: SendFailureBadge?
@ -378,6 +386,7 @@ public class CVComponentState: Equatable, Dependencies {
typingIndicator: typingIndicator,
threadDetails: threadDetails,
unknownThreadWarning: unknownThreadWarning,
defaultDisappearingMessageTimer: defaultDisappearingMessageTimer,
bottomButtons: bottomButtons,
failedOrPendingDownloads: failedOrPendingDownloads,
sendFailureBadge: sendFailureBadge)
@ -409,6 +418,9 @@ public class CVComponentState: Equatable, Dependencies {
if unknownThreadWarning != nil {
return .unknownThreadWarning
}
if defaultDisappearingMessageTimer != nil {
return .defaultDisappearingMessageTimer
}
if systemMessage != nil {
return .systemMessage
}
@ -504,6 +516,9 @@ public class CVComponentState: Equatable, Dependencies {
if unknownThreadWarning != nil {
result.insert(.unknownThreadWarning)
}
if defaultDisappearingMessageTimer != nil {
result.insert(.defaultDisappearingMessageTimer)
}
if bottomButtons != nil {
result.insert(.bottomButtons)
}
@ -611,6 +626,13 @@ fileprivate extension CVComponentState.Builder {
threadViewModel: threadViewModel,
transaction: transaction)
return build()
case .defaultDisappearingMessageTimer:
self.unknownThreadWarning = CVComponentSystemMessage.buildDefaultDisappearingMessageTimerState(
interaction: interaction,
threadViewModel: threadViewModel,
transaction: transaction
)
return build()
case .typingIndicator:
guard let typingIndicatorInteraction = interaction as? TypingIndicatorInteraction else {
owsFailDebug("Invalid typingIndicator.")

View File

@ -120,7 +120,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
// We don't render sender avatars with a subcomponent.
case .senderAvatar:
return nil
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning:
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning, .defaultDisappearingMessageTimer:
return nil
}
}
@ -1239,7 +1239,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
case .senderAvatar:
owsFailDebug("Invalid component key: \(key)")
return nil
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning:
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning, .defaultDisappearingMessageTimer:
owsFailDebug("Invalid component key: \(key)")
return nil
}
@ -1277,7 +1277,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
// We don't render sender avatars with a subcomponent.
case .senderAvatar:
owsAssertDebug(subcomponentView == nil)
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning:
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge, .unknownThreadWarning, .defaultDisappearingMessageTimer:
owsAssertDebug(subcomponentView == nil)
}
}

View File

@ -782,6 +782,36 @@ extension CVComponentSystemMessage {
}
}
// MARK: - Default Disappearing Message Timer
static func buildDefaultDisappearingMessageTimerState(
interaction: TSInteraction,
threadViewModel: ThreadViewModel,
transaction: SDSAnyReadTransaction
) -> CVComponentState.SystemMessage {
let configuration = OWSDisappearingMessagesConfiguration.fetchOrBuildDefaultUniversalConfiguration(with: transaction)
let labelText = NSMutableAttributedString()
labelText.appendImage(
Theme.iconImage(.timer16).withRenderingMode(.alwaysTemplate),
font: Self.titleLabelFont,
heightReference: ImageAttachmentHeightReference.lineHeight
)
labelText.append(" ", attributes: [:])
let titleFormat = NSLocalizedString(
"SYSTEM_MESSAGE_DEFAULT_DISAPPEARING_MESSAGE_TIMER_FORMAT",
comment: "Indicator that the default disappearing message timer will be applied when you send a message. Embeds {default disappearing message time}"
)
labelText.append(String(format: titleFormat, configuration.durationString))
return CVComponentState.SystemMessage(
title: labelText,
titleColor: Theme.secondaryTextAndIconColor,
action: nil
)
}
// MARK: - Actions
static func action(forInteraction interaction: TSInteraction,

View File

@ -214,7 +214,7 @@ extension CVItemViewModelImpl {
}
switch messageCellType {
case .unknown, .dateHeader, .typingIndicator, .unreadIndicator, .threadDetails, .systemMessage, .unknownThreadWarning:
case .unknown, .dateHeader, .typingIndicator, .unreadIndicator, .threadDetails, .systemMessage, .unknownThreadWarning, .defaultDisappearingMessageTimer:
return false
case .textOnlyMessage, .audio, .genericAttachment, .contactShare, .bodyMedia, .viewOnce, .stickerMessage:
return !hasUnloadedAttachments

View File

@ -91,7 +91,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
// The thread details should have a stable timestamp.
let threadDetailsTimestamp: UInt64
if let firstInteraction = messageMapping.loadedInteractions.first {
threadDetailsTimestamp = max(1, firstInteraction.timestamp) - 2
threadDetailsTimestamp = max(1, firstInteraction.timestamp) - 3
} else {
threadDetailsTimestamp = 1
}
@ -109,7 +109,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
// The "Unknown Thread Warning" should have a stable timestamp.
let timestamp: UInt64
if let firstInteraction = messageMapping.loadedInteractions.first {
timestamp = max(1, firstInteraction.timestamp) - 1
timestamp = max(1, firstInteraction.timestamp) - 2
} else {
timestamp = 2
}
@ -119,6 +119,25 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
owsAssertDebug(item != nil)
}
if messageMapping.shouldShowDefaultTimerIndicator(
thread: thread,
transaction: transaction
) {
// The default timer message should have a stable timestamp.
let timestamp: UInt64
if let firstInteraction = messageMapping.loadedInteractions.first {
timestamp = max(1, firstInteraction.timestamp) - 1
} else {
timestamp = 3
}
let interaction = DefaultDisappearingMessageTimerInteraction(
thread: thread,
timestamp: timestamp
)
let item = addItem(interaction: interaction)
owsAssertDebug(item != nil)
}
var interactionIds = Set<String>()
for interaction in messageMapping.loadedInteractions {
guard !interactionIds.contains(interaction.uniqueId) else {
@ -623,6 +642,11 @@ fileprivate extension CVMessageMapping {
!canLoadOlder && Self.contactsManagerImpl.shouldShowUnknownThreadWarning(thread: thread,
transaction: transaction)
}
func shouldShowDefaultTimerIndicator(thread: TSThread, transaction: SDSAnyReadTransaction) -> Bool {
guard !thread.shouldThreadBeVisible else { return false }
guard thread.lastInteractionRowId == 0 else { return false }
return OWSDisappearingMessagesConfiguration.fetchOrBuildDefaultUniversalConfiguration(with: transaction).isEnabled
}
}
// MARK: -
@ -655,7 +679,7 @@ private class ItemBuilder {
var canShowDate: Bool {
switch interaction.interactionType() {
case .unknown, .typingIndicator, .threadDetails, .dateHeader, .unknownThreadWarning:
case .unknown, .typingIndicator, .threadDetails, .dateHeader, .unknownThreadWarning, .defaultDisappearingMessageTimer:
return false
case .info:
guard let infoMessage = interaction as? TSInfoMessage else {

View File

@ -24,6 +24,7 @@ public enum CVMessageCellType: Int, CustomStringConvertible, Equatable {
case threadDetails
case systemMessage
case unknownThreadWarning
case defaultDisappearingMessageTimer
// MARK: - CustomStringConvertible
@ -44,6 +45,7 @@ public enum CVMessageCellType: Int, CustomStringConvertible, Equatable {
case .threadDetails: return "threadDetails"
case .systemMessage: return "systemMessage"
case .unknownThreadWarning: return "unknownThreadWarning"
case .defaultDisappearingMessageTimer: return "defaultDisappearingMessageTimer"
}
}
}

View File

@ -631,7 +631,7 @@ extension ConversationViewController {
switch interaction.interactionType() {
case .unknown, .unreadIndicator, .dateHeader, .typingIndicator:
return false
case .incomingMessage, .outgoingMessage, .error, .call, .info, .threadDetails, .unknownThreadWarning:
case .incomingMessage, .outgoingMessage, .error, .call, .info, .threadDetails, .unknownThreadWarning, .defaultDisappearingMessageTimer:
return true
}
}

View File

@ -1370,7 +1370,7 @@ typedef enum : NSUInteger {
[self removeGroupCallTooltip];
// We initiated a call, so if there was a pending message request we should accept it.
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:self.thread];
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:self.thread];
[GroupCallViewController presentLobbyForThread:(TSGroupThread *)self.thread];
}
@ -1420,7 +1420,7 @@ typedef enum : NSUInteger {
}
// We initiated a call, so if there was a pending message request we should accept it.
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:self.thread];
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:self.thread];
[self.outboundIndividualCallInitiator initiateCallWithAddress:contactThread.contactAddress isVideo:isVideo];
}
@ -2370,8 +2370,9 @@ typedef enum : NSUInteger {
__block BOOL didAddToProfileWhitelist;
TSThread *thread = self.thread;
DatabaseStorageAsyncWrite(SDSDatabaseStorage.shared, ^(SDSAnyWriteTransaction *transaction) {
didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequest:thread
transaction:transaction];
didAddToProfileWhitelist =
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer:thread
transaction:transaction];
// TODO - in line with QuotedReply and other message attachments, saving should happen as part of sending
// preparation rather than duplicated here and in the SAE
@ -2777,7 +2778,8 @@ typedef enum : NSUInteger {
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
// We updated the group, so if there was a pending message request we should accept it.
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequest:self.thread transaction:transaction];
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer:self.thread
transaction:transaction];
});
}
@ -2915,8 +2917,8 @@ typedef enum : NSUInteger {
}
}
BOOL didAddToProfileWhitelist =
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:self.thread];
BOOL didAddToProfileWhitelist = [ThreadUtil
addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:self.thread];
__block TSOutgoingMessage *message;
[self.databaseStorage uiReadWithBlock:^(SDSAnyReadTransaction *_Nonnull transaction) {
@ -3436,8 +3438,8 @@ typedef enum : NSUInteger {
return;
}
BOOL didAddToProfileWhitelist =
[ThreadUtil addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:self.thread];
BOOL didAddToProfileWhitelist = [ThreadUtil
addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:self.thread];
__block TSOutgoingMessage *message;
[self.databaseStorage uiReadWithBlock:^(SDSAnyReadTransaction *transaction) {

View File

@ -0,0 +1,51 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc(OWSDefaultDisappearingMessageTimerInteraction)
public class DefaultDisappearingMessageTimerInteraction: TSInteraction {
@objc
public override func isDynamicInteraction() -> Bool {
return true
}
@objc
public override func interactionType() -> OWSInteractionType {
return .defaultDisappearingMessageTimer
}
@available(*, unavailable, message: "use other constructor instead.")
@objc
public required init(coder aDecoder: NSCoder) {
notImplemented()
}
@available(*, unavailable, message: "use other constructor instead.")
@objc
public required init(dictionary dictionaryValue: [String: Any]!) throws {
notImplemented()
}
@objc
public init(thread: TSThread, timestamp: UInt64) {
// Include timestamp in uniqueId to ensure invariant that
// interactions don't move in the chat history ordering.
super.init(
uniqueId: "DefaultDisappearingMessageTimer_\(timestamp)",
timestamp: timestamp,
thread: thread
)
}
public override var shouldBeSaved: Bool {
return false
}
@objc
public override func anyWillInsert(with transaction: SDSAnyWriteTransaction) {
owsFailDebug("The transient interaction should not be saved in the database.")
}
}

View File

@ -103,6 +103,7 @@ NS_ASSUME_NONNULL_BEGIN
groupId:nil
name:groupName
avatarData:nil
disappearingMessageToken:DisappearingMessageToken.disabledToken
newGroupSeed:nil
shouldSendMessage:YES
success:^(TSGroupThread *thread) { [SignalApp.shared presentConversationForThread:thread animated:YES]; }

View File

@ -589,6 +589,7 @@ class DebugUIGroupsV2: DebugUIPage {
return firstly {
GroupManager.localCreateNewGroup(members: [otherUserAddress],
name: "Real group, both users are in the group",
disappearingMessageToken: .disabledToken,
shouldSendMessage: false)
}.map(on: .global()) { (groupThread: TSGroupThread) in
guard let validGroupModelV2 = groupThread.groupModel as? TSGroupModelV2 else {
@ -602,6 +603,7 @@ class DebugUIGroupsV2: DebugUIPage {
return firstly {
GroupManager.localCreateNewGroup(members: [],
name: "Real group, recipient is not in the group",
disappearingMessageToken: .disabledToken,
shouldSendMessage: false)
}.map(on: .global()) { (groupThread: TSGroupThread) in
guard let missingOtherUserGroupModelV2 = groupThread.groupModel as? TSGroupModelV2 else {
@ -617,6 +619,7 @@ class DebugUIGroupsV2: DebugUIPage {
return firstly { () -> Promise<TSGroupThread> in
GroupManager.localCreateNewGroup(members: [otherUserAddress],
name: "Real group, sender is not in the group",
disappearingMessageToken: .disabledToken,
shouldSendMessage: false)
}.then(on: .global()) { (groupThread: TSGroupThread) -> Promise<TSGroupThread> in
guard let groupModel = groupThread.groupModel as? TSGroupModelV2 else {

View File

@ -64,7 +64,7 @@ public extension DebugUIMessages {
let members = uuidMembers + [TSAccountManager.localAddress!]
let groupName = "UUID Group"
_ = GroupManager.localCreateNewGroup(members: members, name: groupName, shouldSendMessage: true)
_ = GroupManager.localCreateNewGroup(members: members, name: groupName, disappearingMessageToken: .disabledToken, shouldSendMessage: true)
}
}

View File

@ -4362,14 +4362,11 @@ typedef OWSContact * (^OWSContactBlock)(SDSAnyWriteTransaction *transaction);
groupId:nil
name:groupName
avatarData:nil
disappearingMessageToken:DisappearingMessageToken.disabledToken
newGroupSeed:nil
shouldSendMessage:YES
success:^(TSGroupThread *thread) {
success(thread);
}
failure:^(NSError *error) {
OWSFailDebug(@"Error: %@", error);
}];
success:^(TSGroupThread *thread) { success(thread); }
failure:^(NSError *error) { OWSFailDebug(@"Error: %@", error); }];
}
+ (void)testIndicScriptsInThread:(TSThread *)thread

View File

@ -575,6 +575,7 @@ NS_ASSUME_NONNULL_BEGIN
groupId:nil
name:NSUUID.UUID.UUIDString
avatarData:nil
disappearingMessageToken:DisappearingMessageToken.disabledToken
newGroupSeed:nil
shouldSendMessage:NO
success:^(TSGroupThread *thread) { [SignalApp.shared presentConversationForThread:thread animated:YES]; }

View File

@ -26,6 +26,7 @@ public extension DebugUIStress {
groupId: nil,
name: groupName,
avatarData: oldGroupThread.groupModel.groupAvatarData,
disappearingMessageToken: .disabledToken,
newGroupSeed: nil,
shouldSendMessage: false)
}.done { newGroupThread in
@ -103,6 +104,7 @@ public extension DebugUIStress {
groupId: nil,
name: groupName,
avatarData: oldGroupThread.groupModel.groupAvatarData,
disappearingMessageToken: .disabledToken,
newGroupSeed: nil,
shouldSendMessage: false)
}.done { (newGroupThread) in

View File

@ -142,7 +142,7 @@ extension ForwardMessageNavigationController {
pushViewController(approvalViewController, animated: true)
case .unknown, .viewOnce, .dateHeader, .unreadIndicator, .typingIndicator,
.threadDetails, .systemMessage, .unknownThreadWarning:
.threadDetails, .systemMessage, .unknownThreadWarning, .defaultDisappearingMessageTimer:
throw OWSAssertionError("Invalid message type.")
}
}
@ -257,7 +257,7 @@ extension ForwardMessageNavigationController {
}
// }
case .unknown, .viewOnce, .dateHeader, .unreadIndicator, .typingIndicator,
.threadDetails, .systemMessage, .unknownThreadWarning:
.threadDetails, .systemMessage, .unknownThreadWarning, .defaultDisappearingMessageTimer:
throw OWSAssertionError("Invalid message type.")
}
}

View File

@ -27,6 +27,10 @@ public class NewGroupConfirmViewController: OWSViewController {
private let recipientTableView = OWSTableViewController2()
private lazy var disappearingMessagesConfiguration = databaseStorage.read { transaction in
OWSDisappearingMessagesConfiguration.fetchOrBuildDefaultUniversalConfiguration(with: transaction)
}
required init(newGroupState: NewGroupState) {
self.newGroupState = newGroupState
@ -203,6 +207,39 @@ public class NewGroupConfirmViewController: OWSViewController {
// MARK: -
private func updateTableContents() {
let contents = OWSTableContents()
let disappearingMessagesSection = OWSTableSection()
disappearingMessagesSection.add(.init(
customCellBlock: { [weak self] in
guard let self = self else { return UITableViewCell() }
let cell = OWSTableItem.buildIconNameCell(
icon: self.disappearingMessagesConfiguration.isEnabled
? .settingsTimer
: .settingsTimerDisabled,
itemName: NSLocalizedString(
"DISAPPEARING_MESSAGES",
comment: "table cell label in conversation settings"
),
accessoryText: self.disappearingMessagesConfiguration.isEnabled
? NSString.formatDurationSeconds(self.disappearingMessagesConfiguration.durationSeconds, useShortFormat: true)
: CommonStrings.switchOff,
accessoryType: .disclosureIndicator,
accessoryImage: nil,
accessibilityIdentifier: UIView.accessibilityIdentifier(in: self, name: "disappearing_messages")
)
return cell
}, actionBlock: { [weak self] in
guard let self = self else { return }
let vc = DisappearingMessagesTimerSettingsViewController(configuration: self.disappearingMessagesConfiguration) { configuration in
self.disappearingMessagesConfiguration = configuration
self.updateTableContents()
}
self.presentFormSheet(OWSNavigationController(rootViewController: vc), animated: true)
}
))
contents.addSection(disappearingMessagesSection)
let section = OWSTableSection()
section.headerTitle = NSLocalizedString("GROUP_MEMBERS_SECTION_TITLE_MEMBERS",
comment: "Title for the 'members' section of the 'group members' view.")
@ -251,9 +288,8 @@ public class NewGroupConfirmViewController: OWSViewController {
return cell
}, actionBlock: nil))
}
let contents = OWSTableContents()
contents.addSection(section)
recipientTableView.contents = contents
}
@ -284,6 +320,7 @@ public class NewGroupConfirmViewController: OWSViewController {
let memberSet = Set([localAddress] + recipientSet.orderedMembers.compactMap { $0.address })
let members = Array(memberSet)
let newGroupSeed = groupSeed
let disappearingMessageToken = disappearingMessagesConfiguration.asToken
// GroupsV2 TODO: Should we allow cancel here?
ModalActivityIndicatorViewController.present(fromViewController: self,
@ -293,6 +330,7 @@ public class NewGroupConfirmViewController: OWSViewController {
groupId: nil,
name: groupName,
avatarData: avatarData,
disappearingMessageToken: disappearingMessageToken,
newGroupSeed: newGroupSeed,
shouldSendMessage: true)
}.done { groupThread in

View File

@ -40,6 +40,7 @@ class GroupAttributesEditorHelper: NSObject {
private let iconViewSize: UInt
private let cameraButton = GroupAttributesEditorHelper.buildCameraButtonForCenter()
private let cameraCornerButton = GroupAttributesEditorHelper.buildCameraButtonForCorner()
let nameTextField = UITextField()
@ -101,6 +102,10 @@ class GroupAttributesEditorHelper: NSObject {
avatarWrapper.addSubview(cameraButton)
cameraButton.autoCenterInSuperview()
avatarWrapper.addSubview(cameraCornerButton)
cameraCornerButton.autoPinEdge(toSuperviewEdge: .trailing)
cameraCornerButton.autoPinEdge(toSuperviewEdge: .bottom)
nameTextField.text = groupNameOriginal
nameTextField.font = .ows_dynamicTypeBody
nameTextField.backgroundColor = .clear
@ -143,7 +148,7 @@ class GroupAttributesEditorHelper: NSObject {
public static func buildCameraButtonForCenter() -> UIView {
let cameraImageView = UIImageView()
cameraImageView.setTemplateImageName("camera-outline-24", tintColor: Theme.accentBlueColor)
cameraImageView.setTemplateImageName("camera-outline-24", tintColor: Theme.primaryIconColor)
let iconSize: CGFloat = 32
cameraImageView.autoSetDimensions(to: CGSize(square: iconSize))
return cameraImageView
@ -152,12 +157,16 @@ class GroupAttributesEditorHelper: NSObject {
private func updateAvatarView(groupAvatar: GroupAvatar?) {
if let groupAvatar = groupAvatar {
avatarImageView.image = groupAvatar.image
avatarImageView.backgroundColor = nil
avatarImageView.layer.borderWidth = 0
avatarImageView.layer.borderColor = nil
cameraButton.isHidden = true
cameraCornerButton.isHidden = false
} else {
avatarImageView.image = nil
avatarImageView.backgroundColor = Theme.washColor
avatarImageView.layer.borderWidth = 2
avatarImageView.layer.borderColor = Theme.outlineColor.cgColor
cameraButton.isHidden = false
cameraCornerButton.isHidden = true
}
}

View File

@ -71,11 +71,6 @@ class GroupAttributesViewController: OWSTableViewController2 {
helper.delegate = self
helper.buildContents(avatarViewHelperDelegate: self)
let cameraButton = GroupAttributesEditorHelper.buildCameraButtonForCorner()
helper.avatarWrapper.addSubview(cameraButton)
cameraButton.autoPinEdge(toSuperviewEdge: .trailing)
cameraButton.autoPinEdge(toSuperviewEdge: .bottom)
updateTableContents()
}

View File

@ -4708,6 +4708,9 @@
/* The title for the data settings. */
"SETTINGS_DATA_TITLE" = "Data Usage";
/* table cell label in conversation settings */
"SETTINGS_DEFAULT_DISAPPEARING_MESSAGES" = "Default Timer for New Chats";
/* No comment provided by engineer. */
"SETTINGS_DELETE_ACCOUNT_BUTTON" = "Delete Account";
@ -4732,6 +4735,12 @@
/* Confirmation text for button which deletes all message, calling, attachments, etc. */
"SETTINGS_DELETE_HISTORYLOG_CONFIRMATION_BUTTON" = "Delete Everything";
/* Label for the 'disappearig messages' privacy settings. */
"SETTINGS_DISAPPEARING_MESSAGES" = "Disappearing Messages";
/* Explanation for the 'disappearig messages' privacy settings. */
"SETTINGS_DISAPPEARING_MESSAGES_FOOTER" = "Set a default disappearing message timer for all new chats started by you.";
/* Title for the 'donate to signal' link in settings. */
"SETTINGS_DONATE" = "Donate to Signal";
@ -5539,6 +5548,9 @@
/* Label for button to verify a user's safety number. */
"SYSTEM_MESSAGE_ACTION_VERIFY_SAFETY_NUMBER" = "Verify";
/* Indicator that the default disappearing message timer will be applied when you send a message. Embeds {default disappearing message time} */
"SYSTEM_MESSAGE_DEFAULT_DISAPPEARING_MESSAGE_TIMER_FORMAT" = "The disappearing message time will be set to %@ when you message them.";
/* Indicator warning about an unknown contact thread. */
"SYSTEM_MESSAGE_UNKNOWN_THREAD_WARNING_CONTACT" = "No groups in common. Review requests carefully.";

View File

@ -40,7 +40,7 @@ public class AttachmentMultisend: Dependencies {
}
// If this thread has a pending message request, treat it as accepted.
ThreadUtil.addThread(toProfileWhitelistIfEmptyOrPendingRequest: thread, transaction: transaction)
ThreadUtil.addThread(toProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer: thread, transaction: transaction)
let message = try! ThreadUtil.createUnsentMessage(with: approvalMessageBody,
mediaAttachments: attachments,
@ -113,7 +113,7 @@ public class AttachmentMultisend: Dependencies {
}
// If this thread has a pending message request, treat it as accepted.
ThreadUtil.addThread(toProfileWhitelistIfEmptyOrPendingRequest: thread, transaction: transaction)
ThreadUtil.addThread(toProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer: thread, transaction: transaction)
let message = try! ThreadUtil.createUnsentMessage(with: approvalMessageBody,
mediaAttachments: attachments,

View File

@ -84,9 +84,10 @@ NS_ASSUME_NONNULL_BEGIN
// the local user took an action like initiating a call or updating the DM timer.
//
// Returns YES IFF the thread was just added to the profile whitelist.
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:(TSThread *)thread NS_SWIFT_NAME(addToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction(thread:));
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequest:(TSThread *)thread
transaction:(SDSAnyWriteTransaction *)transaction;
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:(TSThread *)thread
NS_SWIFT_NAME(addToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction(thread:));
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer:(TSThread *)thread
transaction:(SDSAnyWriteTransaction *)transaction;
#pragma mark - Delete Content

View File

@ -271,15 +271,39 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Profile Whitelist
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestWithSneakyTransaction:(TSThread *)thread
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimerWithSneakyTransaction:(TSThread *)thread
{
OWSAssertDebug(thread);
__block BOOL hasPendingMessageRequest;
__block BOOL needsDefaultTimerSet;
__block DisappearingMessageToken *defaultTimerToken;
[self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) {
hasPendingMessageRequest = [thread hasPendingMessageRequestWithTransaction:transaction.unwrapGrdbRead];
OWSDisappearingMessagesConfiguration *configuration =
[thread disappearingMessagesConfigurationWithTransaction:transaction];
needsDefaultTimerSet = thread.lastInteractionRowId == 0
&& ![OWSDisappearingMessagesConfiguration anyExistsWithUniqueId:configuration.uniqueId
transaction:transaction];
defaultTimerToken = configuration.asToken;
}];
if (needsDefaultTimerSet) {
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration applyToken:defaultTimerToken
toThread:thread
transaction:transaction];
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithThread:thread
configuration:configuration
createdByRemoteName:nil
createdInExistingGroup:NO];
[infoMessage anyInsertWithTransaction:transaction];
});
}
// If we're creating this thread or we have a pending message request,
// any action we trigger should share our profile.
if (!thread.shouldThreadBeVisible || hasPendingMessageRequest) {
@ -290,11 +314,30 @@ NS_ASSUME_NONNULL_BEGIN
return NO;
}
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequest:(TSThread *)thread
transaction:(SDSAnyWriteTransaction *)transaction
+ (BOOL)addThreadToProfileWhitelistIfEmptyOrPendingRequestAndSetDefaultTimer:(TSThread *)thread
transaction:(SDSAnyWriteTransaction *)transaction
{
OWSAssertDebug(thread);
OWSDisappearingMessagesConfiguration *defaultConfiguration =
[thread disappearingMessagesConfigurationWithTransaction:transaction];
BOOL needsDefaultTimerSet = thread.lastInteractionRowId == 0
&& ![OWSDisappearingMessagesConfiguration anyExistsWithUniqueId:defaultConfiguration.uniqueId
transaction:transaction];
DisappearingMessageToken *defaultTimerToken = defaultConfiguration.asToken;
if (needsDefaultTimerSet) {
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration applyToken:defaultTimerToken toThread:thread transaction:transaction];
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithThread:thread
configuration:configuration
createdByRemoteName:nil
createdInExistingGroup:NO];
[infoMessage anyInsertWithTransaction:transaction];
}
BOOL hasPendingMessageRequest = [thread hasPendingMessageRequestWithTransaction:transaction.unwrapGrdbRead];
// If we're creating this thread or we have a pending message request,
// any action we trigger should share our profile.

View File

@ -1,12 +1,12 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/BaseModel.h>
NS_ASSUME_NONNULL_BEGIN
#define OWSDisappearingMessagesConfigurationDefaultExpirationDuration kDayInterval
#define OWSDisappearingMessagesConfigurationDefaultExpirationDuration 0
@class SDSAnyReadTransaction;
@class TSThread;
@ -49,6 +49,8 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:durationSeconds:ena
// for a given thread; do not use anyFetchWithUniqueId.
+ (instancetype)fetchOrBuildDefaultWithThread:(TSThread *)thread transaction:(SDSAnyReadTransaction *)transaction;
+ (instancetype)fetchOrBuildDefaultUniversalConfigurationWithTransaction:(SDSAnyReadTransaction *)transaction;
+ (NSArray<NSNumber *> *)validDurationsSeconds;
+ (uint32_t)maxDurationSeconds;

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import "OWSDisappearingMessagesConfiguration.h"
@ -9,6 +9,8 @@
NS_ASSUME_NONNULL_BEGIN
static NSString *const kUniversalTimerThreadId = @"kUniversalTimerThreadId";
@interface OWSDisappearingMessagesConfiguration ()
@property (nonatomic, getter=isEnabled) BOOL enabled;
@ -96,10 +98,15 @@ NS_ASSUME_NONNULL_BEGIN
}
return [[self alloc] initWithThreadId:threadId
enabled:NO
enabled:OWSDisappearingMessagesConfigurationDefaultExpirationDuration > 0
durationSeconds:OWSDisappearingMessagesConfigurationDefaultExpirationDuration];
}
+ (instancetype)fetchOrBuildDefaultUniversalConfigurationWithTransaction:(SDSAnyReadTransaction *)transaction
{
return [self fetchOrBuildDefaultWithThreadId:kUniversalTimerThreadId transaction:transaction];
}
+ (NSArray<NSNumber *> *)validDurationsSeconds
{
return @[
@ -113,7 +120,8 @@ NS_ASSUME_NONNULL_BEGIN
@(6 * kHourInterval),
@(12 * kHourInterval),
@(24 * kHourInterval),
@(1 * kWeekInterval)
@(1 * kWeekInterval),
@(4 * kWeekInterval)
];
}

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -66,10 +66,12 @@ public class DisappearingMessageToken: MTLModel {
// MARK: -
public extension OWSDisappearingMessagesConfiguration {
@objc
var asToken: DisappearingMessageToken {
return DisappearingMessageToken(isEnabled: isEnabled, durationSeconds: durationSeconds)
}
@objc
static func applyToken(_ token: DisappearingMessageToken,
toThread thread: TSThread,
transaction: SDSAnyWriteTransaction) -> OWSDisappearingMessagesConfiguration {
@ -78,6 +80,7 @@ public extension OWSDisappearingMessagesConfiguration {
return oldConfiguration.applyToken(token, transaction: transaction)
}
@objc
func applyToken(_ token: DisappearingMessageToken,
transaction: SDSAnyWriteTransaction) -> OWSDisappearingMessagesConfiguration {
let newConfiguration: OWSDisappearingMessagesConfiguration

View File

@ -1469,8 +1469,18 @@ extension GroupUpdateCopy {
guard let oldToken = oldToken else {
if newToken.isEnabled {
let format = NSLocalizedString("DISAPPEARING_MESSAGES_CONFIGURATION_GROUP_EXISTING_FORMAT",
comment: "Info Message when added to a group which has enabled disappearing messages. Embeds {{time amount}} before messages disappear. See the *_TIME_AMOUNT strings for context.")
let format: String
if updater == .localUser {
format = NSLocalizedString(
"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION",
comment: "Info Message when you update disappearing messages duration. Embeds a {{time amount}} before messages disappear. see the *_TIME_AMOUNT strings for context."
)
} else {
format = NSLocalizedString(
"DISAPPEARING_MESSAGES_CONFIGURATION_GROUP_EXISTING_FORMAT",
comment: "Info Message when added to a group which has enabled disappearing messages. Embeds {{time amount}} before messages disappear. See the *_TIME_AMOUNT strings for context."
)
}
addItem(.disappearingMessagesState_enabled, format: format, durationString)
}
return
@ -1831,7 +1841,7 @@ extension GroupUpdateCopy {
// MARK: - Updater
enum Updater {
enum Updater: Equatable {
case localUser
case otherUser(updaterName: String, updaterAddress: SignalServiceAddress)
case unknown

View File

@ -20,7 +20,8 @@ typedef NS_CLOSED_ENUM(NSInteger, OWSInteractionType) {
OWSInteractionType_ThreadDetails,
OWSInteractionType_UnreadIndicator,
OWSInteractionType_DateHeader,
OWSInteractionType_UnknownThreadWarning
OWSInteractionType_UnknownThreadWarning,
OWSInteractionType_DefaultDisappearingMessageTimer
};
NSString *NSStringFromOWSInteractionType(OWSInteractionType value);

View File

@ -34,6 +34,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
return @"OWSInteractionType_DateHeader";
case OWSInteractionType_UnknownThreadWarning:
return @"OWSInteractionType_UnknownThreadWarning";
case OWSInteractionType_DefaultDisappearingMessageTimer:
return @"OWSInteractionType_DefaultDisappearingMessageTimer";
}
}

View File

@ -225,6 +225,7 @@ public class GroupManager: NSObject {
groupId: Data? = nil,
name: String? = nil,
avatarImage: UIImage?,
disappearingMessageToken: DisappearingMessageToken,
newGroupSeed: NewGroupSeed? = nil,
shouldSendMessage: Bool) -> Promise<TSGroupThread> {
@ -235,6 +236,7 @@ public class GroupManager: NSObject {
groupId: groupId,
name: name,
avatarData: avatarData,
disappearingMessageToken: disappearingMessageToken,
newGroupSeed: newGroupSeed,
shouldSendMessage: shouldSendMessage)
}
@ -245,6 +247,7 @@ public class GroupManager: NSObject {
groupId: Data? = nil,
name: String? = nil,
avatarData: Data? = nil,
disappearingMessageToken: DisappearingMessageToken,
newGroupSeed: NewGroupSeed? = nil,
shouldSendMessage: Bool) -> Promise<TSGroupThread> {
@ -252,9 +255,6 @@ public class GroupManager: NSObject {
return Promise(error: OWSAssertionError("Missing localAddress."))
}
// By default, DMs are disable for new groups.
let disappearingMessageToken = DisappearingMessageToken.disabledToken
return firstly { () -> Promise<Void> in
return self.ensureLocalProfileHasCommitmentIfNecessary()
}.then(on: .global()) { () -> Promise<Void> in
@ -496,6 +496,7 @@ public class GroupManager: NSObject {
groupId: Data?,
name: String,
avatarImage: UIImage?,
disappearingMessageToken: DisappearingMessageToken,
newGroupSeed: NewGroupSeed?,
shouldSendMessage: Bool,
success: @escaping (TSGroupThread) -> Void,
@ -505,6 +506,7 @@ public class GroupManager: NSObject {
groupId: groupId,
name: name,
avatarImage: avatarImage,
disappearingMessageToken: disappearingMessageToken,
newGroupSeed: newGroupSeed,
shouldSendMessage: shouldSendMessage)
}.done { thread in
@ -520,6 +522,7 @@ public class GroupManager: NSObject {
groupId: Data?,
name: String,
avatarData: Data?,
disappearingMessageToken: DisappearingMessageToken,
newGroupSeed: NewGroupSeed?,
shouldSendMessage: Bool,
success: @escaping (TSGroupThread) -> Void,
@ -529,6 +532,7 @@ public class GroupManager: NSObject {
groupId: groupId,
name: name,
avatarData: avatarData,
disappearingMessageToken: disappearingMessageToken,
newGroupSeed: newGroupSeed,
shouldSendMessage: shouldSendMessage)
}.done { thread in