Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
47 changes: 32 additions & 15 deletions DevLog/Presentation/ViewModel/ProfileViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@ final class ProfileViewModel: Store {
var email: String = ""
var statusMessage: String = ""
var avatarURL: URL?

var showDoneButton: Bool = false
var showToast: Bool = false
var toastMessage: String = ""
var showAlert: Bool = false
var alertTitle: String = ""
var alertMessage: String = ""
var resetButtonEnabled: Bool {
!statusMessage.isEmpty && showDoneButton
}
}

enum Action {
case onAppear
case tapConfirmButton
case setAlert(Bool)
case tapResetStatusMessageButton
case willUpdateStatusMessage
case fetchUserData(UserProfile)
case updateStatusMessage(String)
case updateStatusTextFieldFocus(Bool)
case tapCloseToast
}

enum SideEffect {
Expand All @@ -52,11 +51,12 @@ final class ProfileViewModel: Store {

func reduce(with action: Action) -> [SideEffect] {
var state = self.state
var effects: [SideEffect] = []
switch action {
case .onAppear:
return [.fetchUserData]
case .tapConfirmButton:
state.showToast = false
effects = [.fetchUserData]
case .setAlert(let isPresented):
setAlert(&state, isPresented: isPresented)
case .tapResetStatusMessageButton:
state.statusMessage = ""
case .fetchUserData(let profile):
Expand All @@ -66,29 +66,46 @@ final class ProfileViewModel: Store {
state.avatarURL = profile.avatarURL
case .willUpdateStatusMessage:
let message = self.state.statusMessage
return [.updateStatusMessage(message)]
effects = [.updateStatusMessage(message)]
case .updateStatusMessage(let message):
state.statusMessage = message
case .updateStatusTextFieldFocus(let focused):
state.showDoneButton = focused
case .tapCloseToast:
state.showToast = false
}
self.state = state
return []
return effects
}

func run(_ effect: SideEffect) {
switch effect {
case .fetchUserData:
Task {
let profile = try await fetchUserDataUseCase.execute()
send(.fetchUserData(profile))
do {
let profile = try await fetchUserDataUseCase.execute()
send(.fetchUserData(profile))
} catch {
send(.setAlert(true))
}
}
case .updateStatusMessage(let message):
Task {
try await upsertStatusMessageUseCase.execute(message)
do {
try await upsertStatusMessageUseCase.execute(message)
} catch {
send(.setAlert(true))
}
}
}
}
}

private extension ProfileViewModel {
func setAlert(
_ state: inout State,
isPresented: Bool
) {
state.alertTitle = "오류"
state.alertMessage = "문제가 발생했습니다. 잠시 후 다시 시도해주세요."
state.showAlert = isPresented
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ import Foundation

final class PushNotificationSettingsViewModel: Store {
struct State {
var pushNotificationEnable = false
var pushNotificationTime = Date()
var showTimePicker = false
var sheetHeight = CGFloat.pi
var pushNotificationEnable: Bool = false
var pushNotificationTime: Date = .init()
var showTimePicker: Bool = false
var isLoading: Bool = false
var sheetHeight: CGFloat = .pi
var showSheet: Bool = false
var showAlert: Bool = false
var alertTitle: String = ""
var alertMessage: String = ""
var pushNotificationHour: Int {
Calendar.current.component(.hour, from: pushNotificationTime)
}
Expand All @@ -23,6 +28,8 @@ final class PushNotificationSettingsViewModel: Store {

enum Action {
case onAppear
case setAlert(Bool)
case setLoading(Bool)
case setPushNotificationEnable(Bool)
case setPushNotificationHour(Int)
case setPushNotificationTime(Date)
Expand Down Expand Up @@ -53,6 +60,10 @@ final class PushNotificationSettingsViewModel: Store {
switch action {
case .onAppear:
return [.fetchPushNotificationSettings]
case .setAlert(let isPresented):
setAlert(&state, isPresented: isPresented)
case .setLoading(let value):
state.isLoading = value
case .setPushNotificationEnable(let value):
self.state.pushNotificationEnable = value
return [.updatePushNotificationSettings]
Expand Down Expand Up @@ -82,24 +93,46 @@ final class PushNotificationSettingsViewModel: Store {
switch effect {
case .fetchPushNotificationSettings:
Task {
let settings = try await fetchPushSettingsUseCase.execute()
self.send(.setPushNotificationEnable(settings.isEnabled))
if let hour = settings.scheduledTime.hour,
let minute = settings.scheduledTime.minute,
let date = calendar.date(bySettingHour: hour, minute: minute, second: 0, of: Date()) {
self.send(.setPushNotificationTime(date))
do {
defer { send(.setLoading(false)) }
send(.setLoading(true))
let settings = try await fetchPushSettingsUseCase.execute()
self.send(.setPushNotificationEnable(settings.isEnabled))
if let hour = settings.scheduledTime.hour,
let minute = settings.scheduledTime.minute,
let date = calendar.date(bySettingHour: hour, minute: minute, second: 0, of: Date()) {
self.send(.setPushNotificationTime(date))
}
} catch {
send(.setAlert(true))
}
}
case .updatePushNotificationSettings:
Task {
let dateComponents = calendar.dateComponents([.hour, .minute], from: state.pushNotificationTime)
let settings = PushNotificationSettings(
isEnabled: state.pushNotificationEnable,
scheduledTime: dateComponents
)

try await updatePushSettingsUseCase.execute(settings)
do {
defer { send(.setLoading(false)) }
send(.setLoading(true))
let dateComponents = calendar.dateComponents([.hour, .minute], from: state.pushNotificationTime)
let settings = PushNotificationSettings(
isEnabled: state.pushNotificationEnable,
scheduledTime: dateComponents
)
try await updatePushSettingsUseCase.execute(settings)
} catch {
send(.setAlert(true))
}
}
}
}
}

extension PushNotificationSettingsViewModel {
func setAlert(
_ state: inout State,
isPresented: Bool
) {
state.alertTitle = "오류"
state.alertMessage = "문제가 발생했습니다. 잠시 후 다시 시도해주세요."
state.showAlert = isPresented
}
}
19 changes: 18 additions & 1 deletion DevLog/Presentation/ViewModel/SearchViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ final class SearchViewModel: Store {
$0.displayURL.localizedCaseInsensitiveContains(searchQuery)
}
}
var showAlert: Bool = false
var alertTitle: String = ""
var alertMessage: String = ""
}

enum Action {
case onAppear
case fetchWebPage([WebPageItem]? = nil)
case selectWebPage(WebPageItem)
case setAlert(Bool)
case setLoading(Bool)
case setSearching(Bool)
case setSearchQuery(String)
Expand Down Expand Up @@ -59,6 +63,8 @@ final class SearchViewModel: Store {
state.webPages = OrderedSet(items)
case .selectWebPage(let item):
state.selectedWebPage = item
case .setAlert(let isPresented):
setAlert(&state, isPresented: isPresented)
case .setLoading(let isLoading):
state.isLoading = isLoading
case .setSearching(let isSearching):
Expand All @@ -81,9 +87,20 @@ final class SearchViewModel: Store {
let items = try await self.fetchWebPagesUseCase.execute().map { WebPageItem(from: $0) }
send(.fetchWebPage(items))
} catch {

send(.setAlert(true))
}
}
}
}
}

private extension SearchViewModel {
func setAlert(
_ state: inout State,
isPresented: Bool
) {
state.alertTitle = "오류"
state.alertMessage = "문제가 발생했습니다. 잠시 후 다시 시도해주세요."
state.showAlert = isPresented
}
}
64 changes: 41 additions & 23 deletions DevLog/Presentation/ViewModel/SettingViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,32 @@ import Foundation
final class SettingViewModel: Store {
struct State {
var theme = ""
var showDeleteUserAlert = false
var showSignOutAlert = false
var toastMessage = ""
var showToast = false
var isLoading = false
var showAlert: Bool = false
var alertTitle: String = ""
var alertType: AlertType?
var alertMessage: String = ""
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
let policyURL = Bundle.main.object(forInfoDictionaryKey: "PRIVACY_POLICY_URL") as? String
}

enum Action {
case toggleToast(Bool)
case setAlert(isPresented: Bool, type: AlertType? = nil)
case setLoading(Bool)
case setTheme(String)
case setToastMessage(String)
case tapDeleteAuthButton
case tapSignOutButton
case toggleDeleteUserAlert(Bool)
case toggleSignOutAlert(Bool)
}

enum SideEffect {
case deleteAuth
case signOut
}

enum AlertType {
case signOut, delete, error
}

private let deleteAuthuseCase: DeleteAuthUseCase
private let signOutUseCase: SignOutUseCase
private let sessionUseCase: AuthSessionUseCase
Expand All @@ -53,22 +54,16 @@ final class SettingViewModel: Store {

func reduce(with action: Action) -> [SideEffect] {
switch action {
case .toggleToast(let value):
state.showToast = value
case .setAlert(let isPresented, let type):
setAlert(&state, isPresented: isPresented, type: type)
case .setLoading(let value):
state.isLoading = value
case .setTheme(let value):
state.theme = value
case .setToastMessage(let message):
state.toastMessage = message
case .tapDeleteAuthButton:
break
return [.deleteAuth]
case .tapSignOutButton:
return [.signOut]
case .toggleDeleteUserAlert(let value):
state.showDeleteUserAlert = value
case .toggleSignOutAlert(let value):
state.showSignOutAlert = value
}
return []
}
Expand All @@ -79,27 +74,50 @@ final class SettingViewModel: Store {
Task {
do {
defer { send(.setLoading(false)) }
send(.toggleDeleteUserAlert(false))
send(.setAlert(isPresented: false))
send(.setLoading(true))
try await deleteAuthuseCase.execute()
} catch {
send(.toggleToast(true))
send(.setToastMessage(error.localizedDescription))
send(.setAlert(isPresented: true, type: .error))
}
}
case .signOut:
Task {
do {
defer { send(.setLoading(false)) }
send(.toggleSignOutAlert(false))
send(.setAlert(isPresented: false))
send(.setLoading(true))
try await signOutUseCase.execute()
sessionUseCase.execute(false)
} catch {
send(.toggleToast(true))
send(.setToastMessage(error.localizedDescription))
send(.setAlert(isPresented: true, type: .error))
}
}
}
}
}

private extension SettingViewModel {
func setAlert(
_ state: inout State,
isPresented: Bool,
type: AlertType?
) {
switch type {
case .signOut:
state.alertTitle = "로그아웃"
state.alertMessage = "로그아웃 하시겠습니까?"
case .delete:
state.alertTitle = "정말 탈퇴하시겠습니까?"
state.alertMessage = "회원 탈퇴가 진행되면 모든 데이터가 지워지고 복구할 수 없습니다."
case .error:
state.alertTitle = "오류"
state.alertMessage = "문제가 발생했습니다. 잠시 후 다시 시도해주세요."
case .none:
state.alertTitle = ""
state.alertMessage = ""
}
state.showAlert = isPresented
state.alertType = type
}
}
2 changes: 0 additions & 2 deletions DevLog/Presentation/ViewModel/TodoEditorViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ final class TodoEditorViewModel: Store {
}
return []
}

func run(_ effect: SideEffect) { }
}

extension TodoEditorViewModel {
Expand Down
Loading