From 75e856cbeab8ff3d1baf409092203c0d851d82a9 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 May 2023 14:48:37 -0500 Subject: [PATCH 01/11] adding Tabs Signed-off-by: Matt Bruce --- VDSSample.xcodeproj/project.pbxproj | 4 ++ .../ViewControllers/MenuViewController.swift | 1 + .../ViewControllers/TabsViewController.swift | 57 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 VDSSample/ViewControllers/TabsViewController.swift diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index a4bfff5..0223583 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ EA3C3BB628996775000CA526 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB228996775000CA526 /* MenuViewController.swift */; }; EA3C3BB728996775000CA526 /* ToggleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB328996775000CA526 /* ToggleViewController.swift */; }; EA4DB30428DCD25B00103EE3 /* BadgeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4DB30328DCD25B00103EE3 /* BadgeViewController.swift */; }; + EA596ABA2A16B2ED00300C4B /* TabsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA596AB92A16B2ED00300C4B /* TabsViewController.swift */; }; EA5E3050294D11540082B959 /* TileContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E304F294D11540082B959 /* TileContainerViewController.swift */; }; EA5E30552950EA6E0082B959 /* TitleLockupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */; }; EA5E305C295111050082B959 /* TileletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305B295111050082B959 /* TileletViewController.swift */; }; @@ -133,6 +134,7 @@ EA3C3BB228996775000CA526 /* MenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuViewController.swift; sourceTree = ""; }; EA3C3BB328996775000CA526 /* ToggleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleViewController.swift; sourceTree = ""; }; EA4DB30328DCD25B00103EE3 /* BadgeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeViewController.swift; sourceTree = ""; }; + EA596AB92A16B2ED00300C4B /* TabsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsViewController.swift; sourceTree = ""; }; EA5E304F294D11540082B959 /* TileContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainerViewController.swift; sourceTree = ""; }; EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupViewController.swift; sourceTree = ""; }; EA5E305B295111050082B959 /* TileletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletViewController.swift; sourceTree = ""; }; @@ -303,6 +305,7 @@ EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */, EAF7F11928A14A0E00B287F5 /* RadioButtonViewController.swift */, EA84F76128BE4AE500D67ABC /* RadioSwatchGroupViewController.swift */, + EA596AB92A16B2ED00300C4B /* TabsViewController.swift */, EA985C24296E06EA00F2FF2E /* TextAreaViewController.swift */, EAC9257F29119FC400091998 /* TextLinkViewController.swift */, EA0FC2C02912DC5500DF80B4 /* TextLinkCaretViewController.swift */, @@ -485,6 +488,7 @@ EA89204828B66CE2006B9984 /* ScrollViewKeyboardAvoiding.swift in Sources */, EA0FC2C12912DC5500DF80B4 /* TextLinkCaretViewController.swift in Sources */, EAF7F09C2899B92400B287F5 /* CheckboxViewController.swift in Sources */, + EA596ABA2A16B2ED00300C4B /* TabsViewController.swift in Sources */, EA89204E28B67332006B9984 /* CheckBoxGroupViewController.swift in Sources */, EAA5EEAD28EB6924003B3210 /* InputFieldViewController.swift in Sources */, EA985C25296E06EA00F2FF2E /* TextAreaViewController.swift in Sources */, diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index 7d19262..2ac4362 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -85,6 +85,7 @@ class MenuViewController: UITableViewController { MenuComponent(title: "RadioBoxGroup", completed: true, viewController: RadioBoxGroupViewController.self), MenuComponent(title: "RadioButtonGroup", completed: true, viewController: RadioButtonViewController.self), MenuComponent(title: "RadioSwatchGroup", completed: true, viewController: RadioSwatchGroupViewController.self), + MenuComponent(title: "Tabs", completed: false, viewController: TabsViewController.self), MenuComponent(title: "TextArea", completed: false, viewController: TextAreaViewController.self), MenuComponent(title: "TextLink", completed: true, viewController: TextLinkViewController.self), MenuComponent(title: "TextLinkCaret", completed: true, viewController: TextLinkCaretViewController.self), diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift new file mode 100644 index 0000000..6e0e25b --- /dev/null +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -0,0 +1,57 @@ +// +// TabsViewController.swift +// VDSSample +// +// Created by Matt Bruce on 5/18/23. +// + +import Foundation +import UIKit +import VDS +import Combine +import VDSColorTokens + +class TabsViewController: BaseViewController { + + var disabledSwitch = Toggle() + + override func viewDidLoad() { + super.viewDidLoad() + addContentTopView(view: component) + setupPicker() + setupModel() + } + + override func setupForm(){ + super.setupForm() + addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) + addFormRow(label: "Surface", view: surfacePickerSelectorView) + + } + + func setupModel() { + component.overflow = .scroll + component.updateTabItems(with: [ + TabItemModel(text: "All", width: 200), + TabItemModel(text: "Work Devices", width: 250), + TabItemModel(text: "3", width: 100), + TabItemModel(text: "4"), + TabItemModel(text: "5"), + TabItemModel(text: "6 Devices"), + TabItemModel(text: "7 Devices"), + TabItemModel(text: "8 Devices"), + TabItemModel(text: "9 Devices"), + TabItemModel(text: "10 Devices") + ]) + //setup UI + surfacePickerSelectorView.text = component.surface.rawValue + disabledSwitch.isOn = component.disabled + } + + func setupPicker(){ + surfacePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.surface = item + self?.contentTopView.backgroundColor = item.color + } + } +} From 013da49ac1d70b728cecc42b3b89cede8bc12309 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 22 May 2023 16:20:02 -0500 Subject: [PATCH 02/11] added tabs sample Signed-off-by: Matt Bruce --- VDSSample.xcodeproj/project.pbxproj | 2 +- .../ViewControllers/TabsViewController.swift | 170 ++++++++++++++++-- 2 files changed, 158 insertions(+), 14 deletions(-) diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index 0223583..8d320bd 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -306,9 +306,9 @@ EAF7F11928A14A0E00B287F5 /* RadioButtonViewController.swift */, EA84F76128BE4AE500D67ABC /* RadioSwatchGroupViewController.swift */, EA596AB92A16B2ED00300C4B /* TabsViewController.swift */, + EA0FC2C02912DC5500DF80B4 /* TextLinkCaretViewController.swift */, EA985C24296E06EA00F2FF2E /* TextAreaViewController.swift */, EAC9257F29119FC400091998 /* TextLinkViewController.swift */, - EA0FC2C02912DC5500DF80B4 /* TextLinkCaretViewController.swift */, EA5E304F294D11540082B959 /* TileContainerViewController.swift */, EA5E305B295111050082B959 /* TileletViewController.swift */, EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */, diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift index 6e0e25b..3337024 100644 --- a/VDSSample/ViewControllers/TabsViewController.swift +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -14,7 +14,59 @@ import VDSColorTokens class TabsViewController: BaseViewController { var disabledSwitch = Toggle() + var borderlineSwitch = Toggle() + var fillContainerSwitch = Toggle() + var sampleSwitch = Toggle() + var widthValueTextField = NumericField() + var widthPercentageTextField = NumericField() + + var verticalOrientationFormStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fillProportionally + $0.axis = .vertical + $0.spacing = 10 + $0.isHidden = true + } + }() + + var horizontalOrientationFormStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fillProportionally + $0.axis = .vertical + $0.spacing = 10 + } + }() + + override func allTextFields() -> [TextField]? { [widthValueTextField, widthPercentageTextField] } + lazy var orientationPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Orientation.allCases) + }() + + lazy var indicatorPositionPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.IndicatorPosition.allCases) + }() + + lazy var sizePickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Size.allCases) + }() + + lazy var overflowPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Overflow.allCases) + }() + override func viewDidLoad() { super.viewDidLoad() addContentTopView(view: component) @@ -24,28 +76,90 @@ class TabsViewController: BaseViewController { override func setupForm(){ super.setupForm() + addFormRow(label: "Large Sample", view: .makeWrapper(for: sampleSwitch)) addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) + addFormRow(label: "Show Borderline", view: .makeWrapper(for: borderlineSwitch)) addFormRow(label: "Surface", view: surfacePickerSelectorView) + addFormRow(label: "Size", view: sizePickerSelectorView) + if UIDevice.isIPad { + addFormRow(label: "Orientation", view: orientationPickerSelectorView) + //only in vertical mode + addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) + addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) + } + + //only in horizontal mode + addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) + addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) + + formStackView.addArrangedSubview(verticalOrientationFormStackView) + formStackView.addArrangedSubview(horizontalOrientationFormStackView) + + disabledSwitch.onChange = { [weak self] sender in + self?.component.disabled = sender.isOn + } + + borderlineSwitch.onChange = { [weak self] sender in + self?.component.borderLine = sender.isOn + } + + fillContainerSwitch.onChange = { [weak self] sender in + self?.component.fillContainer = sender.isOn + } + + sampleSwitch.onChange = { [weak self] sender in + guard let self else { return } + self.component.selectedIndex = 0 + self.component.tabModels = sender.isOn ? self.allTabs : self.some + } + + widthValueTextField.textPublisher.sink { [weak self] text in + if let value = Double(text) { + self?.component.width = .value(value) + self?.widthPercentageTextField.text = "" + + } + }.store(in: &subscribers) + + widthPercentageTextField.textPublisher.sink { [weak self] text in + if let value = Double(text) { + self?.component.width = .percentage(value) + self?.widthValueTextField.text = "" + } + }.store(in: &subscribers) + } + var allTabs: [TabModel] = [ + TabModel(text: "All"), + TabModel(text: "Work Devices"), + TabModel(text: "Customer Service"), + TabModel(text: "Help") + ] + + var some: [TabModel] = [ + TabModel(text: "All"), + TabModel(text: "Work Devices") + ] + func setupModel() { - component.overflow = .scroll - component.updateTabItems(with: [ - TabItemModel(text: "All", width: 200), - TabItemModel(text: "Work Devices", width: 250), - TabItemModel(text: "3", width: 100), - TabItemModel(text: "4"), - TabItemModel(text: "5"), - TabItemModel(text: "6 Devices"), - TabItemModel(text: "7 Devices"), - TabItemModel(text: "8 Devices"), - TabItemModel(text: "9 Devices"), - TabItemModel(text: "10 Devices") - ]) + //set to the large sample + component.tabModels = allTabs + component.selectedIndex = 3 + + //setup UI surfacePickerSelectorView.text = component.surface.rawValue + sizePickerSelectorView.text = component.size.rawValue + orientationPickerSelectorView.text = component.orientation.rawValue + indicatorPositionPickerSelectorView.text = component.indicatorPosition.rawValue + overflowPickerSelectorView.text = component.overflow.rawValue disabledSwitch.isOn = component.disabled + borderlineSwitch.isOn = component.borderLine + fillContainerSwitch.isOn = component.fillContainer + sampleSwitch.isOn = true + updateWidth() } func setupPicker(){ @@ -53,5 +167,35 @@ class TabsViewController: BaseViewController { self?.component.surface = item self?.contentTopView.backgroundColor = item.color } + + sizePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.size = item + } + + orientationPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.orientation = item + self?.verticalOrientationFormStackView.isHidden = item == .horizontal + self?.horizontalOrientationFormStackView.isHidden = item == .vertical + } + + indicatorPositionPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.indicatorPosition = item + } + + overflowPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.overflow = item + } + } + + func updateWidth() { + switch component.width { + case .percentage(let percentage): + widthPercentageTextField.text = "\(percentage)" + case .value(let value): + widthValueTextField.text = "\(value)" + widthPercentageTextField.text = "" + @unknown default: + print("") + } } } From d9cfffe6c51da9fd3060f1e93fc9cdc7644313dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 23 May 2023 12:29:59 -0500 Subject: [PATCH 03/11] added release notes Signed-off-by: Matt Bruce --- .../ViewControllers/MenuViewController.swift | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index 2ac4362..7e153c7 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -63,13 +63,29 @@ class MenuCell: UITableViewCell { } } -class MenuViewController: UITableViewController { +class MenuViewController: UITableViewController, TooltipLaunchable { override func viewDidLoad() { + title = "VDS Sample: Build \(Bundle.main.buildNumber ?? "none")" + let tooltip = VDS.Tooltip() + tooltip.title = "Release Notes" + tooltip.content = getReleaseNotes() + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: tooltip) // UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(buildInfoTapped)) super.viewDidLoad() overrideUserInterfaceStyle = .light tableView.register(MenuCell.self, forCellReuseIdentifier: "cell") } + func getReleaseNotes() -> String { + let bundle = VDS.Bundle(for: VDS.Badge.self) + guard let fileURL = bundle.url(forResource: "ReleaseNotes", withExtension: "txt") else { return "none" } + do { + return try String(contentsOf: fileURL) + } catch { + print("error reading releaseNotes") + return "none" + } + } + let items: [MenuComponent] = [ MenuComponent(title: "Badge", completed: true, viewController: BadgeViewController.self), MenuComponent(title: "Button", completed: true, viewController: ButtonViewController.self), @@ -150,3 +166,9 @@ class MenuViewController: UITableViewController { } } } + +extension Bundle { + var buildNumber: String? { + infoDictionary?["CFBundleVersion"] as? String + } +} From b49d3f736c66087c7d91aa27f64552e0e82dfe18 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 23 May 2023 12:30:59 -0500 Subject: [PATCH 04/11] fixed tabs Signed-off-by: Matt Bruce --- VDSSample/ViewControllers/TabsViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift index 3337024..175a44a 100644 --- a/VDSSample/ViewControllers/TabsViewController.swift +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -90,6 +90,7 @@ class TabsViewController: BaseViewController { } //only in horizontal mode + addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch), stackView: horizontalOrientationFormStackView) addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) From d1f5245df0f82949b46ea53c7713bbb6fc7e1c59 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 24 May 2023 18:37:11 -0500 Subject: [PATCH 05/11] Added tabs Signed-off-by: Matt Bruce --- .../ViewControllers/TabsViewController.swift | 80 +++++++++---------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift index 175a44a..d9fed6b 100644 --- a/VDSSample/ViewControllers/TabsViewController.swift +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -84,9 +84,9 @@ class TabsViewController: BaseViewController { if UIDevice.isIPad { addFormRow(label: "Orientation", view: orientationPickerSelectorView) - //only in vertical mode - addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) - addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) +// //only in vertical mode +// addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) +// addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) } //only in horizontal mode @@ -94,7 +94,7 @@ class TabsViewController: BaseViewController { addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) - formStackView.addArrangedSubview(verticalOrientationFormStackView) +// formStackView.addArrangedSubview(verticalOrientationFormStackView) formStackView.addArrangedSubview(horizontalOrientationFormStackView) disabledSwitch.onChange = { [weak self] sender in @@ -115,40 +115,38 @@ class TabsViewController: BaseViewController { self.component.tabModels = sender.isOn ? self.allTabs : self.some } - widthValueTextField.textPublisher.sink { [weak self] text in - if let value = Double(text) { - self?.component.width = .value(value) - self?.widthPercentageTextField.text = "" - - } - }.store(in: &subscribers) - - widthPercentageTextField.textPublisher.sink { [weak self] text in - if let value = Double(text) { - self?.component.width = .percentage(value) - self?.widthValueTextField.text = "" - } - }.store(in: &subscribers) +// widthValueTextField.textPublisher.sink { [weak self] text in +// if let value = Double(text) { +// self?.component.width = .value(value) +// self?.widthPercentageTextField.text = "" +// +// } +// }.store(in: &subscribers) +// +// widthPercentageTextField.textPublisher.sink { [weak self] text in +// if let value = Double(text) { +// self?.component.width = .percentage(value) +// self?.widthValueTextField.text = "" +// } +// }.store(in: &subscribers) } - var allTabs: [TabModel] = [ - TabModel(text: "All"), - TabModel(text: "Work Devices"), - TabModel(text: "Customer Service"), - TabModel(text: "Help") + var allTabs: [Tabs.TabModel] = [ + .init(text: "Accessories"), + .init(text: "Internet and TV"), + .init(text: "Customer Service"), + .init(text: "Contact Us") ] - var some: [TabModel] = [ - TabModel(text: "All"), - TabModel(text: "Work Devices") + var some: [Tabs.TabModel] = [ + .init(text: "Accessories"), + .init(text: "Internet and TV") ] func setupModel() { //set to the large sample - component.tabModels = allTabs - component.selectedIndex = 3 - + component.tabModels = allTabs //setup UI surfacePickerSelectorView.text = component.surface.rawValue @@ -160,7 +158,7 @@ class TabsViewController: BaseViewController { borderlineSwitch.isOn = component.borderLine fillContainerSwitch.isOn = component.fillContainer sampleSwitch.isOn = true - updateWidth() +// updateWidth() } func setupPicker(){ @@ -188,15 +186,15 @@ class TabsViewController: BaseViewController { } } - func updateWidth() { - switch component.width { - case .percentage(let percentage): - widthPercentageTextField.text = "\(percentage)" - case .value(let value): - widthValueTextField.text = "\(value)" - widthPercentageTextField.text = "" - @unknown default: - print("") - } - } +// func updateWidth() { +// switch component.width { +// case .percentage(let percentage): +// widthPercentageTextField.text = "\(percentage)" +// case .value(let value): +// widthValueTextField.text = "\(value)" +// widthPercentageTextField.text = "" +// @unknown default: +// print("") +// } +// } } From d9d37059279d5fd8e2023158ebcc5c3a5614b248 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 24 May 2023 19:18:06 -0500 Subject: [PATCH 06/11] initial tabscontainer Signed-off-by: Matt Bruce --- VDSSample.xcodeproj/project.pbxproj | 4 + .../ViewControllers/MenuViewController.swift | 3 +- .../TabsContainerViewController.swift | 399 ++++++++++++++++++ 3 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 VDSSample/ViewControllers/TabsContainerViewController.swift diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index 8d320bd..abcbff8 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ EA5E3050294D11540082B959 /* TileContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E304F294D11540082B959 /* TileContainerViewController.swift */; }; EA5E30552950EA6E0082B959 /* TitleLockupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */; }; EA5E305C295111050082B959 /* TileletViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305B295111050082B959 /* TileletViewController.swift */; }; + EA5F86CE2A1E863F00BC83E4 /* TabsContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5F86CD2A1E863F00BC83E4 /* TabsContainerViewController.swift */; }; EA81410E2A0ED8DC004F60D2 /* ButtonIconViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410D2A0ED8DC004F60D2 /* ButtonIconViewController.swift */; }; EA84F76228BE4AE500D67ABC /* RadioSwatchGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA84F76128BE4AE500D67ABC /* RadioSwatchGroupViewController.swift */; }; EA89201928B56DF5006B9984 /* RadioBoxGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */; }; @@ -138,6 +139,7 @@ EA5E304F294D11540082B959 /* TileContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainerViewController.swift; sourceTree = ""; }; EA5E30542950EA6E0082B959 /* TitleLockupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupViewController.swift; sourceTree = ""; }; EA5E305B295111050082B959 /* TileletViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletViewController.swift; sourceTree = ""; }; + EA5F86CD2A1E863F00BC83E4 /* TabsContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsContainerViewController.swift; sourceTree = ""; }; EA81410D2A0ED8DC004F60D2 /* ButtonIconViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconViewController.swift; sourceTree = ""; }; EA84F76128BE4AE500D67ABC /* RadioSwatchGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchGroupViewController.swift; sourceTree = ""; }; EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBoxGroupViewController.swift; sourceTree = ""; }; @@ -305,6 +307,7 @@ EA89201828B56DF5006B9984 /* RadioBoxGroupViewController.swift */, EAF7F11928A14A0E00B287F5 /* RadioButtonViewController.swift */, EA84F76128BE4AE500D67ABC /* RadioSwatchGroupViewController.swift */, + EA5F86CD2A1E863F00BC83E4 /* TabsContainerViewController.swift */, EA596AB92A16B2ED00300C4B /* TabsViewController.swift */, EA0FC2C02912DC5500DF80B4 /* TextLinkCaretViewController.swift */, EA985C24296E06EA00F2FF2E /* TextAreaViewController.swift */, @@ -495,6 +498,7 @@ EA81410E2A0ED8DC004F60D2 /* ButtonIconViewController.swift in Sources */, EA985C20296DECF600F2FF2E /* IconName.swift in Sources */, EA89204928B66CE2006B9984 /* KeyboardFrameChangeListening.swift in Sources */, + EA5F86CE2A1E863F00BC83E4 /* TabsContainerViewController.swift in Sources */, EA985C01296CC21C00F2FF2E /* IconViewController.swift in Sources */, EAC9258029119FC400091998 /* TextLinkViewController.swift in Sources */, EAB1D2D428AC409F00DAE764 /* LabelViewController.swift in Sources */, diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index 7e153c7..e437e08 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -101,7 +101,8 @@ class MenuViewController: UITableViewController, TooltipLaunchable { MenuComponent(title: "RadioBoxGroup", completed: true, viewController: RadioBoxGroupViewController.self), MenuComponent(title: "RadioButtonGroup", completed: true, viewController: RadioButtonViewController.self), MenuComponent(title: "RadioSwatchGroup", completed: true, viewController: RadioSwatchGroupViewController.self), - MenuComponent(title: "Tabs", completed: false, viewController: TabsViewController.self), + MenuComponent(title: "TabsContainer", completed: false, viewController: TabsContainerViewController.self), + MenuComponent(title: "Tabs", completed: true, viewController: TabsViewController.self), MenuComponent(title: "TextArea", completed: false, viewController: TextAreaViewController.self), MenuComponent(title: "TextLink", completed: true, viewController: TextLinkViewController.self), MenuComponent(title: "TextLinkCaret", completed: true, viewController: TextLinkCaretViewController.self), diff --git a/VDSSample/ViewControllers/TabsContainerViewController.swift b/VDSSample/ViewControllers/TabsContainerViewController.swift new file mode 100644 index 0000000..38ec7a4 --- /dev/null +++ b/VDSSample/ViewControllers/TabsContainerViewController.swift @@ -0,0 +1,399 @@ +// +// TabViewContainerViewController.swift +// VDSSample +// +// Created by Matt Bruce on 5/24/23. +// + +import Foundation +import UIKit +import VDS +import Combine +import VDSColorTokens + +class TabsContainerViewController: BaseViewController { + + var disabledSwitch = Toggle() + var borderlineSwitch = Toggle() + var fillContainerSwitch = Toggle() + var sampleSwitch = Toggle() + var widthValueTextField = NumericField() + var widthPercentageTextField = NumericField() + + var verticalOrientationFormStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fill + $0.axis = .vertical + $0.spacing = 10 + $0.isHidden = true + } + }() + + var horizontalOrientationFormStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fill + $0.axis = .vertical + $0.spacing = 10 + } + }() + + override func allTextFields() -> [TextField]? { [widthValueTextField, widthPercentageTextField] } + + lazy var orientationPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Orientation.allCases) + }() + + lazy var indicatorPositionPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.IndicatorPosition.allCases) + }() + + lazy var sizePickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Size.allCases) + }() + + lazy var overflowPickerSelectorView = { + PickerSelectorView(title: "", + picker: self.picker, + items: Tabs.Overflow.allCases) + }() + + override func viewDidLoad() { + super.viewDidLoad() + addContentTopView(view: component) + setupPicker() + setupModel() + } + + override func setupForm(){ + super.setupForm() + addFormRow(label: "Large Sample", view: .makeWrapper(for: sampleSwitch)) + addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) + addFormRow(label: "Show Borderline", view: .makeWrapper(for: borderlineSwitch)) + addFormRow(label: "Surface", view: surfacePickerSelectorView) + addFormRow(label: "Size", view: sizePickerSelectorView) + + if UIDevice.isIPad { + addFormRow(label: "Orientation", view: orientationPickerSelectorView) + //only in vertical mode + addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) + addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) + } + + //only in horizontal mode + addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch), stackView: horizontalOrientationFormStackView) + addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) + addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) + + formStackView.addArrangedSubview(verticalOrientationFormStackView) + formStackView.addArrangedSubview(horizontalOrientationFormStackView) + + disabledSwitch.onChange = { [weak self] sender in + self?.component.disabled = sender.isOn + } + + borderlineSwitch.onChange = { [weak self] sender in + self?.component.borderLine = sender.isOn + } + + fillContainerSwitch.onChange = { [weak self] sender in + self?.component.fillContainer = sender.isOn + } + + sampleSwitch.onChange = { [weak self] sender in + guard let self else { return } + self.component.selectedIndex = 0 + self.component.tabModels = sender.isOn ? self.getAllTabs() : self.getSomeTabs() + } + + widthValueTextField.textPublisher.sink { [weak self] text in + if let value = Double(text) { + self?.component.width = .value(value) + self?.widthPercentageTextField.text = "" + + } + }.store(in: &subscribers) + + widthPercentageTextField.textPublisher.sink { [weak self] text in + if let value = Double(text) { + self?.component.width = .percentage(value) + self?.widthValueTextField.text = "" + } + }.store(in: &subscribers) + + } + + func getTabs(texts:[String]) -> [TabsContainer.TabModel] { + texts.compactMap { + let label = Label() + label.text = "This is an example of the \($0) Tab. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + return TabsContainer.TabModel(model: .init(text: $0), view: label) + } + } + + func getAllTabs() -> [TabsContainer.TabModel] { + getTabs(texts: ["Accessories", "Internet and TV", "Customer Service", "Contact Us"]) + } + + func getSomeTabs() -> [TabsContainer.TabModel] { + getTabs(texts: ["Accessories", "Internet and TV"]) + } + + func setupModel() { + //set to the large sample + component.tabModels = getAllTabs() + + //setup UI + surfacePickerSelectorView.text = component.surface.rawValue + sizePickerSelectorView.text = component.size.rawValue + orientationPickerSelectorView.text = component.orientation.rawValue + indicatorPositionPickerSelectorView.text = component.indicatorPosition.rawValue + overflowPickerSelectorView.text = component.overflow.rawValue + disabledSwitch.isOn = component.disabled + borderlineSwitch.isOn = component.borderLine + fillContainerSwitch.isOn = component.fillContainer + sampleSwitch.isOn = true + updateWidth() + } + + func setupPicker(){ + surfacePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.surface = item + self?.contentTopView.backgroundColor = item.color + } + + sizePickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.size = item + } + + orientationPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.orientation = item + self?.verticalOrientationFormStackView.isHidden = item == .horizontal + self?.horizontalOrientationFormStackView.isHidden = item == .vertical + } + + indicatorPositionPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.indicatorPosition = item + } + + overflowPickerSelectorView.onPickerDidSelect = { [weak self] item in + self?.component.overflow = item + } + } + + func updateWidth() { + switch component.width { + case .percentage(let percentage): + widthPercentageTextField.text = "\(percentage)" + case .value(let value): + widthValueTextField.text = "\(value)" + widthPercentageTextField.text = "" + @unknown default: + print("") + } + } + +} + +open class TabsContainer: View { + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var tabMenu = Tabs() + + ///An optional callback that is called when the selectedIndex changes. Passes parameters (event, tabIndex). + open var onTabChange: ((Int) -> Void)? + + ///Determines the layout of the Tabs, defaults to horizontal + open var orientation: Tabs.Orientation = .horizontal { didSet { setNeedsUpdate() } } + + ///When true, Tabs will have border line. If false is passed then the border line won't be visible. + open var borderLine: Bool = true { didSet { setNeedsUpdate() } } + + ///It will fill the Tabs to the width of the compoent and all Tabs will be in equal width when orientation is horizontal. This is recommended when there are no more than 2-3 tabs. + open var fillContainer: Bool = false { didSet { setNeedsUpdate() } } + + ///When true, Tabs will be sticky to top of page, when orientation is vertical. + open var indicatorFillTab: Bool = false { didSet { setNeedsUpdate() } } + + ///Sets the Position of the Selected/Hover Border Accent for All Tabs, only for Horizontal Orientation + open var indicatorPosition: Tabs.IndicatorPosition = .bottom { didSet { setNeedsUpdate() } } + + ///Minimum Width for All Tabs, when orientation is horizontal. + open var minWidth: CGFloat = 44.0 { didSet { setNeedsUpdate() } } + + ///If set to 'scroll', Tabs can be overflow and scrollable. With 'none', tabs will not overflow and labels will be wrapped to multiple lines if the label text is long. + open var overflow: Tabs.Overflow = .scroll { didSet { setNeedsUpdate() } } + + ///The initial Selected Tab's index and is set once a Tab is clicked + open var selectedIndex: Int = 0 { didSet { setNeedsUpdate() } } + + ///Determines the size of the Tabs TextStyle + open var size: Tabs.Size = .medium { didSet { setNeedsUpdate() } } + + ///When true, Tabs will be sticky to top of page, when orientation is vertical. + open var sticky: Bool = false { didSet { setNeedsUpdate() } } + + ///rules for width + private var _width: Tabs.Width = .percentage(0.25) + + ///Width of all Tabs when orientation is vertical, defaults to 25%. + open var width: Tabs.Width { + get { + return _width + } + set { + switch newValue { + case .percentage(let percentage): + if percentage >= 0 && percentage <= 1 { + _width = newValue + setNeedsUpdate() + } else { + print("Invalid percentage value. It should be between 0 and 1.") + } + case .value(let value): + if value >= minWidth { + _width = newValue + setNeedsUpdate() + } else { + print("Invalid value. It should be greater than or equal to \(minWidth).") + } + @unknown default: + print("new value passed.") + } + } + } + + ///Model of the Tabs you are wanting to show. + open var tabModels: [TabModel] = [] { + didSet { + tabMenu.tabModels = tabModels.compactMap{ $0.model } + bottomView.arrangedSubviews.forEach{ $0.removeFromSuperview() } + tabModels.forEach { + var view = $0.view + view.isHidden = true + bottomView.addArrangedSubview($0.view) + } + setNeedsUpdate() + } + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var contentViewWidthConstraint: NSLayoutConstraint? + + private var stackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .vertical + $0.spacing = 5 + $0.alignment = .fill + $0.distribution = .fill + } + + private var bottomView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fillProportionally + $0.axis = .vertical + $0.spacing = 10 + } + + private var tabMenuLayoutGuide = UILayoutGuide() + + open override func setup() { + super.setup() + tabMenu.addLayoutGuide(tabMenuLayoutGuide) + addSubview(stackView) + stackView.pinToSuperView() + stackView.addArrangedSubview(tabMenu) + stackView.addArrangedSubview(bottomView) + + NSLayoutConstraint.activate([ + tabMenuLayoutGuide.topAnchor.constraint(equalTo: topAnchor), + tabMenuLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), + tabMenuLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), + tabMenuLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor) + ]) + } + + open override func updateView() { + super.updateView() + stackView.alignment = orientation == .horizontal ? .fill : .top + stackView.axis = orientation == .horizontal ? .vertical : .horizontal + + tabMenu.onTabChange = { [weak self] index in + guard let self else { return } + self.tabClicked(index: index) + } + + contentViewWidthConstraint?.isActive = false + + if orientation == .vertical { + switch width { + case .percentage(let amount): + contentViewWidthConstraint = tabMenu.widthAnchor.constraint(equalTo: tabMenuLayoutGuide.widthAnchor, multiplier: amount) + case .value(let amount): + contentViewWidthConstraint = tabMenu.widthAnchor.constraint(equalToConstant: amount) + @unknown default: break + } + contentViewWidthConstraint?.isActive = true + } + + tabMenu.surface = surface + tabMenu.disabled = disabled + tabMenu.orientation = orientation + tabMenu.borderLine = borderLine + tabMenu.fillContainer = fillContainer + tabMenu.indicatorFillTab = indicatorFillTab + tabMenu.indicatorPosition = indicatorPosition + tabMenu.minWidth = minWidth + tabMenu.overflow = overflow + tabMenu.selectedIndex = selectedIndex + tabMenu.size = size + tabMenu.sticky = sticky + + setSelected(index: selectedIndex) + + tabModels.forEach { + var view = $0.view + view.surface = surface + } + } + + private func tabClicked(index: Int) { + onTabChange?(index) + setSelected(index: index) + } + + private func setSelected(index: Int) { + for (modelIndex, model) in tabModels.enumerated() { + var view = model.view + let shouldShow = index == modelIndex + view.isHidden = !shouldShow + } + } +} + +extension TabsContainer { + public struct TabModel { + public typealias AnySurfaceableView = UIView & Surfaceable + public var model: Tabs.TabModel + public var view: AnySurfaceableView + + public init(model: Tabs.TabModel, view: AnySurfaceableView) { + self.model = model + self.view = view + } + } +} From 089020c64b1483e08df9f9545e9a18a1e60306b2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 25 May 2023 08:04:28 -0500 Subject: [PATCH 07/11] removed tabscontainer and pushed to vds Signed-off-by: Matt Bruce --- .../TabsContainerViewController.swift | 195 ------------------ 1 file changed, 195 deletions(-) diff --git a/VDSSample/ViewControllers/TabsContainerViewController.swift b/VDSSample/ViewControllers/TabsContainerViewController.swift index 38ec7a4..41588db 100644 --- a/VDSSample/ViewControllers/TabsContainerViewController.swift +++ b/VDSSample/ViewControllers/TabsContainerViewController.swift @@ -201,199 +201,4 @@ class TabsContainerViewController: BaseViewController { print("") } } - -} - -open class TabsContainer: View { - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - open var tabMenu = Tabs() - - ///An optional callback that is called when the selectedIndex changes. Passes parameters (event, tabIndex). - open var onTabChange: ((Int) -> Void)? - - ///Determines the layout of the Tabs, defaults to horizontal - open var orientation: Tabs.Orientation = .horizontal { didSet { setNeedsUpdate() } } - - ///When true, Tabs will have border line. If false is passed then the border line won't be visible. - open var borderLine: Bool = true { didSet { setNeedsUpdate() } } - - ///It will fill the Tabs to the width of the compoent and all Tabs will be in equal width when orientation is horizontal. This is recommended when there are no more than 2-3 tabs. - open var fillContainer: Bool = false { didSet { setNeedsUpdate() } } - - ///When true, Tabs will be sticky to top of page, when orientation is vertical. - open var indicatorFillTab: Bool = false { didSet { setNeedsUpdate() } } - - ///Sets the Position of the Selected/Hover Border Accent for All Tabs, only for Horizontal Orientation - open var indicatorPosition: Tabs.IndicatorPosition = .bottom { didSet { setNeedsUpdate() } } - - ///Minimum Width for All Tabs, when orientation is horizontal. - open var minWidth: CGFloat = 44.0 { didSet { setNeedsUpdate() } } - - ///If set to 'scroll', Tabs can be overflow and scrollable. With 'none', tabs will not overflow and labels will be wrapped to multiple lines if the label text is long. - open var overflow: Tabs.Overflow = .scroll { didSet { setNeedsUpdate() } } - - ///The initial Selected Tab's index and is set once a Tab is clicked - open var selectedIndex: Int = 0 { didSet { setNeedsUpdate() } } - - ///Determines the size of the Tabs TextStyle - open var size: Tabs.Size = .medium { didSet { setNeedsUpdate() } } - - ///When true, Tabs will be sticky to top of page, when orientation is vertical. - open var sticky: Bool = false { didSet { setNeedsUpdate() } } - - ///rules for width - private var _width: Tabs.Width = .percentage(0.25) - - ///Width of all Tabs when orientation is vertical, defaults to 25%. - open var width: Tabs.Width { - get { - return _width - } - set { - switch newValue { - case .percentage(let percentage): - if percentage >= 0 && percentage <= 1 { - _width = newValue - setNeedsUpdate() - } else { - print("Invalid percentage value. It should be between 0 and 1.") - } - case .value(let value): - if value >= minWidth { - _width = newValue - setNeedsUpdate() - } else { - print("Invalid value. It should be greater than or equal to \(minWidth).") - } - @unknown default: - print("new value passed.") - } - } - } - - ///Model of the Tabs you are wanting to show. - open var tabModels: [TabModel] = [] { - didSet { - tabMenu.tabModels = tabModels.compactMap{ $0.model } - bottomView.arrangedSubviews.forEach{ $0.removeFromSuperview() } - tabModels.forEach { - var view = $0.view - view.isHidden = true - bottomView.addArrangedSubview($0.view) - } - setNeedsUpdate() - } - } - - //-------------------------------------------------- - // MARK: - Private Properties - //-------------------------------------------------- - private var contentViewWidthConstraint: NSLayoutConstraint? - - private var stackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.axis = .vertical - $0.spacing = 5 - $0.alignment = .fill - $0.distribution = .fill - } - - private var bottomView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fillProportionally - $0.axis = .vertical - $0.spacing = 10 - } - - private var tabMenuLayoutGuide = UILayoutGuide() - - open override func setup() { - super.setup() - tabMenu.addLayoutGuide(tabMenuLayoutGuide) - addSubview(stackView) - stackView.pinToSuperView() - stackView.addArrangedSubview(tabMenu) - stackView.addArrangedSubview(bottomView) - - NSLayoutConstraint.activate([ - tabMenuLayoutGuide.topAnchor.constraint(equalTo: topAnchor), - tabMenuLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - tabMenuLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - tabMenuLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor) - ]) - } - - open override func updateView() { - super.updateView() - stackView.alignment = orientation == .horizontal ? .fill : .top - stackView.axis = orientation == .horizontal ? .vertical : .horizontal - - tabMenu.onTabChange = { [weak self] index in - guard let self else { return } - self.tabClicked(index: index) - } - - contentViewWidthConstraint?.isActive = false - - if orientation == .vertical { - switch width { - case .percentage(let amount): - contentViewWidthConstraint = tabMenu.widthAnchor.constraint(equalTo: tabMenuLayoutGuide.widthAnchor, multiplier: amount) - case .value(let amount): - contentViewWidthConstraint = tabMenu.widthAnchor.constraint(equalToConstant: amount) - @unknown default: break - } - contentViewWidthConstraint?.isActive = true - } - - tabMenu.surface = surface - tabMenu.disabled = disabled - tabMenu.orientation = orientation - tabMenu.borderLine = borderLine - tabMenu.fillContainer = fillContainer - tabMenu.indicatorFillTab = indicatorFillTab - tabMenu.indicatorPosition = indicatorPosition - tabMenu.minWidth = minWidth - tabMenu.overflow = overflow - tabMenu.selectedIndex = selectedIndex - tabMenu.size = size - tabMenu.sticky = sticky - - setSelected(index: selectedIndex) - - tabModels.forEach { - var view = $0.view - view.surface = surface - } - } - - private func tabClicked(index: Int) { - onTabChange?(index) - setSelected(index: index) - } - - private func setSelected(index: Int) { - for (modelIndex, model) in tabModels.enumerated() { - var view = model.view - let shouldShow = index == modelIndex - view.isHidden = !shouldShow - } - } -} - -extension TabsContainer { - public struct TabModel { - public typealias AnySurfaceableView = UIView & Surfaceable - public var model: Tabs.TabModel - public var view: AnySurfaceableView - - public init(model: Tabs.TabModel, view: AnySurfaceableView) { - self.model = model - self.view = view - } - } } From 38e7c6b8de14050a58166325bb44587603662208 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 25 May 2023 11:51:57 -0500 Subject: [PATCH 08/11] udpated base viewcontroller to fix bug in form creation Signed-off-by: Matt Bruce --- VDSSample.xcodeproj/project.pbxproj | 6 +- .../ViewControllers/BaseViewController.swift | 76 +++++++++++-------- .../TabsContainerViewController.swift | 43 ++++------- .../ViewControllers/TabsViewController.swift | 72 ++---------------- .../ToggleViewController.swift | 23 ++---- 5 files changed, 76 insertions(+), 144 deletions(-) diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index abcbff8..93bfb3b 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -651,7 +651,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 17; - DEVELOPMENT_TEAM = FCMA4QKS77; + DEVELOPMENT_TEAM = 59V5935DHZ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VDSSample/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -665,7 +665,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vzw.VDSSample; + PRODUCT_BUNDLE_IDENTIFIER = com.vzw.enterprise.VDSSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -681,7 +681,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 17; - DEVELOPMENT_TEAM = FCMA4QKS77; + DEVELOPMENT_TEAM = 59V5935DHZ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VDSSample/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; diff --git a/VDSSample/ViewControllers/BaseViewController.swift b/VDSSample/ViewControllers/BaseViewController.swift index 06fc770..08b964c 100644 --- a/VDSSample/ViewControllers/BaseViewController.swift +++ b/VDSSample/ViewControllers/BaseViewController.swift @@ -10,6 +10,45 @@ import UIKit import Combine import VDS +public class FormSection: UIStackView { + public override init(frame: CGRect) { + super.init(frame: frame) + translatesAutoresizingMaskIntoConstraints = false + alignment = .fill + distribution = .fill + axis = .vertical + spacing = 10 + } + + public convenience init() { + self.init(frame: .zero) + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func addFormRow(label: String, view: UIView) { + let formRow = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .fill + $0.distribution = .fillEqually + $0.axis = .horizontal + $0.spacing = 5 + } + + let label = Label().with { + $0.text = label + $0.textStyle = .bodyLarge + } + + formRow.addArrangedSubview(label) + formRow.addArrangedSubview(view) + + addArrangedSubview(formRow) + } +} + public class BaseViewController: UIViewController, Initable { deinit { print("\(Self.self) deinit") @@ -85,15 +124,7 @@ public class BaseViewController: UIViewController, Initable { } }() - public var formStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fill - $0.axis = .vertical - $0.spacing = 10 - } - }() + public var formStackView = FormSection() public var contentTopView: UIView = { return UIView().with { @@ -173,29 +204,12 @@ public class BaseViewController: UIViewController, Initable { view.pinToSuperView(.init(top: edgeSpacing, left: edgeSpacing, bottom: edgeSpacing, right: edgeSpacing)) } - open func addFormRow(label: String, view: UIView, stackView: UIStackView? = nil) { - let formRow = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fillEqually - $0.axis = .horizontal - $0.spacing = 5 - } - - let label = Label().with { - $0.text = label - $0.textStyle = .bodyLarge - } - - formRow.addArrangedSubview(label) - formRow.addArrangedSubview(view) - - if let stackView { - stackView.addArrangedSubview(formRow) - } else { - formStackView.addArrangedSubview(formRow) - } + open func append(section: FormSection) { + formStackView.addArrangedSubview(section) + } + open func addFormRow(label: String, view: UIView) { + formStackView.addFormRow(label: label, view: view) if let pickerViewable = view as? any PickerViewable { pickerViewable.scrollToBottom = { [weak self] in self?.scrollToBottom() } } diff --git a/VDSSample/ViewControllers/TabsContainerViewController.swift b/VDSSample/ViewControllers/TabsContainerViewController.swift index 41588db..fd33f47 100644 --- a/VDSSample/ViewControllers/TabsContainerViewController.swift +++ b/VDSSample/ViewControllers/TabsContainerViewController.swift @@ -11,8 +11,10 @@ import VDS import Combine import VDSColorTokens + + class TabsContainerViewController: BaseViewController { - + var disabledSwitch = Toggle() var borderlineSwitch = Toggle() var fillContainerSwitch = Toggle() @@ -20,26 +22,8 @@ class TabsContainerViewController: BaseViewController { var widthValueTextField = NumericField() var widthPercentageTextField = NumericField() - var verticalOrientationFormStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fill - $0.axis = .vertical - $0.spacing = 10 - $0.isHidden = true - } - }() - - var horizontalOrientationFormStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fill - $0.axis = .vertical - $0.spacing = 10 - } - }() + var verticalOrientationFormStackView = FormSection() + var horizontalOrientationFormStackView = FormSection() override func allTextFields() -> [TextField]? { [widthValueTextField, widthPercentageTextField] } @@ -77,7 +61,6 @@ class TabsContainerViewController: BaseViewController { override func setupForm(){ super.setupForm() addFormRow(label: "Large Sample", view: .makeWrapper(for: sampleSwitch)) - addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) addFormRow(label: "Show Borderline", view: .makeWrapper(for: borderlineSwitch)) addFormRow(label: "Surface", view: surfacePickerSelectorView) addFormRow(label: "Size", view: sizePickerSelectorView) @@ -85,17 +68,17 @@ class TabsContainerViewController: BaseViewController { if UIDevice.isIPad { addFormRow(label: "Orientation", view: orientationPickerSelectorView) //only in vertical mode - addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) - addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) + verticalOrientationFormStackView.addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField) + verticalOrientationFormStackView.addFormRow(label: "# Width", view: widthValueTextField) } //only in horizontal mode - addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch), stackView: horizontalOrientationFormStackView) - addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) - addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) + horizontalOrientationFormStackView.addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch)) + horizontalOrientationFormStackView.addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView) + horizontalOrientationFormStackView.addFormRow(label: "Overflow", view: overflowPickerSelectorView) - formStackView.addArrangedSubview(verticalOrientationFormStackView) - formStackView.addArrangedSubview(horizontalOrientationFormStackView) + append(section: verticalOrientationFormStackView) + append(section: horizontalOrientationFormStackView) disabledSwitch.onChange = { [weak self] sender in self?.component.disabled = sender.isOn @@ -151,7 +134,7 @@ class TabsContainerViewController: BaseViewController { func setupModel() { //set to the large sample component.tabModels = getAllTabs() - + //setup UI surfacePickerSelectorView.text = component.surface.rawValue sizePickerSelectorView.text = component.size.rawValue diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift index d9fed6b..ce37a64 100644 --- a/VDSSample/ViewControllers/TabsViewController.swift +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -17,31 +17,8 @@ class TabsViewController: BaseViewController { var borderlineSwitch = Toggle() var fillContainerSwitch = Toggle() var sampleSwitch = Toggle() - var widthValueTextField = NumericField() - var widthPercentageTextField = NumericField() - var verticalOrientationFormStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fillProportionally - $0.axis = .vertical - $0.spacing = 10 - $0.isHidden = true - } - }() - - var horizontalOrientationFormStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fillProportionally - $0.axis = .vertical - $0.spacing = 10 - } - }() - - override func allTextFields() -> [TextField]? { [widthValueTextField, widthPercentageTextField] } + var horizontalOrientationFormStackView = FormSection() lazy var orientationPickerSelectorView = { PickerSelectorView(title: "", @@ -77,25 +54,20 @@ class TabsViewController: BaseViewController { override func setupForm(){ super.setupForm() addFormRow(label: "Large Sample", view: .makeWrapper(for: sampleSwitch)) - addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) addFormRow(label: "Show Borderline", view: .makeWrapper(for: borderlineSwitch)) addFormRow(label: "Surface", view: surfacePickerSelectorView) addFormRow(label: "Size", view: sizePickerSelectorView) - + if UIDevice.isIPad { addFormRow(label: "Orientation", view: orientationPickerSelectorView) -// //only in vertical mode -// addFormRow(label: "% Width (0.25 -> 1.0)", view: widthPercentageTextField, stackView: verticalOrientationFormStackView) -// addFormRow(label: "# Width", view: widthValueTextField, stackView: verticalOrientationFormStackView) } - + //only in horizontal mode - addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch), stackView: horizontalOrientationFormStackView) - addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView, stackView: horizontalOrientationFormStackView) - addFormRow(label: "Overflow", view: overflowPickerSelectorView, stackView: horizontalOrientationFormStackView) + horizontalOrientationFormStackView.addFormRow(label: "Fill Container", view: .makeWrapper(for: fillContainerSwitch)) + horizontalOrientationFormStackView.addFormRow(label: "Indicator Position", view: indicatorPositionPickerSelectorView) + horizontalOrientationFormStackView.addFormRow(label: "Overflow", view: overflowPickerSelectorView) -// formStackView.addArrangedSubview(verticalOrientationFormStackView) - formStackView.addArrangedSubview(horizontalOrientationFormStackView) + append(section: horizontalOrientationFormStackView) disabledSwitch.onChange = { [weak self] sender in self?.component.disabled = sender.isOn @@ -114,22 +86,6 @@ class TabsViewController: BaseViewController { self.component.selectedIndex = 0 self.component.tabModels = sender.isOn ? self.allTabs : self.some } - -// widthValueTextField.textPublisher.sink { [weak self] text in -// if let value = Double(text) { -// self?.component.width = .value(value) -// self?.widthPercentageTextField.text = "" -// -// } -// }.store(in: &subscribers) -// -// widthPercentageTextField.textPublisher.sink { [weak self] text in -// if let value = Double(text) { -// self?.component.width = .percentage(value) -// self?.widthValueTextField.text = "" -// } -// }.store(in: &subscribers) - } var allTabs: [Tabs.TabModel] = [ @@ -158,7 +114,6 @@ class TabsViewController: BaseViewController { borderlineSwitch.isOn = component.borderLine fillContainerSwitch.isOn = component.fillContainer sampleSwitch.isOn = true -// updateWidth() } func setupPicker(){ @@ -173,7 +128,6 @@ class TabsViewController: BaseViewController { orientationPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.orientation = item - self?.verticalOrientationFormStackView.isHidden = item == .horizontal self?.horizontalOrientationFormStackView.isHidden = item == .vertical } @@ -185,16 +139,4 @@ class TabsViewController: BaseViewController { self?.component.overflow = item } } - -// func updateWidth() { -// switch component.width { -// case .percentage(let percentage): -// widthPercentageTextField.text = "\(percentage)" -// case .value(let value): -// widthValueTextField.text = "\(value)" -// widthPercentageTextField.text = "" -// @unknown default: -// print("") -// } -// } } diff --git a/VDSSample/ViewControllers/ToggleViewController.swift b/VDSSample/ViewControllers/ToggleViewController.swift index b256f26..0d38720 100644 --- a/VDSSample/ViewControllers/ToggleViewController.swift +++ b/VDSSample/ViewControllers/ToggleViewController.swift @@ -28,15 +28,7 @@ class ToggleViewController: BaseViewController { var disabledSwitch = Toggle() var showTextSwitch = Toggle() - var textFormStackView: UIStackView = { - return UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.alignment = .fill - $0.distribution = .fillProportionally - $0.axis = .vertical - $0.spacing = 10 - } - }() + var textFormStackView = FormSection() var boldSwitch = Toggle() var onTextField = TextField() @@ -59,13 +51,14 @@ class ToggleViewController: BaseViewController { addFormRow(label: "Disabled", view: .makeWrapper(for: disabledSwitch)) //add the hidden elements to textFormStackView - addFormRow(label: "Bold", view: .makeWrapper(for: boldSwitch), stackView: textFormStackView) - addFormRow(label: "Text Size", view: textSizePickerSelectorView, stackView: textFormStackView) - addFormRow(label: "Text Position", view: textPositionPickerSelectorView, stackView: textFormStackView) - addFormRow(label: "On Text", view: onTextField, stackView: textFormStackView) - addFormRow(label: "Off Text", view: offTextField, stackView: textFormStackView) + textFormStackView.addFormRow(label: "Bold", view: .makeWrapper(for: boldSwitch)) + textFormStackView.addFormRow(label: "Text Size", view: textSizePickerSelectorView) + textFormStackView.addFormRow(label: "Text Position", view: textPositionPickerSelectorView) + textFormStackView.addFormRow(label: "On Text", view: onTextField) + textFormStackView.addFormRow(label: "Off Text", view: offTextField) + //add textFormStackView to main form - formStackView.addArrangedSubview(textFormStackView) + append(section: textFormStackView) component.onChange = { [weak self] toggle in let alertController:UIAlertController = UIAlertController(title: "Alert", From a4598644f7e4a518cb8c59c8ea638f90589fd4ef Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 25 May 2023 13:05:08 -0500 Subject: [PATCH 09/11] commented out TabsContainer for now Signed-off-by: Matt Bruce --- VDSSample/ViewControllers/MenuViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index e437e08..cf82f54 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -101,7 +101,7 @@ class MenuViewController: UITableViewController, TooltipLaunchable { MenuComponent(title: "RadioBoxGroup", completed: true, viewController: RadioBoxGroupViewController.self), MenuComponent(title: "RadioButtonGroup", completed: true, viewController: RadioButtonViewController.self), MenuComponent(title: "RadioSwatchGroup", completed: true, viewController: RadioSwatchGroupViewController.self), - MenuComponent(title: "TabsContainer", completed: false, viewController: TabsContainerViewController.self), + //MenuComponent(title: "TabsContainer", completed: false, viewController: TabsContainerViewController.self), MenuComponent(title: "Tabs", completed: true, viewController: TabsViewController.self), MenuComponent(title: "TextArea", completed: false, viewController: TextAreaViewController.self), MenuComponent(title: "TextLink", completed: true, viewController: TextLinkViewController.self), From ee772648b197359efdddbbd36a5972751f33b744 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 25 May 2023 14:14:52 -0500 Subject: [PATCH 10/11] fixed issue with buttons in selector Signed-off-by: Matt Bruce --- VDSSample/Classes/Helper.swift | 12 +++++++++--- VDSSample/Protocols/PickerBase.swift | 3 ++- VDSSample/ViewControllers/TabsViewController.swift | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/VDSSample/Classes/Helper.swift b/VDSSample/Classes/Helper.swift index 8540dec..4b24467 100644 --- a/VDSSample/Classes/Helper.swift +++ b/VDSSample/Classes/Helper.swift @@ -10,7 +10,7 @@ import VDS import UIKit extension UIView { - public static func makeWrapper(for view: UIView, edgeSpacing: CGFloat = 0.0) -> UIView { + public static func makeWrapper(for view: UIView, edgeSpacing: CGFloat = 0.0, isTrailing: Bool = true) -> UIView { let wrapper = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } @@ -18,8 +18,14 @@ extension UIView { view .pinTop(edgeSpacing) .pinBottom(edgeSpacing) - .pinLeading(edgeSpacing) - view.trailingAnchor.constraint(lessThanOrEqualTo: wrapper.trailingAnchor).isActive = true + + if isTrailing { + view.pinLeading(edgeSpacing) + view.trailingAnchor.constraint(lessThanOrEqualTo: wrapper.trailingAnchor).isActive = true + } else { + view.leadingAnchor.constraint(greaterThanOrEqualTo: wrapper.leadingAnchor).isActive = true + view.pinTrailing(edgeSpacing) + } return wrapper } } diff --git a/VDSSample/Protocols/PickerBase.swift b/VDSSample/Protocols/PickerBase.swift index 201b8d4..36ad337 100644 --- a/VDSSample/Protocols/PickerBase.swift +++ b/VDSSample/Protocols/PickerBase.swift @@ -60,6 +60,7 @@ public class PickerSelectorView: UIStackView, Picker public var items: [EnumType] { didSet { selectedIndex = 0 } } + public var onClick: AnyCancellable? public var onPickerDidSelect: ((EnumType) -> Void)? public var scrollToBottom: (()->Void)? public init(title: String, picker: UIPickerView? = nil, items: [EnumType]) { @@ -74,7 +75,7 @@ public class PickerSelectorView: UIStackView, Picker label.text = title updateSelectedIndex() addArrangedSubview(label) - addArrangedSubview(button) + addArrangedSubview(.makeWrapper(for: button, isTrailing: false)) button.onClick = { [weak self] _ in self?.picker?.delegate = self self?.picker?.dataSource = self diff --git a/VDSSample/ViewControllers/TabsViewController.swift b/VDSSample/ViewControllers/TabsViewController.swift index ce37a64..32fd06a 100644 --- a/VDSSample/ViewControllers/TabsViewController.swift +++ b/VDSSample/ViewControllers/TabsViewController.swift @@ -57,7 +57,7 @@ class TabsViewController: BaseViewController { addFormRow(label: "Show Borderline", view: .makeWrapper(for: borderlineSwitch)) addFormRow(label: "Surface", view: surfacePickerSelectorView) addFormRow(label: "Size", view: sizePickerSelectorView) - + if UIDevice.isIPad { addFormRow(label: "Orientation", view: orientationPickerSelectorView) } From 4dd121f961189e92e60b4100843c0c8352048acc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 25 May 2023 14:34:22 -0500 Subject: [PATCH 11/11] updated version Signed-off-by: Matt Bruce --- VDSSample.xcodeproj/project.pbxproj | 4 +- .../ViewControllers/MenuViewController.swift | 38 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/VDSSample.xcodeproj/project.pbxproj b/VDSSample.xcodeproj/project.pbxproj index 93bfb3b..4122d31 100644 --- a/VDSSample.xcodeproj/project.pbxproj +++ b/VDSSample.xcodeproj/project.pbxproj @@ -650,7 +650,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 18; DEVELOPMENT_TEAM = 59V5935DHZ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VDSSample/Info.plist; @@ -680,7 +680,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 18; DEVELOPMENT_TEAM = 59V5935DHZ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VDSSample/Info.plist; diff --git a/VDSSample/ViewControllers/MenuViewController.swift b/VDSSample/ViewControllers/MenuViewController.swift index cf82f54..5063362 100644 --- a/VDSSample/ViewControllers/MenuViewController.swift +++ b/VDSSample/ViewControllers/MenuViewController.swift @@ -65,27 +65,17 @@ class MenuCell: UITableViewCell { class MenuViewController: UITableViewController, TooltipLaunchable { override func viewDidLoad() { - title = "VDS Sample: Build \(Bundle.main.buildNumber ?? "none")" + title = "VDS Sample: Build \(Bundle.main.build ?? "none")" let tooltip = VDS.Tooltip() - tooltip.title = "Release Notes" - tooltip.content = getReleaseNotes() + let bundle = VDS.Bundle(for: VDS.Badge.self) + tooltip.title = "Release Notes: \(bundle.build ?? "")" + tooltip.content = bundle.contents("ReleaseNotes") navigationItem.rightBarButtonItem = UIBarButtonItem(customView: tooltip) // UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(buildInfoTapped)) super.viewDidLoad() overrideUserInterfaceStyle = .light tableView.register(MenuCell.self, forCellReuseIdentifier: "cell") } - - func getReleaseNotes() -> String { - let bundle = VDS.Bundle(for: VDS.Badge.self) - guard let fileURL = bundle.url(forResource: "ReleaseNotes", withExtension: "txt") else { return "none" } - do { - return try String(contentsOf: fileURL) - } catch { - print("error reading releaseNotes") - return "none" - } - } - + let items: [MenuComponent] = [ MenuComponent(title: "Badge", completed: true, viewController: BadgeViewController.self), MenuComponent(title: "Button", completed: true, viewController: ButtonViewController.self), @@ -169,7 +159,25 @@ class MenuViewController: UITableViewController, TooltipLaunchable { } extension Bundle { + var versionNumber: String? { + infoDictionary?["CFBundleShortVersionString"] as? String + } var buildNumber: String? { infoDictionary?["CFBundleVersion"] as? String } + + var build: String? { + guard let versionNumber, let buildNumber else { return nil } + return "\(versionNumber).\(buildNumber)" + } + + func contents(_ fileName: String, fileExtension: String = "txt" ) -> String { + guard let fileURL = url(forResource: fileName, withExtension: fileExtension) else { return "none" } + do { + return try String(contentsOf: fileURL) + } catch { + print("error reading releaseNotes") + return "none" + } + } }