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
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ struct CategoryManageFeature {
case tapEditUserCategory(TodoCategoryItem)
case tapDeleteUserCategory(TodoCategoryItem)
case tapDoneButton
case setCategorySheet(CategorySheetState?)

enum Alert: Equatable {
case confirmDeleteUserCategory(TodoCategoryItem)
}

enum CategorySheet: Equatable {
case setCategoryName(String)
case setCategoryColor(String)
enum CategorySheet: BindableAction, Equatable {
case binding(BindingAction<CategorySheetState>)
case tapCloseButton
case tapRandomColorButton
case tapSaveButton
Expand All @@ -124,14 +124,6 @@ struct CategoryManageFeature {
state.categorySheet = nil
case .categorySheet(.presented(.tapCloseButton)):
state.categorySheet = nil
case .categorySheet(.presented(.setCategoryName(let name))):
state.categorySheet?.category.name = String(name.prefix(20))
case .categorySheet(.presented(.setCategoryColor(let colorHex))):
state.categorySheet?.category.colorHex = colorHex
case .categorySheet(.presented(.tapRandomColorButton)):
if let randomHexValue = Color.randomValue.hexValue {
state.categorySheet?.category.colorHex = randomHexValue
}
case .categorySheet(.presented(.tapSaveButton)):
if var item = state.categorySheet?.todoCategoryItem {
if let index = state.preferences.firstIndex(where: { $0.id == item.id }) {
Expand Down Expand Up @@ -175,10 +167,39 @@ struct CategoryManageFeature {
}
case .tapDoneButton:
break
case .setCategorySheet(let sheet):
state.categorySheet = sheet
}
return .none
}
.ifLet(\.$alert, action: \.alert)
.ifLet(\.$categorySheet, action: \.categorySheet) {
CategoryManageSheetFeature()
}
}
}

private struct CategoryManageSheetFeature: Reducer {
typealias State = CategoryManageFeature.CategorySheetState
typealias Action = CategoryManageFeature.Action.CategorySheet

var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .binding(\.category.name):
state.category.name = String(state.category.name.prefix(20))
case .binding:
break
case .tapRandomColorButton:
if let randomHexValue = Color.randomValue.hexValue {
state.category.colorHex = randomHexValue
}
case .tapCloseButton, .tapSaveButton:
break
}
return .none
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ struct CategoryManageView: View {
.navigationTitle(String(localized: "nav_todo_manage"))
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden()
.sheet(item: $store.scope(state: \.categorySheet, action: \.categorySheet)) { store in
CategoryManageSheet(store: store)
.sheet(item: $store.scope(state: \.categorySheet, action: \.categorySheet)) { sheetStore in
sheetContent(sheetStore)
}
.alert($store.scope(state: \.alert, action: \.alert))
.toolbar {
Expand All @@ -91,10 +91,17 @@ struct CategoryManageView: View {
}
.presentationDragIndicator(.visible)
}

@ViewBuilder
private func sheetContent(
_ sheetStore: Store<CategoryManageFeature.CategorySheetState, CategoryManageFeature.Action.CategorySheet>
) -> some View {
CategoryManageSheet(store: sheetStore)
}
}

private struct CategoryManageSheet: View {
let store: Store<CategoryManageFeature.CategorySheetState, CategoryManageFeature.Action.CategorySheet>
@Bindable var store: Store<CategoryManageFeature.CategorySheetState, CategoryManageFeature.Action.CategorySheet>

var body: some View {
NavigationStack {
Expand All @@ -103,10 +110,7 @@ private struct CategoryManageSheet: View {
HStack(spacing: 8) {
TextField(
"",
text: Binding(
get: { store.category.name },
set: { store.send(.setCategoryName($0)) }
),
text: $store.category.name,
prompt: Text(store.placeholder).foregroundStyle(.secondary)
)
.frame(height: UIFont.preferredFont(forTextStyle: .body).lineHeight)
Expand All @@ -119,21 +123,14 @@ private struct CategoryManageSheet: View {
}

Section {
let color = Color(hexString: store.category.colorHex) ?? .randomValue
ColorPicker(selection: Binding(
get: { color },
set: {
guard let hexValue = $0.hexValue else { return }
store.send(.setCategoryColor(hexValue))
}
), supportsOpacity: false) {
ColorPicker(selection: $store.category.colorHex.colorValue, supportsOpacity: false) {
Text(store.category.colorHex.isEmpty ? "#" : store.category.colorHex)
.overlay(alignment: .bottom) {
Rectangle()
.frame(height: 1)
.offset(y: 1)
}
.foregroundStyle(color)
.foregroundStyle(store.category.colorHex.colorValue)
.onTapGesture {
store.send(.tapRandomColorButton)
}
Expand All @@ -160,3 +157,14 @@ private struct CategoryManageSheet: View {
}
}
}

private extension String {
var colorValue: Color {
get { Color(hexString: self) ?? .randomValue }
set {
if let hexValue = newValue.hexValue {
self = hexValue
}
}
}
}
Comment thread
opficdev marked this conversation as resolved.
32 changes: 10 additions & 22 deletions Application/DevLogPresentation/Sources/Login/LoginFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct LoginFeature {
case error
}

@Dependency(SignInUseCaseDependency.self) var signInUseCase
@Dependency(\.signInUseCase) var signInUseCase

var body: some ReducerOf<Self> {
Reduce { state, action in
Expand Down Expand Up @@ -61,32 +61,20 @@ struct LoginFeature {
}
}

struct SignInUseCaseDependency {
var execute: (AuthProvider) async throws -> Void

init(execute: @escaping (AuthProvider) async throws -> Void) {
self.execute = execute
extension DependencyValues {
var signInUseCase: SignInUseCase {
get { self[SignInUseCaseKey.self] }
set { self[SignInUseCaseKey.self] = newValue }
}
}

extension SignInUseCaseDependency: DependencyKey {
static let liveValue = Self { _ in
preconditionFailure("SignInUseCaseDependency must be provided.")
}

static let testValue = liveValue

static func live(_ signInUseCase: SignInUseCase) -> SignInUseCaseDependency {
Self {
try await signInUseCase.execute($0)
}
private enum SignInUseCaseKey: DependencyKey {
static var liveValue: SignInUseCase {
preconditionFailure("SignInUseCase must be provided.")
}
}

extension DependencyValues {
var signInUseCase: SignInUseCaseDependency {
get { self[SignInUseCaseDependency.self] }
set { self[SignInUseCaseDependency.self] = newValue }
static var testValue: SignInUseCase {
liveValue
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct LoginView: View {
) {
LoginFeature()
} withDependencies: {
$0.signInUseCase = .live(signInUseCase)
$0.signInUseCase = signInUseCase
})
}

Expand Down
2 changes: 1 addition & 1 deletion Application/DevLogPresentation/Sources/Main/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ struct MainView: View {
viewModel: profileViewCoordinator.makePushNotificationSettingsViewModel()
)
case .account:
AccountView(viewModel: profileViewCoordinator.makeAccountViewModel())
AccountView(store: profileViewCoordinator.makeAccountStore())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ struct ProfileView: View {
case .pushNotification:
PushNotificationSettingsView(viewModel: coordinator.makePushNotificationSettingsViewModel())
case .account:
AccountView(viewModel: coordinator.makeAccountViewModel())
AccountView(store: coordinator.makeAccountStore())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ final class ProfileViewCoordinator {
viewModel.send(.fetchData)
}

func makeAccountViewModel() -> AccountViewModel {
AccountViewModel(
fetchProvidersUseCase: container.resolve(FetchAuthProvidersUseCase.self),
linkProviderUseCase: container.resolve(LinkAuthProviderUseCase.self),
unlinkProviderUseCase: container.resolve(UnlinkAuthProviderUseCase.self)
)
func makeAccountStore() -> StoreOf<AccountFeature> {
Store(initialState: AccountFeature.State()) {
AccountFeature()
} withDependencies: {
$0.fetchAuthProvidersUseCase = self.container.resolve(FetchAuthProvidersUseCase.self)
$0.linkAuthProviderUseCase = self.container.resolve(LinkAuthProviderUseCase.self)
$0.unlinkAuthProviderUseCase = self.container.resolve(UnlinkAuthProviderUseCase.self)
}
}
Comment thread
opficdev marked this conversation as resolved.

func makePushNotificationSettingsViewModel() -> PushNotificationSettingsViewModel {
Expand Down
Loading