diff --git a/mobile/mobile/ColorTheme.swift b/mobile/mobile/ColorTheme.swift index 599a356..6d08704 100644 --- a/mobile/mobile/ColorTheme.swift +++ b/mobile/mobile/ColorTheme.swift @@ -8,6 +8,7 @@ struct ColorTheme { static let darkDarkGrey = Color(white: 0.15) static let superDarkGrey = Color(white: 0.1) - static let primary: Color = Color(red: 0.25, green: 0.6, blue: 1.0) - static let secondary: Color = Color(red: 0.27, green: 0.25, blue: 1.0) + static let primary: Color = Color(red: 0.28, green: 0.5, blue: 1.0) // #477eff + static let primaryLight: Color = Color(red: 0.55, green: 0.68, blue: 1.0) // #8caeff + static let indigo: Color = Color(red: 0.42, green: 0.28, blue: 1.0) // #6c47ff } diff --git a/mobile/mobile/ContentView.swift b/mobile/mobile/ContentView.swift index 83f6b24..2cb6072 100644 --- a/mobile/mobile/ContentView.swift +++ b/mobile/mobile/ContentView.swift @@ -23,19 +23,6 @@ struct ContentView: View { } } -struct IsLoadingView: View { - var body: some View { - ColorTheme.white - .edgesIgnoringSafeArea(.all) - - ProgressView("Loading...") - .progressViewStyle(CircularProgressViewStyle(tint: ColorTheme.superDarkGrey)) - .padding(20) - .background(ColorTheme.white) - .cornerRadius(10) - } -} - struct ContentView_Previews: PreviewProvider { @StateObject private var appState = AppState() diff --git a/mobile/mobile/DashboardNavbar.swift b/mobile/mobile/DashboardNavbar.swift index d9e0221..99061f8 100644 --- a/mobile/mobile/DashboardNavbar.swift +++ b/mobile/mobile/DashboardNavbar.swift @@ -1,34 +1,32 @@ import SwiftUI struct DashboardNavbar: View { - @State private var isDropdownOpen: Bool = false var onLogout: () -> Void var body: some View { - VStack(spacing: 0) { - HStack { - Text("Track") - .font(.title) - .fontWeight(.semibold) - .foregroundColor(ColorTheme.superDarkGrey) - + Text("Flow") - .font(.title) - .fontWeight(.semibold) - .foregroundColor(ColorTheme.primary) + HStack { + Text("Track") + .font(.title) + .fontWeight(.semibold) + .foregroundColor(ColorTheme.white) + + Text("Flow") + .font(.title) + .fontWeight(.semibold) + .foregroundColor(ColorTheme.primary) - Spacer() + Spacer() - Menu { - Button("Logout", action: onLogout) - } label: { - Image(systemName: "person.circle") - .resizable() - .frame(width: 30, height: 30) - .foregroundColor(ColorTheme.superDarkGrey) - } + Menu { + Button("Logout", action: onLogout) + } label: { + Image(systemName: "person.circle") + .resizable() + .frame(width: 30, height: 30) + .foregroundColor(ColorTheme.white) } - .padding() } - .background(ColorTheme.lightLightGrey) + .padding() + .background(ColorTheme.darkDarkGrey) + .cornerRadius(12) } } diff --git a/mobile/mobile/DashboardView.swift b/mobile/mobile/DashboardView.swift index 87c4b51..3008bfa 100644 --- a/mobile/mobile/DashboardView.swift +++ b/mobile/mobile/DashboardView.swift @@ -1,45 +1,33 @@ -import Foundation import SwiftUI struct DashboardView: View { @EnvironmentObject var appState: AppState @State private var trainingWeekData: TrainingWeekData? - @State private var profileData: ProfileData? - @State private var isLoadingProfile: Bool = true @State private var isLoadingTrainingWeek: Bool = true var body: some View { NavigationView { - ZStack(alignment: .top) { - ColorTheme.white.edgesIgnoringSafeArea(.all) - - VStack(spacing: 0) { + ScrollView { + VStack(spacing: 24) { DashboardNavbar(onLogout: handleLogout) - - ScrollView { - VStack(spacing: 20) { - if isLoadingProfile || isLoadingTrainingWeek { - LoadingView() - } - - if let profile = profileData { - ProfileView(data: profile) - } else if !isLoadingProfile { - Text("Error loading profile data") - } - - if let data = trainingWeekData { - TrainingWeekView(data: data) - } else if !isLoadingTrainingWeek { - Text("No training data available") - .font(.headline) - .foregroundColor(ColorTheme.darkGrey) - } - } - .padding() + + Text("Your Training Week") + .font(.system(size: 28, weight: .bold)) + .foregroundColor(ColorTheme.white) + + if isLoadingTrainingWeek { + LoadingView() + } else if let data = trainingWeekData { + TrainingWeekView(data: data) + } else { + Text("No training data available") + .font(.headline) + .foregroundColor(ColorTheme.lightGrey) } } + .padding() } + .background(ColorTheme.superDarkGrey.edgesIgnoringSafeArea(.all)) .navigationBarHidden(true) } .onAppear(perform: fetchData) @@ -53,25 +41,10 @@ struct DashboardView: View { private func fetchData() { guard let token = appState.jwtToken else { - isLoadingProfile = false isLoadingTrainingWeek = false return } - // Fetch profile data - APIManager.shared.fetchProfileData(token: token) { result in - DispatchQueue.main.async { - self.isLoadingProfile = false - switch result { - case .success(let profile): - self.profileData = profile - case .failure(let error): - print("Error fetching profile data: \(error)") - } - } - } - - // Fetch training week data APIManager.shared.fetchTrainingWeekData(token: token) { result in DispatchQueue.main.async { self.isLoadingTrainingWeek = false diff --git a/mobile/mobile/LandingPageView.swift b/mobile/mobile/LandingPageView.swift index f1e051d..60a93cb 100644 --- a/mobile/mobile/LandingPageView.swift +++ b/mobile/mobile/LandingPageView.swift @@ -11,7 +11,6 @@ struct Feature: Identifiable { struct LandingPageView: View { @ObservedObject var authManager: StravaAuthManager - // List of features let features: [Feature] = [ Feature( icon: "figure.run", title: "Personalized Plans", @@ -36,7 +35,7 @@ struct LandingPageView: View { HStack(spacing: 0) { Text("Track") .font(.system(size: 50, weight: .black)) - .foregroundColor(ColorTheme.white) + .foregroundColor(ColorTheme.primaryLight) Text("Flow") .font(.system(size: 50, weight: .black)) .foregroundColor(ColorTheme.primary) @@ -44,7 +43,7 @@ struct LandingPageView: View { Text("Step into the Next Generation of Training") .font(.title2) - .foregroundColor(.secondary) + .foregroundColor(ColorTheme.lightGrey) .multilineTextAlignment(.center) .padding(.horizontal) @@ -83,10 +82,10 @@ struct LandingPageView: View { .frame(maxWidth: .infinity) .background( LinearGradient( - gradient: Gradient(colors: [ColorTheme.secondary, ColorTheme.primary]), + gradient: Gradient(colors: [ColorTheme.primary, ColorTheme.primaryLight]), startPoint: .leading, endPoint: .trailing) ) - .foregroundColor(.white) + .foregroundColor(ColorTheme.white) .cornerRadius(12) .shadow(radius: 5) } diff --git a/mobile/mobile/LoadingView.swift b/mobile/mobile/LoadingView.swift index c9d5486..4381f4e 100644 --- a/mobile/mobile/LoadingView.swift +++ b/mobile/mobile/LoadingView.swift @@ -8,24 +8,28 @@ struct LoadingView: View { var body: some View { ZStack { - ColorTheme.white + ColorTheme.superDarkGrey .edgesIgnoringSafeArea(.all) - VStack(spacing: 20) { - ProgressView() - .scaleEffect(2.0) - .progressViewStyle(CircularProgressViewStyle(tint: ColorTheme.superDarkGrey)) + VStack(spacing: 40) { + brandingView + + VStack(spacing: 30) { + ProgressView() + .scaleEffect(1.5) + .progressViewStyle(CircularProgressViewStyle(tint: ColorTheme.primary)) - Text(loadingText) - .font(.caption) - .foregroundColor(ColorTheme.darkGrey) + Text(loadingText) + .font(.system(size: 16, weight: .light, design: .monospaced)) + .foregroundColor(ColorTheme.primaryLight) - if showError { - Text(errorMessage) - .font(.caption) - .foregroundColor(ColorTheme.darkGrey) - .multilineTextAlignment(.center) - .padding() + if showError { + Text(errorMessage) + .font(.system(size: 14, weight: .regular, design: .monospaced)) + .foregroundColor(ColorTheme.indigo) + .multilineTextAlignment(.center) + .padding() + } } } .padding() @@ -36,4 +40,25 @@ struct LoadingView: View { } } } + + private var brandingView: some View { + VStack(spacing: 16) { + Text("🏃‍♂️🎯") + .font(.system(size: 20)) + + HStack(spacing: 0) { + Text("Track") + .font(.system(size: 40, weight: .black)) + .foregroundColor(ColorTheme.primaryLight) + Text("Flow") + .font(.system(size: 40, weight: .black)) + .foregroundColor(ColorTheme.primary) + } + + Text("Step into the Next Generation of Training") + .font(.system(size: 16, weight: .light)) + .foregroundColor(ColorTheme.lightGrey) + .multilineTextAlignment(.center) + } + } } diff --git a/mobile/mobile/ProfileView.swift b/mobile/mobile/ProfileView.swift index 103ee6d..e8b8849 100644 --- a/mobile/mobile/ProfileView.swift +++ b/mobile/mobile/ProfileView.swift @@ -16,24 +16,26 @@ struct ProfileView: View { VStack(alignment: .leading, spacing: 6) { Text("\(data.firstname) \(data.lastname)") .font(.system(size: 18, weight: .semibold)) - .foregroundColor(ColorTheme.superDarkGrey) + .foregroundColor(ColorTheme.white) Text(data.email) .font(.system(size: 14)) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) HStack(spacing: 6) { Circle() - .fill(data.isActive ? Color.green : Color.red) + .fill(data.isActive ? Color.cyan : Color.red) .frame(width: 8, height: 8) Text(data.isActive ? "Active" : "Inactive") .font(.system(size: 12)) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) } } } .padding(.vertical, 16) + .padding(.horizontal) + .background(ColorTheme.darkDarkGrey) .cornerRadius(12) } } diff --git a/mobile/mobile/TrainingWeek.swift b/mobile/mobile/TrainingWeek.swift index 6d344f7..1ce15bb 100644 --- a/mobile/mobile/TrainingWeek.swift +++ b/mobile/mobile/TrainingWeek.swift @@ -4,8 +4,7 @@ struct TrainingWeekView: View { let data: TrainingWeekData var body: some View { - VStack(alignment: .leading) { - + VStack(alignment: .leading, spacing: 16) { WeeklyProgressView(sessions: data.sessions) ForEach(data.sessions) { session in @@ -13,7 +12,8 @@ struct TrainingWeekView: View { } } .padding() - .background(ColorTheme.lightLightGrey) + .background(ColorTheme.darkDarkGrey) + .cornerRadius(12) } } @@ -36,12 +36,12 @@ struct WeeklyProgressView: View { VStack(alignment: .leading, spacing: 10) { Text("Weekly Progress") .font(.headline) - .foregroundColor(ColorTheme.superDarkGrey) + .foregroundColor(ColorTheme.white) HStack { Text("\(progressPercentage)%") .font(.system(size: 36, weight: .bold)) - .foregroundColor(ColorTheme.superDarkGrey) + .foregroundColor(ColorTheme.primary) Spacer() @@ -49,21 +49,21 @@ struct WeeklyProgressView: View { "\(String(format: "%.1f", completedMileage)) of \(String(format: "%.1f", totalMileage)) miles completed" ) .font(.caption) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) } GeometryReader { geometry in ZStack(alignment: .leading) { Rectangle() - .fill(ColorTheme.lightLightGrey) + .fill(ColorTheme.darkGrey) .frame(height: 8) .cornerRadius(4) Rectangle() .fill( LinearGradient( - gradient: Gradient(colors: [.green, .green.opacity(0.5)]), startPoint: .leading, - endPoint: .trailing) + gradient: Gradient(colors: [ColorTheme.primaryLight, ColorTheme.primary]), + startPoint: .leading, endPoint: .trailing) ) .frame(width: geometry.size.width * CGFloat(progressPercentage) / 100, height: 8) .cornerRadius(4) @@ -72,11 +72,11 @@ struct WeeklyProgressView: View { .frame(height: 8) } .padding() - .background(ColorTheme.white) + .background(ColorTheme.darkDarkGrey) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) - .stroke(ColorTheme.superDarkGrey, lineWidth: 0.5) + .stroke(ColorTheme.darkGrey, lineWidth: 0.5) ) } } @@ -88,7 +88,7 @@ struct SessionView: View { HStack(alignment: .top) { Text(session.day.prefix(3).uppercased()) .font(.headline) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) .frame(width: 40, alignment: .leading) VStack(alignment: .leading, spacing: 4) { @@ -96,29 +96,29 @@ struct SessionView: View { Text(String(format: "%.1f mi", session.distance)) .font(.title2) .fontWeight(.bold) - .foregroundColor(ColorTheme.superDarkGrey) + .foregroundColor(ColorTheme.white) Spacer() Circle() - .fill(session.completed ? .green : ColorTheme.white) + .fill(session.completed ? ColorTheme.indigo : ColorTheme.darkGrey) .frame(width: 12, height: 12) } Text(session.sessionType) .font(.subheadline) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) if !session.notes.isEmpty { Text(session.notes) .font(.caption) - .foregroundColor(ColorTheme.darkGrey) + .foregroundColor(ColorTheme.lightGrey) .padding(.top, 4) } } } .padding() - .background(ColorTheme.lightGrey) + .background(ColorTheme.darkDarkGrey) .cornerRadius(10) } }