Path: blob/main/SignalServiceKit/Messages/Interactions/TSInfoMessage.swift
1 views
//
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import LibSignalClient
extension TSInfoMessage {
// MARK: - Convenience initializers
public convenience init(
thread: TSThread,
messageType: TSInfoMessageType,
timestamp: UInt64 = MessageTimestampGenerator.sharedInstance.generateTimestamp(),
expireTimerVersion: UInt32? = nil,
expiresInSeconds: UInt32? = nil,
infoMessageUserInfo: [InfoMessageUserInfoKey: Any]? = nil,
) {
self.init(
thread: thread,
timestamp: timestamp,
serverGuid: nil,
messageType: messageType,
expireTimerVersion: expireTimerVersion as NSNumber?,
expiresInSeconds: expiresInSeconds ?? 0,
infoMessageUserInfo: infoMessageUserInfo,
)
}
@objc
func _infoMessagePreviewText(tx: DBReadTransaction) -> String {
switch messageType {
case .typeLocalUserEndedSession:
fallthrough
case .typeRemoteUserEndedSession:
return OWSLocalizedString("SECURE_SESSION_RESET", comment: "")
case .typeUnsupportedMessage:
return OWSLocalizedString("UNSUPPORTED_ATTACHMENT", comment: "")
case .userNotRegistered:
if let unregisteredAddress, unregisteredAddress.isValid {
let recipientName = SSKEnvironment.shared.contactManagerRef.displayNameString(for: unregisteredAddress, transaction: tx)
return String.nonPluralLocalizedStringWithFormat(
OWSLocalizedString(
"ERROR_UNREGISTERED_USER_FORMAT",
comment: "Format string for 'unregistered user' error. Embeds {{the unregistered user's name or signal id}}.",
),
recipientName,
)
} else {
return OWSLocalizedString("CONTACT_DETAIL_COMM_TYPE_INSECURE", comment: "")
}
case .typeGroupQuit:
return OWSLocalizedString("GROUP_YOU_LEFT", comment: "")
case .typeGroupUpdate:
return self.groupUpdateDescription(tx: tx).string
case .addToContactsOffer:
return OWSLocalizedString("ADD_TO_CONTACTS_OFFER", comment: "Message shown in conversation view that offers to add an unknown user to your phone's contacts.")
case .verificationStateChange:
return OWSLocalizedString("VERIFICATION_STATE_CHANGE_GENERIC", comment: "Generic message indicating that verification state changed for a given user.")
case .addUserToProfileWhitelistOffer:
return OWSLocalizedString("ADD_USER_TO_PROFILE_WHITELIST_OFFER", comment: "Message shown in conversation view that offers to share your profile with a user.")
case .addGroupToProfileWhitelistOffer:
return OWSLocalizedString("ADD_GROUP_TO_PROFILE_WHITELIST_OFFER", comment: "Message shown in conversation view that offers to share your profile with a group.")
case .typeDisappearingMessagesUpdate:
break
case .unknownProtocolVersion:
break
case .userJoinedSignal:
let address = TSContactThread.contactAddress(fromThreadId: self.uniqueThreadId, transaction: tx)
let recipientName = SSKEnvironment.shared.contactManagerRef.displayNameString(for: address!, transaction: tx)
let format = OWSLocalizedString("INFO_MESSAGE_USER_JOINED_SIGNAL_BODY_FORMAT", comment: "Shown in inbox and conversation when a user joins Signal, embeds the new user's {{contact name}}")
return String.nonPluralLocalizedStringWithFormat(format, recipientName)
case .syncedThread:
return ""
case .profileUpdate:
return self.profileChangeDescription(tx: tx)
case .phoneNumberChange:
guard let aci = self.phoneNumberChangeInfoAci() else {
owsFailDebug("Invalid info message")
return ""
}
let address = SignalServiceAddress(aci.wrappedAciValue)
let userName = SSKEnvironment.shared.contactManagerRef.displayNameString(for: address, transaction: tx)
let format = OWSLocalizedString(
"INFO_MESSAGE_USER_CHANGED_PHONE_NUMBER_FORMAT",
comment: "Indicates that another user has changed their phone number. Embeds: {{ the user's name}}",
)
return String.nonPluralLocalizedStringWithFormat(format, userName)
case .recipientHidden:
/// This does not control whether to show the info message in the chat
/// preview. To control that, see ``TSInteraction.shouldAppearInInbox``.
let address = TSContactThread.contactAddress(fromThreadId: self.uniqueThreadId, transaction: tx)
if DependenciesBridge.shared.recipientHidingManager.isHiddenAddress(address!, tx: tx) {
return OWSLocalizedString(
"INFO_MESSAGE_CONTACT_REMOVED",
comment: "Indicates that the recipient has been removed from the current user's contacts and that messaging them will re-add them.",
)
} else {
return OWSLocalizedString(
"INFO_MESSAGE_CONTACT_REINSTATED",
comment: "Indicates that a previously-removed recipient has been added back to the current user's contacts.",
)
}
case .paymentsActivationRequest:
return self.paymentsActivationRequestDescription(tx: tx) ?? ""
case .paymentsActivated:
return self.paymentsActivatedDescription(tx: tx) ?? ""
case .threadMerge:
return self.threadMergeDescription(tx: tx)
case .sessionSwitchover:
return self.sessionSwitchoverDescription(tx: tx)
case .reportedSpam:
return OWSLocalizedString(
"INFO_MESSAGE_REPORTED_SPAM",
comment: "Shown when a user reports a conversation as spam.",
)
case .learnedProfileName:
return self.learnedProfileNameDescription(tx: tx)
case .blockedOtherUser:
return OWSLocalizedString(
"INFO_MESSAGE_BLOCKED_OTHER_USER",
comment: "An info message inserted into a 1:1 chat when you block another user.",
)
case .blockedGroup:
return OWSLocalizedString(
"INFO_MESSAGE_BLOCKED_GROUP",
comment: "An info message inserted into a group chat when you block the group.",
)
case .unblockedOtherUser:
return OWSLocalizedString(
"INFO_MESSAGE_UNBLOCKED_OTHER_USER",
comment: "An info message inserted into a 1:1 chat when you unblock another user.",
)
case .unblockedGroup:
return OWSLocalizedString(
"INFO_MESSAGE_UNBLOCKED_GROUP",
comment: "An info message inserted into a group chat when you unblock the group.",
)
case .acceptedMessageRequest:
let thread = TSThread.fetchViaCache(uniqueId: self.uniqueThreadId, transaction: tx)
if let thread, thread.isGroupThread {
return OWSLocalizedString(
"INFO_MESSAGE_ACCEPTED_MESSAGE_REQUEST_GROUP",
comment: "An info message inserted into the chat when you accept a message request in a group chat.",
)
}
if let address = TSContactThread.contactAddress(fromThreadId: self.uniqueThreadId, transaction: tx) {
let recipientName = SSKEnvironment.shared.contactManagerRef.displayNameString(for: address, transaction: tx)
let format = OWSLocalizedString(
"INFO_MESSAGE_ACCEPTED_MESSAGE_REQUEST_ONE_ON_ONE",
comment: "An info message inserted into the chat when you accept a message request in a 1:1. {{ Embeds name of your chat partner }}.",
)
return String.nonPluralLocalizedStringWithFormat(format, recipientName)
}
owsFailDebug("No contact address for message request that is not in a group thread")
return OWSLocalizedString(
"INFO_MESSAGE_ACCEPTED_MESSAGE_REQUEST",
comment: "An info message inserted into the chat when you accept a message request, in a 1:1 or group chat.",
)
case .typeEndPoll:
return self.endPollDescription(transaction: tx) ?? ""
case .typePinnedMessage:
return self.pinnedMessageDescription(transaction: tx) ?? ""
}
owsFailDebug("Unknown info message type")
return ""
}
// MARK: - InfoMessageUserInfo
func infoMessageValue<T>(forKey key: InfoMessageUserInfoKey) -> T? {
guard let value = infoMessageUserInfo?[key] as? T else {
return nil
}
return value
}
func setInfoMessageValue(_ value: Any, forKey key: InfoMessageUserInfoKey) {
if self.infoMessageUserInfo != nil {
self.infoMessageUserInfo![key] = value
} else {
self.infoMessageUserInfo = [key: value]
}
}
}