feat(ui): add sport backgrounds to share cards, achievement filtering, and wizard validation
- Add ShareCardSportBackground with floating sport icons for share cards - Share cards now show sport-specific backgrounds (single or multiple sports) - Achievement collection share respects sport filter selection - Add ability to share individual achievements from detail sheet - Trip wizard ReviewStep highlights missing required fields in red - Add FieldValidation model to TripWizardViewModel Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,8 @@ struct AchievementSpotlightContent: ShareableContent {
|
||||
struct AchievementCollectionContent: ShareableContent {
|
||||
let achievements: [AchievementProgress]
|
||||
let year: Int
|
||||
var sports: Set<Sport> = [] // Sports for background icons
|
||||
var filterSport: Sport? = nil // The sport filter applied (for header title)
|
||||
|
||||
var cardType: ShareCardType { .achievementCollection }
|
||||
|
||||
@@ -46,6 +48,8 @@ struct AchievementCollectionContent: ShareableContent {
|
||||
let cardView = AchievementCollectionView(
|
||||
achievements: achievements,
|
||||
year: year,
|
||||
sports: sports,
|
||||
filterSport: filterSport,
|
||||
theme: theme
|
||||
)
|
||||
|
||||
@@ -120,9 +124,16 @@ private struct AchievementSpotlightView: View {
|
||||
let achievement: AchievementProgress
|
||||
let theme: ShareTheme
|
||||
|
||||
private var sports: Set<Sport> {
|
||||
if let sport = achievement.definition.sport {
|
||||
return [sport]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ShareCardBackground(theme: theme)
|
||||
ShareCardBackground(theme: theme, sports: sports)
|
||||
|
||||
VStack(spacing: 50) {
|
||||
Spacer()
|
||||
@@ -176,6 +187,8 @@ private struct AchievementSpotlightView: View {
|
||||
private struct AchievementCollectionView: View {
|
||||
let achievements: [AchievementProgress]
|
||||
let year: Int
|
||||
let sports: Set<Sport>
|
||||
let filterSport: Sport?
|
||||
let theme: ShareTheme
|
||||
|
||||
private let columns = [
|
||||
@@ -184,13 +197,20 @@ private struct AchievementCollectionView: View {
|
||||
GridItem(.flexible(), spacing: 30)
|
||||
]
|
||||
|
||||
private var headerTitle: String {
|
||||
if let sport = filterSport {
|
||||
return "My \(String(year)) \(sport.rawValue) Achievements"
|
||||
}
|
||||
return "My \(String(year)) Achievements"
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ShareCardBackground(theme: theme)
|
||||
ShareCardBackground(theme: theme, sports: sports)
|
||||
|
||||
VStack(spacing: 40) {
|
||||
// Header
|
||||
Text("My \(String(year)) Achievements")
|
||||
Text(headerTitle)
|
||||
.font(.system(size: 48, weight: .bold, design: .rounded))
|
||||
.foregroundStyle(theme.textColor)
|
||||
|
||||
@@ -241,9 +261,16 @@ private struct AchievementMilestoneView: View {
|
||||
|
||||
private let goldColor = Color(hex: "FFD700")
|
||||
|
||||
private var sports: Set<Sport> {
|
||||
if let sport = achievement.definition.sport {
|
||||
return [sport]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ShareCardBackground(theme: theme)
|
||||
ShareCardBackground(theme: theme, sports: sports)
|
||||
|
||||
// Confetti burst pattern
|
||||
ConfettiBurst()
|
||||
@@ -304,9 +331,16 @@ private struct AchievementContextView: View {
|
||||
let mapSnapshot: UIImage?
|
||||
let theme: ShareTheme
|
||||
|
||||
private var sports: Set<Sport> {
|
||||
if let sport = achievement.definition.sport {
|
||||
return [sport]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ShareCardBackground(theme: theme)
|
||||
ShareCardBackground(theme: theme, sports: sports)
|
||||
|
||||
VStack(spacing: 40) {
|
||||
// Header with badge and name
|
||||
|
||||
Reference in New Issue
Block a user