mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			286 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			286 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Swift
		
	
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
 | 
						|
 | 
						|
import UIKit
 | 
						|
import SessionUIKit
 | 
						|
import SignalUtilitiesKit
 | 
						|
 | 
						|
final class AppearanceViewController: BaseVC {
 | 
						|
    // MARK: - Components
 | 
						|
    
 | 
						|
    private let scrollView: UIScrollView = {
 | 
						|
        let result: UIScrollView = UIScrollView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.showsVerticalScrollIndicator = false
 | 
						|
        result.showsHorizontalScrollIndicator = false
 | 
						|
        result.contentInset = UIEdgeInsets(
 | 
						|
            top: 0,
 | 
						|
            leading: 0,
 | 
						|
            bottom: Values.largeSpacing,
 | 
						|
            trailing: 0
 | 
						|
        )
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let contentView: UIView = UIView()
 | 
						|
    
 | 
						|
    private let themesTitleLabel: UILabel = {
 | 
						|
        let result: UILabel = UILabel()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .regular)
 | 
						|
        result.themeTextColor = .textSecondary
 | 
						|
        result.text = "APPEARANCE_THEMES_TITLE".localized()
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let themesStackView: UIStackView = {
 | 
						|
        let result: UIStackView = UIStackView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = true
 | 
						|
        result.axis = .vertical
 | 
						|
        result.distribution = .equalCentering
 | 
						|
        result.alignment = .fill
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private lazy var themeSelectionViews: [ThemeSelectionView] = Theme.allCases
 | 
						|
        .map { theme in
 | 
						|
            let result: ThemeSelectionView = ThemeSelectionView(theme: theme) { [weak self] theme in
 | 
						|
                ThemeManager.currentTheme = theme
 | 
						|
            }
 | 
						|
            result.update(isSelected: (ThemeManager.currentTheme == theme))
 | 
						|
            
 | 
						|
            return result
 | 
						|
        }
 | 
						|
    
 | 
						|
    private let primaryColorTitleLabel: UILabel = {
 | 
						|
        let result: UILabel = UILabel()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .regular)
 | 
						|
        result.themeTextColor = .textSecondary
 | 
						|
        result.text = "APPEARANCE_PRIMARY_COLOR_TITLE".localized()
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let primaryColorPreviewStackView: UIStackView = {
 | 
						|
        let result: UIStackView = UIStackView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.axis = .vertical
 | 
						|
        result.distribution = .equalCentering
 | 
						|
        result.alignment = .fill
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let primaryColorPreviewView: ThemePreviewView = {
 | 
						|
        let result: ThemePreviewView = ThemePreviewView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let primaryColorScrollView: UIScrollView = {
 | 
						|
        let result: UIScrollView = UIScrollView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.showsVerticalScrollIndicator = false
 | 
						|
        result.showsHorizontalScrollIndicator = false
 | 
						|
        result.contentInset = UIEdgeInsets(
 | 
						|
            top: 0,
 | 
						|
            leading: Values.largeSpacing,
 | 
						|
            bottom: 0,
 | 
						|
            trailing: Values.largeSpacing
 | 
						|
        )
 | 
						|
        
 | 
						|
        if CurrentAppContext().isRTL {
 | 
						|
            result.transform = CGAffineTransform.identity.scaledBy(x: -1, y: 1)
 | 
						|
        }
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let primaryColorSelectionStackView: UIStackView = {
 | 
						|
        let result: UIStackView = UIStackView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.axis = .horizontal
 | 
						|
        result.distribution = .equalCentering
 | 
						|
        result.alignment = .fill
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private lazy var primaryColorSelectionViews: [PrimaryColorSelectionView] = Theme.PrimaryColor.allCases
 | 
						|
        .map { color in
 | 
						|
            let result: PrimaryColorSelectionView = PrimaryColorSelectionView(color: color) { [weak self] color in
 | 
						|
                ThemeManager.primaryColor = color
 | 
						|
            }
 | 
						|
            result.update(isSelected: (ThemeManager.primaryColor == color))
 | 
						|
            
 | 
						|
            return result
 | 
						|
        }
 | 
						|
    
 | 
						|
    private let nightModeTitleLabel: UILabel = {
 | 
						|
        let result: UILabel = UILabel()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .regular)
 | 
						|
        result.themeTextColor = .textSecondary
 | 
						|
        result.text = "APPEARANCE_NIGHT_MODE_TITLE".localized()
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let nightModeStackView: UIStackView = {
 | 
						|
        let result: UIStackView = UIStackView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.axis = .vertical
 | 
						|
        result.distribution = .equalCentering
 | 
						|
        result.alignment = .fill
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let nightModeToggleView: UIView = {
 | 
						|
        let result: UIView = UIView()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.themeBackgroundColor = .appearance_sectionBackground
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private let nightModeToggleLabel: UILabel = {
 | 
						|
        let result: UILabel = UILabel()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .regular)
 | 
						|
        result.themeTextColor = .textPrimary
 | 
						|
        result.text = "APPEARANCE_NIGHT_MODE_TOGGLE".localized()
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    private lazy var nightModeToggleSwitch: UISwitch = {
 | 
						|
        let result: UISwitch = UISwitch()
 | 
						|
        result.translatesAutoresizingMaskIntoConstraints = false
 | 
						|
        result.themeOnTintColor = .primary
 | 
						|
        result.isOn = ThemeManager.matchSystemNightModeSetting
 | 
						|
        result.addTarget(self, action: #selector(nightModeToggleChanged(sender:)), for: .valueChanged)
 | 
						|
        
 | 
						|
        return result
 | 
						|
    }()
 | 
						|
    
 | 
						|
    // MARK: - Lifecycle
 | 
						|
    
 | 
						|
    override func viewDidLoad() {
 | 
						|
        super.viewDidLoad()
 | 
						|
        
 | 
						|
        ViewControllerUtilities.setUpDefaultSessionStyle(
 | 
						|
            for: self,
 | 
						|
            title: "APPEARANCE_TITLE".localized(),
 | 
						|
            hasCustomBackButton: false
 | 
						|
        )
 | 
						|
        
 | 
						|
        view.themeBackgroundColor = .backgroundPrimary
 | 
						|
        view.addSubview(scrollView)
 | 
						|
        
 | 
						|
        // Note: Need to add to a 'contentView' to ensure the automatic RTL behaviour
 | 
						|
        // works properly (apparently it doesn't play nicely with UIScrollView internals)
 | 
						|
        scrollView.addSubview(contentView)
 | 
						|
        
 | 
						|
        contentView.addSubview(themesTitleLabel)
 | 
						|
        contentView.addSubview(themesStackView)
 | 
						|
        contentView.addSubview(primaryColorTitleLabel)
 | 
						|
        contentView.addSubview(primaryColorPreviewStackView)
 | 
						|
        contentView.addSubview(primaryColorScrollView)
 | 
						|
        contentView.addSubview(nightModeTitleLabel)
 | 
						|
        contentView.addSubview(nightModeStackView)
 | 
						|
        
 | 
						|
        themesStackView.addArrangedSubview(UIView.separator())
 | 
						|
        themeSelectionViews.forEach { view in
 | 
						|
            themesStackView.addArrangedSubview(view)
 | 
						|
            themesStackView.addArrangedSubview(UIView.separator())
 | 
						|
        }
 | 
						|
        
 | 
						|
        primaryColorPreviewStackView.addArrangedSubview(UIView.separator())
 | 
						|
        primaryColorPreviewStackView.addArrangedSubview(primaryColorPreviewView)
 | 
						|
        primaryColorPreviewStackView.addArrangedSubview(UIView.separator())
 | 
						|
        
 | 
						|
        primaryColorScrollView.addSubview(primaryColorSelectionStackView)
 | 
						|
        
 | 
						|
        primaryColorSelectionViews.forEach { view in
 | 
						|
            primaryColorSelectionStackView.addArrangedSubview(view)
 | 
						|
        }
 | 
						|
        
 | 
						|
        nightModeStackView.addArrangedSubview(UIView.separator())
 | 
						|
        nightModeStackView.addArrangedSubview(nightModeToggleView)
 | 
						|
        nightModeStackView.addArrangedSubview(UIView.separator())
 | 
						|
        
 | 
						|
        nightModeToggleView.addSubview(nightModeToggleLabel)
 | 
						|
        nightModeToggleView.addSubview(nightModeToggleSwitch)
 | 
						|
        
 | 
						|
        // Register an observer so when the theme changes the selected theme and primary colour
 | 
						|
        // are both updated to match
 | 
						|
        ThemeManager.onThemeChange(observer: self) { [weak self] theme, primaryColor in
 | 
						|
            self?.themeSelectionViews.forEach { view in
 | 
						|
                view.update(isSelected: (theme == view.theme))
 | 
						|
            }
 | 
						|
            
 | 
						|
            self?.primaryColorSelectionViews.forEach { view in
 | 
						|
                view.update(isSelected: (primaryColor == view.color))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        setupLayout()
 | 
						|
    }
 | 
						|
    
 | 
						|
    private func setupLayout() {
 | 
						|
        scrollView.pin(to: view)
 | 
						|
        contentView.pin(to: scrollView)
 | 
						|
        contentView.set(.width, to: .width, of: scrollView)
 | 
						|
        
 | 
						|
        themesTitleLabel.pin(.top, to: .top, of: contentView)
 | 
						|
        themesTitleLabel.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing)
 | 
						|
        
 | 
						|
        themesStackView.pin(.top, to: .bottom, of: themesTitleLabel, withInset: Values.mediumSpacing)
 | 
						|
        themesStackView.pin(.leading, to: .leading, of: contentView)
 | 
						|
        themesStackView.set(.width, to: .width, of: contentView)
 | 
						|
        
 | 
						|
        primaryColorTitleLabel.pin(.top, to: .bottom, of: themesStackView, withInset: Values.mediumSpacing)
 | 
						|
        primaryColorTitleLabel.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing)
 | 
						|
        
 | 
						|
        primaryColorPreviewStackView.pin(.top, to: .bottom, of: primaryColorTitleLabel, withInset: Values.smallSpacing)
 | 
						|
        primaryColorPreviewStackView.pin(.leading, to: .leading, of: contentView)
 | 
						|
        primaryColorPreviewStackView.set(.width, to: .width, of: contentView)
 | 
						|
        
 | 
						|
        primaryColorScrollView.pin(.top, to: .bottom, of: primaryColorPreviewStackView, withInset: Values.mediumSpacing)
 | 
						|
        primaryColorScrollView.pin(.leading, to: .leading, of: contentView)
 | 
						|
        primaryColorScrollView.set(.width, to: .width, of: contentView)
 | 
						|
        
 | 
						|
        primaryColorSelectionStackView.pin(to: primaryColorScrollView)
 | 
						|
        primaryColorSelectionStackView.set(.height, to: .height, of: primaryColorScrollView)
 | 
						|
        
 | 
						|
        nightModeTitleLabel.pin(.top, to: .bottom, of: primaryColorScrollView, withInset: Values.largeSpacing)
 | 
						|
        nightModeTitleLabel.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing)
 | 
						|
        nightModeTitleLabel.set(.width, to: .width, of: contentView, withOffset: -(Values.largeSpacing * 2))
 | 
						|
        
 | 
						|
        nightModeStackView.pin(.top, to: .bottom, of: nightModeTitleLabel, withInset: Values.smallSpacing)
 | 
						|
        nightModeStackView.pin(.bottom, to: .bottom, of: contentView)
 | 
						|
        nightModeStackView.pin(.leading, to: .leading, of: contentView)
 | 
						|
        nightModeStackView.set(.width, to: .width, of: contentView)
 | 
						|
        
 | 
						|
        nightModeToggleLabel.setContentHuggingVerticalHigh()
 | 
						|
        nightModeToggleLabel.setCompressionResistanceVerticalHigh()
 | 
						|
        nightModeToggleLabel.center(.vertical, in: nightModeToggleView)
 | 
						|
        nightModeToggleLabel.pin(.leading, to: .leading, of: nightModeToggleView, withInset: Values.largeSpacing)
 | 
						|
        
 | 
						|
        nightModeToggleSwitch.pin(.top, to: .top, of: nightModeToggleView, withInset: Values.smallSpacing)
 | 
						|
        nightModeToggleSwitch.pin(.bottom, to: .bottom, of: nightModeToggleView, withInset: -Values.smallSpacing)
 | 
						|
        nightModeToggleSwitch.pin(.trailing, to: .trailing, of: nightModeToggleView, withInset: -Values.largeSpacing)
 | 
						|
    }
 | 
						|
    
 | 
						|
    // MARK: - Actions
 | 
						|
    
 | 
						|
    @objc private func nightModeToggleChanged(sender: UISwitch) {
 | 
						|
        ThemeManager.matchSystemNightModeSetting = sender.isOn
 | 
						|
    }
 | 
						|
}
 |