Skip to content

Commit c7e95ac

Browse files
rename folder
1 parent 3f5027e commit c7e95ac

File tree

2 files changed

+369
-0
lines changed

2 files changed

+369
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import ComponentsKit
2+
import SwiftUI
3+
4+
struct SwiftUILogin: View {
5+
enum Pages {
6+
case signIn
7+
case signUp
8+
}
9+
enum Input {
10+
case name
11+
case email
12+
case password
13+
}
14+
15+
@State private var selectedPage = Pages.signIn
16+
17+
@State private var name = ""
18+
@State private var email = ""
19+
@State private var password = ""
20+
21+
@FocusState private var focusedInput: Input?
22+
@State private var isConsented: Bool = false
23+
@State private var isLoading = false
24+
25+
private var isButtonEnabled: Bool {
26+
return self.email.isNotEmpty
27+
&& self.password.isNotEmpty
28+
&& self.isConsented
29+
&& (
30+
self.selectedPage == .signUp && self.name.isNotEmpty
31+
|| self.selectedPage == .signIn
32+
)
33+
}
34+
35+
@Environment(\.colorScheme) var colorScheme
36+
37+
var body: some View {
38+
ZStack {
39+
Palette.Base.background.color(for: self.colorScheme)
40+
41+
ScrollView {
42+
VStack(spacing: 20) {
43+
SUSegmentedControl<Pages>(
44+
selectedId: self.$selectedPage,
45+
model: .init {
46+
$0.items = [
47+
.init(id: .signIn) {
48+
$0.title = "Sign In"
49+
},
50+
.init(id: .signUp) {
51+
$0.title = "Sign Up"
52+
}
53+
]
54+
$0.isEnabled = !self.isLoading
55+
}
56+
)
57+
58+
Text(
59+
self.selectedPage == .signIn
60+
? "Welcome back"
61+
: "Create an account"
62+
)
63+
.font(.system(size: 30, weight: .bold))
64+
.padding(.vertical, 30)
65+
66+
if self.selectedPage == .signUp {
67+
SUInputField(
68+
text: self.$name,
69+
globalFocus: self.$focusedInput,
70+
localFocus: .name,
71+
model: .init {
72+
$0.title = "Name"
73+
$0.isRequired = true
74+
$0.isEnabled = !self.isLoading
75+
}
76+
)
77+
}
78+
SUInputField(
79+
text: self.$email,
80+
globalFocus: self.$focusedInput,
81+
localFocus: .email,
82+
model: .init {
83+
$0.title = "Email"
84+
$0.isRequired = true
85+
$0.isEnabled = !self.isLoading
86+
}
87+
)
88+
SUInputField(
89+
text: self.$password,
90+
globalFocus: self.$focusedInput,
91+
localFocus: .password,
92+
model: .init {
93+
$0.title = "Password"
94+
$0.isRequired = true
95+
$0.isSecureInput = true
96+
$0.isEnabled = !self.isLoading
97+
}
98+
)
99+
100+
SUCheckbox(
101+
isSelected: self.$isConsented,
102+
model: .init {
103+
$0.title = "By continuing, you accept our Terms of Service and Privacy Policy"
104+
$0.isEnabled = !self.isLoading
105+
}
106+
)
107+
108+
Group {
109+
if self.isLoading {
110+
SULoading()
111+
} else {
112+
SUButton(
113+
model: .init {
114+
$0.title = "Continue"
115+
$0.isFullWidth = true
116+
$0.isEnabled = self.isButtonEnabled
117+
},
118+
action: {
119+
self.isLoading = true
120+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
121+
self.isLoading = false
122+
UINotificationFeedbackGenerator().notificationOccurred(.success)
123+
}
124+
}
125+
)
126+
}
127+
}
128+
.padding(.top, 10)
129+
}
130+
.padding()
131+
}
132+
}
133+
.frame(maxWidth: 500)
134+
.onChange(of: self.selectedPage) { _, newValue in
135+
if newValue == .signIn && self.focusedInput == .name {
136+
self.focusedInput = .email
137+
}
138+
}
139+
.onTapGesture {
140+
self.focusedInput = nil
141+
}
142+
}
143+
}
144+
145+
#Preview {
146+
SwiftUILogin()
147+
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import ComponentsKit
2+
import SwiftUI
3+
import UIKit
4+
5+
final class UIKitLogin: UIViewController {
6+
enum Pages {
7+
case signIn
8+
case signUp
9+
}
10+
11+
private let scrollView: UIScrollView = {
12+
let scrollView = UIScrollView()
13+
scrollView.delaysContentTouches = false
14+
return scrollView
15+
}()
16+
private lazy var stackView: UIStackView = {
17+
let stackView = UIStackView()
18+
stackView.axis = .vertical
19+
stackView.spacing = 20
20+
stackView.alignment = .center
21+
return stackView
22+
}()
23+
24+
private let pageControl = UKSegmentedControl<Pages>(
25+
selectedId: .signIn,
26+
model: .init {
27+
$0.items = [
28+
.init(id: .signIn) {
29+
$0.title = "Sign In"
30+
},
31+
.init(id: .signUp) {
32+
$0.title = "Sign Up"
33+
}
34+
]
35+
}
36+
)
37+
private let titleLabel: UILabel = {
38+
let label = UILabel()
39+
label.font = .systemFont(ofSize: 30, weight: .bold)
40+
return label
41+
}()
42+
private let nameInput = UKInputField(
43+
model: .init {
44+
$0.title = "Name"
45+
$0.isRequired = true
46+
}
47+
)
48+
private let emailInput = UKInputField(
49+
model: .init {
50+
$0.title = "Email"
51+
$0.isRequired = true
52+
}
53+
)
54+
private let passwordInput = UKInputField(
55+
model: .init {
56+
$0.title = "Password"
57+
$0.isRequired = true
58+
$0.isSecureInput = true
59+
}
60+
)
61+
private let consentCheckbox = UKCheckbox(
62+
model: .init {
63+
$0.title = "By continuing, you accept our Terms of Service and Privacy Policy"
64+
}
65+
)
66+
private let continueButton = UKButton(
67+
model: .init {
68+
$0.title = "Continue"
69+
$0.isFullWidth = true
70+
}
71+
)
72+
private let loader = UKLoading()
73+
74+
private var isLoading = false {
75+
didSet { self.update() }
76+
}
77+
78+
private var isButtonEnabled: Bool {
79+
return self.emailInput.text.isNotEmpty
80+
&& self.passwordInput.text.isNotEmpty
81+
&& self.consentCheckbox.isSelected
82+
&& (
83+
self.pageControl.selectedId == .signUp && self.nameInput.text.isNotEmpty
84+
|| self.pageControl.selectedId == .signIn
85+
)
86+
}
87+
88+
override func viewDidLoad() {
89+
super.viewDidLoad()
90+
91+
self.setup()
92+
self.style()
93+
self.layout()
94+
self.update()
95+
}
96+
97+
private func setup() {
98+
self.view.addSubview(self.scrollView)
99+
self.scrollView.addSubview(self.stackView)
100+
self.scrollView.addSubview(self.loader)
101+
102+
self.stackView.addArrangedSubview(self.pageControl)
103+
self.stackView.addArrangedSubview(self.titleLabel)
104+
self.stackView.addArrangedSubview(self.nameInput)
105+
self.stackView.addArrangedSubview(self.emailInput)
106+
self.stackView.addArrangedSubview(self.passwordInput)
107+
self.stackView.addArrangedSubview(self.consentCheckbox)
108+
self.stackView.addArrangedSubview(self.continueButton)
109+
110+
self.pageControl.onSelectionChange = { [weak self] selectedPage in
111+
guard let self else { return }
112+
113+
if selectedPage == .signIn && self.nameInput.isFirstResponder {
114+
self.emailInput.becomeFirstResponder()
115+
}
116+
117+
self.update()
118+
}
119+
self.nameInput.onValueChange = { [weak self] _ in
120+
self?.update()
121+
}
122+
self.emailInput.onValueChange = { [weak self] _ in
123+
self?.update()
124+
}
125+
self.passwordInput.onValueChange = { [weak self] _ in
126+
self?.update()
127+
}
128+
self.consentCheckbox.onValueChange = { [weak self] _ in
129+
self?.update()
130+
}
131+
self.continueButton.action = {
132+
self.isLoading = true
133+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
134+
self.isLoading = false
135+
UINotificationFeedbackGenerator().notificationOccurred(.success)
136+
}
137+
}
138+
139+
self.scrollView.addGestureRecognizer(
140+
UITapGestureRecognizer(
141+
target: self,
142+
action: #selector(self.dismissKeyboard)
143+
)
144+
)
145+
}
146+
147+
@objc private func dismissKeyboard() {
148+
self.nameInput.resignFirstResponder()
149+
self.emailInput.resignFirstResponder()
150+
self.passwordInput.resignFirstResponder()
151+
}
152+
153+
private func style() {
154+
self.scrollView.backgroundColor = Palette.Base.background.uiColor
155+
156+
self.stackView.setCustomSpacing(50, after: self.pageControl)
157+
self.stackView.setCustomSpacing(50, after: self.titleLabel)
158+
self.stackView.setCustomSpacing(50, after: self.consentCheckbox)
159+
}
160+
161+
private func layout() {
162+
self.scrollView.allEdges()
163+
164+
self.stackView.top(20)
165+
self.stackView.bottom(20)
166+
167+
self.stackView.leadingAnchor.constraint(
168+
greaterThanOrEqualTo: self.view.leadingAnchor,
169+
constant: 20
170+
).isActive = true
171+
self.stackView.trailingAnchor.constraint(
172+
lessThanOrEqualTo: self.view.trailingAnchor,
173+
constant: -20
174+
).isActive = true
175+
self.stackView.widthAnchor.constraint(
176+
lessThanOrEqualToConstant: 500
177+
).isActive = true
178+
self.stackView.centerHorizontally()
179+
180+
self.loader.below(self.stackView, padding: 50)
181+
self.loader.centerHorizontally()
182+
}
183+
184+
private func update() {
185+
switch self.pageControl.selectedId {
186+
case .signIn:
187+
self.nameInput.isHidden = true
188+
self.titleLabel.text = "Welcome back"
189+
case .signUp:
190+
self.nameInput.isHidden = false
191+
self.titleLabel.text = "Create an account"
192+
}
193+
194+
self.pageControl.model.update {
195+
$0.isEnabled = !self.isLoading
196+
}
197+
self.nameInput.model.update {
198+
$0.isEnabled = !self.isLoading
199+
}
200+
self.emailInput.model.update {
201+
$0.isEnabled = !self.isLoading
202+
}
203+
self.passwordInput.model.update {
204+
$0.isEnabled = !self.isLoading
205+
}
206+
self.consentCheckbox.model.update {
207+
$0.isEnabled = !self.isLoading
208+
}
209+
self.continueButton.model.update { [weak self] in
210+
guard let self else { return }
211+
$0.isEnabled = self.isButtonEnabled
212+
}
213+
self.loader.isHidden = !self.isLoading
214+
self.continueButton.isHidden = self.isLoading
215+
}
216+
}
217+
218+
#Preview {
219+
UIViewControllerRepresenting {
220+
UIKitLogin()
221+
}
222+
}

0 commit comments

Comments
 (0)