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
23 changes: 15 additions & 8 deletions CalenTask/DesignSystem/Components/WorkspaceScopePicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ struct WorkspaceScopePicker: View {
.buttonStyle(.plain)
.dsHoverHighlight()
.popover(isPresented: $showsSwitcher, arrowEdge: .bottom) {
OpenCountsReader { counts, total in
OpenCountsReader(workspaceIDs: workspaces.map(\.id)) { counts, total in
switcherPopover(counts: counts, total: total)
}
}
Expand Down Expand Up @@ -299,16 +299,23 @@ struct WorkspaceScopePicker: View {
.modelContainer(PreviewSampleData.make().container)
}

/// #5 — I contatori per spazio servono solo a popover aperto: la query di
/// tutte le attività aperte vive qui, non in ogni selettore montato.
/// #5 — I contatori per spazio servono solo a popover aperto e si calcolano
/// con `fetchCount` nello store, senza caricare le attività.
private struct OpenCountsReader<Content: View>: View {
@Query(filter: TodoTask.openPredicate) private var openTasks: [TodoTask]
@Environment(\.modelContext) private var modelContext
let workspaceIDs: [UUID]
let content: (_ byWorkspace: [UUID: Int], _ total: Int) -> Content

var body: some View {
content(
openTasks.reduce(into: [:]) { $0[$1.workspaceID, default: 0] += 1 },
openTasks.count
)
let total = count(TodoTask.openPredicate)
var byWorkspace: [UUID: Int] = [:]
for id in workspaceIDs {
byWorkspace[id] = count(TodoTask.openPredicate(workspaceID: id))
}
return content(byWorkspace, total)
}

private func count(_ predicate: Predicate<TodoTask>) -> Int {
(try? modelContext.fetchCount(FetchDescriptor<TodoTask>(predicate: predicate))) ?? 0
}
}
16 changes: 6 additions & 10 deletions CalenTask/Features/Team/TeamView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,17 @@ struct TeamView: View {
sort: \UserProfile.createdAt)
private var people: [UserProfile]

@Query(filter: TodoTask.openPredicate)
private var openTasks: [TodoTask]

/// Attività aperte per persona, contate in un solo passaggio.
private var loadByPerson: [UUID: Int] {
openTasks.reduce(into: [:]) { counts, task in
if let id = task.assigneeID { counts[id, default: 0] += 1 }
}
/// Attività aperte di una persona, contate nello store.
private func load(for person: UserProfile) -> Int {
let predicate = TodoTask.openAssignedPredicate(assigneeID: person.id)
return (try? modelContext.fetchCount(FetchDescriptor<TodoTask>(predicate: predicate))) ?? 0
}

@State private var newName = ""
@State private var newEmail = ""

var body: some View {
NavigationStack {
let load = loadByPerson
List {
ForEach(people, id: \.id) { person in
HStack(spacing: DS.m) {
Expand All @@ -41,7 +36,8 @@ struct TeamView: View {
}
}
Spacer()
if let count = load[person.id], count > 0 {
let count = load(for: person)
if count > 0 {
Text("\(count) attività")
.font(.dsNumeric)
.foregroundStyle(.secondary)
Expand Down
10 changes: 10 additions & 0 deletions CalenTask/Models/TodoTask+Predicates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ extension TodoTask {
}
}

/// Attività aperte assegnate a una persona (per i contatori di carico).
static func openAssignedPredicate(assigneeID: UUID) -> Predicate<TodoTask> {
let doneRaw = TaskStatus.done.rawValue
let phaseRaw = TaskKind.phase.rawValue
return #Predicate<TodoTask> { task in
task.assigneeID == assigneeID && task.deletedAt == nil
&& task.statusRaw != doneRaw && task.kindRaw != phaseRaw && !task.isTemplate
}
}

static func inboxPredicate(workspaceID: UUID?) -> Predicate<TodoTask> {
let doneRaw = TaskStatus.done.rawValue
let phaseRaw = TaskKind.phase.rawValue
Expand Down
Loading