Implement custom 5-color design system across entire iOS app

Apply consistent branding colors (BlueGreen, Cerulean, BrightAmber, PrimaryScarlet,
cream backgrounds) to all screens, components, buttons, icons, and text throughout
the app. Update all Form/List views with proper list row backgrounds to ensure
visual consistency with card-based layouts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-21 07:58:01 -06:00
parent a4ba6794d5
commit a2b81a244b
70 changed files with 920 additions and 417 deletions

View File

@@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "icon.png", "filename" : "logo_primary.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.031",
"green" : "0.784",
"red" : "0.941"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.031",
"green" : "0.784",
"red" : "0.941"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.816",
"green" : "0.945",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.161",
"green" : "0.098",
"red" : "0.039"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.247",
"green" : "0.184",
"red" : "0.102"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.102",
"green" : "0.110",
"red" : "0.867"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.267",
"green" : "0.267",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.765",
"green" : "0.627",
"red" : "0.027"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.765",
"green" : "0.627",
"red" : "0.027"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.533",
"green" : "0.404",
"red" : "0.031"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.745",
"green" : "0.624",
"red" : "0.039"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.533",
"green" : "0.404",
"red" : "0.031"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.816",
"green" : "0.945",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.600",
"blue" : "0.533",
"green" : "0.404",
"red" : "0.031"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.700",
"blue" : "0.816",
"green" : "0.945",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -26,13 +26,14 @@ struct TaskSummaryCard: View {
Text("Tasks") Text("Tasks")
.font(.headline) .font(.headline)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
ForEach(filteredCategories, id: \.name) { category in ForEach(filteredCategories, id: \.name) { category in
TaskCategoryRow(category: category) TaskCategoryRow(category: category)
} }
} }
.padding(16) .padding(16)
.background(Color(.systemBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(12) .cornerRadius(12)
.shadow(color: Color.black.opacity(0.1), radius: 4, x: 0, y: 2) .shadow(color: Color.black.opacity(0.1), radius: 4, x: 0, y: 2)
} }
@@ -55,14 +56,14 @@ struct TaskCategoryRow: View {
.frame(width: 32, height: 32) .frame(width: 32, height: 32)
Image(systemName: category.icons.ios) Image(systemName: category.icons.ios)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.font(.system(size: 14, weight: .semibold)) .font(.system(size: 14, weight: .semibold))
} }
// Category name // Category name
Text(category.displayName) Text(category.displayName)
.font(.body) .font(.body)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
Spacer() Spacer()
@@ -70,7 +71,7 @@ struct TaskCategoryRow: View {
Text("\(category.count)") Text("\(category.count)")
.font(.subheadline) .font(.subheadline)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.vertical, 4) .padding(.vertical, 4)
.background(categoryColor) .background(categoryColor)

View File

@@ -10,12 +10,12 @@ struct ContractorCard: View {
// Avatar // Avatar
ZStack { ZStack {
Circle() Circle()
.fill(.blue.opacity(0.1)) .fill(Color.appPrimary.opacity(0.1))
.frame(width: 56, height: 56) .frame(width: 56, height: 56)
Image(systemName: "person.fill") Image(systemName: "person.fill")
.font(.title2) .font(.title2)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
// Content // Content
@@ -24,13 +24,13 @@ struct ContractorCard: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
Text(contractor.name) Text(contractor.name)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
.lineLimit(1) .lineLimit(1)
if contractor.isFavorite { if contractor.isFavorite {
Image(systemName: "star.fill") Image(systemName: "star.fill")
.font(.caption) .font(.caption)
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
} }
} }
@@ -38,7 +38,7 @@ struct ContractorCard: View {
if let company = contractor.company { if let company = contractor.company {
Text(company) Text(company)
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.lineLimit(1) .lineLimit(1)
} }
@@ -48,21 +48,21 @@ struct ContractorCard: View {
if let specialty = contractor.specialty { if let specialty = contractor.specialty {
Label(specialty, systemImage: "wrench.and.screwdriver") Label(specialty, systemImage: "wrench.and.screwdriver")
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
// Rating // Rating
if let rating = contractor.averageRating, rating.doubleValue > 0 { if let rating = contractor.averageRating, rating.doubleValue > 0 {
Label(String(format: "%.1f", rating.doubleValue), systemImage: "star.fill") Label(String(format: "%.1f", rating.doubleValue), systemImage: "star.fill")
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
} }
// Task count // Task count
if contractor.taskCount > 0 { if contractor.taskCount > 0 {
Label("\(contractor.taskCount) tasks", systemImage: "checkmark.circle") Label("\(contractor.taskCount) tasks", systemImage: "checkmark.circle")
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
} }
} }
} }
@@ -73,17 +73,17 @@ struct ContractorCard: View {
Button(action: onToggleFavorite) { Button(action: onToggleFavorite) {
Image(systemName: contractor.isFavorite ? "star.fill" : "star") Image(systemName: contractor.isFavorite ? "star.fill" : "star")
.font(.title3) .font(.title3)
.foregroundColor(contractor.isFavorite ? .orange : Color(.tertiaryLabel)) .foregroundColor(contractor.isFavorite ? Color.appAccent : Color.appTextSecondary.opacity(0.7))
} }
.buttonStyle(PlainButtonStyle()) .buttonStyle(PlainButtonStyle())
// Chevron // Chevron
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.caption) .font(.caption)
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y) .shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y)
} }

View File

@@ -12,7 +12,7 @@ struct ContractorDetailView: View {
var body: some View { var body: some View {
ZStack { ZStack {
Color(.systemGroupedBackground).ignoresSafeArea() Color.appBackgroundPrimary.ignoresSafeArea()
if viewModel.isLoading { if viewModel.isLoading {
ProgressView() ProgressView()
@@ -29,24 +29,24 @@ struct ContractorDetailView: View {
// Avatar // Avatar
ZStack { ZStack {
Circle() Circle()
.fill(.blue.opacity(0.1)) .fill(Color.appPrimary.opacity(0.1))
.frame(width: 80, height: 80) .frame(width: 80, height: 80)
Image(systemName: "person.fill") Image(systemName: "person.fill")
.font(.system(size: 40)) .font(.system(size: 40))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
// Name // Name
Text(contractor.name) Text(contractor.name)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
// Company // Company
if let company = contractor.company { if let company = contractor.company {
Text(company) Text(company)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
// Specialty Badge // Specialty Badge
@@ -59,8 +59,8 @@ struct ContractorDetailView: View {
} }
.padding(.horizontal, AppSpacing.sm) .padding(.horizontal, AppSpacing.sm)
.padding(.vertical, AppSpacing.xxs) .padding(.vertical, AppSpacing.xxs)
.background(.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.cornerRadius(AppRadius.full) .cornerRadius(AppRadius.full)
} }
@@ -69,43 +69,43 @@ struct ContractorDetailView: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
ForEach(0..<5) { index in ForEach(0..<5) { index in
Image(systemName: index < Int(rating.doubleValue) ? "star.fill" : "star") Image(systemName: index < Int(rating.doubleValue) ? "star.fill" : "star")
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.font(.caption) .font(.caption)
} }
Text(String(format: "%.1f", rating.doubleValue)) Text(String(format: "%.1f", rating.doubleValue))
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
} }
if contractor.taskCount > 0 { if contractor.taskCount > 0 {
Text("\(contractor.taskCount) completed tasks") Text("\(contractor.taskCount) completed tasks")
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
} }
.padding(AppSpacing.lg) .padding(AppSpacing.lg)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y) .shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y)
// Contact Information // Contact Information
DetailSection(title: "Contact Information") { DetailSection(title: "Contact Information") {
if let phone = contractor.phone { if let phone = contractor.phone {
DetailRow(icon: "phone", label: "Phone", value: phone, iconColor: .blue) DetailRow(icon: "phone", label: "Phone", value: phone, iconColor: Color.appPrimary)
} }
if let email = contractor.email { if let email = contractor.email {
DetailRow(icon: "envelope", label: "Email", value: email, iconColor: .purple) DetailRow(icon: "envelope", label: "Email", value: email, iconColor: Color.appPrimary)
} }
if let secondaryPhone = contractor.secondaryPhone { if let secondaryPhone = contractor.secondaryPhone {
DetailRow(icon: "phone", label: "Secondary Phone", value: secondaryPhone, iconColor: .green) DetailRow(icon: "phone", label: "Secondary Phone", value: secondaryPhone, iconColor: Color.appAccent)
} }
if let website = contractor.website { if let website = contractor.website {
DetailRow(icon: "globe", label: "Website", value: website, iconColor: .orange) DetailRow(icon: "globe", label: "Website", value: website, iconColor: Color.appAccent)
} }
} }
@@ -113,7 +113,7 @@ struct ContractorDetailView: View {
if contractor.licenseNumber != nil { if contractor.licenseNumber != nil {
DetailSection(title: "Business Details") { DetailSection(title: "Business Details") {
if let licenseNumber = contractor.licenseNumber { if let licenseNumber = contractor.licenseNumber {
DetailRow(icon: "doc.badge", label: "License Number", value: licenseNumber, iconColor: .blue) DetailRow(icon: "doc.badge", label: "License Number", value: licenseNumber, iconColor: Color.appPrimary)
} }
} }
} }
@@ -132,7 +132,7 @@ struct ContractorDetailView: View {
icon: "mappin.circle", icon: "mappin.circle",
label: "Location", label: "Location",
value: addressComponents.joined(separator: "\n"), value: addressComponents.joined(separator: "\n"),
iconColor: .red iconColor: Color.appError
) )
} }
} }
@@ -143,7 +143,7 @@ struct ContractorDetailView: View {
DetailSection(title: "Notes") { DetailSection(title: "Notes") {
Text(notes) Text(notes)
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.padding(AppSpacing.md) .padding(AppSpacing.md)
} }
@@ -153,11 +153,11 @@ struct ContractorDetailView: View {
DetailSection(title: "Task History") { DetailSection(title: "Task History") {
HStack { HStack {
Image(systemName: "checkmark.circle") Image(systemName: "checkmark.circle")
.foregroundColor(.green) .foregroundColor(Color.appAccent)
Spacer() Spacer()
Text("\(contractor.taskCount) completed tasks") Text("\(contractor.taskCount) completed tasks")
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
} }
@@ -191,7 +191,7 @@ struct ContractorDetailView: View {
} }
} label: { } label: {
Image(systemName: "ellipsis.circle") Image(systemName: "ellipsis.circle")
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
} }
} }
@@ -243,13 +243,13 @@ struct DetailSection<Content: View>: View {
VStack(alignment: .leading, spacing: AppSpacing.sm) { VStack(alignment: .leading, spacing: AppSpacing.sm) {
Text(title) Text(title)
.font(.headline) .font(.headline)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
.padding(.horizontal, AppSpacing.md) .padding(.horizontal, AppSpacing.md)
VStack(spacing: 0) { VStack(spacing: 0) {
content() content()
} }
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y) .shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y)
} }
@@ -272,11 +272,11 @@ struct DetailRow: View {
VStack(alignment: .leading, spacing: AppSpacing.xxs) { VStack(alignment: .leading, spacing: AppSpacing.xxs) {
Text(label) Text(label)
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(value) Text(value)
.font(.body) .font(.body)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
} }
Spacer() Spacer()

View File

@@ -52,7 +52,7 @@ struct ContractorFormSheet: View {
Section { Section {
HStack { HStack {
Image(systemName: "person") Image(systemName: "person")
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("Name", text: $name) TextField("Name", text: $name)
.focused($focusedField, equals: .name) .focused($focusedField, equals: .name)
@@ -60,7 +60,7 @@ struct ContractorFormSheet: View {
HStack { HStack {
Image(systemName: "building.2") Image(systemName: "building.2")
.foregroundColor(.purple) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("Company", text: $company) TextField("Company", text: $company)
.focused($focusedField, equals: .company) .focused($focusedField, equals: .company)
@@ -70,14 +70,15 @@ struct ContractorFormSheet: View {
} footer: { } footer: {
Text("Required: Name") Text("Required: Name")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Contact Information // Contact Information
Section { Section {
HStack { HStack {
Image(systemName: "phone.fill") Image(systemName: "phone.fill")
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("Phone", text: $phone) TextField("Phone", text: $phone)
.keyboardType(.phonePad) .keyboardType(.phonePad)
@@ -86,7 +87,7 @@ struct ContractorFormSheet: View {
HStack { HStack {
Image(systemName: "envelope.fill") Image(systemName: "envelope.fill")
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.frame(width: 24) .frame(width: 24)
TextField("Email", text: $email) TextField("Email", text: $email)
.keyboardType(.emailAddress) .keyboardType(.emailAddress)
@@ -97,7 +98,7 @@ struct ContractorFormSheet: View {
HStack { HStack {
Image(systemName: "phone.badge.plus") Image(systemName: "phone.badge.plus")
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("Secondary Phone", text: $secondaryPhone) TextField("Secondary Phone", text: $secondaryPhone)
.keyboardType(.phonePad) .keyboardType(.phonePad)
@@ -106,28 +107,29 @@ struct ContractorFormSheet: View {
} header: { } header: {
Text("Contact Information") Text("Contact Information")
} footer: { } footer: {
} }
.listRowBackground(Color.appBackgroundSecondary)
// Business Details // Business Details
Section { Section {
Button(action: { showingSpecialtyPicker = true }) { Button(action: { showingSpecialtyPicker = true }) {
HStack { HStack {
Image(systemName: "wrench.and.screwdriver") Image(systemName: "wrench.and.screwdriver")
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
Text(specialty.isEmpty ? "Specialty" : specialty) Text(specialty.isEmpty ? "Specialty" : specialty)
.foregroundColor(specialty.isEmpty ? Color(.placeholderText) : Color(.label)) .foregroundColor(specialty.isEmpty ? Color.appTextSecondary.opacity(0.5) : Color.appTextPrimary)
Spacer() Spacer()
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.font(.caption) .font(.caption)
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
} }
} }
HStack { HStack {
Image(systemName: "doc.badge") Image(systemName: "doc.badge")
.foregroundColor(.purple) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("License Number", text: $licenseNumber) TextField("License Number", text: $licenseNumber)
.focused($focusedField, equals: .licenseNumber) .focused($focusedField, equals: .licenseNumber)
@@ -135,7 +137,7 @@ struct ContractorFormSheet: View {
HStack { HStack {
Image(systemName: "globe") Image(systemName: "globe")
.foregroundColor(.blue) .foregroundColor(Color.appAccent)
.frame(width: 24) .frame(width: 24)
TextField("Website", text: $website) TextField("Website", text: $website)
.keyboardType(.URL) .keyboardType(.URL)
@@ -146,12 +148,13 @@ struct ContractorFormSheet: View {
} header: { } header: {
Text("Business Details") Text("Business Details")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Address // Address
Section { Section {
HStack { HStack {
Image(systemName: "location.fill") Image(systemName: "location.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
.frame(width: 24) .frame(width: 24)
TextField("Street Address", text: $address) TextField("Street Address", text: $address)
.focused($focusedField, equals: .address) .focused($focusedField, equals: .address)
@@ -159,7 +162,7 @@ struct ContractorFormSheet: View {
HStack { HStack {
Image(systemName: "building.2.crop.circle") Image(systemName: "building.2.crop.circle")
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.frame(width: 24) .frame(width: 24)
TextField("City", text: $city) TextField("City", text: $city)
.focused($focusedField, equals: .city) .focused($focusedField, equals: .city)
@@ -168,7 +171,7 @@ struct ContractorFormSheet: View {
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
HStack { HStack {
Image(systemName: "map") Image(systemName: "map")
.foregroundColor(.green) .foregroundColor(Color.appAccent)
.frame(width: 24) .frame(width: 24)
TextField("State", text: $state) TextField("State", text: $state)
.focused($focusedField, equals: .state) .focused($focusedField, equals: .state)
@@ -185,12 +188,13 @@ struct ContractorFormSheet: View {
} header: { } header: {
Text("Address") Text("Address")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Notes // Notes
Section { Section {
HStack(alignment: .top) { HStack(alignment: .top) {
Image(systemName: "note.text") Image(systemName: "note.text")
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.frame(width: 24) .frame(width: 24)
.padding(.top, 8) .padding(.top, 8)
@@ -204,29 +208,35 @@ struct ContractorFormSheet: View {
Text("Private notes about this contractor") Text("Private notes about this contractor")
.font(.caption) .font(.caption)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Favorite // Favorite
Section { Section {
Toggle(isOn: $isFavorite) { Toggle(isOn: $isFavorite) {
Label("Mark as Favorite", systemImage: "star.fill") Label("Mark as Favorite", systemImage: "star.fill")
.foregroundColor(isFavorite ? .orange : Color(.label)) .foregroundColor(isFavorite ? Color.appAccent : Color.appTextPrimary)
} }
.tint(.orange) .tint(Color.appAccent)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Error Message // Error Message
if let error = viewModel.errorMessage { if let error = viewModel.errorMessage {
Section { Section {
HStack { HStack {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
Text(error) Text(error)
.font(.callout) .font(.callout)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle(contractor == nil ? "Add Contractor" : "Edit Contractor") .navigationTitle(contractor == nil ? "Add Contractor" : "Edit Contractor")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
@@ -258,16 +268,18 @@ struct ContractorFormSheet: View {
}) { }) {
HStack { HStack {
Text(spec) Text(spec)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Spacer() Spacer()
if specialty == spec { if specialty == spec {
Image(systemName: "checkmark") Image(systemName: "checkmark")
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
} }
} }
} }
} }
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Select Specialty") .navigationTitle("Select Specialty")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -26,7 +26,7 @@ struct ContractorsListView: View {
var body: some View { var body: some View {
ZStack { ZStack {
Color(.systemGroupedBackground).ignoresSafeArea() Color.appBackgroundPrimary.ignoresSafeArea()
VStack(spacing: 0) { VStack(spacing: 0) {
// Search Bar // Search Bar
@@ -115,7 +115,7 @@ struct ContractorsListView: View {
loadContractors() loadContractors()
}) { }) {
Image(systemName: showFavoritesOnly ? "star.fill" : "star") Image(systemName: showFavoritesOnly ? "star.fill" : "star")
.foregroundColor(showFavoritesOnly ? .orange : Color(.secondaryLabel)) .foregroundColor(showFavoritesOnly ? Color.appAccent : Color.appTextSecondary)
} }
// Specialty Filter // Specialty Filter
@@ -139,14 +139,14 @@ struct ContractorsListView: View {
} }
} label: { } label: {
Image(systemName: "line.3.horizontal.decrease.circle") Image(systemName: "line.3.horizontal.decrease.circle")
.foregroundColor(selectedSpecialty != nil ? .blue : Color(.secondaryLabel)) .foregroundColor(selectedSpecialty != nil ? Color.appPrimary : Color.appTextSecondary)
} }
// Add Button // Add Button
Button(action: { showingAddSheet = true }) { Button(action: { showingAddSheet = true }) {
Image(systemName: "plus.circle.fill") Image(systemName: "plus.circle.fill")
.font(.title2) .font(.title2)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
.accessibilityIdentifier(AccessibilityIdentifiers.Contractor.addButton) .accessibilityIdentifier(AccessibilityIdentifiers.Contractor.addButton)
} }
@@ -206,7 +206,7 @@ struct SearchBar: View {
var body: some View { var body: some View {
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
Image(systemName: "magnifyingglass") Image(systemName: "magnifyingglass")
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
TextField(placeholder, text: $text) TextField(placeholder, text: $text)
.font(.body) .font(.body)
@@ -214,12 +214,12 @@ struct SearchBar: View {
if !text.isEmpty { if !text.isEmpty {
Button(action: { text = "" }) { Button(action: { text = "" }) {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
} }
.padding(AppSpacing.sm) .padding(AppSpacing.sm)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y) .shadow(color: AppShadow.sm.color, radius: AppShadow.sm.radius, x: AppShadow.sm.x, y: AppShadow.sm.y)
} }
@@ -247,8 +247,8 @@ struct FilterChip: View {
} }
.padding(.horizontal, AppSpacing.sm) .padding(.horizontal, AppSpacing.sm)
.padding(.vertical, AppSpacing.xxs) .padding(.vertical, AppSpacing.xxs)
.background(.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.cornerRadius(AppRadius.full) .cornerRadius(AppRadius.full)
} }
} }
@@ -261,16 +261,16 @@ struct EmptyContractorsView: View {
VStack(spacing: AppSpacing.md) { VStack(spacing: AppSpacing.md) {
Image(systemName: "person.badge.plus") Image(systemName: "person.badge.plus")
.font(.system(size: 64)) .font(.system(size: 64))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
Text(hasFilters ? "No contractors found" : "No contractors yet") Text(hasFilters ? "No contractors found" : "No contractors yet")
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
if !hasFilters { if !hasFilters {
Text("Add your first contractor to get started") Text("Add your first contractor to get started")
.font(.callout) .font(.callout)
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
} }
} }
.padding(AppSpacing.xl) .padding(AppSpacing.xl)

View File

@@ -3,6 +3,49 @@ import SwiftUI
// MARK: - Design System // MARK: - Design System
// Modern, sleek design system for MyCrib with Light and Dark mode support // Modern, sleek design system for MyCrib with Light and Dark mode support
// MARK: - Colors
extension Color {
// MARK: - Semantic Colors (Use These in UI)
static let appPrimary = Color("Primary")
static let appSecondary = Color("Secondary")
static let appAccent = Color("Accent")
static let appBackgroundPrimary = Color("BackgroundPrimary")
static let appBackgroundSecondary = Color("BackgroundSecondary")
static let appError = Color("Error")
static let appTextPrimary = Color("TextPrimary")
static let appTextSecondary = Color("TextSecondary")
static let appTextOnPrimary = Color("TextOnPrimary")
// MARK: - Hex Support
init?(hex: String) {
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int: UInt64 = 0
Scanner(string: hex).scanHexInt64(&int)
let a, r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
return nil
}
self.init(
.sRGB,
red: Double(r) / 255,
green: Double(g) / 255,
blue: Double(b) / 255,
opacity: Double(a) / 255
)
}
}
// MARK: - Spacing
struct AppSpacing { struct AppSpacing {
static let xxs: CGFloat = 4 static let xxs: CGFloat = 4
static let xs: CGFloat = 8 static let xs: CGFloat = 8
@@ -53,7 +96,7 @@ struct CardStyle: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: shadow.color, radius: shadow.radius, x: shadow.x, y: shadow.y) .shadow(color: shadow.color, radius: shadow.radius, x: shadow.x, y: shadow.y)
} }
@@ -65,11 +108,11 @@ struct PrimaryButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {
configuration.label configuration.label
.font(.headline) .font(.headline)
.foregroundColor(.white) .foregroundColor(.appTextOnPrimary)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 56) .frame(height: 56)
.background( .background(
configuration.isPressed ? .blue : .blue configuration.isPressed ? Color.appPrimary.opacity(0.8) : Color.appPrimary
) )
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.scaleEffect(configuration.isPressed ? 0.98 : 1.0) .scaleEffect(configuration.isPressed ? 0.98 : 1.0)
@@ -81,10 +124,10 @@ struct SecondaryButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {
configuration.label configuration.label
.font(.headline) .font(.headline)
.foregroundColor(.blue) .foregroundColor(.appPrimary)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 56) .frame(height: 56)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appPrimary.opacity(0.1))
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.scaleEffect(configuration.isPressed ? 0.98 : 1.0) .scaleEffect(configuration.isPressed ? 0.98 : 1.0)
.animation(.easeInOut(duration: 0.1), value: configuration.isPressed) .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
@@ -95,11 +138,11 @@ struct TextFieldStyle: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.overlay( .overlay(
RoundedRectangle(cornerRadius: AppRadius.md) RoundedRectangle(cornerRadius: AppRadius.md)
.stroke(Color(.opaqueSeparator), lineWidth: 1) .stroke(Color.appTextSecondary.opacity(0.3), lineWidth: 1)
) )
} }
} }
@@ -116,31 +159,3 @@ extension View {
} }
} }
// MARK: - Color Extension for Hex Support
extension Color {
init?(hex: String) {
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int: UInt64 = 0
Scanner(string: hex).scanHexInt64(&int)
let a, r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
return nil
}
self.init(
.sRGB,
red: Double(r) / 255,
green: Double(g) / 255,
blue: Double(b) / 255,
opacity: Double(a) / 255
)
}
}

View File

@@ -6,11 +6,11 @@ struct DocumentCard: View {
var typeColor: Color { var typeColor: Color {
switch document.documentType { switch document.documentType {
case "warranty": return .blue case "warranty": return Color.appPrimary
case "manual": return .purple case "manual": return Color.appSecondary
case "receipt": return .green case "receipt": return Color.appAccent
case "inspection": return .orange case "inspection": return Color.appAccent
default: return .gray default: return Color.appTextSecondary
} }
} }
@@ -41,13 +41,13 @@ struct DocumentCard: View {
Text(document.title) Text(document.title)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
.lineLimit(1) .lineLimit(1)
if let description = document.description_, !description.isEmpty { if let description = document.description_, !description.isEmpty {
Text(description) Text(description)
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.lineLimit(2) .lineLimit(2)
} }
@@ -63,7 +63,7 @@ struct DocumentCard: View {
if let fileSize = document.fileSize { if let fileSize = document.fileSize {
Text(formatFileSize(Int(fileSize))) Text(formatFileSize(Int(fileSize)))
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
} }
@@ -71,11 +71,11 @@ struct DocumentCard: View {
Spacer() Spacer()
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.font(.system(size: 14)) .font(.system(size: 14))
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1) .shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1)
} }

View File

@@ -9,15 +9,15 @@ struct EmptyStateView: View {
VStack(spacing: AppSpacing.md) { VStack(spacing: AppSpacing.md) {
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 64)) .font(.system(size: 64))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(title) Text(title)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(message) Text(message)
.font(.body) .font(.body)
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.padding(AppSpacing.lg) .padding(AppSpacing.lg)

View File

@@ -9,11 +9,11 @@ struct WarrantyCard: View {
} }
var statusColor: Color { var statusColor: Color {
if !document.isActive { return .gray } if !document.isActive { return Color.appTextSecondary }
if daysUntilExpiration < 0 { return .red } if daysUntilExpiration < 0 { return Color.appError }
if daysUntilExpiration < 30 { return .orange } if daysUntilExpiration < 30 { return Color.appAccent }
if daysUntilExpiration < 90 { return .yellow } if daysUntilExpiration < 90 { return Color.appAccent.opacity(0.7) }
return .green return Color.appPrimary
} }
var statusText: String { var statusText: String {
@@ -31,11 +31,11 @@ struct WarrantyCard: View {
Text(document.title) Text(document.title)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Text(document.itemName ?? "") Text(document.itemName ?? "")
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
Spacer() Spacer()
@@ -58,11 +58,11 @@ struct WarrantyCard: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("Provider") Text("Provider")
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(document.provider ?? "N/A") Text(document.provider ?? "N/A")
.font(.body) .font(.body)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
} }
Spacer() Spacer()
@@ -70,11 +70,11 @@ struct WarrantyCard: View {
VStack(alignment: .trailing, spacing: 2) { VStack(alignment: .trailing, spacing: 2) {
Text("Expires") Text("Expires")
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(document.endDate ?? "N/A") Text(document.endDate ?? "N/A")
.font(.body) .font(.body)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
} }
} }
@@ -88,15 +88,15 @@ struct WarrantyCard: View {
if let category = document.category { if let category = document.category {
Text(getCategoryDisplayName(category)) Text(getCategoryDisplayName(category))
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(hex: "374151")) .foregroundColor(Color.appTextPrimary)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
.background(Color(hex: "E5E7EB")) .background(Color.appBackgroundSecondary.opacity(0.8))
.cornerRadius(4) .cornerRadius(4)
} }
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1) .shadow(color: Color.black.opacity(0.05), radius: 2, x: 0, y: 1)
} }

View File

@@ -119,7 +119,7 @@ struct DocumentFormView: View {
if !itemNameError.isEmpty { if !itemNameError.isEmpty {
Text(itemNameError) Text(itemNameError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
TextField("Model Number (optional)", text: $modelNumber) TextField("Model Number (optional)", text: $modelNumber)
@@ -129,7 +129,7 @@ struct DocumentFormView: View {
if !providerError.isEmpty { if !providerError.isEmpty {
Text(providerError) Text(providerError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
TextField("Provider Contact (optional)", text: $providerContact) TextField("Provider Contact (optional)", text: $providerContact)
@@ -138,8 +138,9 @@ struct DocumentFormView: View {
} footer: { } footer: {
Text("Required for warranties: Item Name and Provider") Text("Required for warranties: Item Name and Provider")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section("Warranty Claims") { Section("Warranty Claims") {
TextField("Claim Phone (optional)", text: $claimPhone) TextField("Claim Phone (optional)", text: $claimPhone)
@@ -149,12 +150,14 @@ struct DocumentFormView: View {
TextField("Claim Website (optional)", text: $claimWebsite) TextField("Claim Website (optional)", text: $claimWebsite)
.keyboardType(.URL) .keyboardType(.URL)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section("Warranty Dates") { Section("Warranty Dates") {
TextField("Purchase Date (YYYY-MM-DD)", text: $purchaseDate) TextField("Purchase Date (YYYY-MM-DD)", text: $purchaseDate)
TextField("Warranty Start Date (YYYY-MM-DD)", text: $startDate) TextField("Warranty Start Date (YYYY-MM-DD)", text: $startDate)
TextField("Warranty End Date (YYYY-MM-DD)", text: $endDate) TextField("Warranty End Date (YYYY-MM-DD)", text: $endDate)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
} }
@@ -181,6 +184,7 @@ struct DocumentFormView: View {
.frame(height: 200) .frame(height: 200)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
Section("Photos") { Section("Photos") {
@@ -200,6 +204,7 @@ struct DocumentFormView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
var body: some View { var body: some View {
@@ -207,6 +212,9 @@ struct DocumentFormView: View {
Form { Form {
formContent formContent
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle(isEditMode ? (isWarranty ? "Edit Warranty" : "Edit Document") : (isWarranty ? "Add Warranty" : "Add Document")) .navigationTitle(isEditMode ? (isWarranty ? "Edit Warranty" : "Edit Document") : (isWarranty ? "Add Warranty" : "Add Document"))
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
@@ -282,7 +290,7 @@ struct DocumentFormView: View {
if !residenceError.isEmpty { if !residenceError.isEmpty {
Text(residenceError) Text(residenceError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
} header: { } header: {
@@ -290,8 +298,9 @@ struct DocumentFormView: View {
} footer: { } footer: {
Text("Required") Text("Required")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
// Document Type // Document Type
@@ -314,6 +323,7 @@ struct DocumentFormView: View {
} }
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
// Basic Information // Basic Information
Section { Section {
@@ -321,7 +331,7 @@ struct DocumentFormView: View {
if !titleError.isEmpty { if !titleError.isEmpty {
Text(titleError) Text(titleError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
TextField("Description (optional)", text: $description, axis: .vertical) TextField("Description (optional)", text: $description, axis: .vertical)
@@ -331,8 +341,9 @@ struct DocumentFormView: View {
} footer: { } footer: {
Text("Required: Title") Text("Required: Title")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Warranty-specific fields // Warranty-specific fields
warrantySection warrantySection
@@ -347,6 +358,7 @@ struct DocumentFormView: View {
} }
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
// Additional Information // Additional Information
@@ -356,12 +368,14 @@ struct DocumentFormView: View {
TextField("Notes (optional)", text: $notes, axis: .vertical) TextField("Notes (optional)", text: $notes, axis: .vertical)
.lineLimit(3...6) .lineLimit(3...6)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Active Status (Edit mode only) // Active Status (Edit mode only)
if isEditMode { if isEditMode {
Section { Section {
Toggle("Active", isOn: $isActive) Toggle("Active", isOn: $isActive)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
// Photos // Photos

View File

@@ -28,7 +28,7 @@ struct DocumentsWarrantiesView: View {
var body: some View { var body: some View {
ZStack { ZStack {
Color(.systemGroupedBackground).ignoresSafeArea() Color.appBackgroundPrimary.ignoresSafeArea()
VStack(spacing: 0) { VStack(spacing: 0) {
// Segmented Control for Tabs // Segmented Control for Tabs
@@ -104,7 +104,7 @@ struct DocumentsWarrantiesView: View {
loadWarranties() loadWarranties()
}) { }) {
Image(systemName: showActiveOnly ? "checkmark.circle.fill" : "checkmark.circle") Image(systemName: showActiveOnly ? "checkmark.circle.fill" : "checkmark.circle")
.foregroundColor(showActiveOnly ? .green : Color(.secondaryLabel)) .foregroundColor(showActiveOnly ? Color.appPrimary : Color.appTextSecondary)
} }
} }
@@ -149,7 +149,7 @@ struct DocumentsWarrantiesView: View {
} }
} label: { } label: {
Image(systemName: "line.3.horizontal.decrease.circle") Image(systemName: "line.3.horizontal.decrease.circle")
.foregroundColor((selectedCategory != nil || selectedDocType != nil) ? .blue : Color(.secondaryLabel)) .foregroundColor((selectedCategory != nil || selectedDocType != nil) ? Color.appPrimary : Color.appTextSecondary)
} }
// Add Button // Add Button
@@ -158,7 +158,7 @@ struct DocumentsWarrantiesView: View {
}) { }) {
Image(systemName: "plus.circle.fill") Image(systemName: "plus.circle.fill")
.font(.title2) .font(.title2)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
} }
} }

View File

@@ -26,7 +26,7 @@ struct LoginView: View {
private var buttonBackgroundColor: Color { private var buttonBackgroundColor: Color {
if viewModel.isLoading || !isFormValid { if viewModel.isLoading || !isFormValid {
return Color(.tertiaryLabel) return Color.appTextSecondary
} }
return .clear return .clear
} }
@@ -39,7 +39,7 @@ struct LoginView: View {
NavigationView { NavigationView {
ZStack { ZStack {
// Background gradient // Background gradient
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
ScrollView { ScrollView {
@@ -52,9 +52,9 @@ struct LoginView: View {
// App Icon with gradient // App Icon with gradient
ZStack { ZStack {
Circle() Circle()
.fill(LinearGradient(colors: [.blue, .blue.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing)) .fill(LinearGradient(colors: [Color.appPrimary, Color.appPrimary.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing))
.frame(width: 100, height: 100) .frame(width: 100, height: 100)
.shadow(color: .blue.opacity(0.3), radius: 20, y: 10) .shadow(color: Color.appPrimary.opacity(0.3), radius: 20, y: 10)
Image(systemName: "house.fill") Image(systemName: "house.fill")
.font(.system(size: 50, weight: .semibold)) .font(.system(size: 50, weight: .semibold))
@@ -64,11 +64,11 @@ struct LoginView: View {
VStack(spacing: AppSpacing.xs) { VStack(spacing: AppSpacing.xs) {
Text("Welcome Back") Text("Welcome Back")
.font(.title2.weight(.bold)) .font(.title2.weight(.bold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Text("Sign in to manage your properties") Text("Sign in to manage your properties")
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -78,11 +78,11 @@ struct LoginView: View {
VStack(alignment: .leading, spacing: AppSpacing.xs) { VStack(alignment: .leading, spacing: AppSpacing.xs) {
Text("Email or Username") Text("Email or Username")
.font(.subheadline.weight(.medium)) .font(.subheadline.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
Image(systemName: "envelope.fill") Image(systemName: "envelope.fill")
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
.frame(width: 20) .frame(width: 20)
TextField("Enter your email", text: $viewModel.username) TextField("Enter your email", text: $viewModel.username)
@@ -100,13 +100,13 @@ struct LoginView: View {
.accessibilityIdentifier(AccessibilityIdentifiers.Authentication.usernameField) .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.usernameField)
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.overlay( .overlay(
RoundedRectangle(cornerRadius: AppRadius.md) RoundedRectangle(cornerRadius: AppRadius.md)
.stroke(focusedField == .username ? .blue : Color(.separator), lineWidth: 1.5) .stroke(focusedField == .username ? Color.appPrimary : Color.appTextSecondary.opacity(0.3), lineWidth: 1.5)
) )
.shadow(color: focusedField == .username ? .blue.opacity(0.1) : .clear, radius: 8) .shadow(color: focusedField == .username ? Color.appPrimary.opacity(0.1) : .clear, radius: 8)
.animation(.easeInOut(duration: 0.2), value: focusedField) .animation(.easeInOut(duration: 0.2), value: focusedField)
} }
@@ -114,11 +114,11 @@ struct LoginView: View {
VStack(alignment: .leading, spacing: AppSpacing.xs) { VStack(alignment: .leading, spacing: AppSpacing.xs) {
Text("Password") Text("Password")
.font(.subheadline.weight(.medium)) .font(.subheadline.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
Image(systemName: "lock.fill") Image(systemName: "lock.fill")
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
.frame(width: 20) .frame(width: 20)
Group { Group {
@@ -147,19 +147,19 @@ struct LoginView: View {
isPasswordVisible.toggle() isPasswordVisible.toggle()
}) { }) {
Image(systemName: isPasswordVisible ? "eye.slash.fill" : "eye.fill") Image(systemName: isPasswordVisible ? "eye.slash.fill" : "eye.fill")
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
.frame(width: 20) .frame(width: 20)
} }
.accessibilityIdentifier(AccessibilityIdentifiers.Authentication.passwordVisibilityToggle) .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.passwordVisibilityToggle)
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.overlay( .overlay(
RoundedRectangle(cornerRadius: AppRadius.md) RoundedRectangle(cornerRadius: AppRadius.md)
.stroke(focusedField == .password ? .blue : Color(.separator), lineWidth: 1.5) .stroke(focusedField == .password ? Color.appPrimary : Color.appTextSecondary.opacity(0.3), lineWidth: 1.5)
) )
.shadow(color: focusedField == .password ? .blue.opacity(0.1) : .clear, radius: 8) .shadow(color: focusedField == .password ? Color.appPrimary.opacity(0.1) : .clear, radius: 8)
.animation(.easeInOut(duration: 0.2), value: focusedField) .animation(.easeInOut(duration: 0.2), value: focusedField)
.onChange(of: viewModel.password) { _, _ in .onChange(of: viewModel.password) { _, _ in
viewModel.clearError() viewModel.clearError()
@@ -173,7 +173,7 @@ struct LoginView: View {
showPasswordReset = true showPasswordReset = true
} }
.font(.subheadline.weight(.medium)) .font(.subheadline.weight(.medium))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.accessibilityIdentifier(AccessibilityIdentifiers.Authentication.forgotPasswordButton) .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.forgotPasswordButton)
} }
@@ -181,14 +181,14 @@ struct LoginView: View {
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
Image(systemName: "exclamationmark.circle.fill") Image(systemName: "exclamationmark.circle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
Text(errorMessage) Text(errorMessage)
.font(.callout) .font(.callout)
.foregroundColor(.red) .foregroundColor(Color.appError)
Spacer() Spacer()
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(.red.opacity(0.1)) .background(Color.appError.opacity(0.1))
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
} }
@@ -203,19 +203,19 @@ struct LoginView: View {
HStack(spacing: AppSpacing.xs) { HStack(spacing: AppSpacing.xs) {
Text("Don't have an account?") Text("Don't have an account?")
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
Button("Sign Up") { Button("Sign Up") {
showingRegister = true showingRegister = true
} }
.font(.body) .font(.body)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.accessibilityIdentifier(AccessibilityIdentifiers.Authentication.signUpButton) .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.signUpButton)
} }
} }
.padding(AppSpacing.xl) .padding(AppSpacing.xl)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.xxl) .cornerRadius(AppRadius.xxl)
.shadow(color: .black.opacity(0.08), radius: 20, y: 10) .shadow(color: .black.opacity(0.08), radius: 20, y: 10)
.padding(.horizontal, AppSpacing.lg) .padding(.horizontal, AppSpacing.lg)
@@ -282,11 +282,11 @@ struct LoginView: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 56) .frame(height: 56)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.background(loginButtonBackground) .background(loginButtonBackground)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
.shadow( .shadow(
color: shouldShowShadow ? .blue.opacity(0.3) : .clear, color: shouldShowShadow ? Color.appPrimary.opacity(0.3) : .clear,
radius: 10, radius: 10,
y: 5 y: 5
) )
@@ -294,9 +294,9 @@ struct LoginView: View {
private var loginButtonBackground: AnyShapeStyle { private var loginButtonBackground: AnyShapeStyle {
if viewModel.isLoading || !isFormValid { if viewModel.isLoading || !isFormValid {
AnyShapeStyle(Color(.tertiaryLabel)) AnyShapeStyle(Color.appTextSecondary)
} else { } else {
AnyShapeStyle(LinearGradient(colors: [.blue, .blue.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing)) AnyShapeStyle(LinearGradient(colors: [Color.appPrimary, Color.appPrimary.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing))
} }
} }
} }

View File

@@ -51,6 +51,7 @@ struct MainTabView: View {
.tag(4) .tag(4)
.accessibilityIdentifier(AccessibilityIdentifiers.Navigation.profileTab) .accessibilityIdentifier(AccessibilityIdentifiers.Navigation.profileTab)
} }
.tint(Color.appPrimary)
.onChange(of: authManager.isAuthenticated) { _ in .onChange(of: authManager.isAuthenticated) { _ in
selectedTab = 0 selectedTab = 0
} }

View File

@@ -13,7 +13,7 @@ struct ForgotPasswordView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
Image(systemName: "key.fill") Image(systemName: "key.fill")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
.padding(.vertical) .padding(.vertical)
Text("Forgot Password?") Text("Forgot Password?")
@@ -22,7 +22,7 @@ struct ForgotPasswordView: View {
Text("Enter your email address and we'll send you a verification code") Text("Enter your email address and we'll send you a verification code")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -49,30 +49,33 @@ struct ForgotPasswordView: View {
} footer: { } footer: {
Text("We'll send a 6-digit verification code to this address") Text("We'll send a 6-digit verification code to this address")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Error/Success Messages // Error/Success Messages
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
Label { Label {
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
} icon: { } icon: {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
if let successMessage = viewModel.successMessage { if let successMessage = viewModel.successMessage {
Section { Section {
Label { Label {
Text(successMessage) Text(successMessage)
.foregroundColor(.green) .foregroundColor(Color.appAccent)
} icon: { } icon: {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green) .foregroundColor(Color.appAccent)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
// Send Code Button // Send Code Button
@@ -99,12 +102,16 @@ struct ForgotPasswordView: View {
HStack { HStack {
Spacer() Spacer()
Text("Back to Login") Text("Back to Login")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
Spacer() Spacer()
} }
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Reset Password") .navigationTitle("Reset Password")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.onAppear { .onAppear {

View File

@@ -20,16 +20,17 @@ struct ResetPasswordView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
Image(systemName: "lock.rotation") Image(systemName: "lock.rotation")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
.padding(.vertical) .padding(.vertical)
Text("Set New Password") Text("Set New Password")
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
Text("Create a strong password to secure your account") Text("Create a strong password to secure your account")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -42,30 +43,34 @@ struct ResetPasswordView: View {
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: viewModel.newPassword.count >= 8 ? "checkmark.circle.fill" : "circle") Image(systemName: viewModel.newPassword.count >= 8 ? "checkmark.circle.fill" : "circle")
.foregroundColor(viewModel.newPassword.count >= 8 ? .green : .secondary) .foregroundColor(viewModel.newPassword.count >= 8 ? Color.appPrimary : Color.appTextSecondary)
Text("At least 8 characters") Text("At least 8 characters")
.font(.caption) .font(.caption)
.foregroundColor(Color.appTextPrimary)
} }
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: hasLetter ? "checkmark.circle.fill" : "circle") Image(systemName: hasLetter ? "checkmark.circle.fill" : "circle")
.foregroundColor(hasLetter ? .green : .secondary) .foregroundColor(hasLetter ? Color.appPrimary : Color.appTextSecondary)
Text("Contains letters") Text("Contains letters")
.font(.caption) .font(.caption)
.foregroundColor(Color.appTextPrimary)
} }
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: hasNumber ? "checkmark.circle.fill" : "circle") Image(systemName: hasNumber ? "checkmark.circle.fill" : "circle")
.foregroundColor(hasNumber ? .green : .secondary) .foregroundColor(hasNumber ? Color.appPrimary : Color.appTextSecondary)
Text("Contains numbers") Text("Contains numbers")
.font(.caption) .font(.caption)
.foregroundColor(Color.appTextPrimary)
} }
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: passwordsMatch ? "checkmark.circle.fill" : "circle") Image(systemName: passwordsMatch ? "checkmark.circle.fill" : "circle")
.foregroundColor(passwordsMatch ? .green : .secondary) .foregroundColor(passwordsMatch ? Color.appPrimary : Color.appTextSecondary)
Text("Passwords match") Text("Passwords match")
.font(.caption) .font(.caption)
.foregroundColor(Color.appTextPrimary)
} }
} }
} header: { } header: {
@@ -97,7 +102,7 @@ struct ResetPasswordView: View {
isNewPasswordVisible.toggle() isNewPasswordVisible.toggle()
}) { }) {
Image(systemName: isNewPasswordVisible ? "eye.slash.fill" : "eye.fill") Image(systemName: isNewPasswordVisible ? "eye.slash.fill" : "eye.fill")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.buttonStyle(.plain) .buttonStyle(.plain)
} }
@@ -133,7 +138,7 @@ struct ResetPasswordView: View {
isConfirmPasswordVisible.toggle() isConfirmPasswordVisible.toggle()
}) { }) {
Image(systemName: isConfirmPasswordVisible ? "eye.slash.fill" : "eye.fill") Image(systemName: isConfirmPasswordVisible ? "eye.slash.fill" : "eye.fill")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.buttonStyle(.plain) .buttonStyle(.plain)
} }
@@ -149,10 +154,10 @@ struct ResetPasswordView: View {
Section { Section {
Label { Label {
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
} icon: { } icon: {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
} }
@@ -161,11 +166,11 @@ struct ResetPasswordView: View {
Section { Section {
Label { Label {
Text(successMessage) Text(successMessage)
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} icon: { } icon: {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
} }
} }
} }
@@ -204,6 +209,9 @@ struct ResetPasswordView: View {
} }
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Reset Password") .navigationTitle("Reset Password")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)

View File

@@ -13,21 +13,22 @@ struct VerifyResetCodeView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
Image(systemName: "envelope.badge.fill") Image(systemName: "envelope.badge.fill")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
.padding(.vertical) .padding(.vertical)
Text("Check Your Email") Text("Check Your Email")
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
Text("We sent a 6-digit code to") Text("We sent a 6-digit code to")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
Text(viewModel.email) Text(viewModel.email)
.font(.subheadline) .font(.subheadline)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical) .padding(.vertical)
@@ -39,11 +40,13 @@ struct VerifyResetCodeView: View {
Label { Label {
Text("Code expires in 15 minutes") Text("Code expires in 15 minutes")
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color.appTextPrimary)
} icon: { } icon: {
Image(systemName: "clock.fill") Image(systemName: "clock.fill")
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
// Code Input Section // Code Input Section
Section { Section {
@@ -66,30 +69,33 @@ struct VerifyResetCodeView: View {
} footer: { } footer: {
Text("Enter the 6-digit code from your email") Text("Enter the 6-digit code from your email")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Error/Success Messages // Error/Success Messages
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
Label { Label {
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
} icon: { } icon: {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
if let successMessage = viewModel.successMessage { if let successMessage = viewModel.successMessage {
Section { Section {
Label { Label {
Text(successMessage) Text(successMessage)
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
} icon: { } icon: {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
// Verify Button // Verify Button
@@ -110,13 +116,14 @@ struct VerifyResetCodeView: View {
} }
.disabled(viewModel.code.count != 6 || viewModel.isLoading) .disabled(viewModel.code.count != 6 || viewModel.isLoading)
} }
.listRowBackground(Color.appBackgroundSecondary)
// Help Section // Help Section
Section { Section {
VStack(spacing: 12) { VStack(spacing: 12) {
Text("Didn't receive the code?") Text("Didn't receive the code?")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
Button(action: { Button(action: {
// Clear code and go back to request new one // Clear code and go back to request new one
@@ -131,13 +138,16 @@ struct VerifyResetCodeView: View {
Text("Check your spam folder if you don't see it") Text("Check your spam folder if you don't see it")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
.listRowBackground(Color.clear) .listRowBackground(Color.clear)
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Verify Code") .navigationTitle("Verify Code")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)

View File

@@ -11,18 +11,20 @@ struct ProfileTabView: View {
Image(systemName: "person.circle.fill") Image(systemName: "person.circle.fill")
.resizable() .resizable()
.frame(width: 60, height: 60) .frame(width: 60, height: 60)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text("User Profile") Text("User Profile")
.font(.headline) .font(.headline)
.foregroundColor(Color.appTextPrimary)
Text("Manage your account") Text("Manage your account")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
.padding(.vertical, 8) .padding(.vertical, 8)
.listRowBackground(Color.appBackgroundSecondary)
} }
Section("Account") { Section("Account") {
@@ -30,7 +32,7 @@ struct ProfileTabView: View {
showingProfileEdit = true showingProfileEdit = true
}) { }) {
Label("Edit Profile", systemImage: "person.crop.circle") Label("Edit Profile", systemImage: "person.crop.circle")
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
} }
NavigationLink(destination: Text("Notifications")) { NavigationLink(destination: Text("Notifications")) {
@@ -41,15 +43,17 @@ struct ProfileTabView: View {
Label("Privacy", systemImage: "lock.shield") Label("Privacy", systemImage: "lock.shield")
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
Button(action: { Button(action: {
showingLogoutAlert = true showingLogoutAlert = true
}) { }) {
Label("Log Out", systemImage: "rectangle.portrait.and.arrow.right") Label("Log Out", systemImage: "rectangle.portrait.and.arrow.right")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.accessibilityIdentifier(AccessibilityIdentifiers.Profile.logoutButton) .accessibilityIdentifier(AccessibilityIdentifiers.Profile.logoutButton)
.listRowBackground(Color.appBackgroundSecondary)
} }
Section { Section {
@@ -57,13 +61,17 @@ struct ProfileTabView: View {
Text("MyCrib") Text("MyCrib")
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color.appTextPrimary)
Text("Version 1.0.0") Text("Version 1.0.0")
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
} }
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Profile") .navigationTitle("Profile")
.sheet(isPresented: $showingProfileEdit) { .sheet(isPresented: $showingProfileEdit) {
ProfileView() ProfileView()

View File

@@ -16,7 +16,7 @@ struct ProfileView: View {
ProgressView() ProgressView()
Text("Loading profile...") Text("Loading profile...")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.padding(.top, 8) .padding(.top, 8)
} }
} else { } else {
@@ -25,11 +25,12 @@ struct ProfileView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "person.circle.fill") Image(systemName: "person.circle.fill")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
Text("Profile Settings") Text("Profile Settings")
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical) .padding(.vertical)
@@ -57,6 +58,7 @@ struct ProfileView: View {
} header: { } header: {
Text("Personal Information") Text("Personal Information")
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
TextField("Email", text: $viewModel.email) TextField("Email", text: $viewModel.email)
@@ -73,29 +75,32 @@ struct ProfileView: View {
} footer: { } footer: {
Text("Email is required and must be unique") Text("Email is required and must be unique")
} }
.listRowBackground(Color.appBackgroundSecondary)
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
HStack { HStack {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
.font(.subheadline) .font(.subheadline)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
if let successMessage = viewModel.successMessage { if let successMessage = viewModel.successMessage {
Section { Section {
HStack { HStack {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
Text(successMessage) Text(successMessage)
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
.font(.subheadline) .font(.subheadline)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
Section { Section {
@@ -113,7 +118,11 @@ struct ProfileView: View {
} }
.disabled(viewModel.isLoading || viewModel.email.isEmpty) .disabled(viewModel.isLoading || viewModel.email.isEmpty)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Profile") .navigationTitle("Profile")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -18,7 +18,7 @@ struct RegisterView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "person.badge.plus") Image(systemName: "person.badge.plus")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
Text("Join MyCrib") Text("Join MyCrib")
.font(.largeTitle) .font(.largeTitle)
@@ -26,7 +26,7 @@ struct RegisterView: View {
Text("Start managing your properties today") Text("Start managing your properties today")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical) .padding(.vertical)
@@ -57,6 +57,7 @@ struct RegisterView: View {
} header: { } header: {
Text("Account Information") Text("Account Information")
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
SecureField("Password", text: $viewModel.password) SecureField("Password", text: $viewModel.password)
@@ -79,17 +80,19 @@ struct RegisterView: View {
} footer: { } footer: {
Text("Password must be secure") Text("Password must be secure")
} }
.listRowBackground(Color.appBackgroundSecondary)
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
HStack { HStack {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
.font(.subheadline) .font(.subheadline)
} }
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
Section { Section {
@@ -108,7 +111,11 @@ struct RegisterView: View {
.disabled(viewModel.isLoading) .disabled(viewModel.isLoading)
.accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerButton) .accessibilityIdentifier(AccessibilityIdentifiers.Authentication.registerButton)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Create Account") .navigationTitle("Create Account")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -28,14 +28,16 @@ struct JoinResidenceView: View {
Text("Enter Share Code") Text("Enter Share Code")
} footer: { } footer: {
Text("Enter the 6-character code shared with you to join a residence") Text("Enter the 6-character code shared with you to join a residence")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.listRowBackground(Color.appBackgroundSecondary)
if let error = viewModel.errorMessage { if let error = viewModel.errorMessage {
Section { Section {
Text(error) Text(error)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
Section { Section {
@@ -54,7 +56,11 @@ struct JoinResidenceView: View {
} }
.disabled(shareCode.count != 6 || viewModel.isLoading) .disabled(shareCode.count != 6 || viewModel.isLoading)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Join Residence") .navigationTitle("Join Residence")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -17,7 +17,7 @@ struct ManageUsersView: View {
var body: some View { var body: some View {
NavigationView { NavigationView {
ZStack { ZStack {
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
if isLoading { if isLoading {
@@ -63,6 +63,9 @@ struct ManageUsersView: View {
} }
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Manage Users") .navigationTitle("Manage Users")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -30,9 +30,9 @@ struct ResidenceDetailView: View {
var body: some View { var body: some View {
ZStack { ZStack {
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
mainContent mainContent
} }
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
@@ -174,7 +174,7 @@ private extension ResidenceDetailView {
ProgressView() ProgressView()
Text("Loading residence...") Text("Loading residence...")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -209,7 +209,7 @@ private extension ResidenceDetailView {
ProgressView("Loading tasks...") ProgressView("Loading tasks...")
} else if let tasksError = tasksError { } else if let tasksError = tasksError {
Text("Error loading tasks: \(tasksError)") Text("Error loading tasks: \(tasksError)")
.foregroundColor(.red) .foregroundColor(Color.appError)
.padding() .padding()
} }
} }
@@ -266,7 +266,7 @@ private extension ResidenceDetailView {
showDeleteConfirmation = true showDeleteConfirmation = true
} label: { } label: {
Image(systemName: "trash") Image(systemName: "trash")
.foregroundStyle(.red) .foregroundStyle(Color.appError)
} }
.accessibilityIdentifier(AccessibilityIdentifiers.Residence.deleteButton) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.deleteButton)
} }

View File

@@ -10,7 +10,7 @@ struct ResidencesListView: View {
var body: some View { var body: some View {
ZStack { ZStack {
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
if viewModel.myResidences == nil && viewModel.isLoading { if viewModel.myResidences == nil && viewModel.isLoading {
@@ -19,7 +19,7 @@ struct ResidencesListView: View {
.scaleEffect(1.2) .scaleEffect(1.2)
Text("Loading properties...") Text("Loading properties...")
.font(.body) .font(.body)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} else if let response = viewModel.myResidences { } else if let response = viewModel.myResidences {
if response.residences.isEmpty { if response.residences.isEmpty {
@@ -37,10 +37,10 @@ struct ResidencesListView: View {
VStack(alignment: .leading, spacing: AppSpacing.xxs) { VStack(alignment: .leading, spacing: AppSpacing.xxs) {
Text("Your Properties") Text("Your Properties")
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Text("\(response.residences.count) \(response.residences.count == 1 ? "property" : "properties")") Text("\(response.residences.count) \(response.residences.count == 1 ? "property" : "properties")")
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
Spacer() Spacer()
} }
@@ -75,7 +75,7 @@ struct ResidencesListView: View {
}) { }) {
Image(systemName: "person.badge.plus") Image(systemName: "person.badge.plus")
.font(.system(size: 18, weight: .semibold)) .font(.system(size: 18, weight: .semibold))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
Button(action: { Button(action: {
@@ -83,7 +83,7 @@ struct ResidencesListView: View {
}) { }) {
Image(systemName: "plus.circle.fill") Image(systemName: "plus.circle.fill")
.font(.system(size: 22, weight: .semibold)) .font(.system(size: 22, weight: .semibold))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} }
.accessibilityIdentifier(AccessibilityIdentifiers.Residence.addButton) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.addButton)
} }

View File

@@ -55,7 +55,7 @@ struct ResidenceFormView: View {
if !nameError.isEmpty { if !nameError.isEmpty {
Text(nameError) Text(nameError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
Picker("Property Type", selection: $selectedPropertyType) { Picker("Property Type", selection: $selectedPropertyType) {
@@ -70,8 +70,9 @@ struct ResidenceFormView: View {
} footer: { } footer: {
Text("Required: Name") Text("Required: Name")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
TextField("Street Address", text: $streetAddress) TextField("Street Address", text: $streetAddress)
@@ -100,6 +101,7 @@ struct ResidenceFormView: View {
} header: { } header: {
Text("Address") Text("Address")
} }
.listRowBackground(Color.appBackgroundSecondary)
Section(header: Text("Property Features")) { Section(header: Text("Property Features")) {
HStack { HStack {
@@ -139,6 +141,7 @@ struct ResidenceFormView: View {
.focused($focusedField, equals: .yearBuilt) .focused($focusedField, equals: .yearBuilt)
.accessibilityIdentifier(AccessibilityIdentifiers.Residence.yearBuiltField) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.yearBuiltField)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section(header: Text("Additional Details")) { Section(header: Text("Additional Details")) {
TextField("Description (optional)", text: $description, axis: .vertical) TextField("Description (optional)", text: $description, axis: .vertical)
@@ -148,15 +151,20 @@ struct ResidenceFormView: View {
Toggle("Primary Residence", isOn: $isPrimary) Toggle("Primary Residence", isOn: $isPrimary)
.accessibilityIdentifier(AccessibilityIdentifiers.Residence.isPrimaryToggle) .accessibilityIdentifier(AccessibilityIdentifiers.Residence.isPrimaryToggle)
} }
.listRowBackground(Color.appBackgroundSecondary)
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
.font(.caption) .font(.caption)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle(isEditMode ? "Edit Residence" : "Add Residence") .navigationTitle(isEditMode ? "Edit Residence" : "Add Residence")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -7,11 +7,12 @@ struct LoginHeader: View {
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80) .frame(width: 80, height: 80)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
Text("MyCrib") Text("MyCrib")
.font(.largeTitle) .font(.largeTitle)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
} }
.padding(.top, 60) .padding(.top, 60)
.padding(.bottom, 20) .padding(.bottom, 20)

View File

@@ -7,15 +7,16 @@ struct RegisterHeader: View {
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 64, height: 64) .frame(width: 64, height: 64)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
Text("Join MyCrib") Text("Join MyCrib")
.font(.largeTitle) .font(.largeTitle)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
Text("Start managing your properties today") Text("Start managing your properties today")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.padding(.top, 40) .padding(.top, 40)
.padding(.bottom, 20) .padding(.bottom, 20)

View File

@@ -7,21 +7,21 @@ struct ErrorMessageView: View {
var body: some View { var body: some View {
HStack { HStack {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
Text(message) Text(message)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
Spacer() Spacer()
Button(action: onDismiss) { Button(action: onDismiss) {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
.padding() .padding()
.background(Color.red.opacity(0.1)) .background(Color.appError.opacity(0.1))
.cornerRadius(8) .cornerRadius(8)
} }
} }

View File

@@ -8,18 +8,18 @@ struct ErrorView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle") Image(systemName: "exclamationmark.triangle")
.font(.system(size: 64)) .font(.system(size: 64))
.foregroundColor(.red) .foregroundColor(Color.appError)
Text("Error: \(message)") Text("Error: \(message)")
.foregroundColor(.red) .foregroundColor(Color.appError)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Button(action: retryAction) { Button(action: retryAction) {
Text("Retry") Text("Retry")
.padding(.horizontal, 32) .padding(.horizontal, 32)
.padding(.vertical, 12) .padding(.vertical, 12)
.background(Color.blue) .background(Color.appPrimary)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.cornerRadius(8) .cornerRadius(8)
} }
} }

View File

@@ -10,13 +10,13 @@ struct HomeNavigationCard: View {
// Icon with gradient background // Icon with gradient background
ZStack { ZStack {
RoundedRectangle(cornerRadius: AppRadius.md) RoundedRectangle(cornerRadius: AppRadius.md)
.fill(LinearGradient(colors: [.blue, .blue.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing)) .fill(LinearGradient(colors: [Color.appPrimary, Color.appPrimary.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing))
.frame(width: 60, height: 60) .frame(width: 60, height: 60)
.shadow(color: .blue.opacity(0.3), radius: 8, y: 4) .shadow(color: Color.appPrimary.opacity(0.3), radius: 8, y: 4)
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 28, weight: .semibold)) .font(.system(size: 28, weight: .semibold))
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
} }
// Text Content // Text Content
@@ -24,11 +24,11 @@ struct HomeNavigationCard: View {
Text(title) Text(title)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Text(subtitle) Text(subtitle)
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
Spacer() Spacer()
@@ -36,10 +36,10 @@ struct HomeNavigationCard: View {
// Chevron // Chevron
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.system(size: 16, weight: .semibold)) .font(.system(size: 16, weight: .semibold))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
} }
.padding(AppSpacing.lg) .padding(AppSpacing.lg)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y) .shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y)
} }

View File

@@ -19,7 +19,7 @@ struct ImageThumbnailView: View {
Button(action: onRemove) { Button(action: onRemove) {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
.font(.title3) .font(.title3)
.foregroundStyle(.white) .foregroundStyle(Color.appTextOnPrimary)
.background { .background {
Circle() Circle()
.fill(.black.opacity(0.6)) .fill(.black.opacity(0.6))

View File

@@ -11,17 +11,17 @@ struct OverviewCard: View {
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
ZStack { ZStack {
Circle() Circle()
.fill(LinearGradient(colors: [.blue, .blue.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing)) .fill(LinearGradient(colors: [Color.appPrimary, Color.appPrimary.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing))
.frame(width: 44, height: 44) .frame(width: 44, height: 44)
Image(systemName: "chart.bar.fill") Image(systemName: "chart.bar.fill")
.font(.system(size: 20, weight: .semibold)) .font(.system(size: 20, weight: .semibold))
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
} }
Text("Overview") Text("Overview")
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
} }
Spacer() Spacer()
} }
@@ -32,7 +32,7 @@ struct OverviewCard: View {
icon: "house.fill", icon: "house.fill",
value: "\(summary.totalResidences)", value: "\(summary.totalResidences)",
label: "Properties", label: "Properties",
color: .blue color: Color.appPrimary
) )
Divider() Divider()
@@ -42,7 +42,7 @@ struct OverviewCard: View {
icon: "list.bullet", icon: "list.bullet",
value: "\(summary.totalTasks)", value: "\(summary.totalTasks)",
label: "Total Tasks", label: "Total Tasks",
color: .blue color: Color.appPrimary
) )
Divider() Divider()
@@ -52,12 +52,12 @@ struct OverviewCard: View {
icon: "clock.fill", icon: "clock.fill",
value: "\(summary.totalPending)", value: "\(summary.totalPending)",
label: "Pending", label: "Pending",
color: .orange color: Color.appAccent
) )
} }
} }
.padding(AppSpacing.xl) .padding(AppSpacing.xl)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.xl) .cornerRadius(AppRadius.xl)
.shadow(color: AppShadow.lg.color, radius: AppShadow.lg.radius, x: AppShadow.lg.x, y: AppShadow.lg.y) .shadow(color: AppShadow.lg.color, radius: AppShadow.lg.radius, x: AppShadow.lg.x, y: AppShadow.lg.y)
.padding(.horizontal, AppSpacing.md) .padding(.horizontal, AppSpacing.md)

View File

@@ -4,7 +4,7 @@ struct StatView: View {
let icon: String let icon: String
let value: String let value: String
let label: String let label: String
var color: Color = .blue var color: Color = Color.appPrimary
var body: some View { var body: some View {
VStack(spacing: AppSpacing.sm) { VStack(spacing: AppSpacing.sm) {
@@ -21,11 +21,11 @@ struct StatView: View {
Text(value) Text(value)
.font(.title2.weight(.semibold)) .font(.title2.weight(.semibold))
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Text(label) Text(label)
.font(.footnote.weight(.medium)) .font(.footnote.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)

View File

@@ -5,15 +5,16 @@ struct EmptyResidencesView: View {
VStack(spacing: 16) { VStack(spacing: 16) {
Image(systemName: "house") Image(systemName: "house")
.font(.system(size: 80)) .font(.system(size: 80))
.foregroundColor(.blue.opacity(0.6)) .foregroundColor(Color.appPrimary.opacity(0.6))
Text("No properties yet") Text("No properties yet")
.font(.title2) .font(.title2)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color.appTextPrimary)
Text("Add your first property to get started!") Text("Add your first property to get started!")
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
} }

View File

@@ -9,15 +9,16 @@ struct PropertyDetailItem: View {
VStack(spacing: 4) { VStack(spacing: 4) {
Image(systemName: icon) Image(systemName: icon)
.font(.caption) .font(.caption)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
Text(value) Text(value)
.font(.subheadline) .font(.subheadline)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color.appTextPrimary)
Text(label) Text(label)
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
} }

View File

@@ -9,17 +9,18 @@ struct PropertyHeaderCard: View {
HStack { HStack {
Image(systemName: "house.fill") Image(systemName: "house.fill")
.font(.title2) .font(.title2)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(residence.name) Text(residence.name)
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
if let propertyType = residence.propertyType { if let propertyType = residence.propertyType {
Text(propertyType) Text(propertyType)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -32,18 +33,19 @@ struct PropertyHeaderCard: View {
if let streetAddress = residence.streetAddress { if let streetAddress = residence.streetAddress {
Label(streetAddress, systemImage: "mappin.circle.fill") Label(streetAddress, systemImage: "mappin.circle.fill")
.font(.subheadline) .font(.subheadline)
.foregroundColor(Color.appTextPrimary)
} }
if residence.city != nil || residence.stateProvince != nil || residence.postalCode != nil { if residence.city != nil || residence.stateProvince != nil || residence.postalCode != nil {
Text("\(residence.city ?? ""), \(residence.stateProvince ?? "") \(residence.postalCode ?? "")") Text("\(residence.city ?? ""), \(residence.stateProvince ?? "") \(residence.postalCode ?? "")")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
if let country = residence.country, !country.isEmpty { if let country = residence.country, !country.isEmpty {
Text(country) Text(country)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -62,8 +64,9 @@ struct PropertyHeaderCard: View {
} }
} }
.padding(20) .padding(20)
.background(Color.blue.opacity(0.1)) .background(Color.appBackgroundSecondary)
.cornerRadius(16) .cornerRadius(16)
.shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y)
} }
} }

View File

@@ -10,26 +10,26 @@ struct ResidenceCard: View {
HStack(spacing: AppSpacing.sm) { HStack(spacing: AppSpacing.sm) {
ZStack { ZStack {
RoundedRectangle(cornerRadius: AppRadius.sm) RoundedRectangle(cornerRadius: AppRadius.sm)
.fill(LinearGradient(colors: [.blue, .blue.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing)) .fill(LinearGradient(colors: [Color.appPrimary, Color.appPrimary.opacity(0.8)], startPoint: .topLeading, endPoint: .bottomTrailing))
.frame(width: 44, height: 44) .frame(width: 44, height: 44)
.shadow(color: .blue.opacity(0.3), radius: 6, y: 3) .shadow(color: Color.appPrimary.opacity(0.3), radius: 6, y: 3)
Image(systemName: "house.fill") Image(systemName: "house.fill")
.font(.system(size: 20, weight: .semibold)) .font(.system(size: 20, weight: .semibold))
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
} }
VStack(alignment: .leading, spacing: AppSpacing.xxs) { VStack(alignment: .leading, spacing: AppSpacing.xxs) {
Text(residence.name) Text(residence.name)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
.lineLimit(1) .lineLimit(1)
if let propertyType = residence.propertyType { if let propertyType = residence.propertyType {
Text(propertyType) Text(propertyType)
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
.textCase(.uppercase) .textCase(.uppercase)
.tracking(0.5) .tracking(0.5)
} }
@@ -40,11 +40,11 @@ struct ResidenceCard: View {
if residence.isPrimary { if residence.isPrimary {
ZStack { ZStack {
Circle() Circle()
.fill(.purple.opacity(0.1)) .fill(Color.appAccent.opacity(0.2))
.frame(width: 32, height: 32) .frame(width: 32, height: 32)
Image(systemName: "star.fill") Image(systemName: "star.fill")
.font(.system(size: 14, weight: .bold)) .font(.system(size: 14, weight: .bold))
.foregroundColor(.purple) .foregroundColor(Color.appAccent)
} }
} }
} }
@@ -55,10 +55,10 @@ struct ResidenceCard: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
Image(systemName: "mappin.circle.fill") Image(systemName: "mappin.circle.fill")
.font(.system(size: 12, weight: .medium)) .font(.system(size: 12, weight: .medium))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
Text(streetAddress) Text(streetAddress)
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -66,10 +66,10 @@ struct ResidenceCard: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
Image(systemName: "location.fill") Image(systemName: "location.fill")
.font(.system(size: 12, weight: .medium)) .font(.system(size: 12, weight: .medium))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary)
Text("\(residence.city ?? ""), \(residence.stateProvince ?? "")") Text("\(residence.city ?? ""), \(residence.stateProvince ?? "")")
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
} }
} }
@@ -86,13 +86,13 @@ struct ResidenceCard: View {
icon: category.icons.ios, icon: category.icons.ios,
value: "\(category.count)", value: "\(category.count)",
label: category.displayName, label: category.displayName,
color: Color(hex: category.color) ?? .gray color: Color(hex: category.color) ?? Color.appTextSecondary
) )
} }
} }
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y) .shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y)
} }
@@ -160,5 +160,5 @@ struct ResidenceCard: View {
updatedAt: "2024-01-01T00:00:00Z" updatedAt: "2024-01-01T00:00:00Z"
)) ))
.padding() .padding()
.background(Color(.systemGroupedBackground)) .background(Color.appBackgroundPrimary)
} }

View File

@@ -14,17 +14,17 @@ struct ShareCodeCard: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text("Share Code") Text("Share Code")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
if let shareCode = shareCode { if let shareCode = shareCode {
Text(shareCode.code) Text(shareCode.code)
.font(.title) .font(.title)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
} else { } else {
Text("No active code") Text("No active code")
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -43,11 +43,11 @@ struct ShareCodeCard: View {
if shareCode != nil { if shareCode != nil {
Text("Share this code with others to give them access to \(residenceName)") Text("Share this code with others to give them access to \(residenceName)")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
.padding() .padding()
.background(Color.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.cornerRadius(12) .cornerRadius(12)
} }
} }

View File

@@ -46,8 +46,9 @@ struct SummaryCard: View {
} }
} }
.padding(20) .padding(20)
.background(Color.blue.opacity(0.1)) .background(Color.appBackgroundSecondary)
.cornerRadius(16) .cornerRadius(16)
.shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y)
} }
} }

View File

@@ -9,15 +9,16 @@ struct SummaryStatView: View {
VStack(spacing: 8) { VStack(spacing: 8) {
Image(systemName: icon) Image(systemName: icon)
.font(.title3) .font(.title3)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
Text(value) Text(value)
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
Text(label) Text(label)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)

View File

@@ -19,7 +19,7 @@ struct TaskStatChip: View {
Text(label) Text(label)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
} }

View File

@@ -15,15 +15,16 @@ struct UserListItem: View {
Text(user.username) Text(user.username)
.font(.body) .font(.body)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(Color.appTextPrimary)
if isOwner { if isOwner {
Text("Owner") Text("Owner")
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 2) .padding(.vertical, 2)
.background(Color.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.cornerRadius(4) .cornerRadius(4)
} }
} }
@@ -31,7 +32,7 @@ struct UserListItem: View {
if !user.email.isEmpty { if !user.email.isEmpty {
Text(user.email) Text(user.email)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
let fullName = [user.firstName, user.lastName] let fullName = [user.firstName, user.lastName]
@@ -42,7 +43,7 @@ struct UserListItem: View {
if !fullName.isEmpty { if !fullName.isEmpty {
Text(fullName) Text(fullName)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -51,12 +52,12 @@ struct UserListItem: View {
if isPrimaryOwner && !isOwner { if isPrimaryOwner && !isOwner {
Button(action: onRemove) { Button(action: onRemove) {
Image(systemName: "trash") Image(systemName: "trash")
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} }
} }
.padding() .padding()
.background(Color(.systemBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(12) .cornerRadius(12)
.padding(.horizontal) .padding(.horizontal)
} }

View File

@@ -11,7 +11,7 @@ struct CompletionCardView: View {
Text(formatDate(completion.completionDate)) Text(formatDate(completion.completionDate))
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
Spacer() Spacer()
@@ -23,10 +23,10 @@ struct CompletionCardView: View {
.font(.caption) .font(.caption)
.fontWeight(.bold) .fontWeight(.bold)
} }
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
.background(Color.orange.opacity(0.1)) .background(Color.appAccent.opacity(0.1))
.cornerRadius(6) .cornerRadius(6)
} }
} }
@@ -36,38 +36,38 @@ struct CompletionCardView: View {
HStack(alignment: .top, spacing: 6) { HStack(alignment: .top, spacing: 6) {
Image(systemName: "wrench.and.screwdriver") Image(systemName: "wrench.and.screwdriver")
.font(.caption2) .font(.caption2)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("By: \(contractorDetails.name)") Text("By: \(contractorDetails.name)")
.font(.caption2) .font(.caption2)
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
if let company = contractorDetails.company { if let company = contractorDetails.company {
Text(company) Text(company)
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
} }
} else if let completedBy = completion.completedByName { } else if let completedBy = completion.completedByName {
Text("By: \(completedBy)") Text("By: \(completedBy)")
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
if let cost = completion.actualCost { if let cost = completion.actualCost {
Text("Cost: $\(cost)") Text("Cost: $\(cost)")
.font(.caption2) .font(.caption2)
.foregroundColor(.green) .foregroundColor(Color.appPrimary)
.fontWeight(.medium) .fontWeight(.medium)
} }
if let notes = completion.notes { if let notes = completion.notes {
Text(notes) Text(notes)
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.lineLimit(2) .lineLimit(2)
} }
@@ -85,14 +85,14 @@ struct CompletionCardView: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical, 8) .padding(.vertical, 8)
.background(Color.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.cornerRadius(8) .cornerRadius(8)
} }
} }
} }
.padding(12) .padding(12)
.background(Color(.systemGray6)) .background(Color.appBackgroundSecondary.opacity(0.5))
.cornerRadius(8) .cornerRadius(8)
.sheet(isPresented: $showPhotoSheet) { .sheet(isPresented: $showPhotoSheet) {
if let images = completion.images { if let images = completion.images {

View File

@@ -38,21 +38,21 @@ struct DynamicTaskCard: View {
if let description = task.description_, !description.isEmpty { if let description = task.description_, !description.isEmpty {
Text(description) Text(description)
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.lineLimit(2) .lineLimit(2)
} }
HStack { HStack {
Label(task.frequency.displayName, systemImage: "repeat") Label(task.frequency.displayName, systemImage: "repeat")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
Spacer() Spacer()
if let due_date = task.dueDate { if let due_date = task.dueDate {
Label(formatDate(due_date), systemImage: "calendar") Label(formatDate(due_date), systemImage: "calendar")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
} }
@@ -62,15 +62,15 @@ struct DynamicTaskCard: View {
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
HStack { HStack {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green) .foregroundColor(Color.appAccent)
Text("Completions (\(task.completions.count))") Text("Completions (\(task.completions.count))")
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
Spacer() Spacer()
Image(systemName: isCompletionsExpanded ? "chevron.up" : "chevron.down") Image(systemName: isCompletionsExpanded ? "chevron.up" : "chevron.down")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
@@ -102,12 +102,12 @@ struct DynamicTaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical, 12) .padding(.vertical, 12)
.background(Color.blue.opacity(0.1)) .background(Color.appPrimary.opacity(0.1))
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.cornerRadius(8) .cornerRadius(8)
.overlay( .overlay(
RoundedRectangle(cornerRadius: 8) RoundedRectangle(cornerRadius: 8)
.stroke(Color.blue, lineWidth: 2) .stroke(Color.appPrimary, lineWidth: 2)
) )
} }
.zIndex(10) .zIndex(10)
@@ -115,7 +115,7 @@ struct DynamicTaskCard: View {
} }
} }
.padding(16) .padding(16)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(12) .cornerRadius(12)
.shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2) .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
.simultaneousGesture(TapGesture(), including: .subviews) .simultaneousGesture(TapGesture(), including: .subviews)

View File

@@ -18,7 +18,7 @@ struct DynamicTaskColumnView: View {
} }
private var columnColor: Color { private var columnColor: Color {
Color(hex: column.color) ?? .primary Color(hex: column.color) ?? Color.appTextPrimary
} }
var body: some View { var body: some View {
@@ -40,7 +40,7 @@ struct DynamicTaskColumnView: View {
Text("\(column.count)") Text("\(column.count)")
.font(.caption) .font(.caption)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
.background(columnColor) .background(columnColor)
@@ -55,7 +55,7 @@ struct DynamicTaskColumnView: View {
Text("No tasks") Text("No tasks")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.top, 40) .padding(.top, 40)

View File

@@ -5,15 +5,15 @@ struct EmptyTasksView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
Image(systemName: "checkmark.circle") Image(systemName: "checkmark.circle")
.font(.system(size: 48)) .font(.system(size: 48))
.foregroundColor(.gray.opacity(0.5)) .foregroundColor(Color.appTextSecondary.opacity(0.5))
Text("No tasks yet") Text("No tasks yet")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(32) .padding(32)
.background(Color(.systemBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(12) .cornerRadius(12)
} }
} }

View File

@@ -32,9 +32,9 @@ struct PhotoViewerSheet: View {
VStack { VStack {
Image(systemName: "photo") Image(systemName: "photo")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundColor(.gray) .foregroundColor(Color.appTextSecondary)
Text("Failed to load image") Text("Failed to load image")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(height: 300) .frame(height: 300)
@unknown default: @unknown default:
@@ -46,12 +46,14 @@ struct PhotoViewerSheet: View {
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
Text("Caption") Text("Caption")
.font(.headline) .font(.headline)
.foregroundColor(Color.appTextPrimary)
Text(caption) Text(caption)
.font(.body) .font(.body)
.foregroundColor(Color.appTextPrimary)
} }
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.padding() .padding()
.background(Color(.systemGray6)) .background(Color.appBackgroundSecondary)
.cornerRadius(12) .cornerRadius(12)
.padding(.horizontal) .padding(.horizontal)
} }
@@ -104,10 +106,10 @@ struct PhotoViewerSheet: View {
VStack { VStack {
Image(systemName: "photo") Image(systemName: "photo")
.font(.system(size: 40)) .font(.system(size: 40))
.foregroundColor(.gray) .foregroundColor(Color.appTextSecondary)
Text("Failed to load") Text("Failed to load")
.font(.caption2) .font(.caption2)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(height: 150) .frame(height: 150)
@unknown default: @unknown default:
@@ -119,7 +121,7 @@ struct PhotoViewerSheet: View {
if let caption = image.caption { if let caption = image.caption {
Text(caption) Text(caption)
.font(.caption2) .font(.caption2)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
.lineLimit(2) .lineLimit(2)
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
} }

View File

@@ -21,10 +21,10 @@ struct PriorityBadge: View {
private var priorityColor: Color { private var priorityColor: Color {
switch priority.lowercased() { switch priority.lowercased() {
case "high": return .red case "high": return Color.appError
case "medium": return .orange case "medium": return Color.appAccent
case "low": return .green case "low": return Color.appPrimary
default: return Color(.tertiaryLabel) default: return Color.appTextSecondary.opacity(0.7)
} }
} }
} }
@@ -36,5 +36,5 @@ struct PriorityBadge: View {
PriorityBadge(priority: "low") PriorityBadge(priority: "low")
} }
.padding() .padding()
.background(Color(.systemGroupedBackground)) .background(Color.appBackgroundPrimary)
} }

View File

@@ -24,11 +24,11 @@ struct StatusBadge: View {
private var statusColor: Color { private var statusColor: Color {
switch status { switch status {
case "completed": return .green case "completed": return Color.appPrimary
case "in_progress": return .orange case "in_progress": return Color.appAccent
case "pending": return .orange case "pending": return Color.appAccent
case "cancelled": return .red case "cancelled": return Color.appError
default: return Color(.tertiaryLabel) default: return Color.appTextSecondary.opacity(0.7)
} }
} }
} }
@@ -41,5 +41,5 @@ struct StatusBadge: View {
StatusBadge(status: "cancelled") StatusBadge(status: "cancelled")
} }
.padding() .padding()
.background(Color(.systemGroupedBackground)) .background(Color.appBackgroundPrimary)
} }

View File

@@ -38,7 +38,7 @@ struct CancelTaskButton: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
.tint(.red) .tint(Color.appError)
.alert("Cancel Task", isPresented: $showConfirmation) { .alert("Cancel Task", isPresented: $showConfirmation) {
Button("Cancel", role: .cancel) { } Button("Cancel", role: .cancel) { }
Button("Cancel Task", role: .destructive) { Button("Cancel Task", role: .destructive) {
@@ -79,7 +79,7 @@ struct UncancelTaskButton: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
.tint(.blue) .tint(Color.appPrimary)
} }
} }
@@ -111,7 +111,7 @@ struct MarkInProgressButton: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
.tint(.orange) .tint(Color.appAccent)
} }
} }
@@ -198,6 +198,6 @@ struct UnarchiveTaskButton: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
.tint(.blue) .tint(Color.appPrimary)
} }
} }

View File

@@ -20,7 +20,7 @@ struct TaskCard: View {
VStack(alignment: .leading, spacing: AppSpacing.xs) { VStack(alignment: .leading, spacing: AppSpacing.xs) {
Text(task.title) Text(task.title)
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
.lineLimit(2) .lineLimit(2)
if let status = task.status { if let status = task.status {
@@ -37,7 +37,7 @@ struct TaskCard: View {
if let description = task.description_, !description.isEmpty { if let description = task.description_, !description.isEmpty {
Text(description) Text(description)
.font(.callout) .font(.callout)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.lineLimit(3) .lineLimit(3)
} }
@@ -46,14 +46,14 @@ struct TaskCard: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
Image(systemName: "repeat") Image(systemName: "repeat")
.font(.system(size: 12, weight: .medium)) .font(.system(size: 12, weight: .medium))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
Text(task.frequency.displayName) Text(task.frequency.displayName)
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
.padding(.horizontal, AppSpacing.sm) .padding(.horizontal, AppSpacing.sm)
.padding(.vertical, AppSpacing.xxs) .padding(.vertical, AppSpacing.xxs)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.xs) .cornerRadius(AppRadius.xs)
Spacer() Spacer()
@@ -62,14 +62,14 @@ struct TaskCard: View {
HStack(spacing: AppSpacing.xxs) { HStack(spacing: AppSpacing.xxs) {
Image(systemName: "calendar") Image(systemName: "calendar")
.font(.system(size: 12, weight: .medium)) .font(.system(size: 12, weight: .medium))
.foregroundColor(Color(.tertiaryLabel)) .foregroundColor(Color.appTextSecondary.opacity(0.7))
Text(formatDate(dueDate)) Text(formatDate(dueDate))
.font(.caption.weight(.medium)) .font(.caption.weight(.medium))
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
.padding(.horizontal, AppSpacing.sm) .padding(.horizontal, AppSpacing.sm)
.padding(.vertical, AppSpacing.xxs) .padding(.vertical, AppSpacing.xxs)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.xs) .cornerRadius(AppRadius.xs)
} }
} }
@@ -83,20 +83,20 @@ struct TaskCard: View {
HStack(spacing: AppSpacing.xs) { HStack(spacing: AppSpacing.xs) {
ZStack { ZStack {
Circle() Circle()
.fill(Color.green.opacity(0.1)) .fill(Color.appAccent.opacity(0.1))
.frame(width: 24, height: 24) .frame(width: 24, height: 24)
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.font(.system(size: 14, weight: .semibold)) .font(.system(size: 14, weight: .semibold))
.foregroundColor(.green) .foregroundColor(Color.appAccent)
} }
Text("Completions (\(task.completions.count))") Text("Completions (\(task.completions.count))")
.font(.footnote.weight(.medium)) .font(.footnote.weight(.medium))
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color(.label)) .foregroundColor(Color.appTextPrimary)
Spacer() Spacer()
Image(systemName: isCompletionsExpanded ? "chevron.up" : "chevron.down") Image(systemName: isCompletionsExpanded ? "chevron.up" : "chevron.down")
.font(.caption) .font(.caption)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
@@ -127,8 +127,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 44) .frame(height: 44)
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.background(Color.orange.opacity(0.1)) .background(Color.appAccent.opacity(0.1))
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
} }
} }
@@ -144,8 +144,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 44) .frame(height: 44)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.background(.green) .background(Color.appPrimary)
.cornerRadius(AppRadius.md) .cornerRadius(AppRadius.md)
} }
} }
@@ -164,8 +164,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 36) .frame(height: 36)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.sm) .cornerRadius(AppRadius.sm)
} }
@@ -179,8 +179,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 36) .frame(height: 36)
.foregroundColor(.red) .foregroundColor(Color.appError)
.background(Color.red.opacity(0.1)) .background(Color.appError.opacity(0.1))
.cornerRadius(AppRadius.sm) .cornerRadius(AppRadius.sm)
} }
} else if let onUncancel = onUncancel { } else if let onUncancel = onUncancel {
@@ -193,8 +193,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 36) .frame(height: 36)
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.background(.blue) .background(Color.appPrimary)
.cornerRadius(AppRadius.sm) .cornerRadius(AppRadius.sm)
} }
} }
@@ -211,8 +211,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 36) .frame(height: 36)
.foregroundColor(.blue) .foregroundColor(Color.appPrimary)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.sm) .cornerRadius(AppRadius.sm)
} }
} }
@@ -227,8 +227,8 @@ struct TaskCard: View {
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.frame(height: 36) .frame(height: 36)
.foregroundColor(Color(.secondaryLabel)) .foregroundColor(Color.appTextSecondary)
.background(Color(.tertiarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.sm) .cornerRadius(AppRadius.sm)
} }
} }
@@ -236,7 +236,7 @@ struct TaskCard: View {
} }
} }
.padding(AppSpacing.md) .padding(AppSpacing.md)
.background(Color(.secondarySystemGroupedBackground)) .background(Color.appBackgroundSecondary)
.cornerRadius(AppRadius.lg) .cornerRadius(AppRadius.lg)
.shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y) .shadow(color: AppShadow.md.color, radius: AppShadow.md.radius, x: AppShadow.md.x, y: AppShadow.md.y)
} }
@@ -287,5 +287,5 @@ struct TaskCard: View {
) )
} }
.padding() .padding()
.background(Color(.systemGroupedBackground)) .background(Color.appBackgroundPrimary)
} }

View File

@@ -24,9 +24,9 @@ struct TaskPill: View {
#Preview { #Preview {
HStack(spacing: 8) { HStack(spacing: 8) {
TaskPill(count: 12, label: "Total", color: .blue) TaskPill(count: 12, label: "Total", color: Color.appPrimary)
TaskPill(count: 5, label: "Pending", color: .orange) TaskPill(count: 5, label: "Pending", color: Color.appAccent)
TaskPill(count: 3, label: "Done", color: .green) TaskPill(count: 3, label: "Done", color: Color.appPrimary)
} }
.padding() .padding()
} }

View File

@@ -20,6 +20,7 @@ struct TasksSection: View {
Text("Tasks") Text("Tasks")
.font(.title2) .font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
if hasNoTasks { if hasNoTasks {
EmptyTasksView() EmptyTasksView()

View File

@@ -99,7 +99,7 @@ struct AllTasksView: View {
@ViewBuilder @ViewBuilder
private var mainContent: some View { private var mainContent: some View {
ZStack { ZStack {
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
if hasNoTasks && isLoadingTasks { if hasNoTasks && isLoadingTasks {
@@ -113,18 +113,19 @@ struct AllTasksView: View {
// Empty state with big button // Empty state with big button
VStack(spacing: 24) { VStack(spacing: 24) {
Spacer() Spacer()
Image(systemName: "checklist") Image(systemName: "checklist")
.font(.system(size: 64)) .font(.system(size: 64))
.foregroundStyle(.blue.opacity(0.6)) .foregroundStyle(Color.appPrimary.opacity(0.6))
Text("No tasks yet") Text("No tasks yet")
.font(.title2) .font(.title2)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundColor(Color.appTextPrimary)
Text("Create your first task to get started") Text("Create your first task to get started")
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Button(action: { Button(action: {
@@ -147,7 +148,7 @@ struct AllTasksView: View {
if residenceViewModel.myResidences?.residences.isEmpty ?? true { if residenceViewModel.myResidences?.residences.isEmpty ?? true {
Text("Add a property first from the Residences tab") Text("Add a property first from the Residences tab")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
Spacer() Spacer()
@@ -216,6 +217,8 @@ struct AllTasksView: View {
} }
} }
} }
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("All Tasks") .navigationTitle("All Tasks")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -52,6 +52,7 @@ struct CompleteTaskView: View {
} header: { } header: {
Text("Task Details") Text("Task Details")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Contractor Selection Section // Contractor Selection Section
Section { Section {
@@ -89,6 +90,7 @@ struct CompleteTaskView: View {
} footer: { } footer: {
Text("Select a contractor if they completed this work, or leave blank for manual entry.") Text("Select a contractor if they completed this work, or leave blank for manual entry.")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Completion Details Section // Completion Details Section
Section { Section {
@@ -117,6 +119,7 @@ struct CompleteTaskView: View {
} footer: { } footer: {
Text("Add any additional details about completing this task.") Text("Add any additional details about completing this task.")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Notes Section // Notes Section
Section { Section {
@@ -132,6 +135,7 @@ struct CompleteTaskView: View {
} footer: { } footer: {
Text("Optional notes about the work completed.") Text("Optional notes about the work completed.")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Rating Section // Rating Section
Section { Section {
@@ -165,6 +169,7 @@ struct CompleteTaskView: View {
} footer: { } footer: {
Text("Rate the quality of work from 1 to 5 stars.") Text("Rate the quality of work from 1 to 5 stars.")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Images Section // Images Section
Section { Section {
@@ -175,7 +180,7 @@ struct CompleteTaskView: View {
}) { }) {
Label("Take Photo", systemImage: "camera") Label("Take Photo", systemImage: "camera")
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.foregroundStyle(.blue) .foregroundStyle(Color.appPrimary)
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
@@ -187,7 +192,7 @@ struct CompleteTaskView: View {
) { ) {
Label("Library", systemImage: "photo.on.rectangle.angled") Label("Library", systemImage: "photo.on.rectangle.angled")
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.foregroundStyle(.blue) .foregroundStyle(Color.appPrimary)
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
@@ -228,6 +233,7 @@ struct CompleteTaskView: View {
} footer: { } footer: {
Text("Add up to 5 photos documenting the completed work.") Text("Add up to 5 photos documenting the completed work.")
} }
.listRowBackground(Color.appBackgroundSecondary)
// Complete Button Section // Complete Button Section
Section { Section {
@@ -243,11 +249,14 @@ struct CompleteTaskView: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.fontWeight(.semibold) .fontWeight(.semibold)
} }
.listRowBackground(isSubmitting ? Color.gray : Color.green) .listRowBackground(isSubmitting ? Color.gray : Color.appPrimary)
.foregroundStyle(.white) .foregroundStyle(Color.appTextOnPrimary)
.disabled(isSubmitting) .disabled(isSubmitting)
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle("Complete Task") .navigationTitle("Complete Task")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
@@ -397,7 +406,7 @@ struct ContractorPickerView: View {
Spacer() Spacer()
if selectedContractor == nil { if selectedContractor == nil {
Image(systemName: "checkmark") Image(systemName: "checkmark")
.foregroundStyle(.blue) .foregroundStyle(Color.appPrimary)
} }
} }
} }
@@ -411,7 +420,7 @@ struct ContractorPickerView: View {
} }
} else if let errorMessage = contractorViewModel.errorMessage { } else if let errorMessage = contractorViewModel.errorMessage {
Text(errorMessage) Text(errorMessage)
.foregroundStyle(.red) .foregroundStyle(Color.appError)
.font(.caption) .font(.caption)
} else { } else {
ForEach(contractorViewModel.contractors, id: \.id) { contractor in ForEach(contractorViewModel.contractors, id: \.id) { contractor in
@@ -445,7 +454,7 @@ struct ContractorPickerView: View {
if selectedContractor?.id == contractor.id { if selectedContractor?.id == contractor.id {
Image(systemName: "checkmark") Image(systemName: "checkmark")
.foregroundStyle(.blue) .foregroundStyle(Color.appPrimary)
} }
} }
} }

View File

@@ -107,15 +107,16 @@ struct TaskFormView: View {
if !residenceError.isEmpty { if !residenceError.isEmpty {
Text(residenceError) Text(residenceError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
} header: { } header: {
Text("Property") Text("Property")
} footer: { } footer: {
Text("Required") Text("Required")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
Section { Section {
@@ -125,7 +126,7 @@ struct TaskFormView: View {
if !titleError.isEmpty { if !titleError.isEmpty {
Text(titleError) Text(titleError)
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
TextField("Description (optional)", text: $description, axis: .vertical) TextField("Description (optional)", text: $description, axis: .vertical)
@@ -136,8 +137,9 @@ struct TaskFormView: View {
} footer: { } footer: {
Text("Required: Title") Text("Required: Title")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
Picker("Category", selection: $selectedCategory) { Picker("Category", selection: $selectedCategory) {
@@ -151,8 +153,9 @@ struct TaskFormView: View {
} footer: { } footer: {
Text("Required") Text("Required")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
Picker("Frequency", selection: $selectedFrequency) { Picker("Frequency", selection: $selectedFrequency) {
@@ -174,8 +177,9 @@ struct TaskFormView: View {
} footer: { } footer: {
Text("Required: Frequency") Text("Required: Frequency")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section { Section {
Picker("Priority", selection: $selectedPriority) { Picker("Priority", selection: $selectedPriority) {
@@ -196,21 +200,24 @@ struct TaskFormView: View {
} footer: { } footer: {
Text("Required: Both Priority and Status") Text("Required: Both Priority and Status")
.font(.caption) .font(.caption)
.foregroundColor(.red) .foregroundColor(Color.appError)
} }
.listRowBackground(Color.appBackgroundSecondary)
Section(header: Text("Cost")) { Section(header: Text("Cost")) {
TextField("Estimated Cost (optional)", text: $estimatedCost) TextField("Estimated Cost (optional)", text: $estimatedCost)
.keyboardType(.decimalPad) .keyboardType(.decimalPad)
.focused($focusedField, equals: .estimatedCost) .focused($focusedField, equals: .estimatedCost)
} }
.listRowBackground(Color.appBackgroundSecondary)
if let errorMessage = viewModel.errorMessage { if let errorMessage = viewModel.errorMessage {
Section { Section {
Text(errorMessage) Text(errorMessage)
.foregroundColor(.red) .foregroundColor(Color.appError)
.font(.caption) .font(.caption)
} }
.listRowBackground(Color.appBackgroundSecondary)
} }
} }
.disabled(isLoadingLookups) .disabled(isLoadingLookups)
@@ -221,12 +228,15 @@ struct TaskFormView: View {
ProgressView() ProgressView()
.scaleEffect(1.5) .scaleEffect(1.5)
Text("Loading...") Text("Loading...")
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(uiColor: .systemBackground).opacity(0.8)) .background(Color.appBackgroundPrimary.opacity(0.8))
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationTitle(isEditMode ? "Edit Task" : "Add Task") .navigationTitle(isEditMode ? "Edit Task" : "Add Task")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {

View File

@@ -9,7 +9,7 @@ struct VerifyEmailView: View {
var body: some View { var body: some View {
NavigationView { NavigationView {
ZStack { ZStack {
Color(.systemGroupedBackground) Color.appBackgroundPrimary
.ignoresSafeArea() .ignoresSafeArea()
ScrollView { ScrollView {
@@ -20,16 +20,17 @@ struct VerifyEmailView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
Image(systemName: "envelope.badge.shield.half.filled") Image(systemName: "envelope.badge.shield.half.filled")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundStyle(.blue.gradient) .foregroundStyle(Color.appPrimary.gradient)
.padding(.bottom, 8) .padding(.bottom, 8)
Text("Verify Your Email") Text("Verify Your Email")
.font(.title) .font(.title)
.fontWeight(.bold) .fontWeight(.bold)
.foregroundColor(Color.appTextPrimary)
Text("You must verify your email address to continue") Text("You must verify your email address to continue")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding(.horizontal) .padding(.horizontal)
} }
@@ -38,12 +39,12 @@ struct VerifyEmailView: View {
GroupBox { GroupBox {
HStack(spacing: 12) { HStack(spacing: 12) {
Image(systemName: "exclamationmark.shield.fill") Image(systemName: "exclamationmark.shield.fill")
.foregroundColor(.orange) .foregroundColor(Color.appAccent)
.font(.title2) .font(.title2)
Text("Email verification is required. Check your inbox for a 6-digit code.") Text("Email verification is required. Check your inbox for a 6-digit code.")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.primary) .foregroundColor(Color.appTextPrimary)
.fontWeight(.semibold) .fontWeight(.semibold)
} }
.padding(.vertical, 4) .padding(.vertical, 4)
@@ -54,6 +55,7 @@ struct VerifyEmailView: View {
VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 12) {
Text("Verification Code") Text("Verification Code")
.font(.headline) .font(.headline)
.foregroundColor(Color.appTextPrimary)
.padding(.horizontal) .padding(.horizontal)
TextField("000000", text: $viewModel.code) TextField("000000", text: $viewModel.code)
@@ -75,7 +77,7 @@ struct VerifyEmailView: View {
Text("Code must be 6 digits") Text("Code must be 6 digits")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.padding(.horizontal) .padding(.horizontal)
} }
@@ -103,10 +105,10 @@ struct VerifyEmailView: View {
.frame(height: 50) .frame(height: 50)
.background( .background(
viewModel.code.count == 6 && !viewModel.isLoading viewModel.code.count == 6 && !viewModel.isLoading
? Color.blue ? Color.appPrimary
: Color.gray.opacity(0.3) : Color.gray.opacity(0.3)
) )
.foregroundColor(.white) .foregroundColor(Color.appTextOnPrimary)
.cornerRadius(12) .cornerRadius(12)
} }
.disabled(viewModel.code.count != 6 || viewModel.isLoading) .disabled(viewModel.code.count != 6 || viewModel.isLoading)
@@ -117,12 +119,15 @@ struct VerifyEmailView: View {
// Help Text // Help Text
Text("Didn't receive the code? Check your spam folder or contact support.") Text("Didn't receive the code? Check your spam folder or contact support.")
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(Color.appTextSecondary)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding(.horizontal, 32) .padding(.horizontal, 32)
} }
} }
} }
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(Color.appBackgroundPrimary)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true) .navigationBarBackButtonHidden(true)
.interactiveDismissDisabled(true) .interactiveDismissDisabled(true)