Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Refactor] SettingView 리팩토링 / SettingReducer 구현 #81

Merged
merged 21 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 128 additions & 1 deletion Soomsil-USaint/Application/Feature/Setting/Core/SettingReducer.swift
Original file line number Diff line number Diff line change
@@ -5,10 +5,137 @@
// Created by 이조은 on 1/6/25.
//

import Foundation
import UIKit

import ComposableArchitecture
import YDS_SwiftUI

@Reducer
struct SettingReducer {
@ObservableState
struct State {
@Shared(.appStorage("permission")) var permission = false
@Presents var alert: AlertState<Action.Alert>?
var path = StackState<Path.State>()
var appState: AppReducer.State?
}

enum Action: BindableAction {
case binding(BindingAction<State>)
case logoutButtonTapped
case togglePushAuthorization(Bool)
case pushAuthorizationResponse(Result<Bool, Error>)
case requestPushAuthorizationResponse(Result<Bool, Error>)
case termsOfServiceButtonTapped
case privacyPolicyButtonTapped
case path(StackActionOf<Path>)
case alert(PresentationAction<Alert>)
case appState(AppReducer.Action)

enum Alert: Equatable {
case logout
case configurePushAuthorization
Comment on lines +36 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소한 부분이지만, Alert의 Action도 버튼을 누른 것이라면, logoutTapped와 같이 "Tapped"를 붙이는 것은 어떤가요?
추후에 CoreData 내 정보를 삭제하기 위해 GradeClient 및 StudentClient의 delete를 실행할 때, Response를 받는 부분과 구분을 확실하게 하려면 네이밍을 확실하게 구분짓는게 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀대로 네이밍을 통해 혼선을 방지할 수 있을 것 같네요!
#84 이슈에서 반영해놓겠습니다!

}
}

@Dependency(\.localNotificationClient) var localNotificationClient

var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .logoutButtonTapped:
state.alert = AlertState {
TextState("로그아웃 하시겠습니까?")
} actions: {
ButtonState(
role: .destructive,
action: .logout) {
TextState("로그아웃")
}
ButtonState(
role: .cancel) {
TextState("취소")
}
}
return .none
case .alert(.presented(.logout)):
debugPrint("settingReducer: logout")
YDSToast("로그아웃", haptic: .success)
state.appState = .loggedOut(LoginReducer.State())
return .none
case .togglePushAuthorization(true):
return .run { send in
await send(.pushAuthorizationResponse(Result {
await localNotificationClient.getPushAuthorizationStatus()
}))
}
case .togglePushAuthorization(false):
state.$permission.withLock { $0 = false }
return .none
case .pushAuthorizationResponse(.success(let granted)):
state.$permission.withLock { $0 = granted }
if !granted {
state.alert = AlertState {
TextState("알림 설정")
} actions: {
ButtonState(
role: .destructive,
action: .configurePushAuthorization
) {
TextState("설정")
}
ButtonState(
role: .cancel) {
TextState("취소")
}
} message: {
TextState("알림에 대한 권한 사용을 거부하였습니다. 기능 사용을 원하실 경우 설정 > 앱 > 숨쉴때 유세인트 > 알림 권한 허용을 해주세요.")
}
}
return .none
case .requestPushAuthorizationResponse(.success(let granted)):
if !granted {
if let url = URL(string: UIApplication.openSettingsURLString) {
DispatchQueue.main.async {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
}
}
}
return .none
case .alert(.presented(.configurePushAuthorization)):
debugPrint("alert permission")
return .run { send in
await send(.requestPushAuthorizationResponse(Result {
try await localNotificationClient.requestPushAuthorization()
}))
}
case .termsOfServiceButtonTapped:
state.path.append(
.navigateToTermsWebView(WebReducer.State(
url: URL(string: "https://auth.yourssu.com/terms/service.html")!)))
return .none
case .privacyPolicyButtonTapped:
state.path.append(.navigateToTermsWebView(WebReducer.State(
url: URL(string: "https://auth.yourssu.com/terms/information.html")!)))
return .none
default:
return .none
}
}
.ifLet(\.appState, action: \.appState) {
AppReducer()
}
.ifLet(\.$alert, action: \.alert)
.forEach(\.path, action: \.path)
}
}

extension SettingReducer {
@Reducer
enum Path {
case navigateToTermsWebView(WebReducer)
}
}
36 changes: 36 additions & 0 deletions Soomsil-USaint/Application/Feature/Setting/Core/WebReducer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// WebReducer.swift
// Soomsil-USaint
//
// Created by 최지우 on 1/27/25.
//

import Foundation

import ComposableArchitecture

@Reducer
struct WebReducer {

@ObservableState
struct State: Equatable {
let url: URL
}

enum Action {
case dismiss
}

@Dependency(\.dismiss) var dismiss

var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .dismiss:
return .run { _ in
await self.dismiss()
}
}
}
}
}
Loading