Skip to content

Commit 479dd2a

Browse files
committed
Added actions onboarding screen.
1 parent 26b79df commit 479dd2a

File tree

8 files changed

+298
-80
lines changed

8 files changed

+298
-80
lines changed

Example App/NativeUIKit.xcodeproj/xcshareddata/xcschemes/watchOS Example.xcscheme

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,46 +54,33 @@
5454
debugDocumentVersioning = "YES"
5555
debugServiceExtension = "internal"
5656
allowLocationSimulation = "YES">
57-
<RemoteRunnable
58-
runnableDebuggingMode = "2"
59-
BundleIdentifier = "com.apple.Carousel"
60-
RemotePath = "/(null)">
57+
<BuildableProductRunnable
58+
runnableDebuggingMode = "0">
6159
<BuildableReference
6260
BuildableIdentifier = "primary"
6361
BlueprintIdentifier = "F4C33E2F26C932C8001A28B1"
6462
BuildableName = "watchOS Example.app"
6563
BlueprintName = "watchOS Example"
6664
ReferencedContainer = "container:NativeUIKit.xcodeproj">
6765
</BuildableReference>
68-
</RemoteRunnable>
66+
</BuildableProductRunnable>
6967
</LaunchAction>
7068
<ProfileAction
7169
buildConfiguration = "Release"
7270
shouldUseLaunchSchemeArgsEnv = "YES"
7371
savedToolIdentifier = ""
7472
useCustomWorkingDirectory = "NO"
7573
debugDocumentVersioning = "YES">
76-
<RemoteRunnable
77-
runnableDebuggingMode = "2"
78-
BundleIdentifier = "com.apple.Carousel"
79-
RemotePath = "/(null)">
74+
<BuildableProductRunnable
75+
runnableDebuggingMode = "0">
8076
<BuildableReference
8177
BuildableIdentifier = "primary"
8278
BlueprintIdentifier = "F4C33E2F26C932C8001A28B1"
8379
BuildableName = "watchOS Example.app"
8480
BlueprintName = "watchOS Example"
8581
ReferencedContainer = "container:NativeUIKit.xcodeproj">
8682
</BuildableReference>
87-
</RemoteRunnable>
88-
<MacroExpansion>
89-
<BuildableReference
90-
BuildableIdentifier = "primary"
91-
BlueprintIdentifier = "F4C33E2F26C932C8001A28B1"
92-
BuildableName = "watchOS Example.app"
93-
BlueprintName = "watchOS Example"
94-
ReferencedContainer = "container:NativeUIKit.xcodeproj">
95-
</BuildableReference>
96-
</MacroExpansion>
83+
</BuildableProductRunnable>
9784
</ProfileAction>
9885
<AnalyzeAction
9986
buildConfiguration = "Debug">

NativeUIKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22

33
s.name = 'NativeUIKit'
4-
s.version = '1.2.7'
4+
s.version = '1.2.8'
55
s.summary = 'Mimicrated views and controls to native Apple appearance.'
66
s.homepage = 'https://github.com/ivanvorobei/NativeUIKit'
77
s.source = { :git => 'https://github.com/ivanvorobei/NativeUIKit.git', :tag => s.version }
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// The MIT License (MIT)
2+
// Copyright © 2021 Ivan Vorobei ([email protected])
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in all
12+
// copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
// SOFTWARE.
21+
22+
#if canImport(UIKit) && (os(iOS))
23+
import UIKit
24+
import SparrowKit
25+
26+
public class NativeOnbiardingActionButton: SPDimmedButton {
27+
28+
// MARK: - Data
29+
30+
private let model: ActionModel
31+
32+
// MARK: - Views
33+
34+
let disclouserIndicator = SPDimmedButton().do {
35+
if #available(iOS 13, *) {
36+
$0.setImage(.system("chevron.right", font: .preferredFont(forTextStyle: .body, weight: .medium)).alwaysTemplate)
37+
$0.tintColor = .tertiaryLabel
38+
}
39+
}
40+
41+
let actionIconView = SPImageView().do {
42+
$0.contentMode = .scaleAspectFit
43+
}
44+
45+
let actionTitleLabel = SPLabel().do {
46+
$0.font = .preferredFont(forTextStyle: .body, weight: .semibold)
47+
if #available(iOS 13.0, *) {
48+
$0.textColor = .label
49+
} else {
50+
$0.textColor = .black
51+
}
52+
$0.numberOfLines = .zero
53+
}
54+
55+
let actionDescriptionLabel = SPLabel().do {
56+
$0.font = .preferredFont(forTextStyle: .subheadline)
57+
if #available(iOS 13.0, *) {
58+
$0.textColor = .secondaryLabel
59+
} else {
60+
$0.textColor = .black
61+
}
62+
$0.numberOfLines = .zero
63+
}
64+
65+
// MARK: - Init
66+
67+
init(with model: ActionModel) {
68+
self.model = model
69+
super.init()
70+
actionIconView.image = model.iconImage
71+
actionTitleLabel.text = model.title
72+
actionDescriptionLabel.text = model.description
73+
74+
addTarget(self, action: #selector(self.didTap), for: .touchUpInside)
75+
}
76+
77+
required init?(coder aDecoder: NSCoder) {
78+
fatalError("init(coder:) has not been implemented")
79+
}
80+
81+
public override func commonInit() {
82+
super.commonInit()
83+
higlightStyle = .background
84+
if #available(iOS 13.0, *) {
85+
applyDefaultAppearance(with: .init(content: .label, background: .secondarySystemBackground))
86+
}
87+
roundCorners(radius: NativeLayout.Spaces.default_less)
88+
layoutMargins = .init(horizontal: NativeLayout.Spaces.default_more, vertical: NativeLayout.Spaces.default_more)
89+
addSubviews(actionIconView, actionTitleLabel, actionDescriptionLabel, disclouserIndicator)
90+
}
91+
92+
// MARK: - Layout
93+
94+
public override func layoutSubviews() {
95+
super.layoutSubviews()
96+
actionIconView.frame = .init(side: 28)
97+
actionIconView.frame.origin.x = layoutMargins.left
98+
99+
disclouserIndicator.sizeToFit()
100+
disclouserIndicator.setMaxXToSuperviewRightMargin()
101+
102+
let leftSpace: CGFloat = NativeLayout.Spaces.default_more
103+
let rightSpace: CGFloat = NativeLayout.Spaces.default
104+
let labelWidth = layoutWidth - actionIconView.frame.width - disclouserIndicator.frame.width - leftSpace - rightSpace
105+
106+
actionTitleLabel.layoutDynamicHeight(width: labelWidth)
107+
actionTitleLabel.frame.origin.x = actionIconView.frame.maxX + leftSpace
108+
actionTitleLabel.frame.origin.y = layoutMargins.top
109+
110+
actionDescriptionLabel.layoutDynamicHeight(width: labelWidth)
111+
actionDescriptionLabel.frame.origin.x = actionTitleLabel.frame.origin.x
112+
actionDescriptionLabel.frame.origin.y = actionTitleLabel.frame.maxY + NativeLayout.Spaces.step
113+
114+
disclouserIndicator.setYCenter()
115+
actionIconView.setYCenter()
116+
}
117+
118+
public override func sizeThatFits(_ size: CGSize) -> CGSize {
119+
layoutSubviews()
120+
return .init(width: size.width, height: actionDescriptionLabel.frame.maxY + layoutMargins.bottom)
121+
}
122+
123+
// MARK: - Action
124+
125+
@objc func didTap() {
126+
self.model.action()
127+
}
128+
129+
// MARK: - Models
130+
131+
/**
132+
Wrapper of data for action model.
133+
134+
- important: Recomended save app tint color for icons like native.
135+
*/
136+
public class ActionModel {
137+
138+
let iconImage: UIImage
139+
let title: String
140+
let description: String
141+
let action: ()->Void
142+
143+
public init(iconImage: UIImage, title: String, description: String, action: @escaping ()->Void) {
144+
self.iconImage = iconImage
145+
self.title = title
146+
self.description = description
147+
self.action = action
148+
}
149+
}
150+
}
151+
#endif
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// The MIT License (MIT)
2+
// Copyright © 2021 Ivan Vorobei ([email protected])
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in all
12+
// copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
// SOFTWARE.
21+
22+
#if canImport(UIKit) && (os(iOS))
23+
import UIKit
24+
import SparrowKit
25+
26+
open class NativeOnboardingActionsController: NativeHeaderController {
27+
28+
private var views: [NativeOnbiardingActionButton] = []
29+
30+
// MARK: - Init
31+
32+
public init(
33+
iconImage: UIImage?,
34+
title: String,
35+
subtitle: String
36+
) {
37+
super.init(image: iconImage, title: title, subtitle: subtitle)
38+
}
39+
40+
public required init?(coder: NSCoder) {
41+
fatalError("init(coder:) has not been implemented")
42+
}
43+
44+
// MARK: - Lifecycle
45+
46+
open override func viewDidLoad() {
47+
super.viewDidLoad()
48+
if #available(iOS 13.0, *) {
49+
self.view.backgroundColor = .systemBackground
50+
} else {
51+
view.backgroundColor = .white
52+
}
53+
scrollView.addSubviews(views)
54+
}
55+
56+
open func setActions(_ models: [NativeOnbiardingActionButton.ActionModel]) {
57+
// Clean old
58+
views.forEach({ $0.removeFromSuperview() })
59+
views.removeAll()
60+
61+
// Add new
62+
views = models.map({ NativeOnbiardingActionButton(with: $0) })
63+
64+
// Added like subviews
65+
if isViewLoaded {
66+
scrollView.addSubviews(views)
67+
}
68+
}
69+
70+
// MARK: - Layout
71+
72+
open override func viewDidLayoutSubviews() {
73+
super.viewDidLayoutSubviews()
74+
var currentYPosition = headerView.frame.maxY + NativeLayout.Spaces.default_double
75+
let elementWidth: CGFloat = min(scrollView.readableWidth, 320)
76+
for (_, itemView) in views.enumerated() {
77+
itemView.setWidthAndFit(width: elementWidth)
78+
itemView.setXCenter()
79+
itemView.frame.origin.y = currentYPosition
80+
currentYPosition = itemView.frame.maxY + NativeLayout.Spaces.default_half
81+
}
82+
scrollView.contentSize = .init(width: scrollView.frame.width, height: views.last?.frame.maxY ?? .zero)
83+
}
84+
}
85+
#endif

Sources/NativeUIKit/Controllers/Complex/Onboarding/NativeOnboardingItemView.swift renamed to Sources/NativeUIKit/Controllers/Complex/Onboarding/Features/NativeOnboardingFeatureView.swift

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
import UIKit
2424
import SparrowKit
2525

26-
public class NativeOnboardingItemView: SPView {
26+
public class NativeOnboardingFeatureView: SPView {
27+
28+
// MARK: - Data
29+
30+
let model: FeatureModel
2731

2832
// MARK: - Views
2933

@@ -53,11 +57,12 @@ public class NativeOnboardingItemView: SPView {
5357

5458
// MARK: - Init
5559

56-
init(item: NativeOnboardingItem) {
60+
init(with model: FeatureModel) {
61+
self.model = model
5762
super.init()
58-
iconView.image = item.iconImage
59-
titleLabel.text = item.title
60-
descriptionLabel.text = item.description
63+
iconView.image = model.iconImage
64+
titleLabel.text = model.title
65+
descriptionLabel.text = model.description
6166
}
6267

6368
required init?(coder aDecoder: NSCoder) {
@@ -103,5 +108,25 @@ public class NativeOnboardingItemView: SPView {
103108
self.backgroundColor = .secondarySystemBackground.alpha(1 - value)
104109
}
105110
}
111+
112+
// MARK: - Models
113+
114+
/**
115+
Wrapper of data for feature model.
116+
117+
- important: Recomended use custom tint color for icons like native.
118+
*/
119+
public class FeatureModel {
120+
121+
let iconImage: UIImage
122+
let title: String
123+
let description: String
124+
125+
public init(iconImage: UIImage, title: String, description: String) {
126+
self.iconImage = iconImage
127+
self.title = title
128+
self.description = description
129+
}
130+
}
106131
}
107132
#endif

0 commit comments

Comments
 (0)