<commit_before>import UIKit

final class NotificationsCenterView: SetupView {

    // MARK: - Nested Types

    enum EmptyOverlayStrings {
        static let noUnreadMessages = WMFLocalizedString("notifications-center-empty-no-unread-messages", value: "You have no unread messages", comment: "Text displayed when no Notifications Center notifications are available.")
        static let notSubscribed = WMFLocalizedString("notifications-center-empty-not-subscribed", value: "You are not currently subscribed to any Wikipedia Notifications", comment: "Text displayed when user has not subscribed to any Wikipedia notifications.")
        static let checkingForNotifications = WMFLocalizedString("notifications-center-empty-checking-for-notifications", value: "Checking for notifications...", comment: "Text displayed when Notifications Center is checking for notifications.")
    }

    // MARK: - Properties

	lazy var collectionView: UICollectionView = {
		let collectionView = UICollectionView(frame: .zero, collectionViewLayout: tableStyleLayout)
		collectionView.register(NotificationsCenterCell.self, forCellWithReuseIdentifier: NotificationsCenterCell.reuseIdentifier)
		collectionView.alwaysBounceVertical = true
		collectionView.translatesAutoresizingMaskIntoConstraints = false
		// collectionView.allowsMultipleSelection = true
		return collectionView
	}()

	private lazy var tableStyleLayout: UICollectionViewLayout = {
        let estimatedHeightDimension = NSCollectionLayoutDimension.estimated(130)
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),heightDimension: estimatedHeightDimension)
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),heightDimension: estimatedHeightDimension)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
	}()

    private lazy var emptyScrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.isUserInteractionEnabled = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.isHidden = true
        return scrollView
    }()

    private lazy var emptyOverlayStack: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.alignment = .center
        stackView.spacing = 15
        return stackView
    }()

    private lazy var emptyStateImageView: UIImageView = {
        let image = UIImage(named: "notifications-center-empty")
        let imageView = UIImageView(image: image)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    private lazy var emptyOverlayHeaderLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.wmf_font(.mediumBody, compatibleWithTraitCollection: traitCollection)
        label.adjustsFontForContentSizeCategory = true
        label.textAlignment = .center
        label.numberOfLines = 0
        return label
    }()

    private lazy var emptyOverlaySubheaderLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.wmf_font(.subheadline, compatibleWithTraitCollection: traitCollection)
        label.adjustsFontForContentSizeCategory = true
        label.textAlignment = .center
        label.numberOfLines = 0
        return label
    }()

    // MARK: - Lifecycle

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory {
            emptyOverlayHeaderLabel.font = UIFont.wmf_font(.mediumBody, compatibleWithTraitCollection: traitCollection)
            emptyOverlaySubheaderLabel.font = UIFont.wmf_font(.subheadline, compatibleWithTraitCollection: traitCollection)
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // If the stack view content is approaching or greater than the visible view's height, allow scrolling to read all content
        emptyScrollView.alwaysBounceVertical = emptyOverlayStack.bounds.height > emptyScrollView.bounds.height - 100
    }

    // MARK: - Setup

    override func setup() {
        backgroundColor = .white
        wmf_addSubviewWithConstraintsToEdges(collectionView)
        wmf_addSubviewWithConstraintsToEdges(emptyScrollView)

        emptyOverlayStack.addArrangedSubview(emptyStateImageView)
        emptyOverlayStack.addArrangedSubview(emptyOverlayHeaderLabel)
        emptyOverlayStack.addArrangedSubview(emptyOverlaySubheaderLabel)

        emptyScrollView.addSubview(emptyOverlayStack)

        NSLayoutConstraint.activate([
            emptyScrollView.contentLayoutGuide.widthAnchor.constraint(equalTo: emptyScrollView.frameLayoutGuide.widthAnchor),
            emptyScrollView.contentLayoutGuide.heightAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.frameLayoutGuide.heightAnchor),

            emptyOverlayStack.centerXAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.centerXAnchor),
            emptyOverlayStack.centerYAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.centerYAnchor),

            emptyOverlayStack.topAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.contentLayoutGuide.topAnchor, constant: 100),
            emptyOverlayStack.leadingAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.contentLayoutGuide.leadingAnchor, constant: 50),
            emptyOverlayStack.trailingAnchor.constraint(lessThanOrEqualTo: emptyScrollView.contentLayoutGuide.trailingAnchor, constant: -50),
            emptyOverlayStack.bottomAnchor.constraint(lessThanOrEqualTo: emptyScrollView.contentLayoutGuide.bottomAnchor, constant: -100),

            emptyStateImageView.heightAnchor.constraint(equalToConstant: 185),
            emptyStateImageView.widthAnchor.constraint(equalToConstant: 185),

            emptyOverlayHeaderLabel.widthAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.widthAnchor, multiplier: 3/4),
            emptyOverlaySubheaderLabel.widthAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.widthAnchor, multiplier: 4/5)
        ])
    }

    // MARK: - Public

    func updateEmptyOverlay(visible: Bool, headerText: String = "", subheaderText: String = "") {
        emptyScrollView.isHidden = !visible
        emptyScrollView.isUserInteractionEnabled = visible
        emptyOverlayHeaderLabel.text = headerText
        emptyOverlaySubheaderLabel.text = subheaderText
    }

}

extension NotificationsCenterView: Themeable {

    func apply(theme: Theme) {
        backgroundColor = theme.colors.paperBackground
        collectionView.backgroundColor = theme.colors.paperBackground
        emptyOverlayHeaderLabel.textColor = theme.colors.primaryText
        emptyOverlaySubheaderLabel.textColor = theme.colors.primaryText
    }

}<commit_msg>Constrain empty state label width to containing stack.<commit_after>import UIKit

final class NotificationsCenterView: SetupView {

    // MARK: - Nested Types

    enum EmptyOverlayStrings {
        static let noUnreadMessages = WMFLocalizedString("notifications-center-empty-no-unread-messages", value: "You have no unread messages", comment: "Text displayed when no Notifications Center notifications are available.")
        static let notSubscribed = WMFLocalizedString("notifications-center-empty-not-subscribed", value: "You are not currently subscribed to any Wikipedia Notifications", comment: "Text displayed when user has not subscribed to any Wikipedia notifications.")
        static let checkingForNotifications = WMFLocalizedString("notifications-center-empty-checking-for-notifications", value: "Checking for notifications...", comment: "Text displayed when Notifications Center is checking for notifications.")
    }

    // MARK: - Properties

	lazy var collectionView: UICollectionView = {
		let collectionView = UICollectionView(frame: .zero, collectionViewLayout: tableStyleLayout)
		collectionView.register(NotificationsCenterCell.self, forCellWithReuseIdentifier: NotificationsCenterCell.reuseIdentifier)
		collectionView.alwaysBounceVertical = true
		collectionView.translatesAutoresizingMaskIntoConstraints = false
		// collectionView.allowsMultipleSelection = true
		return collectionView
	}()

	private lazy var tableStyleLayout: UICollectionViewLayout = {
        let estimatedHeightDimension = NSCollectionLayoutDimension.estimated(130)
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),heightDimension: estimatedHeightDimension)
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),heightDimension: estimatedHeightDimension)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
	}()

    private lazy var emptyScrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.isUserInteractionEnabled = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.isHidden = true
        return scrollView
    }()

    private lazy var emptyOverlayStack: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.alignment = .center
        stackView.spacing = 15
        return stackView
    }()

    private lazy var emptyStateImageView: UIImageView = {
        let image = UIImage(named: "notifications-center-empty")
        let imageView = UIImageView(image: image)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    private lazy var emptyOverlayHeaderLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.wmf_font(.mediumBody, compatibleWithTraitCollection: traitCollection)
        label.adjustsFontForContentSizeCategory = true
        label.textAlignment = .center
        label.numberOfLines = 0
        return label
    }()

    private lazy var emptyOverlaySubheaderLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.wmf_font(.subheadline, compatibleWithTraitCollection: traitCollection)
        label.adjustsFontForContentSizeCategory = true
        label.textAlignment = .center
        label.numberOfLines = 0
        return label
    }()

    // MARK: - Lifecycle

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory {
            emptyOverlayHeaderLabel.font = UIFont.wmf_font(.mediumBody, compatibleWithTraitCollection: traitCollection)
            emptyOverlaySubheaderLabel.font = UIFont.wmf_font(.subheadline, compatibleWithTraitCollection: traitCollection)
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // If the stack view content is approaching or greater than the visible view's height, allow scrolling to read all content
        emptyScrollView.alwaysBounceVertical = emptyOverlayStack.bounds.height > emptyScrollView.bounds.height - 100
    }

    // MARK: - Setup

    override func setup() {
        backgroundColor = .white
        wmf_addSubviewWithConstraintsToEdges(collectionView)
        wmf_addSubviewWithConstraintsToEdges(emptyScrollView)

        emptyOverlayStack.addArrangedSubview(emptyStateImageView)
        emptyOverlayStack.addArrangedSubview(emptyOverlayHeaderLabel)
        emptyOverlayStack.addArrangedSubview(emptyOverlaySubheaderLabel)

        emptyScrollView.addSubview(emptyOverlayStack)

        NSLayoutConstraint.activate([
            emptyScrollView.contentLayoutGuide.widthAnchor.constraint(equalTo: emptyScrollView.frameLayoutGuide.widthAnchor),
            emptyScrollView.contentLayoutGuide.heightAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.frameLayoutGuide.heightAnchor),

            emptyOverlayStack.centerXAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.centerXAnchor),
            emptyOverlayStack.centerYAnchor.constraint(equalTo: emptyScrollView.contentLayoutGuide.centerYAnchor),

            emptyOverlayStack.topAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.contentLayoutGuide.topAnchor, constant: 100),
            emptyOverlayStack.leadingAnchor.constraint(greaterThanOrEqualTo: emptyScrollView.contentLayoutGuide.leadingAnchor, constant: 25),
            emptyOverlayStack.trailingAnchor.constraint(lessThanOrEqualTo: emptyScrollView.contentLayoutGuide.trailingAnchor, constant: -25),
            emptyOverlayStack.bottomAnchor.constraint(lessThanOrEqualTo: emptyScrollView.contentLayoutGuide.bottomAnchor, constant: -100),

            emptyStateImageView.heightAnchor.constraint(equalToConstant: 185),
            emptyStateImageView.widthAnchor.constraint(equalToConstant: 185),

            emptyOverlayHeaderLabel.widthAnchor.constraint(equalTo: emptyOverlayStack.widthAnchor, multiplier: 3/4),
            emptyOverlaySubheaderLabel.widthAnchor.constraint(equalTo: emptyOverlayStack.widthAnchor, multiplier: 4/5)
        ])
    }

    // MARK: - Public

    func updateEmptyOverlay(visible: Bool, headerText: String = "", subheaderText: String = "") {
        emptyScrollView.isHidden = !visible
        emptyScrollView.isUserInteractionEnabled = visible
        emptyOverlayHeaderLabel.text = headerText
        emptyOverlaySubheaderLabel.text = subheaderText
    }

}

extension NotificationsCenterView: Themeable {

    func apply(theme: Theme) {
        backgroundColor = theme.colors.paperBackground
        collectionView.backgroundColor = theme.colors.paperBackground
        emptyOverlayHeaderLabel.textColor = theme.colors.primaryText
        emptyOverlaySubheaderLabel.textColor = theme.colors.primaryText
    }

}
{'fraction_non_alphanumeric': 0.06811737553577316, 'fraction_numerical': 0.004484009231783713, 'mean_word_length': 4.006932981181908, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '403403', 'n_tokens_mistral': 3858, 'n_tokens_neox': 3745, 'n_words': 739}