|
|
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import SessionUIKit
|
|
|
|
import SessionUtilitiesKit
|
|
|
|
|
|
|
|
final class PrimaryColorSelectionView: UIView {
|
|
|
|
public static let size: SessionCell.Accessory.Size = .fillWidthWrapHeight
|
|
|
|
|
|
|
|
private var onChange: ((Theme.PrimaryColor) -> ())?
|
|
|
|
|
|
|
|
// MARK: - Components
|
|
|
|
|
|
|
|
private let scrollView: UIScrollView = {
|
|
|
|
let result: UIScrollView = UIScrollView()
|
|
|
|
result.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
result.showsVerticalScrollIndicator = false
|
|
|
|
result.showsHorizontalScrollIndicator = false
|
|
|
|
|
|
|
|
if Dependencies.isRTL {
|
|
|
|
result.transform = CGAffineTransform.identity.scaledBy(x: -1, y: 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}()
|
|
|
|
|
|
|
|
private let stackView: UIStackView = {
|
|
|
|
let result: UIStackView = UIStackView()
|
|
|
|
result.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
result.axis = .horizontal
|
|
|
|
result.distribution = .equalCentering
|
|
|
|
result.alignment = .fill
|
|
|
|
result.spacing = Values.verySmallSpacing
|
|
|
|
|
|
|
|
return result
|
|
|
|
}()
|
|
|
|
|
|
|
|
private lazy var primaryColorViews: [ColourView] = Theme.PrimaryColor.allCases
|
|
|
|
.map { color in ColourView(color: color) { [weak self] in self?.onChange?(color) } }
|
|
|
|
|
|
|
|
// MARK: - Initializtion
|
|
|
|
|
|
|
|
init() {
|
|
|
|
super.init(frame: .zero)
|
|
|
|
|
|
|
|
setupUI()
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
fatalError("Use init(color:) instead")
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Layout
|
|
|
|
|
|
|
|
private func setupUI() {
|
|
|
|
addSubview(scrollView)
|
|
|
|
scrollView.addSubview(stackView)
|
|
|
|
primaryColorViews.forEach { stackView.addArrangedSubview($0) }
|
|
|
|
|
|
|
|
setupLayout()
|
|
|
|
|
|
|
|
// 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] _, primaryColor in
|
|
|
|
self?.primaryColorViews.forEach { view in
|
|
|
|
view.update(isSelected: (primaryColor == view.color))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func setupLayout() {
|
|
|
|
scrollView.pin(.top, to: .top, of: self)
|
|
|
|
scrollView.pin(.leading, to: .leading, of: self)
|
|
|
|
scrollView.pin(.trailing, lessThanOrEqualTo: .trailing, of: self)
|
|
|
|
.setting(priority: .required)
|
|
|
|
scrollView.pin(.bottom, to: .bottom, of: self)
|
|
|
|
scrollView.set(.width, to: .width, of: stackView)
|
|
|
|
.setting(priority: .defaultLow)
|
|
|
|
|
|
|
|
stackView.pin(to: scrollView)
|
|
|
|
stackView.set(.height, to: .height, of: scrollView)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Content
|
|
|
|
|
|
|
|
func update(
|
|
|
|
with primaryColor: Theme.PrimaryColor,
|
|
|
|
onChange: @escaping (Theme.PrimaryColor) -> ()
|
|
|
|
) {
|
|
|
|
self.onChange = onChange
|
|
|
|
|
|
|
|
primaryColorViews.forEach { view in
|
|
|
|
view.update(isSelected: view.color == primaryColor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Info
|
|
|
|
|
|
|
|
extension PrimaryColorSelectionView: SessionCell.Accessory.CustomView {
|
|
|
|
struct Info: Equatable, SessionCell.Accessory.CustomViewInfo {
|
|
|
|
typealias View = PrimaryColorSelectionView
|
|
|
|
|
|
|
|
let primaryColor: Theme.PrimaryColor
|
|
|
|
let onChange: (Theme.PrimaryColor) -> ()
|
|
|
|
|
|
|
|
static func == (lhs: Info, rhs: Info) -> Bool {
|
|
|
|
return (lhs.primaryColor == rhs.primaryColor)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
|
|
primaryColor.hash(into: &hasher)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static func create(maxContentWidth: CGFloat, using dependencies: Dependencies) -> PrimaryColorSelectionView {
|
|
|
|
return PrimaryColorSelectionView()
|
|
|
|
}
|
|
|
|
|
|
|
|
func update(with info: Info) {
|
|
|
|
update(with: info.primaryColor, onChange: info.onChange)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - ColourView
|
|
|
|
|
|
|
|
extension PrimaryColorSelectionView {
|
|
|
|
class ColourView: UIView {
|
|
|
|
private static let selectionBorderSize: CGFloat = 34
|
|
|
|
private static let selectionSize: CGFloat = 26
|
|
|
|
|
|
|
|
fileprivate let color: Theme.PrimaryColor
|
|
|
|
private let onSelected: () -> ()
|
|
|
|
|
|
|
|
// MARK: - Components
|
|
|
|
|
|
|
|
private lazy var backgroundButton: UIButton = UIButton(
|
|
|
|
type: .custom,
|
|
|
|
primaryAction: UIAction(handler: { [weak self] _ in
|
|
|
|
self?.onSelected()
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
private let selectionBorderView: UIView = {
|
|
|
|
let result: UIView = UIView()
|
|
|
|
result.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
result.isUserInteractionEnabled = false
|
|
|
|
result.themeBorderColor = .radioButton_selectedBorder
|
|
|
|
result.layer.borderWidth = 1
|
|
|
|
result.layer.cornerRadius = (ColourView.selectionBorderSize / 2)
|
|
|
|
result.isHidden = true
|
|
|
|
|
|
|
|
return result
|
|
|
|
}()
|
|
|
|
|
|
|
|
private let selectionView: UIView = {
|
|
|
|
let result: UIView = UIView()
|
|
|
|
result.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
result.isUserInteractionEnabled = false
|
|
|
|
result.layer.cornerRadius = (ColourView.selectionSize / 2)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}()
|
|
|
|
|
|
|
|
// MARK: - Initializtion
|
|
|
|
|
|
|
|
init(color: Theme.PrimaryColor, onSelected: @escaping () -> ()) {
|
|
|
|
self.color = color
|
|
|
|
self.onSelected = onSelected
|
|
|
|
|
|
|
|
super.init(frame: .zero)
|
|
|
|
|
|
|
|
setupUI(color: color)
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
fatalError("Use init(color:) instead")
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Layout
|
|
|
|
|
|
|
|
private func setupUI(color: Theme.PrimaryColor) {
|
|
|
|
// Set the appropriate colours
|
|
|
|
selectionView.themeBackgroundColorForced = .primary(color)
|
|
|
|
|
|
|
|
// Add the UI
|
|
|
|
addSubview(backgroundButton)
|
|
|
|
addSubview(selectionBorderView)
|
|
|
|
addSubview(selectionView)
|
|
|
|
|
|
|
|
setupLayout()
|
|
|
|
}
|
|
|
|
|
|
|
|
private func setupLayout() {
|
|
|
|
backgroundButton.pin(to: self)
|
|
|
|
|
|
|
|
selectionBorderView.pin(to: self)
|
|
|
|
selectionBorderView.set(.width, to: ColourView.selectionBorderSize)
|
|
|
|
selectionBorderView.set(.height, to: ColourView.selectionBorderSize)
|
|
|
|
|
|
|
|
selectionView.center(in: selectionBorderView)
|
|
|
|
selectionView.set(.width, to: ColourView.selectionSize)
|
|
|
|
selectionView.set(.height, to: ColourView.selectionSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Content
|
|
|
|
|
|
|
|
func update(isSelected: Bool) {
|
|
|
|
selectionBorderView.isHidden = !isSelected
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|