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 @@ -59,6 +59,11 @@ private extension AppGraph {
.developmentRecordMutationUseCaseGraph
.restoreDevelopmentRecordUseCase
)
DevelopmentDependencyPreparation.prepareTodo(
&dependencies,
fetchTodosUseCase: todoGraphSet.todoUseCaseGraph.fetchTodosUseCase,
updateTodoGoalUseCase: todoGraphSet.todoGoalUseCaseGraph.updateTodoGoalUseCase
)
}

func prepareEntryDependencies(_ dependencies: inout DependencyValues) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ public enum DevelopmentDependencyPreparation {
dependencies.developmentConfirmRecordUseCase = confirmRecordUseCase
dependencies.developmentRestoreRecordUseCase = restoreRecordUseCase
}

public static func prepareTodo(
_ dependencies: inout DependencyValues,
fetchTodosUseCase: FetchTodosUseCase,
updateTodoGoalUseCase: UpdateTodoGoalUseCase
) {
dependencies.developmentFetchTodosUseCase = fetchTodosUseCase
dependencies.developmentUpdateTodoGoalUseCase = updateTodoGoalUseCase
}
}

extension DependencyValues {
Expand Down Expand Up @@ -88,6 +97,16 @@ extension DependencyValues {
get { self[DevelopmentRestoreRecordUseCaseKey.self] }
set { self[DevelopmentRestoreRecordUseCaseKey.self] = newValue }
}

var developmentFetchTodosUseCase: FetchTodosUseCase {
get { self[DevelopmentFetchTodosUseCaseKey.self] }
set { self[DevelopmentFetchTodosUseCaseKey.self] = newValue }
}

var developmentUpdateTodoGoalUseCase: UpdateTodoGoalUseCase {
get { self[DevelopmentUpdateTodoGoalUseCaseKey.self] }
set { self[DevelopmentUpdateTodoGoalUseCaseKey.self] = newValue }
}
}

private enum DevelopmentFetchGoalUseCaseKey: DependencyKey {
Expand Down Expand Up @@ -143,3 +162,15 @@ private enum DevelopmentRestoreRecordUseCaseKey: DependencyKey {
preconditionFailure("RestoreDevelopmentRecordUseCase must be provided.")
}
}

private enum DevelopmentFetchTodosUseCaseKey: DependencyKey {
static var liveValue: FetchTodosUseCase {
preconditionFailure("FetchTodosUseCase must be provided.")
}
}

private enum DevelopmentUpdateTodoGoalUseCaseKey: DependencyKey {
static var liveValue: UpdateTodoGoalUseCase {
preconditionFailure("UpdateTodoGoalUseCase must be provided.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,6 @@ public struct RecordEditorView: View {

}

private extension View {
@ViewBuilder
func topBarButtonStyle(color: Color = .clear) -> some View {
if #available(iOS 26.0, *) {
adaptiveButtonStyle(shape: .circle, color: color, glassEffect: .enabled)
} else {
adaptiveButtonStyle(color: color, glassEffect: .enabled)
}
}
}

private struct FieldCard<Content: View>: View {
let title: String
@ViewBuilder let content: Content
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// GoalDetailFeature+Support.swift
// Development
//
// Created by opfic on 9/15/26.
//

import Domain
import Foundation
import PresentationShared

extension GoalDetailFeature {
static func precedes(_ lhs: DevelopmentRecord, _ rhs: DevelopmentRecord) -> Bool {
if lhs.createdAt == rhs.createdAt { return lhs.id < rhs.id }
return rhs.createdAt < lhs.createdAt
}

static func canTransition(
from currentStatus: DevelopmentGoal.Status,
to status: DevelopmentGoal.Status
) -> Bool {
switch (currentStatus, status) {
case (.inProgress, .completed),
(.inProgress, .archived),
(.completed, .inProgress),
(.archived, .inProgress):
true
default:
false
}
}

static func completionBlockingAlert(
items: [RecordTimelineItem]
) -> AlertState<Action.Alert>? {
guard !items.isEmpty else {
return informationAlert(
titleKey: "development_goal_completion_record_required_title",
messageKey: "development_goal_completion_record_required_message"
)
}
guard items.first?.isUnconfirmed == false else {
return informationAlert(
titleKey: "development_goal_completion_version_required_title",
messageKey: "development_goal_completion_version_required_message"
)
}
guard !items.contains(where: \.hasDraft) else {
return informationAlert(
titleKey: "development_goal_completion_draft_title",
messageKey: "development_goal_completion_draft_message"
)
}
return nil
}

static func transitionConfirmationAlert(
_ status: DevelopmentGoal.Status
) -> AlertState<Action.Alert> {
let keys: (title: String.LocalizationValue, message: String.LocalizationValue)
switch status {
case .inProgress:
keys = (
"development_goal_resume_alert_title",
"development_goal_resume_alert_message"
)
case .completed:
keys = (
"development_goal_complete_alert_title",
"development_goal_complete_alert_message"
)
case .archived:
keys = (
"development_goal_archive_alert_title",
"development_goal_archive_alert_message"
)
}

return AlertState {
TextState(String(localized: keys.title, bundle: PresentationResources.bundle))
} actions: {
ButtonState(role: .cancel) {
TextState(String(localized: "common_cancel", bundle: PresentationResources.bundle))
}
ButtonState(action: .confirmTransition(status)) {
TextState(String(
localized: transitionActionKey(status),
bundle: PresentationResources.bundle
))
}
} message: {
TextState(String(localized: keys.message, bundle: PresentationResources.bundle))
}
}

static var errorAlert: AlertState<Action.Alert> {
AlertState {
TextState(String(localized: "common_error_title", bundle: PresentationResources.bundle))
} actions: {
ButtonState(role: .cancel) {
TextState(String(localized: "common_close", bundle: PresentationResources.bundle))
}
} message: {
TextState(String(
localized: "development_record_timeline_error_message",
bundle: PresentationResources.bundle
))
}
}

static var transitionErrorAlert: AlertState<Action.Alert> {
informationAlert(
titleKey: "common_error_title",
messageKey: "development_goal_transition_error_message"
)
}

static func transitionActionKey(
_ status: DevelopmentGoal.Status
) -> String.LocalizationValue {
switch status {
case .inProgress:
"development_goal_resume"
case .completed:
"development_goal_complete"
case .archived:
"development_goal_archive"
}
}

static func informationAlert(
titleKey: String.LocalizationValue,
messageKey: String.LocalizationValue
) -> AlertState<Action.Alert> {
AlertState {
TextState(String(localized: titleKey, bundle: PresentationResources.bundle))
} actions: {
ButtonState(role: .cancel) {
TextState(String(localized: "common_close", bundle: PresentationResources.bundle))
}
} message: {
TextState(String(localized: messageKey, bundle: PresentationResources.bundle))
}
}
}
Loading
Loading