diff --git a/Projects/Feature/SettingsFeature/Sources/Component/SettingsBlockView.swift b/Projects/Feature/SettingsFeature/Sources/Component/SettingsBlockView.swift new file mode 100644 index 0000000..1749601 --- /dev/null +++ b/Projects/Feature/SettingsFeature/Sources/Component/SettingsBlockView.swift @@ -0,0 +1,49 @@ +import SwiftUI +import UIKit + +struct SettingsBlockView: View { + let spacing: CGFloat + let corners: UIRectCorner + let action: (() -> Void)? + let label: () -> Content + + init( + spacing: CGFloat = 16, + corners: UIRectCorner = .allCorners, + action: (() -> Void)? = nil, + label: @escaping () -> Content + ) { + self.spacing = spacing + self.corners = corners + self.action = action + self.label = label + } + + var body: some View { + if let action { + Button(action: action) { + VStack(alignment: .leading, spacing: spacing) { + label() + .frame(maxWidth: .infinity, alignment: .leading) + } + .padding(16) + .frame(maxWidth: .infinity) + .background { + Color.cardBackgroundSecondary + } + .cornerRadius(16, corners: corners) + } + } else { + VStack(alignment: .leading, spacing: spacing) { + label() + .frame(maxWidth: .infinity, alignment: .leading) + } + .padding(16) + .frame(maxWidth: .infinity) + .background { + Color.cardBackgroundSecondary + } + .cornerRadius(16, corners: corners) + } + } +} diff --git a/Projects/Feature/SettingsFeature/Sources/SettingsCore.swift b/Projects/Feature/SettingsFeature/Sources/SettingsCore.swift index 35314b8..c03bf38 100644 --- a/Projects/Feature/SettingsFeature/Sources/SettingsCore.swift +++ b/Projects/Feature/SettingsFeature/Sources/SettingsCore.swift @@ -66,16 +66,16 @@ public struct SettingsCore: Reducer { public var body: some ReducerOf { Reduce { state, action in switch action { - case .onAppear: - let pageShowedEvengLog = PageShowedEventLog(pageName: "setting_page") - TWLog.event(pageShowedEvengLog) - - state.schoolName = userDefaultsClient.getValue(.school) as? String ?? "" - state.grade = userDefaultsClient.getValue(.grade) as? Int ?? 0 - state.class = userDefaultsClient.getValue(.class) as? Int ?? 0 - state.isSkipWeekend = userDefaultsClient.getValue(.isSkipWeekend) as? Bool ?? false - state.isSkipAfterDinner = userDefaultsClient.getValue(.isSkipAfterDinner) as? Bool ?? true - state.isOnModifiedTimeTable = userDefaultsClient.getValue(.isOnModifiedTimeTable) as? Bool ?? false +// case .onAppear: +// let pageShowedEvengLog = PageShowedEventLog(pageName: "setting_page") +// TWLog.event(pageShowedEvengLog) +// +// state.schoolName = userDefaultsClient.getValue(.school) as? String ?? "" +// state.grade = userDefaultsClient.getValue(.grade) as? Int ?? 0 +// state.class = userDefaultsClient.getValue(.class) as? Int ?? 0 +// state.isSkipWeekend = userDefaultsClient.getValue(.isSkipWeekend) as? Bool ?? false +// state.isSkipAfterDinner = userDefaultsClient.getValue(.isSkipAfterDinner) as? Bool ?? true +// state.isOnModifiedTimeTable = userDefaultsClient.getValue(.isOnModifiedTimeTable) as? Bool ?? false case let .isSkipWeekendChanged(isSkipWeekend): state.isSkipWeekend = isSkipWeekend @@ -136,21 +136,27 @@ public struct SettingsCore: Reducer { case .consultingButtonDidTap: if deviceClient.isPad() { - state.alert = AlertState { - .init("오늘 뭐임") - } actions: { - ButtonState.default(.init("깃허브"), action: .send(.githubIssueButtonDidTap)) - ButtonState.default(.init("메일"), action: .send(.mailIssueButtonDidTap)) - ButtonState.cancel(.init("취소")) - } + state.alert = AlertState( + title: { + TextState.init("오늘 뭐임") + }, + actions: { + ButtonState.default(.init("깃허브"), action: .send(.githubIssueButtonDidTap)) + ButtonState.default(.init("메일"), action: .send(.mailIssueButtonDidTap)) + ButtonState.cancel(.init("취소")) + } + ) } else { - state.confirmationDialog = ConfirmationDialogState { - .init("문의하기") - } actions: { - ButtonState.default(.init("깃허브"), action: .send(.githubIssueButtonDidTap)) - ButtonState.default(.init("메일"), action: .send(.mailIssueButtonDidTap)) - ButtonState.cancel(.init("취소")) - } + state.confirmationDialog = ConfirmationDialogState( + title: { + TextState.init("문의하기") + }, + actions: { + ButtonState.default(.init("깃허브"), action: .send(.githubIssueButtonDidTap)) + ButtonState.default(.init("메일"), action: .send(.mailIssueButtonDidTap)) + ButtonState.cancel(.init("취소")) + } + ) } let log = InquireButtonClickedEventLog() @@ -184,19 +190,18 @@ public struct SettingsCore: Reducer { return .none } - .ifLet(\.$alert, action: \.alert) - .ifLet(\.$confirmationDialog, action: \.confirmationDialog) - .ifLet(\.$schoolSettingCore, action: \.schoolSettingCore) { - SchoolSettingCore() - } - .ifLet(\.$allergySettingCore, action: \.allergySettingCore) { - AllergySettingCore() - } - .ifLet(\.$modifyTimeTableCore, action: \.modifyTimeTableCore) { - ModifyTimeTableCore() - } - .ifLet(\.$tutorialCore, action: \.tutorialCore) { - TutorialCore() - } + .subFeatures() + } +} + +extension Reducer where State == SettingsCore.State, Action == SettingsCore.Action { + func subFeatures() -> some ReducerOf { + self + .ifLet(\.$alert, action: /Action.alert) + .ifLet(\.$confirmationDialog, action: /Action.confirmationDialog) + .ifLet(\.$schoolSettingCore, action: /Action.schoolSettingCore) { SchoolSettingCore() } + .ifLet(\.$allergySettingCore, action: /Action.allergySettingCore) { AllergySettingCore() } + .ifLet(\.$modifyTimeTableCore, action: /Action.modifyTimeTableCore) { ModifyTimeTableCore() } + .ifLet(\.$tutorialCore, action: /Action.tutorialCore) { TutorialCore() } } } diff --git a/Projects/Feature/SettingsFeature/Sources/SettingsView.swift b/Projects/Feature/SettingsFeature/Sources/SettingsView.swift index e93e9cb..9631f33 100644 --- a/Projects/Feature/SettingsFeature/Sources/SettingsView.swift +++ b/Projects/Feature/SettingsFeature/Sources/SettingsView.swift @@ -63,26 +63,28 @@ public struct SettingsView: View { @ViewBuilder func schoolSettingsView() -> some View { - blockView(spacing: 12) { + SettingsBlockView(spacing: 12) { viewStore.send(.schoolBlockButtonDidTap) } label: { - settingsOptionsIconView(.school) + VStack(spacing: 12) { + settingsOptionsIconView(.school) - VStack(alignment: .leading, spacing: 8) { - Text("\(viewStore.grade)학년 \(viewStore.class)반") - .twFont(.caption1, color: .textSecondary) + VStack(alignment: .leading, spacing: 8) { + Text("\(viewStore.grade)학년 \(viewStore.class)반") + .twFont(.caption1, color: .textSecondary) - Text("\(viewStore.schoolName)") - .twFont(.body3, color: .textPrimary) + Text("\(viewStore.schoolName)") + .twFont(.body3, color: .textPrimary) + } + .frame(maxWidth: .infinity, alignment: .leading) } - .frame(maxWidth: .infinity, alignment: .leading) } } // MARK: - Settings Chevron @ViewBuilder func allergySettingsView() -> some View { - blockView(corners: [.topLeft, .topRight]) { + SettingsBlockView(corners: [.topLeft, .topRight]) { viewStore.send(.allergyBlockButtonDidTap) } label: { settingsOptionChevronView(icon: .allergySetting, text: "알레르기 설정") @@ -91,7 +93,7 @@ public struct SettingsView: View { @ViewBuilder func timeTableSettingsView() -> some View { - blockView(corners: []) { + SettingsBlockView(corners: []) { viewStore.send(.modifyTimeTableButtonDidTap) } label: { settingsOptionChevronView(icon: .writingPencil, text: "시간표 수정") @@ -100,7 +102,7 @@ public struct SettingsView: View { @ViewBuilder func tutorialSettingsView() -> some View { - blockView { + SettingsBlockView { viewStore.send(.tutorialButtonDidTap) } label: { settingsOptionChevronView(icon: .tutorial, text: "사용법") @@ -109,7 +111,7 @@ public struct SettingsView: View { @ViewBuilder func consultingSettingsView() -> some View { - blockView(corners: [.bottomLeft, .bottomRight]) { + SettingsBlockView(corners: [.bottomLeft, .bottomRight]) { viewStore.send(.consultingButtonDidTap) } label: { settingsOptionChevronView(icon: .consulting, text: "문의하기") @@ -119,7 +121,7 @@ public struct SettingsView: View { // MARK: - Settings Toggle @ViewBuilder func skipAfterDinnerView() -> some View { - blockView(corners: [.topLeft, .topRight]) { + SettingsBlockView(corners: [.topLeft, .topRight]) { settingsOptionToggleView( icon: .smallMeal, text: "오후 7시 이후 내일 급식 표시", @@ -133,7 +135,7 @@ public struct SettingsView: View { @ViewBuilder func onModifiedTimeTable() -> some View { - blockView(corners: []) { + SettingsBlockView(corners: []) { settingsOptionToggleView( icon: .clock, text: "커스텀 시간표 표시", @@ -147,7 +149,7 @@ public struct SettingsView: View { @ViewBuilder func skipWeekendView() -> some View { - blockView(corners: [.bottomLeft, .bottomRight]) { + SettingsBlockView(corners: [.bottomLeft, .bottomRight]) { settingsOptionToggleView( icon: .calendar, text: "주말 건너뛰기", @@ -159,41 +161,6 @@ public struct SettingsView: View { } } - // MARK: - Reusable View - @ViewBuilder - func blockView( - spacing: CGFloat = 16, - corners: UIRectCorner = .allCorners, - action: (() -> Void)? = nil, - @ViewBuilder label: () -> some View - ) -> some View { - if let action { - Button(action: action) { - VStack(alignment: .leading, spacing: spacing) { - label() - .frame(maxWidth: .infinity, alignment: .leading) - } - .padding(16) - .frame(maxWidth: .infinity) - .background { - Color.cardBackgroundSecondary - } - .cornerRadius(16, corners: corners) - } - } else { - VStack(alignment: .leading, spacing: spacing) { - label() - .frame(maxWidth: .infinity, alignment: .leading) - } - .padding(16) - .frame(maxWidth: .infinity) - .background { - Color.cardBackgroundSecondary - } - .cornerRadius(16, corners: corners) - } - } - @ViewBuilder func settingsOptionChevronView( icon image: Image,