Skip to content

Commit 9a4564d

Browse files
committed
refactor: 웹페이지 입력은 얼럿에서 시트에서 내비게이션 형태로 수정
1 parent 9f0f069 commit 9a4564d

3 files changed

Lines changed: 123 additions & 148 deletions

File tree

Application/DevLogPresentation/Sources/Home/Home/HomeFeature.swift

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct HomeFeature {
1616
struct State: Equatable {
1717
@Presents var alert: AlertState<Never>?
1818
@Presents var sheet: SheetState?
19+
@Presents var webPageInput: WebPageInputState?
1920
var preferences = [TodoCategoryItem]()
2021
var recentTodos = [RecentTodoItem]()
2122
var webPages = [WebPageItem]()
@@ -28,18 +29,8 @@ struct HomeFeature {
2829
var deletedWebPageURLString: String?
2930
var loading = LoadingFeature.State()
3031

31-
var showContentPicker: Bool {
32-
sheet == .contentPicker
33-
}
34-
35-
var reorderTodo: Bool {
36-
sheet == .reorderTodo
37-
}
38-
39-
var contentPickerDestination: ContentPickerState.Destination? {
40-
guard case .contentPicker(let state) = sheet else { return nil }
41-
return state.destination
42-
}
32+
var showContentPicker: Bool { sheet == .contentPicker }
33+
var reorderTodo: Bool { sheet == .reorderTodo }
4334

4435
var isPreferencesLoading: Bool {
4536
loading.visibleTargets.contains(LoadingTarget.preferences.target)
@@ -61,6 +52,7 @@ struct HomeFeature {
6152
enum Action: Equatable {
6253
case alert(PresentationAction<Never>)
6354
case sheet(PresentationAction<Sheet>)
55+
case webPageInput(PresentationAction<Never>)
6456
case startObserving
6557
case fetchData
6658
case refreshRecentTodos
@@ -95,26 +87,19 @@ struct HomeFeature {
9587
}
9688

9789
@ObservableState
98-
struct ContentPickerState: Equatable {
99-
var destination: Destination?
100-
101-
enum Destination: Equatable {
102-
case webPageInput
103-
}
90+
struct WebPageInputState: Equatable, Identifiable {
91+
let id = UUID()
10492
}
10593

10694
@ObservableState
10795
@CasePathable
10896
enum SheetState: Equatable {
10997
case reorderTodo
110-
case contentPicker(ContentPickerState)
111-
112-
static let contentPicker = Self.contentPicker(.init())
98+
case contentPicker
11399
}
114100

115101
enum Sheet: Equatable {
116102
case tapCloseButton
117-
case setContentPickerDestination(ContentPickerState.Destination?)
118103
}
119104

120105
enum ModalType: Hashable {
@@ -167,12 +152,12 @@ struct HomeFeature {
167152
switch action {
168153
case .alert:
169154
break
155+
case .webPageInput(.dismiss):
156+
state.webPageInput = nil
157+
case .webPageInput:
158+
break
170159
case .sheet(.dismiss), .sheet(.presented(.tapCloseButton)):
171160
state.sheet = nil
172-
case .sheet(.presented(.setContentPickerDestination(let destination))):
173-
guard case .contentPicker(var sheetState) = state.sheet else { break }
174-
sheetState.destination = destination
175-
state.sheet = .contentPicker(sheetState)
176161
case .sheet:
177162
break
178163
case .startObserving:
@@ -188,12 +173,7 @@ struct HomeFeature {
188173
case .networkStatusChanged(let isConnected):
189174
state.isNetworkConnected = isConnected
190175
case .tapWebPageInput:
191-
if case .contentPicker(var sheetState) = state.sheet {
192-
sheetState.destination = .webPageInput
193-
state.sheet = .contentPicker(sheetState)
194-
} else {
195-
state.sheet = .contentPicker(.init(destination: .webPageInput))
196-
}
176+
state.webPageInput = .init()
197177
case .setSheet(let sheet):
198178
state.sheet = sheet
199179
case .setPresentation(let presentation, let isPresented):
@@ -232,6 +212,7 @@ struct HomeFeature {
232212
Self.setAlert(&state, isPresented: true, type: .invalidURL)
233213
return .none
234214
}
215+
state.webPageInput = nil
235216
state.sheet = nil
236217
Self.setAlert(&state, isPresented: false, type: nil)
237218
return addWebPageEffect(normalizedURL)
@@ -265,14 +246,17 @@ struct HomeFeature {
265246
}
266247
.ifLet(\.$alert, action: \.alert)
267248
.ifLet(\.$sheet, action: \.sheet) {
268-
HomeSheetFeature()
249+
EmptyReducer()
250+
}
251+
.ifLet(\.$webPageInput, action: \.webPageInput) {
252+
HomeWebPageInputFeature()
269253
}
270254
}
271255
}
272256

273-
private struct HomeSheetFeature: Reducer {
274-
typealias State = HomeFeature.SheetState
275-
typealias Action = HomeFeature.Sheet
257+
private struct HomeWebPageInputFeature: Reducer {
258+
typealias State = HomeFeature.WebPageInputState
259+
typealias Action = Never
276260

277261
var body: some ReducerOf<Self> {
278262
EmptyReducer()

Application/DevLogPresentation/Sources/Home/Home/HomeView.swift

Lines changed: 101 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,8 @@ struct HomeView: View {
3535
.listStyle(.insetGrouped)
3636
.navigationTitle(String(localized: "nav_home"))
3737
.toolbar { toolbar }
38-
.sheet(item: $store.scope(state: \.sheet, action: \.sheet)) { sheetStore in
39-
switch sheetStore.state {
40-
case .reorderTodo:
41-
CategoryManageView(
42-
preferences: store.preferences,
43-
onDismiss: { array in
44-
store.send(.sheet(.dismiss))
45-
store.send(.orderTodoCategory(array), animation: .default)
46-
}
47-
)
48-
case .contentPicker:
49-
contentPicker
50-
}
51-
}
38+
.alert($store.scope(state: \.alert, action: \.alert))
39+
.sheet(item: $store.scope(state: \.sheet, action: \.sheet), content: sheetContent)
5240
.fullScreenCover(isPresented: Binding(
5341
get: { store.showTodoEditor },
5442
set: { store.send(.setPresentation(.todoEditor, $0)) }
@@ -69,14 +57,112 @@ struct HomeView: View {
6957
)) {
7058
SearchView(store: coordinator.makeSearchStore())
7159
}
72-
.alert($store.scope(state: \.alert, action: \.alert))
7360
.overlay {
7461
if store.isAppending {
7562
LoadingView()
7663
}
7764
}
7865
}
7966

67+
@ViewBuilder
68+
private func sheetContent(_ sheetStore: Store<HomeFeature.SheetState, HomeFeature.Sheet>) -> some View {
69+
if sheetStore.state == .contentPicker {
70+
NavigationStack {
71+
List {
72+
Section {
73+
if store.isPreferencesLoading {
74+
LoadingView()
75+
} else {
76+
let preferences = store.preferences.filter(\.isVisible)
77+
ForEach(preferences, id: \.id) { item in
78+
Button {
79+
DispatchQueue.main.async {
80+
openTodoEditor(for: item.category)
81+
}
82+
} label: {
83+
labelImage(
84+
text: item.localizedName,
85+
systemName: item.symbolName,
86+
imageColor: item.color
87+
)
88+
}
89+
}
90+
}
91+
} header: {
92+
Text("TODO")
93+
.foregroundStyle(Color(.label))
94+
}
95+
96+
Section {
97+
Button {
98+
store.send(.tapWebPageInput)
99+
} label: {
100+
labelImage(
101+
text: "URL",
102+
systemName: "globe",
103+
imageColor: .blue
104+
)
105+
}
106+
} header: {
107+
Text("Web Page")
108+
.foregroundStyle(Color(.label))
109+
}
110+
}
111+
.navigationDestination(
112+
item: $store.scope(state: \.webPageInput, action: \.webPageInput)
113+
) { _ in
114+
Form {
115+
Section {
116+
TextField(
117+
"https://",
118+
text: Binding(
119+
get: { store.webPageURLInput },
120+
set: { store.send(.updateWebPageURLInput($0)) }
121+
)
122+
)
123+
.textInputAutocapitalization(.never)
124+
.keyboardType(.URL)
125+
} footer: {
126+
Text(String(localized: "home_webpage_input_message"))
127+
}
128+
}
129+
.scrollDisabled(true)
130+
.toolbar {
131+
ToolbarItem(placement: .principal) {
132+
Text(String(localized: "home_webpage_input_title"))
133+
}
134+
ToolbarItem(placement: .topBarTrailing) {
135+
Button(String(localized: "home_add")) {
136+
store.send(.addWebPage)
137+
}
138+
}
139+
}
140+
}
141+
.toolbar {
142+
ToolbarItem(placement: .principal) {
143+
Text(String(localized: "nav_home_content"))
144+
}
145+
ToolbarItem(placement: .topBarLeading) {
146+
Button {
147+
store.send(.sheet(.presented(.tapCloseButton)))
148+
} label: {
149+
Image(systemName: "xmark")
150+
.bold()
151+
}
152+
}
153+
}
154+
}
155+
} else {
156+
CategoryManageView(
157+
preferences: store.preferences,
158+
onDismiss: { array in
159+
store.send(.sheet(.dismiss))
160+
store.send(.orderTodoCategory(array), animation: .default)
161+
}
162+
)
163+
}
164+
}
165+
80166
private var todoSection: some View {
81167
Section(content: {
82168
if store.isPreferencesLoading {
@@ -269,101 +355,6 @@ struct HomeView: View {
269355
}
270356
}
271357

272-
private var contentPicker: some View {
273-
NavigationStack {
274-
List {
275-
Section {
276-
if store.isPreferencesLoading {
277-
LoadingView()
278-
} else {
279-
let preferences = store.preferences.filter(\.isVisible)
280-
ForEach(preferences, id: \.id) { item in
281-
Button {
282-
DispatchQueue.main.async {
283-
openTodoEditor(for: item.category)
284-
}
285-
} label: {
286-
labelImage(
287-
text: item.localizedName,
288-
systemName: item.symbolName,
289-
imageColor: item.color
290-
)
291-
}
292-
}
293-
}
294-
} header: {
295-
Text("TODO")
296-
.foregroundStyle(Color(.label))
297-
}
298-
299-
Section {
300-
Button {
301-
store.send(.tapWebPageInput)
302-
} label: {
303-
labelImage(
304-
text: "URL",
305-
systemName: "globe",
306-
imageColor: .blue
307-
)
308-
}
309-
} header: {
310-
Text("Web Page")
311-
.foregroundStyle(Color(.label))
312-
}
313-
}
314-
.navigationDestination(
315-
isPresented: Binding(
316-
get: { store.contentPickerDestination == .webPageInput },
317-
set: { isPresented in
318-
if !isPresented {
319-
store.send(.sheet(.presented(.setContentPickerDestination(nil))))
320-
}
321-
}
322-
)
323-
) {
324-
Form {
325-
Section {
326-
TextField(
327-
"https://",
328-
text: Binding(
329-
get: { store.webPageURLInput },
330-
set: { store.send(.updateWebPageURLInput($0)) }
331-
)
332-
)
333-
.textInputAutocapitalization(.never)
334-
.keyboardType(.URL)
335-
} footer: {
336-
Text(String(localized: "home_webpage_input_message"))
337-
}
338-
}
339-
.scrollDisabled(true)
340-
.toolbar {
341-
ToolbarItem(placement: .principal) {
342-
Text(String(localized: "home_webpage_input_title"))
343-
}
344-
ToolbarItem(placement: .topBarTrailing) {
345-
Button(String(localized: "home_add")) {
346-
store.send(.addWebPage)
347-
}
348-
}
349-
}
350-
}
351-
.toolbar {
352-
ToolbarItem(placement: .principal) {
353-
Text(String(localized: "nav_home_content"))
354-
}
355-
ToolbarItem(placement: .topBarLeading) {
356-
Button {
357-
store.send(.sheet(.presented(.tapCloseButton)))
358-
} label: {
359-
Image(systemName: "xmark")
360-
.bold()
361-
}
362-
}
363-
}
364-
}
365-
}
366-
367358
private func labelImage(
368359
text: String,
369360
systemName: String,

Application/DevLogPresentation/Tests/Home/HomeFeatureTestSupport.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ struct HomeStoreTestAdapter: HomeStateDriving {
136136
var webPages: [WebPageItem] { store.state.webPages }
137137
var isNetworkConnected: Bool { store.state.isNetworkConnected }
138138
var showContentPicker: Bool { store.state.showContentPicker }
139-
var showWebPageInputNavigation: Bool { store.state.contentPickerDestination == .webPageInput }
139+
var showWebPageInputNavigation: Bool { store.state.showWebPageInput }
140140
var showTodoEditor: Bool { store.state.showTodoEditor }
141141
var showAlert: Bool { store.state.alert != nil }
142142
var alertType: HomeFeature.AlertType? {
@@ -198,7 +198,7 @@ struct HomeStoreTestAdapter: HomeStateDriving {
198198
}
199199

200200
func openWebPageInput() async {
201-
await store.send(.tapWebPageInput)
201+
await store.send(.sheet(.presented(.contentPicker(.tapWebPageInput))))
202202
await drainReceivedActions()
203203
}
204204

0 commit comments

Comments
 (0)