From 8cedb4c8aa1b389ac041ec5e99299df6a792daae Mon Sep 17 00:00:00 2001 From: Yurii Dukhovnyi Date: Thu, 7 Sep 2023 00:00:26 +0300 Subject: [PATCH] Introduce list queue interface Added mechanism for fetching queue id dynamically and assigning into settings. MOB-2594 --- GliaWidgets/Public/Glia/Glia.swift | 27 ++++++++ GliaWidgets/Public/GliaError.swift | 1 + .../Cells/EnvironmentSettingsTextCell.swift | 14 +---- TestingApp/Settings/Cells/SettingsCell.swift | 22 +++---- .../Settings/Cells/SettingsColorCell.swift | 35 ++--------- .../Settings/Cells/SettingsFontCell.swift | 12 +--- .../Settings/Cells/SettingsSwitchCell.swift | 35 +---------- .../Settings/Cells/SettingsTextCell.swift | 61 +++++++++++++++---- .../Settings/SettingsViewController.swift | 34 +++++++++-- .../ViewController/ViewController.swift | 6 +- 10 files changed, 129 insertions(+), 118 deletions(-) diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index 00e1cb32a..84f2168bf 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -260,6 +260,33 @@ public class Glia { failure: { completion(.failure($0)) } ) } + + /// List all Queues of the configured site. + /// It is also possible to monitor Queues changes with [subscribeForUpdates](x-source-tag://subscribeForUpdates) method. + /// If the request is unsuccessful for any reason then the completion will have an Error. + /// - Parameters: + /// - completion: A callback that will return the Result struct with `Queue` list or `GliaCoreError` + /// + public func listQueues(_ completion: @escaping (Result<[Queue], Error>) -> Void) { + guard interactor != nil else { + completion(.failure(GliaError.sdkIsNotConfigured)) + return + } + + environment.coreSdk.listQueues { queues, error in + if let error { + completion(.failure(error)) + return + } + + if let queues { + completion(.success(queues)) + return + } + + completion(.failure(GliaError.internalError)) + } + } } // MARK: - Private diff --git a/GliaWidgets/Public/GliaError.swift b/GliaWidgets/Public/GliaError.swift index c1b669188..ee9349849 100644 --- a/GliaWidgets/Public/GliaError.swift +++ b/GliaWidgets/Public/GliaError.swift @@ -7,4 +7,5 @@ public enum GliaError: Error { case configuringDuringEngagementIsNotAllowed case clearingVisitorSessionDuringEngagementIsNotAllowed case startingEngagementWithNoQueueIdsIsNotAllowed + case internalError } diff --git a/TestingApp/Settings/Cells/EnvironmentSettingsTextCell.swift b/TestingApp/Settings/Cells/EnvironmentSettingsTextCell.swift index 2579772a6..25741da55 100644 --- a/TestingApp/Settings/Cells/EnvironmentSettingsTextCell.swift +++ b/TestingApp/Settings/Cells/EnvironmentSettingsTextCell.swift @@ -90,18 +90,8 @@ final class EnvironmentSettingsTextCell: SettingsCell { } private func layout() { - contentView.addSubview(stackView) - stackView.addArrangedSubview(segmentedControl) - stackView.addArrangedSubview(customEnvironmentUrlTextField) - stackView.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - let insets = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 20) - constraints += stackView.layoutInSuperview(edges: .vertical, insets: insets) - constraints += stackView.layoutInSuperview(edges: .trailing, insets: insets) - constraints += stackView.leadingAnchor.constraint( - equalTo: titleLabel.trailingAnchor, - constant: 10 - ) + contentStackView.addArrangedSubview(segmentedControl) + contentStackView.addArrangedSubview(customEnvironmentUrlTextField) } @objc diff --git a/TestingApp/Settings/Cells/SettingsCell.swift b/TestingApp/Settings/Cells/SettingsCell.swift index bae3e11a5..7883b753d 100644 --- a/TestingApp/Settings/Cells/SettingsCell.swift +++ b/TestingApp/Settings/Cells/SettingsCell.swift @@ -1,6 +1,9 @@ import UIKit class SettingsCell: UITableViewCell { + lazy var contentStackView = UIStackView.make(.horizontal, spacing: 8)( + titleLabel + ) let titleLabel = UILabel() init(title: String) { @@ -21,20 +24,17 @@ class SettingsCell: UITableViewCell { titleLabel.font = .systemFont(ofSize: 15) titleLabel.textColor = .darkGray titleLabel.numberOfLines = 0 + titleLabel.lineBreakMode = .byWordWrapping + titleLabel.minimumScaleFactor = 0.8 } private func layout() { - contentView.addSubview(titleLabel) - titleLabel.translatesAutoresizingMaskIntoConstraints = false + contentStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(contentStackView) var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - let insets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 0) - constraints += titleLabel.layoutInSuperview( - edges: .vertical, - insets: insets - ) - constraints += titleLabel.layoutInSuperview( - edges: .leading, - insets: insets - ) + let insets = UIEdgeInsets(top: 4, left: 16, bottom: 4, right: 16) + constraints += contentStackView.layoutInSuperview(insets: insets) + + titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal) } } diff --git a/TestingApp/Settings/Cells/SettingsColorCell.swift b/TestingApp/Settings/Cells/SettingsColorCell.swift index 0fd3d56e6..70dd03acd 100644 --- a/TestingApp/Settings/Cells/SettingsColorCell.swift +++ b/TestingApp/Settings/Cells/SettingsColorCell.swift @@ -41,40 +41,15 @@ class SettingsColorCell: SettingsCell { } private func layout() { - contentView.addSubview(sampleView) - sampleView.translatesAutoresizingMaskIntoConstraints = false + contentStackView.addArrangedSubview(UIView()) + contentStackView.addArrangedSubview(sampleView) + contentStackView.addArrangedSubview(rgbTextField) + contentStackView.addArrangedSubview(alphaTextField) + var constraints = [NSLayoutConstraint](); defer { constraints.activate() } constraints += sampleView.match(value: 30) - constraints += sampleView.leadingAnchor.constraint( - greaterThanOrEqualTo: titleLabel.trailingAnchor, - constant: 20 - ) - constraints += sampleView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) - - contentView.addSubview(rgbTextField) - rgbTextField.translatesAutoresizingMaskIntoConstraints = false constraints += rgbTextField.match(.width, value: 100) - constraints += rgbTextField.layoutInSuperview( - edges: .vertical, - insets: .init(top: 10, left: 0, bottom: 10, right: 0) - ) - constraints += rgbTextField.leadingAnchor.constraint( - equalTo: sampleView.trailingAnchor, - constant: 10 - ) - - contentView.addSubview(alphaTextField) - alphaTextField.translatesAutoresizingMaskIntoConstraints = false constraints += alphaTextField.match(.width, value: 50) - constraints += alphaTextField.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) - constraints += alphaTextField.leadingAnchor.constraint( - equalTo: rgbTextField.trailingAnchor, - constant: 10 - ) - constraints += alphaTextField.layoutInSuperview( - edges: .trailing, - insets: UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 20) - ) } @objc private func updateSample() { diff --git a/TestingApp/Settings/Cells/SettingsFontCell.swift b/TestingApp/Settings/Cells/SettingsFontCell.swift index d094b9820..a5124e0c1 100644 --- a/TestingApp/Settings/Cells/SettingsFontCell.swift +++ b/TestingApp/Settings/Cells/SettingsFontCell.swift @@ -42,17 +42,7 @@ class SettingsFontCell: SettingsCell { } private func layout() { - contentView.addSubview(pickerView) - pickerView.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - constraints += pickerView.match(value: 240) - constraints += pickerView.leadingAnchor.constraint( - equalTo: titleLabel.trailingAnchor, - constant: 10 - ) - let insets = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 20) - constraints += pickerView.layoutInSuperview(edges: .vertical, insets: insets) - constraints += pickerView.layoutInSuperview(edges: .trailing, insets: insets) + contentStackView.addArrangedSubview(pickerView) } private func selectDefaultFont() { diff --git a/TestingApp/Settings/Cells/SettingsSwitchCell.swift b/TestingApp/Settings/Cells/SettingsSwitchCell.swift index bb2ec13fa..9884c4787 100644 --- a/TestingApp/Settings/Cells/SettingsSwitchCell.swift +++ b/TestingApp/Settings/Cells/SettingsSwitchCell.swift @@ -10,38 +10,7 @@ final class SettingsSwitchCell: SettingsCell { } private func layout() { - contentView.addSubview(switcher) - switcher.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - let insets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 20) - constraints += switcher.layoutInSuperview(edges: .vertical, insets: insets) - constraints += switcher.layoutInSuperview(edges: .trailing, insets: insets) - constraints += switcher.leadingAnchor.constraint( - equalTo: titleLabel.trailingAnchor, - constant: 10 - ) - } -} - -final class SettingsSegmentedCell: SettingsCell { - let segmentedControl: UISegmentedControl - - init(title: String, items: String...) { - self.segmentedControl = .init(items: items.map(NSString.init(string:))) - super.init(title: title) - layout() - } - - private func layout() { - contentView.addSubview(segmentedControl) - segmentedControl.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - let insets = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 20) - constraints += segmentedControl.layoutInSuperview(edges: .vertical, insets: insets) - constraints += segmentedControl.layoutInSuperview(edges: .trailing, insets: insets) - constraints += segmentedControl.leadingAnchor.constraint( - equalTo: titleLabel.trailingAnchor, - constant: 10 - ) + titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) + contentStackView.addArrangedSubview(switcher) } } diff --git a/TestingApp/Settings/Cells/SettingsTextCell.swift b/TestingApp/Settings/Cells/SettingsTextCell.swift index 71cc3f92f..0de39ea50 100644 --- a/TestingApp/Settings/Cells/SettingsTextCell.swift +++ b/TestingApp/Settings/Cells/SettingsTextCell.swift @@ -2,31 +2,68 @@ import UIKit class SettingsTextCell: SettingsCell { let textField = UITextField() + var button: UIButton? - init(title: String, text: String) { + init( + title: String, + text: String, + isRequired: Bool = false, + extraButton: ExtraButton? = nil + ) { textField.text = text + if let extraButton { + self.button = .init(type: .system) + self.button?.setTitle(extraButton.title, for: .normal) + self.button?.addTarget(extraButton, action: #selector(extraButton.onTouchUpInside), for: .touchUpInside) + } + self.extraButton = extraButton + self.isRequired = isRequired + super.init(title: title) + + if isRequired { + let attributedString = NSMutableAttributedString(string: "\(title) *") + attributedString.setAttributes([.foregroundColor: UIColor.red.cgColor], range: .init(location: attributedString.length - 1, length: 1)) + titleLabel.attributedText = attributedString + } setup() layout() } + // MARK: - Private + + private let extraButton: ExtraButton? + private let isRequired: Bool + private func setup() { textField.borderStyle = .roundedRect textField.autocorrectionType = .no textField.autocapitalizationType = .none + if let button { + addSubview(button) + } } private func layout() { - contentView.addSubview(textField) - textField.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - constraints += textField.widthAnchor.constraint( - equalTo: contentView.widthAnchor, - multiplier: 0.7 - ) - constraints += textField.leadingAnchor.constraint(greaterThanOrEqualTo: titleLabel.trailingAnchor, constant: 10) - let insets = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 20) - constraints += textField.layoutInSuperview(edges: .vertical, insets: insets) - constraints += textField.layoutInSuperview(edges: .trailing, insets: insets) + contentStackView.addArrangedSubview(textField) + if let button { + contentStackView.addArrangedSubview(button) + } + } +} + +extension SettingsTextCell { + class ExtraButton { + let title: String + let tap: () -> Void + + init(title: String, tap: @escaping () -> Void) { + self.title = title + self.tap = tap + } + + @objc func onTouchUpInside() { + tap() + } } } diff --git a/TestingApp/Settings/SettingsViewController.swift b/TestingApp/Settings/SettingsViewController.swift index b240e0a3d..0cfdd1eaa 100644 --- a/TestingApp/Settings/SettingsViewController.swift +++ b/TestingApp/Settings/SettingsViewController.swift @@ -97,22 +97,48 @@ private extension SettingsViewController { private func createCells() { siteApiKeyIdCell = SettingsTextCell( title: "Identifier:", - text: props.config.siteApiKeyId + text: props.config.siteApiKeyId, + isRequired: true ) siteApiKeyIdCell.textField.accessibilityIdentifier = "settings_siteApiKeyId_textfield" siteApiKeySecretCell = SettingsTextCell( title: "Secret:", - text: props.config.siteApiKeySecret + text: props.config.siteApiKeySecret, + isRequired: true ) siteApiKeySecretCell.textField.accessibilityIdentifier = "settings_siteApiKeySecret_textfield" siteCell = SettingsTextCell( title: "Site:", - text: props.config.site + text: props.config.site, + isRequired: true ) siteCell.textField.accessibilityIdentifier = "settings_siteId_textfield" queueIDCell = SettingsTextCell( title: "Queue ID:", - text: props.queueId + text: props.queueId, + extraButton: .init(title: "List queues", tap: { [weak self] in + let alert = UIAlertController(title: "List queues", message: "Please choose queue", preferredStyle: .alert) + + Glia.sharedInstance.listQueues { [weak self] result in + switch result { + case .success(let queues): + queues.forEach { queue in + alert.addAction(.init(title: queue.name, style: .default) { _ in + self?.queueIDCell.textField.text = queue.id + self?.props.changeQueueId(queue.id) + alert.dismiss(animated: true) + }) + } + case .failure(let failure): + let action = UIAlertAction(title: "\(failure)", style: .default) + action.isEnabled = false + alert.addAction(action) + } + alert.addAction(.init(title: "Close", style: .cancel)) + } + + self?.present(alert, animated: true) + }) ) queueIDCell.textField.accessibilityIdentifier = "settings_queueId_textfield" environmentCell = EnvironmentSettingsTextCell( diff --git a/TestingApp/ViewController/ViewController.swift b/TestingApp/ViewController/ViewController.swift index c7c718fdb..93d364ed1 100644 --- a/TestingApp/ViewController/ViewController.swift +++ b/TestingApp/ViewController/ViewController.swift @@ -129,10 +129,7 @@ class ViewController: UIViewController { // only if such engagement exists, we need // to configure SDK, and only then attempt // to end engagement. - try Glia.sharedInstance.configure( - with: configuration, - queueId: queueId - ) { + try Glia.sharedInstance.configure(with: configuration) { Glia.sharedInstance.endEngagement { result in print("End engagement operation has been executed. Result='\(result)'.") } @@ -220,7 +217,6 @@ extension ViewController { do { try Glia.sharedInstance.configure( with: configuration, - queueId: queueId, uiConfig: uiConfig ) { completion("SDK has been configured")