430 lines
22 KiB
Swift
430 lines
22 KiB
Swift
//
|
||
// ScenicQueueSettingsViewController.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import SnapKit
|
||
import UIKit
|
||
|
||
/// 排队设置页,对齐 Android `ScenicQueueSettingsScreen` 的三 Tab 表单。
|
||
final class ScenicQueueSettingsViewController: BaseViewController {
|
||
private let viewModel = ScenicQueueSettingsViewModel()
|
||
private let api: ScenicQueueAPIProtocol
|
||
|
||
private let segmentedControl = UISegmentedControl(items: ScenicQueueSettingsTab.allCases.map(\.title))
|
||
private let scrollView = UIScrollView()
|
||
private let stackView = UIStackView()
|
||
private let saveBar = UIView()
|
||
private let saveButton = UIButton(type: .system)
|
||
|
||
private var fieldRows: [String: ScenicQueueSettingFieldRow] = [:]
|
||
private var switchRows: [String: ScenicQueueSwitchRow] = [:]
|
||
|
||
@MainActor
|
||
init(api: ScenicQueueAPIProtocol? = nil) {
|
||
self.api = api ?? NetworkServices.shared.scenicQueueAPI
|
||
super.init(nibName: nil, bundle: nil)
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
override func setupNavigationBar() {
|
||
title = "设置"
|
||
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||
title: "配置日志",
|
||
style: .plain,
|
||
target: self,
|
||
action: #selector(logTapped)
|
||
)
|
||
}
|
||
|
||
override func setupUI() {
|
||
view.backgroundColor = ScenicQueueTokens.pageBackground
|
||
segmentedControl.selectedSegmentIndex = viewModel.settingsTab.rawValue
|
||
segmentedControl.selectedSegmentTintColor = .white
|
||
segmentedControl.setTitleTextAttributes([
|
||
.font: ScenicQueueTokens.settingsRowTitleFont,
|
||
.foregroundColor: AppColor.textSecondary,
|
||
], for: .normal)
|
||
segmentedControl.setTitleTextAttributes([
|
||
.font: UIFont.systemFont(ofSize: 14, weight: .semibold),
|
||
.foregroundColor: ScenicQueueTokens.bannerBlue,
|
||
], for: .selected)
|
||
|
||
stackView.axis = .vertical
|
||
stackView.spacing = 14
|
||
scrollView.keyboardDismissMode = .onDrag
|
||
scrollView.alwaysBounceVertical = true
|
||
|
||
saveBar.backgroundColor = .white
|
||
saveButton.setTitle("保存", for: .normal)
|
||
saveButton.setTitleColor(.white, for: .normal)
|
||
saveButton.titleLabel?.font = ScenicQueueTokens.settingsSaveButtonFont
|
||
saveButton.backgroundColor = ScenicQueueTokens.bannerBlue
|
||
saveButton.layer.cornerRadius = ScenicQueueTokens.bottomSaveButtonRadius
|
||
saveButton.clipsToBounds = true
|
||
|
||
view.addSubview(segmentedControl)
|
||
view.addSubview(scrollView)
|
||
scrollView.addSubview(stackView)
|
||
view.addSubview(saveBar)
|
||
saveBar.addSubview(saveButton)
|
||
rebuildForm()
|
||
}
|
||
|
||
override func setupConstraints() {
|
||
segmentedControl.snp.makeConstraints { make in
|
||
make.top.equalTo(view.safeAreaLayoutGuide).offset(8)
|
||
make.leading.trailing.equalToSuperview().inset(16)
|
||
make.height.equalTo(40)
|
||
}
|
||
saveBar.snp.makeConstraints { make in
|
||
make.leading.trailing.bottom.equalToSuperview()
|
||
}
|
||
saveButton.snp.makeConstraints { make in
|
||
make.top.equalToSuperview().offset(16)
|
||
make.leading.trailing.equalToSuperview().inset(31)
|
||
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-16)
|
||
make.height.equalTo(48)
|
||
}
|
||
scrollView.snp.makeConstraints { make in
|
||
make.top.equalTo(segmentedControl.snp.bottom).offset(10)
|
||
make.leading.trailing.equalToSuperview()
|
||
make.bottom.equalTo(saveBar.snp.top)
|
||
}
|
||
stackView.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 12, left: 16, bottom: 16, right: 16))
|
||
make.width.equalToSuperview().offset(-32)
|
||
}
|
||
}
|
||
|
||
override func bindActions() {
|
||
segmentedControl.addTarget(self, action: #selector(tabChanged), for: .valueChanged)
|
||
saveButton.addTarget(self, action: #selector(saveTapped), for: .touchUpInside)
|
||
viewModel.onStateChange = { [weak self] in
|
||
Task { @MainActor in self?.applyState() }
|
||
}
|
||
viewModel.onShowMessage = { [weak self] message in
|
||
Task { @MainActor in self?.showToast(message) }
|
||
}
|
||
viewModel.onNavigateBack = { [weak self] in
|
||
Task { @MainActor in self?.navigationController?.popViewController(animated: true) }
|
||
}
|
||
viewModel.onNavigateLog = { [weak self] in
|
||
Task { @MainActor in self?.navigationController?.pushViewController(ScenicQueueSettingChangeLogViewController(), animated: true) }
|
||
}
|
||
}
|
||
|
||
private func applyState() {
|
||
segmentedControl.selectedSegmentIndex = viewModel.settingsTab.rawValue
|
||
rebuildForm()
|
||
}
|
||
|
||
private func rebuildForm() {
|
||
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||
fieldRows.removeAll()
|
||
switchRows.removeAll()
|
||
switch viewModel.settingsTab {
|
||
case .basic:
|
||
buildBasicForm()
|
||
case .notify:
|
||
buildNotifyForm()
|
||
case .voice:
|
||
buildVoiceForm()
|
||
}
|
||
}
|
||
|
||
private func buildBasicForm() {
|
||
stackView.addArrangedSubview(tipCard())
|
||
stackView.addArrangedSubview(actionCard(title: "打卡点", value: viewModel.selectedPunchSpotDisplayText, primary: "选择打卡点", secondary: "保存小程序码", primaryAction: #selector(punchSpotTapped), secondaryAction: #selector(saveQRTapped), invalid: viewModel.highlightedInvalidFieldKeys.contains("punchSpot")))
|
||
addSwitchRow(key: "businessOpen", title: "营业状态", isOn: viewModel.businessOpen, action: #selector(businessOpenChanged(_:)))
|
||
addTextRow(key: "businessStart", title: "营业开始时间", value: viewModel.businessStartTime, suffix: "HH:mm", keyboard: .numbersAndPunctuation, action: #selector(businessStartChanged(_:)))
|
||
addTextRow(key: "businessEnd", title: "营业结束时间", value: viewModel.businessEndTime, suffix: "HH:mm", keyboard: .numbersAndPunctuation, action: #selector(businessEndChanged(_:)))
|
||
addTextRow(key: "queueDistance", title: "允许排队距离", value: "\(viewModel.queueDistanceMeter)", suffix: "米", keyboard: .numberPad, action: #selector(queueDistanceChanged(_:)))
|
||
addTextRow(key: "shootMinute", title: "拍摄时长(分钟)", value: "\(viewModel.shootMinute)", suffix: "分", keyboard: .numberPad, action: #selector(shootMinuteChanged(_:)))
|
||
addTextRow(key: "shootSecond", title: "拍摄时长(秒)", value: "\(viewModel.shootSecond)", suffix: "秒", keyboard: .numberPad, action: #selector(shootSecondChanged(_:)))
|
||
addTextRow(key: "queueTakeLimit", title: "单人取号次数", value: "\(viewModel.queueTakeLimit)", suffix: "次", keyboard: .numberPad, action: #selector(queueTakeLimitChanged(_:)))
|
||
addTextRow(key: "missOffset", title: "过号重排顺延位数", value: "\(viewModel.missCallRequeueOffset)", suffix: "位", keyboard: .numberPad, action: #selector(missOffsetChanged(_:)))
|
||
addSwitchRow(key: "showShoot", title: "展示开始拍摄按钮", isOn: viewModel.showStartShootingButton, action: #selector(showShootChanged(_:)))
|
||
addTextRow(key: "autoCall", title: "自动提前叫号数量", value: "\(viewModel.autoCallAheadCount)", suffix: "人", keyboard: .numberPad, action: #selector(autoCallChanged(_:)))
|
||
addSwitchRow(key: "quickCall", title: "底部快速叫号", isOn: viewModel.quickCallButtonEnabled, action: #selector(quickCallChanged(_:)))
|
||
addSwitchRow(key: "prepareCall", title: "底部准备叫号", isOn: viewModel.prepareCallButtonEnabled, action: #selector(prepareCallChanged(_:)))
|
||
}
|
||
|
||
private func buildNotifyForm() {
|
||
addTextRow(key: "firstAhead", title: "第一次提前通知阈值", value: "\(viewModel.firstAheadCount)", suffix: "位", keyboard: .numberPad, action: #selector(firstAheadChanged(_:)))
|
||
addSwitchRow(key: "firstSms", title: "第一次短信通知", isOn: viewModel.firstSms, action: #selector(firstSmsChanged(_:)))
|
||
addSwitchRow(key: "firstPhone", title: "第一次电话通知", isOn: viewModel.firstPhone, action: #selector(firstPhoneChanged(_:)))
|
||
addTextRow(key: "secondAhead", title: "第二次提前通知阈值", value: "\(viewModel.secondAheadCount)", suffix: "位", keyboard: .numberPad, action: #selector(secondAheadChanged(_:)))
|
||
addSwitchRow(key: "secondSms", title: "第二次短信通知", isOn: viewModel.secondSms, action: #selector(secondSmsChanged(_:)))
|
||
addSwitchRow(key: "secondPhone", title: "第二次电话通知", isOn: viewModel.secondPhone, action: #selector(secondPhoneChanged(_:)))
|
||
}
|
||
|
||
private func buildVoiceForm() {
|
||
addTextRow(key: "broadcastInterval", title: "播报间隔时间", value: "\(viewModel.broadcastIntervalSec)", suffix: "秒", keyboard: .numberPad, action: #selector(broadcastChanged(_:)))
|
||
addTextRow(key: "countdown", title: "进入读秒倒计时阈值", value: "\(viewModel.countdownThresholdSec)", suffix: "秒", keyboard: .numberPad, action: #selector(countdownChanged(_:)))
|
||
addSwitchRow(key: "offlineTTS", title: "离线语音合成", isOn: viewModel.useOfflineTTS, action: #selector(offlineTTSChanged(_:)))
|
||
stackView.addArrangedSubview(actionCard(title: "蓝牙音响测试", value: "请确认外放音量是否合适", primary: "播放测试音", secondary: nil, primaryAction: #selector(testSoundTapped), secondaryAction: nil))
|
||
addTextRow(key: "customTTS", title: "自定义播报文案", value: viewModel.customTTSText, suffix: "", keyboard: .default, action: #selector(customTTSChanged(_:)))
|
||
stackView.addArrangedSubview(actionCard(title: "播报文案", value: "最多保存5个语音", primary: "播放文本", secondary: "保存到预设", primaryAction: #selector(playCustomTapped), secondaryAction: #selector(savePresetTapped)))
|
||
for (index, phrase) in viewModel.presetVoices.enumerated() {
|
||
stackView.addArrangedSubview(presetVoiceCard(index: index, phrase: phrase))
|
||
}
|
||
}
|
||
|
||
private func addTextRow(key: String, title: String, value: String, suffix: String, keyboard: UIKeyboardType, action: Selector) {
|
||
let row = ScenicQueueSettingFieldRow(title: title, value: value, suffix: suffix, keyboard: keyboard)
|
||
row.textField.addTarget(self, action: action, for: .editingChanged)
|
||
fieldRows[key] = row
|
||
stackView.addArrangedSubview(row)
|
||
}
|
||
|
||
private func addSwitchRow(key: String, title: String, isOn: Bool, action: Selector) {
|
||
let row = ScenicQueueSwitchRow(title: title, isOn: isOn)
|
||
row.toggle.addTarget(self, action: action, for: .valueChanged)
|
||
switchRows[key] = row
|
||
stackView.addArrangedSubview(row)
|
||
}
|
||
|
||
private func tipCard() -> UIView {
|
||
let card = ScenicQueueSettingCard()
|
||
card.backgroundColor = ScenicQueueTokens.bannerBlue
|
||
let title = UILabel()
|
||
title.text = "排队基础参数"
|
||
title.textColor = .white
|
||
title.font = ScenicQueueTokens.settingsSectionTitleFont
|
||
let body = UILabel()
|
||
body.text = "选择打卡点后保存配置,顾客即可扫码取号排队。"
|
||
body.textColor = UIColor.white.withAlphaComponent(0.86)
|
||
body.font = ScenicQueueTokens.settingsHintFont
|
||
body.numberOfLines = 0
|
||
let stack = UIStackView(arrangedSubviews: [title, body])
|
||
stack.axis = .vertical
|
||
stack.spacing = 6
|
||
card.addSubview(stack)
|
||
stack.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(14)
|
||
}
|
||
return card
|
||
}
|
||
|
||
private func actionCard(title: String, value: String, primary: String, secondary: String?, primaryAction: Selector, secondaryAction: Selector?, invalid: Bool = false) -> UIView {
|
||
let card = ScenicQueueSettingCard()
|
||
card.layer.borderColor = invalid ? AppColor.danger.cgColor : ScenicQueueTokens.cardOutline.cgColor
|
||
let titleLabel = UILabel()
|
||
titleLabel.text = title
|
||
titleLabel.font = ScenicQueueTokens.settingsFieldLabelFont
|
||
titleLabel.textColor = AppColor.textPrimary
|
||
let valueLabel = UILabel()
|
||
valueLabel.text = value
|
||
valueLabel.font = ScenicQueueTokens.settingsHintFont
|
||
valueLabel.textColor = AppColor.textSecondary
|
||
valueLabel.numberOfLines = 0
|
||
let primaryButton = UIButton(type: .system)
|
||
primaryButton.setTitle(primary, for: .normal)
|
||
primaryButton.titleLabel?.font = ScenicQueueTokens.buttonSecondaryFont
|
||
primaryButton.addTarget(self, action: primaryAction, for: .touchUpInside)
|
||
let buttons = UIStackView(arrangedSubviews: [primaryButton])
|
||
buttons.axis = .horizontal
|
||
buttons.spacing = 12
|
||
if let secondary, let secondaryAction {
|
||
let secondaryButton = UIButton(type: .system)
|
||
secondaryButton.setTitle(secondary, for: .normal)
|
||
secondaryButton.titleLabel?.font = ScenicQueueTokens.buttonSecondaryFont
|
||
secondaryButton.addTarget(self, action: secondaryAction, for: .touchUpInside)
|
||
buttons.addArrangedSubview(secondaryButton)
|
||
}
|
||
let stack = UIStackView(arrangedSubviews: [titleLabel, valueLabel, buttons])
|
||
stack.axis = .vertical
|
||
stack.spacing = 8
|
||
card.addSubview(stack)
|
||
stack.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(14)
|
||
}
|
||
return card
|
||
}
|
||
|
||
private func presetVoiceCard(index: Int, phrase: String) -> UIView {
|
||
let card = ScenicQueueSettingCard()
|
||
let label = UILabel()
|
||
label.text = phrase
|
||
label.font = ScenicQueueTokens.settingsRowTitleFont
|
||
label.textColor = AppColor.textPrimary
|
||
label.numberOfLines = 0
|
||
let delete = UIButton(type: .system)
|
||
delete.setImage(UIImage(systemName: "trash"), for: .normal)
|
||
delete.tintColor = AppColor.danger
|
||
delete.tag = index
|
||
delete.addTarget(self, action: #selector(deletePresetTapped(_:)), for: .touchUpInside)
|
||
card.addSubview(label)
|
||
card.addSubview(delete)
|
||
label.snp.makeConstraints { make in
|
||
make.leading.top.bottom.equalToSuperview().inset(14)
|
||
make.trailing.equalTo(delete.snp.leading).offset(-12)
|
||
}
|
||
delete.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().offset(-14)
|
||
make.centerY.equalToSuperview()
|
||
make.size.equalTo(44)
|
||
}
|
||
return card
|
||
}
|
||
|
||
@objc private func tabChanged() {
|
||
viewModel.setSettingsTab(ScenicQueueSettingsTab(rawValue: segmentedControl.selectedSegmentIndex) ?? .basic)
|
||
}
|
||
|
||
@objc private func logTapped() { viewModel.openSettingChangeLog() }
|
||
|
||
@objc private func saveTapped() {
|
||
view.endEditing(true)
|
||
Task { await viewModel.save(api: api) }
|
||
}
|
||
|
||
@objc private func punchSpotTapped() {
|
||
Task {
|
||
await viewModel.loadPunchSpotOptions(api: api)
|
||
await MainActor.run { presentPunchSpotPicker() }
|
||
}
|
||
}
|
||
|
||
private func presentPunchSpotPicker() {
|
||
let alert = UIAlertController(title: "选择打卡点", message: nil, preferredStyle: .actionSheet)
|
||
viewModel.punchSpotOptions.forEach { option in
|
||
alert.addAction(UIAlertAction(title: option.label, style: .default) { [weak self] _ in
|
||
guard let self else { return }
|
||
Task { await self.viewModel.setPunchSpot(option, api: self.api) }
|
||
})
|
||
}
|
||
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
||
present(alert, animated: true)
|
||
}
|
||
|
||
@objc private func saveQRTapped() { Task { await viewModel.saveShootQueueQRCode(api: api) } }
|
||
@objc private func testSoundTapped() { viewModel.playBluetoothTestSound() }
|
||
@objc private func playCustomTapped() { viewModel.toggleCustomTTSPlayback() }
|
||
@objc private func savePresetTapped() { viewModel.saveCurrentTextAsPresetVoiceLocal() }
|
||
@objc private func deletePresetTapped(_ sender: UIButton) { viewModel.deletePresetVoice(at: sender.tag) }
|
||
|
||
@objc private func businessOpenChanged(_ sender: UISwitch) { viewModel.toggleBusinessOpen() }
|
||
@objc private func showShootChanged(_ sender: UISwitch) { viewModel.toggleShowStartShootingButton() }
|
||
@objc private func quickCallChanged(_ sender: UISwitch) { viewModel.toggleQuickCallButtonEnabled() }
|
||
@objc private func prepareCallChanged(_ sender: UISwitch) { viewModel.togglePrepareCallButtonEnabled() }
|
||
@objc private func firstSmsChanged(_ sender: UISwitch) { viewModel.toggleFirstSms() }
|
||
@objc private func firstPhoneChanged(_ sender: UISwitch) { viewModel.toggleFirstPhone() }
|
||
@objc private func secondSmsChanged(_ sender: UISwitch) { viewModel.toggleSecondSms() }
|
||
@objc private func secondPhoneChanged(_ sender: UISwitch) { viewModel.toggleSecondPhone() }
|
||
|
||
@objc private func businessStartChanged(_ sender: UITextField) { viewModel.setBusinessStartTime(sender.text ?? "") }
|
||
@objc private func businessEndChanged(_ sender: UITextField) { viewModel.setBusinessEndTime(sender.text ?? "") }
|
||
@objc private func queueDistanceChanged(_ sender: UITextField) { viewModel.setQueueDistanceMeter(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func shootMinuteChanged(_ sender: UITextField) { viewModel.setShootMinute(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func shootSecondChanged(_ sender: UITextField) { viewModel.setShootSecond(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func queueTakeLimitChanged(_ sender: UITextField) { viewModel.setQueueTakeLimit(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func missOffsetChanged(_ sender: UITextField) { viewModel.setMissCallRequeueOffset(Int(sender.text ?? "") ?? 1) }
|
||
@objc private func autoCallChanged(_ sender: UITextField) { viewModel.setAutoCallAheadCount(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func firstAheadChanged(_ sender: UITextField) { viewModel.setFirstAheadCount(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func secondAheadChanged(_ sender: UITextField) { viewModel.setSecondAheadCount(Int(sender.text ?? "") ?? 0) }
|
||
@objc private func broadcastChanged(_ sender: UITextField) { viewModel.setBroadcastIntervalSec(Int(sender.text ?? "") ?? 50) }
|
||
@objc private func countdownChanged(_ sender: UITextField) { viewModel.setCountdownThresholdSec(Int(sender.text ?? "") ?? 15) }
|
||
@objc private func offlineTTSChanged(_ sender: UISwitch) { viewModel.setUseOfflineTTS(sender.isOn) }
|
||
@objc private func customTTSChanged(_ sender: UITextField) { viewModel.setCustomTTSText(sender.text ?? "") }
|
||
}
|
||
|
||
/// 设置页卡片容器。
|
||
class ScenicQueueSettingCard: UIView {
|
||
init() {
|
||
super.init(frame: .zero)
|
||
backgroundColor = .white
|
||
layer.cornerRadius = ScenicQueueTokens.radiusCard
|
||
layer.borderWidth = 1
|
||
layer.borderColor = ScenicQueueTokens.cardOutline.cgColor
|
||
clipsToBounds = true
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
}
|
||
|
||
/// 设置页文本字段行。
|
||
final class ScenicQueueSettingFieldRow: ScenicQueueSettingCard {
|
||
let textField = UITextField()
|
||
|
||
init(title: String, value: String, suffix: String, keyboard: UIKeyboardType) {
|
||
super.init()
|
||
let label = UILabel()
|
||
label.text = title
|
||
label.font = ScenicQueueTokens.settingsFieldLabelFont
|
||
label.textColor = AppColor.textPrimary
|
||
textField.text = value
|
||
textField.keyboardType = keyboard
|
||
textField.textAlignment = .right
|
||
textField.font = ScenicQueueTokens.settingsRowTitleFont
|
||
textField.textColor = AppColor.textPrimary
|
||
let suffixLabel = UILabel()
|
||
suffixLabel.text = suffix
|
||
suffixLabel.font = ScenicQueueTokens.settingsHintFont
|
||
suffixLabel.textColor = AppColor.textSecondary
|
||
addSubview(label)
|
||
addSubview(textField)
|
||
addSubview(suffixLabel)
|
||
label.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().offset(14)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
suffixLabel.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().offset(-14)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
textField.snp.makeConstraints { make in
|
||
make.leading.greaterThanOrEqualTo(label.snp.trailing).offset(12)
|
||
make.trailing.equalTo(suffixLabel.snp.leading).offset(-6)
|
||
make.top.bottom.equalToSuperview().inset(8)
|
||
make.height.equalTo(38)
|
||
make.width.greaterThanOrEqualTo(90)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
}
|
||
|
||
/// 设置页开关行。
|
||
final class ScenicQueueSwitchRow: ScenicQueueSettingCard {
|
||
let toggle = UISwitch()
|
||
|
||
init(title: String, isOn: Bool) {
|
||
super.init()
|
||
let label = UILabel()
|
||
label.text = title
|
||
label.font = ScenicQueueTokens.settingsFieldLabelFont
|
||
label.textColor = AppColor.textPrimary
|
||
toggle.isOn = isOn
|
||
toggle.onTintColor = ScenicQueueTokens.bannerBlue
|
||
addSubview(label)
|
||
addSubview(toggle)
|
||
label.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().offset(14)
|
||
make.centerY.equalToSuperview()
|
||
make.top.bottom.equalToSuperview().inset(14)
|
||
}
|
||
toggle.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().offset(-14)
|
||
make.centerY.equalToSuperview()
|
||
make.leading.greaterThanOrEqualTo(label.snp.trailing).offset(12)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
}
|