Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/ConversationView/Components/CVComponentDelegate.swift
1 views
//
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

public import Foundation
public import LibSignalClient
public import SignalServiceKit
public import SignalUI

public enum CVAttachmentTapAction: Int {
    case handledByDelegate
    case `default`
}

public protocol AudioMessageViewDelegate: AnyObject {
    func enqueueReloadWithoutCaches()

    typealias EndCellAnimation = () -> Void
    func beginCellAnimation(maximumDuration: TimeInterval) -> EndCellAnimation
}

public protocol CVComponentDelegate: AnyObject, AudioMessageViewDelegate, CVPollVoteDelegate {

    func enqueueReload()

    // MARK: - Body Text Items

    func didTapBodyTextItem(_ item: CVTextLabel.Item)

    func didLongPressBodyTextItem(_ item: CVTextLabel.Item)

    // MARK: - System Message Items

    func didTapSystemMessageItem(_ item: CVTextLabel.Item)

    // MARK: - Collapse Sets

    func didTapCollapseSet(collapseSetId: String)

    // MARK: - Double-Tap

    func didDoubleTapTextViewItem(_ itemViewModel: CVItemViewModelImpl)

    // MARK: - Long Press

    func didLongPressTextViewItem(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didLongPressMediaViewItem(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didLongPressQuote(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didLongPressSystemMessage(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
    )

    func didLongPressSticker(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didLongPressPaymentMessage(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didLongPressPoll(
        _ cell: CVCell,
        itemViewModel: CVItemViewModelImpl,
        shouldAllowReply: Bool,
    )

    func didChangeLongPress(_ itemViewModel: CVItemViewModelImpl)

    func didEndLongPress(_ itemViewModel: CVItemViewModelImpl)

    func didCancelLongPress(_ itemViewModel: CVItemViewModelImpl)

    // MARK: -

    func willBecomeVisibleWithSkippedDownloads(_ message: TSMessage)

    func didTapSkippedDownloads(_ message: TSMessage)

    func didCancelDownload(_ message: TSMessage, attachmentId: Attachment.IDType)

    // MARK: -

    func didTapReplyToItem(_ itemViewModel: CVItemViewModelImpl)

    func didTapSenderAvatar(_ interaction: TSInteraction)

    func shouldAllowReplyForItem(_ itemViewModel: CVItemViewModelImpl) -> Bool

    func didTapReactions(
        reactionState: InteractionReactionState,
        message: TSMessage,
    )

    var hasPendingMessageRequest: Bool { get }

    func didTapTruncatedTextMessage(_ itemViewModel: CVItemViewModelImpl)

    // MARK: -

    func didTapUndownloadableMedia()

    func didTapUndownloadableGenericFile()

    func didTapUndownloadableOversizeText()

    func didTapUndownloadableAudio()

    func didTapUndownloadableSticker()

    func didTapBrokenVideo()

    // MARK: - Messages

    func didTapBodyMedia(
        itemViewModel: CVItemViewModelImpl,
        attachmentStream: ReferencedAttachmentStream,
        imageView: UIView,
    )

    func didTapGenericAttachment(_ attachment: CVComponentGenericAttachment) -> CVAttachmentTapAction

    func didTapQuotedReply(_ quotedReply: QuotedReplyModel)

    func didTapLinkPreview(url: URL)

    func didTapContactShare(_ contactShare: ContactShareViewModel)

    func didTapSendMessage(to phoneNumbers: [String])

    func didTapSendInvite(toContactShare contactShare: ContactShareViewModel)

    func didTapAddToContacts(contactShare: ContactShareViewModel)

    func didTapStickerPack(_ stickerPackInfo: StickerPackInfo)

    func didTapPayment(_ payment: PaymentsHistoryItem)

    func didTapGroupInviteLink(url: URL)

    func didTapProxyLink(url: URL)

    func didTapShowMessageDetail(_ itemViewModel: CVItemViewModelImpl)

    func didTapShowEditHistory(_ itemViewModel: CVItemViewModelImpl)

    func prepareMessageDetailForInteractivePresentation(_ itemViewModel: CVItemViewModelImpl)

    var view: UIView! { get }

    var wallpaperBlurProvider: WallpaperBlurProvider? { get }

    var spoilerState: SpoilerRenderState { get }

    // MARK: - Gift Badges

    /// Invoked just before a gift is wrapped.
    ///
    /// This allows the view controller to indicate that a particular gift
    /// shouldn't be wrapped (or that *no* gifts should be wrapped, by always
    /// returning false).
    ///
    /// This may not be invoked if the gift has already been redeemed.
    ///
    /// - Parameter messageUniqueId: The gift's TSMessage's uniqueId.
    /// - Returns: Whether or not the gift should be wrapped.
    func willWrapGift(_ messageUniqueId: String) -> Bool

    /// Invoked just before a gift is shaken.
    ///
    /// This allows the view controller to indicate that a particular gift
    /// shouldn't be shaken (or that it shouldn’t be shaken again).
    ///
    /// - Parameter messageUniqueId: The gift's TSMessage's uniqueId.
    /// - Returns: Whether or not the gift should be shaken.
    func willShakeGift(_ messageUniqueId: String) -> Bool

    /// Invoked just before a gift is unwrapped.
    func willUnwrapGift(_ itemViewModel: CVItemViewModelImpl)

    /// Invoked when the button on a gift is tapped.
    func didTapGiftBadge(_ itemViewModel: CVItemViewModelImpl, profileBadge: ProfileBadge, isExpired: Bool, isRedeemed: Bool)

    // MARK: - Selection

    var selectionState: CVSelectionState { get }

    // MARK: - System Cell

    func didTapPreviouslyVerifiedIdentityChange(_ address: SignalServiceAddress)

    func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress)

    func didTapCorruptedMessage(_ message: TSErrorMessage)

    func didTapSessionRefreshMessage(_ message: TSErrorMessage)

    // See: resendGroupUpdate
    func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage)

    func didTapShowFingerprint(_ address: SignalServiceAddress)

    func didTapIndividualCall(_ call: TSCall)

    func didTapLearnMoreMissedCallFromBlockedContact(_ call: TSCall)

    func didTapGroupCall()

    func didTapPendingOutgoingMessage(_ message: TSOutgoingMessage)

    func didTapFailedMessage(_ message: TSMessage)

    func didTapGroupMigrationLearnMore()

    func didTapGroupInviteLinkPromotion(groupModel: TSGroupModel)

    func didTapViewGroupDescription(newGroupDescription: String)

    func didTapNameEducation(type: SafetyTipsType)

    func didTapShowConversationSettings()

    func didTapShowConversationSettingsAndShowMemberRequests()

    func didTapBlockRequest(groupModel: TSGroupModelV2, requesterName: String, requesterAci: Aci)

    func didTapShowUpgradeAppUI()

    func didTapUpdateSystemContact(
        _ address: SignalServiceAddress,
        newNameComponents: PersonNameComponents,
    )
    func didTapPhoneNumberChange(aci: Aci, phoneNumberOld: String, phoneNumberNew: String)

    func didTapViewOnceAttachment(_ interaction: TSInteraction)

    func didTapViewOnceExpired(_ interaction: TSInteraction)

    func didTapContactName(thread: TSContactThread)

    func didTapUnknownThreadWarningGroup()
    func didTapUnknownThreadWarningContact()
    func didTapDeliveryIssueWarning(_ message: TSErrorMessage)

    func didTapActivatePayments()
    func didTapSendPayment()

    func didTapThreadMergeLearnMore(phoneNumber: String)

    func didTapReportSpamLearnMore()

    func didTapMessageRequestAcceptedOptions()

    func didTapJoinCallLinkCall(callLink: CallLink)

    // MARK: - Polls

    func didTapViewVotes(poll: OWSPoll)
    func didTapViewPoll(pollInteractionUniqueId: String)

    func didTapViewPinnedMessage(pinnedMessageUniqueId: String)

    func didTapSafetyTips()
}

// MARK: -

struct CVMessageAction: Equatable {
    let title: String
    let accessibilityIdentifier: String
    let action: Action

    func perform(delegate: CVComponentDelegate) {
        action.perform(delegate: delegate)
    }

    enum Action: Equatable {
        case none
        case didTapPreviouslyVerifiedIdentityChange(address: SignalServiceAddress)
        case didTapUnverifiedIdentityChange(address: SignalServiceAddress)
        case didTapCorruptedMessage(errorMessage: TSErrorMessage)
        case didTapSessionRefreshMessage(errorMessage: TSErrorMessage)
        case didTapResendGroupUpdate(errorMessage: TSErrorMessage)
        case didTapGroupMigrationLearnMore
        case didTapViewGroupDescription(newGroupDescription: String)
        case didTapGroupInviteLinkPromotion(groupModel: TSGroupModel)
        case didTapShowConversationSettingsAndShowMemberRequests
        case didTapBlockRequest(groupModel: TSGroupModelV2, requesterName: String, requesterAci: Aci)
        case didTapShowUpgradeAppUI
        case didTapUpdateSystemContact(address: SignalServiceAddress, newNameComponents: PersonNameComponents)
        case didTapPhoneNumberChange(aci: Aci, phoneNumberOld: String, phoneNumberNew: String)
        case didTapIndividualCall(call: TSCall)
        case didTapLearnMoreMissedCallFromBlockedContact(call: TSCall)
        case didTapGroupCall
        case didTapSendMessage(phoneNumbers: [String])
        case didTapSendInvite(contactShare: ContactShareViewModel)
        case didTapAddToContacts(contactShare: ContactShareViewModel)
        case didTapUnknownThreadWarningGroup
        case didTapUnknownThreadWarningContact
        case didTapDeliveryIssueWarning(errorMessage: TSErrorMessage)
        case didTapActivatePayments
        case didTapSendPayment
        case didTapThreadMergeLearnMore(phoneNumber: String)
        case didTapReportSpamLearnMore
        case didTapMessageRequestAcceptedOptions
        case didTapJoinCallLinkCall(callLink: CallLink)
        case didTapViewVotes(poll: OWSPoll)
        case didTapViewPoll(pollInteractionUniqueId: String)
        case didTapViewPinnedMessage(pinnedMessageUniqueId: String)

        func perform(delegate: CVComponentDelegate) {
            switch self {
            case .none:
                break
            case .didTapPreviouslyVerifiedIdentityChange(let address):
                delegate.didTapPreviouslyVerifiedIdentityChange(address)
            case .didTapUnverifiedIdentityChange(let address):
                delegate.didTapUnverifiedIdentityChange(address)
            case .didTapCorruptedMessage(let errorMessage):
                delegate.didTapCorruptedMessage(errorMessage)
            case .didTapSessionRefreshMessage(let errorMessage):
                delegate.didTapSessionRefreshMessage(errorMessage)
            case .didTapResendGroupUpdate(let errorMessage):
                delegate.didTapResendGroupUpdateForErrorMessage(errorMessage)
            case .didTapGroupMigrationLearnMore:
                delegate.didTapGroupMigrationLearnMore()
            case .didTapViewGroupDescription(let newGroupDescription):
                delegate.didTapViewGroupDescription(newGroupDescription: newGroupDescription)
            case .didTapGroupInviteLinkPromotion(let groupModel):
                delegate.didTapGroupInviteLinkPromotion(groupModel: groupModel)
            case .didTapShowConversationSettingsAndShowMemberRequests:
                delegate.didTapShowConversationSettingsAndShowMemberRequests()
            case .didTapBlockRequest(let groupModel, let requesterName, let requesterAci):
                delegate.didTapBlockRequest(groupModel: groupModel, requesterName: requesterName, requesterAci: requesterAci)
            case .didTapShowUpgradeAppUI:
                delegate.didTapShowUpgradeAppUI()
            case .didTapUpdateSystemContact(let address, let newNameComponents):
                delegate.didTapUpdateSystemContact(address, newNameComponents: newNameComponents)
            case .didTapPhoneNumberChange(let aci, let phoneNumberOld, let phoneNumberNew):
                delegate.didTapPhoneNumberChange(aci: aci, phoneNumberOld: phoneNumberOld, phoneNumberNew: phoneNumberNew)
            case .didTapIndividualCall(let call):
                delegate.didTapIndividualCall(call)
            case .didTapLearnMoreMissedCallFromBlockedContact(let call):
                delegate.didTapLearnMoreMissedCallFromBlockedContact(call)
            case .didTapGroupCall:
                delegate.didTapGroupCall()
            case .didTapSendMessage(let phoneNumbers):
                delegate.didTapSendMessage(to: phoneNumbers)
            case .didTapSendInvite(let contactShare):
                delegate.didTapSendInvite(toContactShare: contactShare)
            case .didTapAddToContacts(let contactShare):
                delegate.didTapAddToContacts(contactShare: contactShare)
            case .didTapUnknownThreadWarningGroup:
                delegate.didTapUnknownThreadWarningGroup()
            case .didTapUnknownThreadWarningContact:
                delegate.didTapUnknownThreadWarningContact()
            case .didTapDeliveryIssueWarning(let errorMessage):
                delegate.didTapDeliveryIssueWarning(errorMessage)
            case .didTapActivatePayments:
                delegate.didTapActivatePayments()
            case .didTapSendPayment:
                delegate.didTapSendPayment()
            case .didTapThreadMergeLearnMore(let phoneNumber):
                delegate.didTapThreadMergeLearnMore(phoneNumber: phoneNumber)
            case .didTapReportSpamLearnMore:
                delegate.didTapReportSpamLearnMore()
            case .didTapMessageRequestAcceptedOptions:
                delegate.didTapMessageRequestAcceptedOptions()
            case .didTapJoinCallLinkCall(let callLink):
                delegate.didTapJoinCallLinkCall(callLink: callLink)
            case .didTapViewVotes(let poll):
                delegate.didTapViewVotes(poll: poll)
            case .didTapViewPoll(let pollInteractionUniqueId):
                delegate.didTapViewPoll(pollInteractionUniqueId: pollInteractionUniqueId)
            case .didTapViewPinnedMessage(let pinnedMessageUniqueId):
                delegate.didTapViewPinnedMessage(pinnedMessageUniqueId: pinnedMessageUniqueId)
            }
        }
    }
}