7
7
8
8
import UIKit
9
9
10
+ import RxCocoa
11
+ import RxSwift
12
+
10
13
final class SetReadyInfoViewController : BaseViewController {
11
14
12
15
13
16
// MARK: - Property
14
17
15
18
private let rootView = SetReadyInfoView ( )
19
+
16
20
private let viewModel : SetReadyInfoViewModel
21
+ private let viewWillAppearRelay = PublishRelay < Void > ( )
22
+ private let disposeBag = DisposeBag ( )
17
23
18
24
19
25
// MARK: - Initializer
@@ -31,108 +37,152 @@ final class SetReadyInfoViewController: BaseViewController {
31
37
// MARK: - LifeCycle
32
38
33
39
override func loadView( ) {
34
- self . view = rootView
40
+ view = rootView
35
41
}
36
42
37
43
override func viewDidLoad( ) {
38
44
super. viewDidLoad ( )
39
45
view. backgroundColor = . white
40
46
41
- setupNavigationBarBackButton ( )
42
- setupNavigationBarTitle ( with: " 준비 정보 입력하기 " )
43
-
44
- setupBinding ( )
45
- setupTapGesture ( )
46
- setupTextField ( )
47
+ bindViewModel ( )
47
48
}
48
49
49
50
override func viewWillAppear( _ animated: Bool ) {
50
51
super. viewWillAppear ( animated)
51
52
52
53
navigationController? . isNavigationBarHidden = false
54
+ viewWillAppearRelay. accept ( ( ) )
55
+ }
56
+
57
+ override func setupView( ) {
58
+ setupNavigationBarBackButton ( )
59
+ setupNavigationBarTitle ( with: " 준비 정보 입력하기 " )
53
60
}
54
61
55
62
override func setupDelegate( ) {
56
63
setTextFieldDelegate ( )
57
64
}
58
65
59
66
override func setupAction( ) {
60
- rootView. readyHourTextField. addTarget (
61
- self ,
62
- action: #selector( textFieldDidChange) ,
63
- for: . editingChanged
64
- )
65
- rootView. readyMinuteTextField. addTarget (
66
- self ,
67
- action: #selector( textFieldDidChange) ,
68
- for: . editingChanged
69
- )
70
- rootView. moveHourTextField. addTarget (
71
- self ,
72
- action: #selector( textFieldDidChange) ,
73
- for: . editingChanged
74
- )
75
- rootView. moveMinuteTextField. addTarget (
76
- self ,
77
- action: #selector( textFieldDidChange) ,
78
- for: . editingChanged
79
- )
80
- rootView. doneButton. addTarget (
81
- self ,
82
- action: #selector( doneButtonDidTap) ,
83
- for: . touchUpInside
84
- )
67
+ setupTextField ( textField: rootView. readyHourTextField)
68
+ setupTextField ( textField: rootView. readyMinuteTextField)
69
+ setupTextField ( textField: rootView. moveHourTextField)
70
+ setupTextField ( textField: rootView. moveMinuteTextField)
71
+
72
+ let tapGesture = UITapGestureRecognizer ( )
73
+ view. addGestureRecognizer ( tapGesture)
74
+ tapGesture. rx. event
75
+ . subscribe ( with: self ) { owner, _ in
76
+ owner. view. endEditing ( true )
77
+ }
78
+ . disposed ( by: disposeBag)
85
79
}
86
80
87
- @objc
88
- private func textFieldDidChange( _ textField: UITextField ) {
89
- let text = textField. text ?? " "
90
- viewModel. updateTime ( textField: textField. accessibilityIdentifier ?? " " , time: text)
91
- viewModel. checkValid (
92
- readyHourText: rootView. readyHourTextField. text ?? " " ,
93
- readyMinuteText: rootView. readyMinuteTextField. text ?? " " ,
94
- moveHourText: rootView. moveHourTextField. text ?? " " ,
95
- moveMinuteText: rootView. moveMinuteTextField. text ?? " "
81
+ private func bindViewModel( ) {
82
+ let input = SetReadyInfoViewModel . Input (
83
+ viewWillAppear: viewWillAppearRelay,
84
+ readyHourText: rootView. readyHourTextField. rx. text. orEmpty. asObservable ( ) ,
85
+ readyMinuteText: rootView. readyMinuteTextField. rx. text. orEmpty. asObservable ( ) ,
86
+ moveHourText: rootView. moveHourTextField. rx. text. orEmpty. asObservable ( ) ,
87
+ moveMinuteText: rootView. moveMinuteTextField. rx. text. orEmpty. asObservable ( ) ,
88
+ doneButtonDidTap: rootView. doneButton. rx. tap. asObservable ( )
96
89
)
90
+
91
+ let output = viewModel. transform ( input: input, disposeBag: disposeBag)
92
+
93
+ output. readyHourText
94
+ . drive ( with: self ) { owner, text in
95
+ owner. rootView. readyHourTextField. text = text
96
+ }
97
+ . disposed ( by: disposeBag)
98
+
99
+ output. readyMinuteText
100
+ . drive ( with: self ) { owner, text in
101
+ owner. rootView. readyMinuteTextField. text = text
102
+ }
103
+ . disposed ( by: disposeBag)
104
+
105
+ output. moveHourText
106
+ . drive ( with: self ) { owner, text in
107
+ owner. rootView. moveHourTextField. text = text
108
+ }
109
+ . disposed ( by: disposeBag)
110
+
111
+ output. moveMinuteText
112
+ . drive ( with: self ) { owner, text in
113
+ owner. rootView. moveMinuteTextField. text = text
114
+ }
115
+ . disposed ( by: disposeBag)
116
+
117
+ output. errorMessage
118
+ . drive ( with: self ) { owner, error in
119
+ owner. showToast ( error)
120
+ }
121
+ . disposed ( by: disposeBag)
122
+
123
+ output. doneButtonIsEnabled
124
+ . drive ( with: self ) { owner, isEnabled in
125
+ owner. rootView. doneButton. backgroundColor = isEnabled ? . maincolor : . gray2
126
+ owner. rootView. doneButton. isEnabled = isEnabled
127
+ }
128
+ . disposed ( by: disposeBag)
129
+
130
+ output. isSucceed
131
+ . drive ( with: self ) { owner, isSucceed in
132
+ if isSucceed {
133
+ owner. navigateToSetReadyCompleted ( )
134
+ }
135
+ }
136
+ . disposed ( by: disposeBag)
97
137
}
98
138
99
- @objc
100
- private func doneButtonDidTap( _ sender: UIButton ) {
101
- viewModel. updateReadyInfo ( )
139
+ private func setupTextField( textField: UITextField ) {
140
+ let textFieldEvent = Observable . merge (
141
+ textField. rx. controlEvent ( . editingDidBegin) . map { UIColor . maincolor. cgColor } ,
142
+ textField. rx. controlEvent ( . editingDidEnd) . map { UIColor . gray3. cgColor } ,
143
+ textField. rx. controlEvent ( . editingDidEndOnExit) . map { UIColor . gray3. cgColor }
144
+ )
145
+
146
+ textFieldEvent
147
+ . bind { borderColor in
148
+ textField. layer. borderColor = borderColor
149
+ }
150
+ . disposed ( by: disposeBag)
102
151
}
103
152
153
+ private func navigateToSetReadyCompleted( ) {
154
+ let setReadyCompletedViewController = SetReadyCompletedViewController ( )
155
+ self . navigationController? . pushViewController (
156
+ setReadyCompletedViewController,
157
+ animated: true
158
+ )
159
+ }
104
160
105
- // MARK: - Keyboard Dismissal
106
-
107
- private func setupTapGesture( ) {
108
- let tapGesture = UITapGestureRecognizer ( target: self , action: #selector( dismissKeyboard) )
109
- view. addGestureRecognizer ( tapGesture)
161
+ private func showToast( _ message: String , bottomInset: CGFloat = 128 ) {
162
+ guard let view else { return }
163
+ Toast ( ) . show ( message: message, view: view, position: . bottom, inset: bottomInset)
110
164
}
111
165
112
- @objc private func dismissKeyboard( ) {
113
- view. endEditing ( true )
166
+ private func setTextFieldDelegate( ) {
167
+ let textFields : [ ( UITextField , String ) ] = [
168
+ ( rootView. readyHourTextField, " readyHour " ) ,
169
+ ( rootView. readyMinuteTextField, " readyMinute " ) ,
170
+ ( rootView. moveHourTextField, " moveHour " ) ,
171
+ ( rootView. moveMinuteTextField, " moveMinute " )
172
+ ]
173
+
174
+ textFields. forEach { ( textField, identifier) in
175
+ textField. delegate = self
176
+ textField. keyboardType = . numberPad
177
+ textField. accessibilityIdentifier = identifier
178
+ }
114
179
}
115
180
}
116
181
117
182
118
183
// MARK: - UITextFieldDelegate
119
184
120
185
extension SetReadyInfoViewController : UITextFieldDelegate {
121
- func textFieldDidBeginEditing( _ textField: UITextField ) {
122
- textField. layer. borderColor = UIColor . maincolor. cgColor
123
- }
124
-
125
- func textFieldDidEndEditing( _ textField: UITextField ) {
126
- textField. layer. borderColor = UIColor . gray3. cgColor
127
-
128
- if let text = textField. text, !text. isEmpty {
129
- viewModel. updateTime (
130
- textField: textField. accessibilityIdentifier ?? " " ,
131
- time: textField. text ?? " "
132
- )
133
- }
134
- }
135
-
136
186
func textField(
137
187
_ textField: UITextField ,
138
188
shouldChangeCharactersIn range: NSRange ,
@@ -143,91 +193,3 @@ extension SetReadyInfoViewController: UITextFieldDelegate {
143
193
return allowedCharacters. isSuperset ( of: characterSet)
144
194
}
145
195
}
146
-
147
-
148
- // MARK: - Function
149
-
150
- private extension SetReadyInfoViewController {
151
- func setupTextField( ) {
152
- /// 저장된 준비 시간이 0이 아니면 텍스트 필드에 설정
153
- if viewModel. storedReadyHour != 0 || viewModel. storedReadyMinute != 0 {
154
- rootView. readyHourTextField. text = String ( viewModel. storedReadyHour)
155
- rootView. readyMinuteTextField. text = String ( viewModel. storedReadyMinute)
156
- }
157
-
158
- /// 저장된 이동 시간이 0이 아니면 텍스트 필드에 설정
159
- if viewModel. storedMoveHour != 0 || viewModel. storedMoveMinute != 0 {
160
- rootView. moveHourTextField. text = String ( viewModel. storedMoveHour)
161
- rootView. moveMinuteTextField. text = String ( viewModel. storedMoveMinute)
162
- }
163
-
164
- viewModel. checkValid (
165
- readyHourText: rootView. readyHourTextField. text ?? " " ,
166
- readyMinuteText: rootView. readyMinuteTextField. text ?? " " ,
167
- moveHourText: rootView. moveHourTextField. text ?? " " ,
168
- moveMinuteText: rootView. moveMinuteTextField. text ?? " "
169
- )
170
- }
171
-
172
- func setTextFieldDelegate( ) {
173
- let textFields : [ ( UITextField , String ) ] = [
174
- ( rootView. readyHourTextField, " readyHour " ) ,
175
- ( rootView. readyMinuteTextField, " readyMinute " ) ,
176
- ( rootView. moveHourTextField, " moveHour " ) ,
177
- ( rootView. moveMinuteTextField, " moveMinute " )
178
- ]
179
-
180
- textFields. forEach { ( textField, identifier) in
181
- textField. delegate = self
182
- textField. keyboardType = . numberPad
183
- textField. accessibilityIdentifier = identifier
184
- }
185
- }
186
-
187
- func showToast( _ message: String , bottomInset: CGFloat = 128 ) {
188
- guard let view else { return }
189
- Toast ( ) . show ( message: message, view: view, position: . bottom, inset: bottomInset)
190
- }
191
-
192
- // MARK: - Data Bind
193
-
194
- func setupBinding( ) {
195
- viewModel. readyHour. bind { [ weak self] readyHour in
196
- self ? . rootView. readyHourTextField. text = readyHour
197
- }
198
-
199
- viewModel. readyMinute. bind { [ weak self] readyMinute in
200
- self ? . rootView. readyMinuteTextField. text = readyMinute
201
- }
202
-
203
- viewModel. moveHour. bind { [ weak self] moveHour in
204
- self ? . rootView. moveHourTextField. text = moveHour
205
- }
206
-
207
- viewModel. moveMinute. bind { [ weak self] moveMinute in
208
- self ? . rootView. moveMinuteTextField. text = moveMinute
209
- }
210
-
211
- viewModel. isValid. bind { [ weak self] isValid in
212
- self ? . rootView. doneButton. isEnabled = isValid
213
- }
214
-
215
- viewModel. errMessage. bind { [ weak self] err in
216
- if !err. isEmpty {
217
- self ? . showToast ( err)
218
- }
219
- }
220
-
221
- viewModel. isSucceedToSave. bind { [ weak self] _ in
222
- if self ? . viewModel. isSucceedToSave. value == true {
223
- DispatchQueue . main. async {
224
- let viewController = SetReadyCompletedViewController ( )
225
- self ? . navigationController? . pushViewController (
226
- viewController,
227
- animated: true
228
- )
229
- }
230
- }
231
- }
232
- }
233
- }
0 commit comments