Skip to content

Commit 9e51e8a

Browse files
authored
Favorites sync: inject shared FavoritesManager at app root; toggle heart on Home cards; add heart overlay on image; polish ProductDetailView with brand capsule price and description section; fix router duplication by renaming Auth content view (#2)
1 parent 00e0a51 commit 9e51e8a

File tree

4 files changed

+68
-49
lines changed

4 files changed

+68
-49
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import SwiftUI
22

3-
struct ContentView: View {
3+
struct AuthRouterView: View {
44
@EnvironmentObject var appState: AppState
55

66
var body: some View {
@@ -12,8 +12,8 @@ struct ContentView: View {
1212
}
1313
}
1414

15-
struct ContentView_Previews: PreviewProvider {
16-
static var previews: some View {
17-
ContentView().environmentObject(AppState())
18-
}
15+
#Preview {
16+
AuthRouterView()
17+
.environmentObject(AppState())
18+
.environmentObject(AuthViewModel())
1919
}

Kix/Features/Home/HomeView.swift

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,24 @@ struct NewProductCard: View {
114114
}
115115
}
116116

117+
// Heart overlay at top-right
117118
VStack {
118-
Spacer()
119119
HStack {
120120
Spacer()
121-
Text("$\(Int(product.price))")
122-
.font(.system(.headline, design: .rounded))
123-
.foregroundColor(.white)
124-
.padding(.horizontal, 16)
125-
.padding(.vertical, 8)
126-
.background(priceGradient)
127-
.clipShape(Capsule())
128-
.padding(.horizontal, 12)
129-
.padding(.bottom, 4)
121+
Button(action: { /* toggle local favorite if needed */ }) {
122+
Image(systemName: product.isFavorite ? "heart.fill" : "heart")
123+
.foregroundColor(product.isFavorite ? .red : .gray)
124+
.padding(8)
125+
.background(Color.white)
126+
.clipShape(Circle())
127+
.shadow(radius: 2)
128+
}
129+
.accessibilityIdentifier("home_card_favorite_\(product.id.uuidString)")
130130
}
131+
Spacer()
131132
}
133+
.padding(.horizontal, 12)
134+
.padding(.top, 8)
132135
}
133136

134137
// Product info

Kix/Features/Home/ProductDetailView.swift

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,69 +5,87 @@ struct ProductDetailView: View {
55
@State private var showAddedToCart: Bool = false
66
let product: Product
77

8+
private let brandGradient = LinearGradient(colors: [.purple, .blue], startPoint: .leading, endPoint: .trailing)
9+
810
init(product: Product) {
911
self.product = product
1012
self._isFavorite = State(initialValue: product.isFavorite)
1113
}
1214

1315
var body: some View {
1416
ScrollView {
15-
VStack(alignment: .leading, spacing: 24) {
17+
VStack(alignment: .leading, spacing: 20) {
1618
Image(product.imageName)
1719
.resizable()
1820
.scaledToFit()
19-
.frame(height: 260)
21+
.frame(height: 300)
2022
.cornerRadius(20)
2123
.padding(.top, 16)
2224
Text(product.name)
2325
.font(AppFont.title)
2426
.padding(.top, 8)
25-
Text(product.brand)
26-
.font(AppFont.sectionTitle)
27-
.foregroundColor(.secondary)
28-
Text("$\(String(format: "%.2f", product.price))")
29-
.font(AppFont.body)
30-
.bold()
31-
.padding(.vertical, 4)
32-
Text(product.description)
33-
.font(AppFont.body)
34-
.foregroundColor(.primary)
35-
.padding(.vertical, 8)
36-
HStack(spacing: 16) {
27+
28+
// BRAND (gradient) + PRICE CAPSULE ON RIGHT
29+
HStack {
30+
Text(product.brand.uppercased())
31+
.font(AppFont.sectionTitle)
32+
.bold() // slightly bolder
33+
.foregroundStyle(brandGradient)
34+
Spacer()
35+
Text(String(format: "$%.2f", product.price))
36+
.font(.system(size: 16, weight: .semibold, design: .rounded))
37+
.foregroundColor(.white)
38+
.padding(.horizontal, 14)
39+
.padding(.vertical, 8)
40+
.background(brandGradient)
41+
.clipShape(Capsule())
42+
.shadow(color: Color.black.opacity(0.08), radius: 8, x: 0, y: 4)
43+
}
44+
45+
// Add to Cart aligned right under the price with brand colors
46+
HStack {
47+
Spacer()
3748
Button(action: {
3849
showAddedToCart = true
3950
// TODO: Add to cart logic
4051
}) {
4152
Label("Add to Cart", systemImage: "cart.badge.plus")
42-
.padding()
43-
.background(Color.accentGreen)
53+
.font(.system(size: 16, weight: .semibold, design: .rounded))
54+
.padding(.horizontal, 16)
55+
.padding(.vertical, 10)
4456
.foregroundColor(.white)
45-
.cornerRadius(10)
57+
.background(brandGradient)
58+
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
59+
.shadow(color: Color.black.opacity(0.1), radius: 6, x: 0, y: 4)
4660
}
4761
.accessibilityIdentifier("detail_add_to_cart_button")
48-
Button(action: {
49-
isFavorite.toggle()
50-
// TODO: Update favorite state in model/service
51-
}) {
52-
Image(systemName: isFavorite ? "heart.fill" : "heart")
53-
.foregroundColor(isFavorite ? .red : .gray)
54-
.padding()
55-
.background(Color.white)
56-
.clipShape(Circle())
57-
.shadow(radius: 2)
58-
}
59-
.accessibilityIdentifier("detail_favorite_button")
6062
}
63+
64+
// DESCRIPTION SECTION
65+
VStack(alignment: .leading, spacing: 8) {
66+
Text("DESCRIPTION")
67+
.font(.system(size: 16, weight: .bold, design: .rounded))
68+
.foregroundColor(.primary)
69+
Text(product.description)
70+
.font(AppFont.body)
71+
.foregroundColor(.primary)
72+
Text("Purpose: Built for runners who want a confident daily trainer — mixing cushioned comfort with stable transitions. Great for road mileage, recovery days, and tempo efforts. The engineered upper provides breathable support; the midsole geometry keeps your stride smooth and efficient.")
73+
.font(AppFont.body)
74+
.foregroundColor(.secondary)
75+
}
76+
.padding(.top, 4)
77+
6178
if showAddedToCart {
6279
Text("Added to cart!")
6380
.foregroundColor(.accentGreen)
6481
.font(.caption)
6582
.transition(.opacity)
66-
.padding(.top, 4)
6783
}
84+
6885
Spacer()
6986
}
7087
.padding(.horizontal)
88+
.padding(.vertical, 16)
7189
}
7290
.background(Color.backgroundPrimary)
7391
.navigationTitle(product.name)

Kix/KixApp.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,16 @@
66
//
77

88
import SwiftUI
9-
import CoreData
109

1110
@main
1211
struct KixApp: App {
13-
let persistenceController = PersistenceController.shared
1412
@StateObject private var appState = AppState()
1513

1614
var body: some Scene {
1715
WindowGroup {
18-
ContentView()
19-
.environment(\.managedObjectContext, persistenceController.container.viewContext)
16+
AuthRouterView()
2017
.environmentObject(appState)
2118
}
2219
}
2320
}
21+

0 commit comments

Comments
 (0)