Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
b444e85b04
commit
5f3f79e6be
@ -1053,10 +1053,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Last 7 days average" : {
|
|
||||||
"comment" : "Explanation of the \"Weekly trend\" insight card, describing how the user's average completion rate over the last 7 days is displayed.",
|
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"Last synced %@" : {
|
"Last synced %@" : {
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2060,10 +2056,6 @@
|
|||||||
"comment" : "An accessibility label for the weekly completion chart in the insight detail sheet.",
|
"comment" : "An accessibility label for the weekly completion chart in the insight detail sheet.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
},
|
},
|
||||||
"Weekly trend" : {
|
|
||||||
"comment" : "Title of an insight card that shows the user their average completion rate over the last 7 days.",
|
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"What this means" : {
|
"What this means" : {
|
||||||
"comment" : "A label displayed above the explanation text in the insight detail sheet.",
|
"comment" : "A label displayed above the explanation text in the insight detail sheet.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
@ -2134,12 +2126,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Your average completion rate over the last 7 days. This shows how consistent you've been recently and helps identify patterns." : {
|
"Your completion percentage for today across all rituals. The chart shows your last 7 days—this helps you spot patterns and stay consistent." : {
|
||||||
"comment" : "Text for the \"Weekly trend\" insight card, describing its purpose and functionality.",
|
"comment" : "Explanation of the insight card that shows the user their completion percentage for today across all their active rituals, with a chart displaying their last 7 days.",
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"Your completion percentage for today across all rituals. This resets each morning, giving you a fresh start every day." : {
|
|
||||||
"comment" : "Explanation of the insight card that shows the user their completion percentage for today across all their active rituals. This percentage resets each morning, providing a fresh start every day.",
|
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
},
|
},
|
||||||
"Your current streak of consecutive days with 100% habit completion. Complete all your habits today to keep the streak going!" : {
|
"Your current streak of consecutive days with 100% habit completion. Complete all your habits today to keep the streak going!" : {
|
||||||
|
|||||||
@ -243,8 +243,11 @@ final class RitualStore: RitualStoreProviding {
|
|||||||
let completedToday = rituals.flatMap { $0.habits }.filter { isHabitCompletedToday($0) }.count
|
let completedToday = rituals.flatMap { $0.habits }.filter { isHabitCompletedToday($0) }.count
|
||||||
let completionRate = totalHabits == 0 ? 0 : Int((Double(completedToday) / Double(totalHabits)) * 100)
|
let completionRate = totalHabits == 0 ? 0 : Int((Double(completedToday) / Double(totalHabits)) * 100)
|
||||||
|
|
||||||
// Build per-ritual breakdowns
|
// Days active = unique calendar days with at least one check-in
|
||||||
let ritualDaysBreakdown = rituals.map { ritual in
|
let daysActiveCount = datesWithActivity().count
|
||||||
|
|
||||||
|
// Build per-ritual progress breakdown
|
||||||
|
let ritualProgressBreakdown = rituals.map { ritual in
|
||||||
BreakdownItem(
|
BreakdownItem(
|
||||||
label: ritual.title,
|
label: ritual.title,
|
||||||
value: ritualDayLabel(for: ritual)
|
value: ritualDayLabel(for: ritual)
|
||||||
@ -259,7 +262,6 @@ final class RitualStore: RitualStoreProviding {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let activeDays = rituals.map { ritualDayIndex(for: $0) }.reduce(0, +)
|
|
||||||
|
|
||||||
// Streak tracking
|
// Streak tracking
|
||||||
let current = currentStreak()
|
let current = currentStreak()
|
||||||
@ -305,26 +307,18 @@ final class RitualStore: RitualStoreProviding {
|
|||||||
title: String(localized: "Completion"),
|
title: String(localized: "Completion"),
|
||||||
value: "\(completionRate)%",
|
value: "\(completionRate)%",
|
||||||
caption: String(localized: "Today's progress"),
|
caption: String(localized: "Today's progress"),
|
||||||
explanation: String(localized: "Your completion percentage for today across all rituals. This resets each morning, giving you a fresh start every day."),
|
explanation: String(localized: "Your completion percentage for today across all rituals. The chart shows your last 7 days—this helps you spot patterns and stay consistent."),
|
||||||
symbolName: "chart.bar.fill",
|
symbolName: "chart.bar.fill",
|
||||||
breakdown: nil
|
|
||||||
),
|
|
||||||
InsightCard(
|
|
||||||
title: String(localized: "Days"),
|
|
||||||
value: "\(activeDays)",
|
|
||||||
caption: String(localized: "Days on your journey"),
|
|
||||||
explanation: String(localized: "The total number of days you've been working on your rituals. This shows your progress through each arc, combining all active rituals."),
|
|
||||||
symbolName: "calendar",
|
|
||||||
breakdown: ritualDaysBreakdown
|
|
||||||
),
|
|
||||||
InsightCard(
|
|
||||||
title: String(localized: "Weekly trend"),
|
|
||||||
value: "\(weeklyAverage)%",
|
|
||||||
caption: String(localized: "Last 7 days average"),
|
|
||||||
explanation: String(localized: "Your average completion rate over the last 7 days. This shows how consistent you've been recently and helps identify patterns."),
|
|
||||||
symbolName: "chart.line.uptrend.xyaxis",
|
|
||||||
breakdown: trendBreakdown,
|
breakdown: trendBreakdown,
|
||||||
trendData: trendData
|
trendData: trendData
|
||||||
|
),
|
||||||
|
InsightCard(
|
||||||
|
title: String(localized: "Days Active"),
|
||||||
|
value: "\(daysActiveCount)",
|
||||||
|
caption: String(localized: "Days you checked in"),
|
||||||
|
explanation: String(localized: "The number of days you've completed at least one habit. Each day you check in counts toward your journey."),
|
||||||
|
symbolName: "calendar",
|
||||||
|
breakdown: ritualProgressBreakdown
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,12 +20,10 @@ struct InsightCardView: View {
|
|||||||
|
|
||||||
private var cardContent: some View {
|
private var cardContent: some View {
|
||||||
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
||||||
HStack(spacing: Design.Spacing.small) {
|
HStack {
|
||||||
Image(systemName: card.symbolName)
|
|
||||||
.foregroundStyle(AppAccent.primary)
|
|
||||||
.accessibilityHidden(true)
|
|
||||||
Text(card.title)
|
Text(card.title)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
|
.bold()
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
.foregroundStyle(AppTextColors.secondary)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@ -37,49 +35,39 @@ struct InsightCardView: View {
|
|||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show mini sparkline if trend data is available
|
// Show value prominently
|
||||||
if let trendData = card.trendData, !trendData.isEmpty {
|
Text(card.value)
|
||||||
HStack(alignment: .bottom, spacing: Design.Spacing.medium) {
|
.font(.title)
|
||||||
VStack(alignment: .leading, spacing: Design.Spacing.xSmall) {
|
.foregroundStyle(AppTextColors.primary)
|
||||||
Text(card.value)
|
.bold()
|
||||||
.font(.title)
|
|
||||||
.foregroundStyle(AppTextColors.primary)
|
// Show caption if present (non-chart cards)
|
||||||
.bold()
|
if !card.caption.isEmpty {
|
||||||
Text(card.caption)
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
// Mini sparkline chart
|
|
||||||
Chart(trendData) { point in
|
|
||||||
BarMark(
|
|
||||||
x: .value("Day", point.label),
|
|
||||||
y: .value("Completion", point.value)
|
|
||||||
)
|
|
||||||
.foregroundStyle(
|
|
||||||
point.value >= 1.0 ? AppStatus.success :
|
|
||||||
point.value >= 0.5 ? AppAccent.primary :
|
|
||||||
AppTextColors.tertiary
|
|
||||||
)
|
|
||||||
.cornerRadius(2)
|
|
||||||
}
|
|
||||||
.chartYScale(domain: 0...1)
|
|
||||||
.chartXAxis(.hidden)
|
|
||||||
.chartYAxis(.hidden)
|
|
||||||
.frame(width: 80, height: 40)
|
|
||||||
.accessibilityHidden(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Text(card.value)
|
|
||||||
.font(.title)
|
|
||||||
.foregroundStyle(AppTextColors.primary)
|
|
||||||
.bold()
|
|
||||||
Text(card.caption)
|
Text(card.caption)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
.foregroundStyle(AppTextColors.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show full-width mini bar chart at bottom (Athlytic style)
|
||||||
|
if let trendData = card.trendData, !trendData.isEmpty {
|
||||||
|
Chart(trendData) { point in
|
||||||
|
BarMark(
|
||||||
|
x: .value("Day", point.label),
|
||||||
|
y: .value("Completion", point.value)
|
||||||
|
)
|
||||||
|
.foregroundStyle(
|
||||||
|
point.value >= 1.0 ? AppStatus.success :
|
||||||
|
point.value >= 0.5 ? AppAccent.primary :
|
||||||
|
AppTextColors.tertiary
|
||||||
|
)
|
||||||
|
.cornerRadius(2)
|
||||||
|
}
|
||||||
|
.chartYScale(domain: 0...1)
|
||||||
|
.chartXAxis(.hidden)
|
||||||
|
.chartYAxis(.hidden)
|
||||||
|
.frame(height: 20)
|
||||||
|
.accessibilityHidden(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding(Design.Spacing.large)
|
.padding(Design.Spacing.large)
|
||||||
.background(AppSurface.card)
|
.background(AppSurface.card)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user