Fix #30: Verlaufsansicht – neue Momente 5 s in Momente, dann in Verlauf
Neue Logbuch-Momente (vergangene Treffen, Notizen) erscheinen nach dem Speichern 5 Sekunden mit 45 % Deckkraft in der Momente-Sektion und wandern dann animiert in den Verlauf. Aktive Momente (offene Vorhaben, Zukunfts- treffen) bleiben dauerhaft in der Momente-Sektion. Der Verlauf zeigt nur noch abgeschlossene/vergangene Einträge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,10 @@ struct PersonDetailView: View {
|
||||
@State private var todoForEdit: Todo? = nil
|
||||
@State private var fadingOutTodos: [Todo] = []
|
||||
|
||||
// Neu hinzugefügte Logbuch-Momente – 5 s in Momente sichtbar, dann in Verlauf
|
||||
@State private var fadingOutMoments: [Moment] = []
|
||||
@State private var seenMomentIDs: Set<UUID> = []
|
||||
|
||||
// Kalender-Lösch-Bestätigung
|
||||
@State private var momentPendingDelete: Moment? = nil
|
||||
@State private var showCalendarDeleteDialog = false
|
||||
@@ -70,7 +74,7 @@ struct PersonDetailView: View {
|
||||
}
|
||||
momentsSection
|
||||
todosSection
|
||||
if !person.sortedMoments.isEmpty || !person.sortedLogEntries.isEmpty { logbuchSection }
|
||||
if !mergedLogPreview.isEmpty { logbuchSection }
|
||||
if hasInfoContent { infoSection }
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
@@ -100,6 +104,26 @@ struct PersonDetailView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: showingAddMoment) { _, isShowing in
|
||||
if isShowing {
|
||||
seenMomentIDs = Set(person.sortedMoments.map(\.id))
|
||||
} else {
|
||||
// Neu gespeicherte Logbuch-Momente (keine Vorhaben, kein Zukunftstreffen) kurz anzeigen
|
||||
let newLogbuchMoments = person.sortedMoments.filter { moment in
|
||||
guard !seenMomentIDs.contains(moment.id) else { return false }
|
||||
let isActive = moment.isOpen || (moment.isMeeting && moment.createdAt > Date())
|
||||
return !isActive
|
||||
}
|
||||
for moment in newLogbuchMoments {
|
||||
withAnimation { fadingOutMoments.append(moment) }
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
|
||||
withAnimation(.easeOut(duration: 0.35)) {
|
||||
fadingOutMoments.removeAll { $0.id == moment.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showingEditPerson) {
|
||||
AddPersonView(existingPerson: person)
|
||||
}
|
||||
@@ -342,6 +366,18 @@ struct PersonDetailView: View {
|
||||
|
||||
// MARK: - Momente
|
||||
|
||||
/// Aktive Momente: offene Vorhaben + noch ausstehende Treffen in der Zukunft.
|
||||
private var activeMoments: [Moment] {
|
||||
person.sortedMoments.filter { $0.isOpen || ($0.isMeeting && $0.createdAt > Date()) }
|
||||
}
|
||||
|
||||
/// Was in der Momente-Sektion angezeigt wird: aktive + kurzzeitig sichtbare neue Logbuch-Momente.
|
||||
private var visibleMoments: [Moment] {
|
||||
let fadingIDs = Set(fadingOutMoments.map(\.id))
|
||||
let active = activeMoments.filter { !fadingIDs.contains($0.id) }
|
||||
return active + fadingOutMoments
|
||||
}
|
||||
|
||||
private var momentsSection: some View {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
HStack {
|
||||
@@ -376,9 +412,9 @@ struct PersonDetailView: View {
|
||||
.font(.system(size: 14))
|
||||
.foregroundStyle(theme.contentTertiary)
|
||||
.padding(.vertical, 4)
|
||||
} else {
|
||||
} else if !visibleMoments.isEmpty {
|
||||
VStack(spacing: 0) {
|
||||
ForEach(Array(person.sortedMoments.enumerated()), id: \.element.id) { index, moment in
|
||||
ForEach(Array(visibleMoments.enumerated()), id: \.element.id) { index, moment in
|
||||
VStack(spacing: 0) {
|
||||
MomentRowView(
|
||||
moment: moment,
|
||||
@@ -390,7 +426,8 @@ struct PersonDetailView: View {
|
||||
onEdit: { momentForTextEdit = moment },
|
||||
onToggleImportant: { toggleImportant(moment) }
|
||||
)
|
||||
if index < person.sortedMoments.count - 1 { RowDivider() }
|
||||
.opacity(fadingOutMoments.contains(where: { $0.id == moment.id }) ? 0.45 : 1.0)
|
||||
if index < visibleMoments.count - 1 { RowDivider() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,7 +497,13 @@ struct PersonDetailView: View {
|
||||
}
|
||||
|
||||
private var mergedLogPreview: [LogPreviewItem] {
|
||||
let momentItems = person.sortedMoments.map {
|
||||
// Nur Momente die weder aktiv (offene Vorhaben / Zukunftstreffen) noch gerade sichtbar ausklingend sind
|
||||
let activeIDs = Set(activeMoments.map(\.id))
|
||||
let fadingIDs = Set(fadingOutMoments.map(\.id))
|
||||
let logbuchMoments = person.sortedMoments.filter {
|
||||
!activeIDs.contains($0.id) && !fadingIDs.contains($0.id)
|
||||
}
|
||||
let momentItems = logbuchMoments.map {
|
||||
LogPreviewItem(id: "m-\($0.id)", icon: $0.type.icon, title: $0.text,
|
||||
typeLabel: $0.type.displayName, date: $0.createdAt)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user