Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/src/ViewControllers/HomeView/Chat List/ChatListBackupProgressView.swift
1 views
//
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import SignalServiceKit
import UIKit

class ChatListBackupProgressView: UIView {

    static func configure(
        label: UILabel,
        font: UIFont = .dynamicTypeSubheadline,
        color: UIColor,
    ) {
        label.translatesAutoresizingMaskIntoConstraints = false
        label.adjustsFontForContentSizeCategory = true
        label.font = .monospacedDigitFont(ofSize: font.pointSize)
        label.textColor = color
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
    }

    // MARK: -

    private lazy var leadingAccessoryImageView = UIImageView()

    private lazy var labelStackView = UIStackView()
    private lazy var titleLabel = UILabel()
    private lazy var progressLabel = UILabel()

    /// A container for the various trailingAccessory views we might display. A
    /// stack view so we can use `isHidden = true` to make subviews take up zero
    /// space.
    private lazy var trailingAccessoryContainerView = UIStackView()

    init() {
        super.init(frame: .zero)

        backgroundColor = .Signal.quaternaryFill
        layer.cornerRadius = if #available(iOS 26, *) { 26 } else { 12 }
        layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 12)

        addSubview(leadingAccessoryImageView)
        leadingAccessoryImageView.translatesAutoresizingMaskIntoConstraints = false

        addSubview(labelStackView)
        labelStackView.translatesAutoresizingMaskIntoConstraints = false
        labelStackView.alignment = .fill
        labelStackView.axis = .vertical
        labelStackView.spacing = 4

        labelStackView.addArrangedSubview(titleLabel)
        Self.configure(label: titleLabel, color: .Signal.label)

        labelStackView.addArrangedSubview(progressLabel)
        Self.configure(label: progressLabel, font: .dynamicTypeFootnote, color: .Signal.secondaryLabel)

        addSubview(trailingAccessoryContainerView)
        trailingAccessoryContainerView.alignment = .trailing
        trailingAccessoryContainerView.translatesAutoresizingMaskIntoConstraints = false

        initializeConstraints()
    }

    required init?(coder: NSCoder) {
        owsFail("Not implemented!")
    }

    // MARK: -

    func initializeTrailingAccessoryViews(_ trailingAccessoryViews: [UIView]) {
        for trailingAccessoryView in trailingAccessoryViews {
            trailingAccessoryContainerView.addArrangedSubview(trailingAccessoryView)
            trailingAccessoryView.translatesAutoresizingMaskIntoConstraints = false
            trailingAccessoryView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        }
    }

    func configure(
        leadingAccessoryImage: UIImage,
        leadingAccessoryImageTintColor: UIColor,
        titleLabelText: String,
        progressLabelText: String?,
        trailingAccessoryView: UIView?,
    ) {
        leadingAccessoryImageView.image = leadingAccessoryImage
        leadingAccessoryImageView.tintColor = leadingAccessoryImageTintColor

        titleLabel.text = titleLabelText
        if let progressLabelText {
            progressLabel.text = progressLabelText
            progressLabel.isHidden = false
        } else {
            progressLabel.isHidden = true
        }

        for view in trailingAccessoryContainerView.arrangedSubviews {
            if view === trailingAccessoryView {
                view.isHidden = false
            } else {
                view.isHidden = true
            }
        }
    }

    // MARK: -

    private func initializeConstraints() {
        labelStackView.setContentHuggingPriority(.defaultLow, for: .horizontal)

        NSLayoutConstraint.activate([
            leadingAccessoryImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
            leadingAccessoryImageView.centerYAnchor.constraint(equalTo: labelStackView.centerYAnchor),
            leadingAccessoryImageView.heightAnchor.constraint(equalToConstant: 24),
            leadingAccessoryImageView.widthAnchor.constraint(equalToConstant: 24),

            labelStackView.leadingAnchor.constraint(equalTo: leadingAccessoryImageView.trailingAnchor, constant: 12),
            labelStackView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
            labelStackView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
            labelStackView.trailingAnchor.constraint(equalTo: trailingAccessoryContainerView.leadingAnchor, constant: -12),

            trailingAccessoryContainerView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
            trailingAccessoryContainerView.centerYAnchor.constraint(equalTo: labelStackView.centerYAnchor),
        ])
    }
}