Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/Threema/Chats/ChatView/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 7 kB image not shown  

Quelle  Old_ScrollToBottomView.swift   Sprache: JAVA

 

import Combine
import Foundation
import SwiftUI
import ThreemaFramework
import UIKit

final class Old_ScrollToBottomView: UIView {
    typealias Config = ChatViewConfiguration.ScrollToBottomButton
    
    // MARK: Private Properties
    
    private let scrollDownAction: () -> Void
    private var currentUnreadCount: Int?
    
    private var cancellables = Set<AnyCancellable>()
    
    private let unreadMessagesSnapshot: UnreadMessagesStateManager
    
    private lazy var scrollDownButton: ThemedCodeButton = {
        let button = ThemedCodeButton { [weak self] _ in
            self?.scrollDownAction()
        }
        
        let image = UIImage(
            systemName: "chevron.down.circle",
            withConfiguration: UIImage.SymbolConfiguration(textStyle: .title1)
        )
        button.setImage(image, for: .normal)
        
        return button
    }()
    
    private lazy var scrollDownButtonStack: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [
            scrollDownButton,
        ])
        
        unreadCountLabel.alpha = 0.0
        stackView.addArrangedSubview(unreadCountLabel)
        
        stackView.spacing = 5
        
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        return stackView
    }()
    
    private lazy var contentStack: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [
            scrollDownButtonStack,
        ])
        
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        return stackView
    }()
    
    private lazy var unreadCountLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        
        label.text = ""
        
        label.font = UIFont.monospacedDigitSystemFont(ofSize: 14.0, weight: .semibold)
        label.textColor = .systemGreen
        label.adjustsFontForContentSizeCategory = true
        
        return label
    }()
    
    private let processingQueue = DispatchQueue(label: "ch.threema.chatView.old_scrollToBottomView")
    
    // MARK: - Lifecycle
    
    init(unreadMessagesSnapshot: UnreadMessagesStateManager, scrollDownAction: @escaping (() -> Void)) {
        self.scrollDownAction = scrollDownAction
        self.unreadMessagesSnapshot = unreadMessagesSnapshot
        
        super.init(frame: .zero)
        
        if let unreadMessagesState = unreadMessagesSnapshot.unreadMessagesState,
           unreadMessagesState.numberOfUnreadMessages == 0 {
            // This avoids a weird animation where the width of the view will change. It is caused by the the
            // subscription to `unreadMessagesSnapshot.$unreadMessagesState` which will get the state only after the
            // view was initially shown.
            hideUnreadCount(animated: false)
        }
        
        unreadMessagesSnapshot.$unreadMessagesState
            .debounce(for: .milliseconds(Config.dataUpdateDebounce), scheduler: processingQueue)
            .receive(on: DispatchQueue.main)
            .sink { [weak self] unreadMessagesState in
                if let unreadMessagesState, unreadMessagesState.numberOfUnreadMessages <= 0 {
                    self?.hideUnreadCount()
                }
                else if let unreadMessagesState {
                    self?.unreadCountLabel.text = "\(unreadMessagesState.numberOfUnreadMessages)"
                    self?.showUnreadCount()
                }
            }
            .store(in: &cancellables)
        
        unreadMessagesSnapshot.$userIsAtBottomOfTableView
            .debounce(for: .milliseconds(Config.dataUpdateDebounce), scheduler: processingQueue)
            .receive(on: DispatchQueue.main)
            .sink { [weak self] userIsAtBottomOfTableView in
                if userIsAtBottomOfTableView {
                    self?.hide()
                }
                else {
                    self?.show()
                }
            }
            .store(in: &cancellables)
        
        configure()
    }
    
    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Configuration Functions
    
    private func configure() {
        addSubview(contentStack)
        
        NSLayoutConstraint.activate([
            contentStack.topAnchor.constraint(equalTo: topAnchor, constant: Config.topBottomInsets),
            contentStack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Config.topBottomInsets),
            contentStack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Config.topBottomInsets),
            contentStack.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Config.topBottomInsets),
        ])
        
        layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
        layer.cornerRadius = Config.cornerRadius
        layer.cornerCurve = .continuous
        
        alpha = 0.0
    }
    
    // MARK: - Update Functions
    
    private func show() {
        guard alpha == 0.0 else {
            return
        }
        
        UIView.animate(
            withDuration: Config.ShowHideAnimation.duration,
            delay: Config.ShowHideAnimation.delay,
            options: .curveEaseInOut
        ) { [self] in
            alpha = 1.0
        }
    }
    
    private func updateUnreadCount(_ count: Int) {
        unreadCountLabel.text = "\(count)"
        
        if count == 0 {
            currentUnreadCount = count
            hideUnreadCount()
        }
        else if count > 0, unreadCountLabel.isHidden, currentUnreadCount != count {
            currentUnreadCount = count
            showUnreadCount()
        }
    }
    
    private func hide() {
        guard alpha == 1.0 else {
            return
        }
        
        UIView.animate(
            withDuration: Config.ShowHideAnimation.duration,
            delay: Config.ShowHideAnimation.delay,
            options: .curveEaseInOut
        ) { [self] in
            alpha = 0.0
        }
        
        hideUnreadCount()
    }
    
    private func hideUnreadCount(animated: Bool = true) {
        guard animated else {
            UIView.performWithoutAnimation {
                self.unreadCountLabel.isHidden = true
                self.unreadCountLabel.text = "0"
                self.unreadCountLabel.alpha = 1.0
            }
            return
        }
        UIView.animate(withDuration: Config.ShowHideAnimation.duration, delay: Config.ShowHideAnimation.delay) {
            self.unreadCountLabel.alpha = 1.0
        }
        UIView.animate(
            withDuration: Config.ShowHideAnimation.duration,
            delay: Config.ShowHideAnimation.duration + Config.ShowHideAnimation.delay
        ) {
            self.unreadCountLabel.isHidden = true
            self.unreadCountLabel.text = "0"
        }
    }
    
    func updateColors() {
        unreadCountLabel.textColor = .tintColor
        backgroundColor = Colors.backgroundChatBar
    }
    
    // MARK: - Private functions
    
    private func showUnreadCount() {
        UIView
            .animate(withDuration: Config.ShowHideAnimation.duration, delay: Config.ShowHideAnimation.delay) { [self] in
                unreadCountLabel.isHidden = false
            }
        UIView.animate(
            withDuration: Config.ShowHideAnimation.duration,
            delay: Config.ShowHideAnimation.duration + Config.ShowHideAnimation.delay
        ) { [self] in
            unreadCountLabel.alpha = 1.0
        }
    }
}

Messung
CHZG
849410092

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.