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

import SignalServiceKit
public import SignalUI

public class CVContactShareView: ManualStackView {

    struct State: Equatable {
        let contactShare: ContactShareViewModel
        let isIncoming: Bool
        let conversationStyle: ConversationStyle
        let avatar: UIImage?
    }

    private let labelStack = ManualStackView(name: "CVContactShareView.labelStack")
    private let avatarView: AvatarImageView = AvatarImageView(shouldDeactivateConstraints: true)

    private let contactNameLabel = CVLabel()
    private let disclosureImageView = CVImageView()

    static func buildState(
        contactShare: ContactShareViewModel,
        isIncoming: Bool,
        conversationStyle: ConversationStyle,
        transaction: DBReadTransaction,
    ) -> State {
        let avatar = contactShare.getAvatarImage(
            diameter: avatarSize,
            transaction: transaction,
        )
        owsAssertDebug(avatar != nil)
        return State(
            contactShare: contactShare,
            isIncoming: isIncoming,
            conversationStyle: conversationStyle,
            avatar: avatar,
        )
    }

    private static var avatarSize: CGFloat { CGFloat(AvatarBuilder.standardAvatarSizePoints) }
    private static let disclosureIconSize = CGSize.square(20)

    func configureForRendering(state: State, cellMeasurement: CVCellMeasurement) {
        let labelConfig = Self.contactNameLabelConfig(state: state)
        labelConfig.applyForRendering(label: contactNameLabel)

        avatarView.image = state.avatar

        let disclosureColor: UIColor = state.isIncoming ? .Signal.tertiaryLabel : .Signal.ColorBase.labelTertiary
        disclosureImageView.setTemplateImage(
            UIImage(imageLiteralResourceName: "chevron-right-20"),
            tintColor: disclosureColor,
        )

        configure(
            config: Self.outerStackConfig,
            cellMeasurement: cellMeasurement,
            measurementKey: Self.measurementKey_outerStack,
            subviews: [
                avatarView,
                contactNameLabel,
                disclosureImageView,
            ],
        )
    }

    private static var outerStackConfig: CVStackViewConfig {
        CVStackViewConfig(
            axis: .horizontal,
            alignment: .center,
            spacing: 12,
            layoutMargins: UIEdgeInsets(hMargin: 0, vMargin: 4),
        )
    }

    private static func contactNameLabelConfig(state: State) -> CVLabelConfig {
        let textColor: UIColor = state.isIncoming ? .Signal.label : .Signal.ColorBase.labelPrimary
        return CVLabelConfig.unstyledText(
            state.contactShare.displayName,
            font: .dynamicTypeHeadline,
            textColor: textColor,
            lineBreakMode: .byTruncatingTail,
        )
    }

    private static let measurementKey_outerStack = "CVContactShareView.measurementKey_outerStack"

    static func measure(
        maxWidth: CGFloat,
        measurementBuilder: CVCellMeasurement.Builder,
        state: State,
    ) -> CGSize {
        owsAssertDebug(maxWidth > 0)

        var maxContentWidth = (
            maxWidth -
                (
                    avatarSize +
                        disclosureIconSize.width +
                        outerStackConfig.spacing * 2
                ),
        )
        maxContentWidth = max(0, maxContentWidth)

        let labelConfig = contactNameLabelConfig(state: state)
        let labelSize = CVText.measureLabel(config: labelConfig, maxWidth: maxContentWidth)

        var outerSubviewInfos = [ManualStackSubviewInfo]()

        let avatarSize = CGSize(square: avatarSize)
        outerSubviewInfos.append(avatarSize.asManualSubviewInfo(hasFixedSize: true))

        outerSubviewInfos.append(labelSize.asManualSubviewInfo)

        outerSubviewInfos.append(disclosureIconSize.asManualSubviewInfo(hasFixedSize: true))

        let outerStackMeasurement = ManualStackView.measure(
            config: outerStackConfig,
            measurementBuilder: measurementBuilder,
            measurementKey: measurementKey_outerStack,
            subviewInfos: outerSubviewInfos,
            maxWidth: maxWidth,
        )
        return outerStackMeasurement.measuredSize
    }

    override public func reset() {
        super.reset()

        labelStack.reset()
        avatarView.image = nil
        contactNameLabel.text = nil
        disclosureImageView.image = nil
    }
}