     1→import SwiftUI
     2→import MapKit
     3→
     4→struct GymDetailView: View {
     5→    let gym: Gym
     6→
     7→    @EnvironmentObject var locationService: LocationService
     8→    @StateObject private var favoritesService = FavoritesService()
     9→    @StateObject private var directionsService = DirectionsService()
    10→    @Environment(\.dismiss) private var dismiss
    11→
    12→    @State private var routeInfo: RouteInfo?
    13→    @State private var selectedTransport: MKDirectionsTransportType = .automobile
    14→    @State private var showingDirectionsSheet = false
    15→
    16→    var body: some View {
    17→        NavigationStack {
    18→            ScrollView {
    19→                VStack(spacing: 0) {
    20→                    // Map header
    21→                    mapHeader
    22→
    23→                    VStack(alignment: .leading, spacing: 20) {
    24→                        // Header
    25→                        headerSection
    26→
    27→                        // Route info (if available)
    28→                        if let routeInfo = routeInfo {
    29→                            routeInfoSection(routeInfo)
    30→                        }
    31→
    32→                        Divider()
    33→
    34→                        // Quick Actions
    35→                        quickActionsSection
    36→
    37→                        Divider()
    38→
    39→                        // Contact Info
    40→                        if gym.phone != nil || gym.website != nil {
    41→                            contactSection
    42→                            Divider()
    43→                        }
    44→
    45→                        // Amenities
    46→                        if !gym.amenities.isEmpty {
    47→                            amenitiesSection
    48→                            Divider()
    49→                        }
    50→
    51→                        // Directions
    52→                        directionsSection
    53→                    }
    54→                    .padding()
    55→                }
    56→            }
    57→            .navigationTitle(gym.name)
    58→            .navigationBarTitleDisplayMode(.inline)
    59→            .toolbar {
    60→                ToolbarItem(placement: .topBarTrailing) {
    61→                    Button {
    62→                        favoritesService.toggleFavorite(gym.id)
    63→                    } label: {
    64→                        Image(systemName: favoritesService.isFavorite(gym.id) ? "heart.fill" : "heart")
    65→                            .foregroundStyle(favoritesService.isFavorite(gym.id) ? .red : .primary)
    66→                    }
    67→                }
    68→            }
    69→            .task {
    70→                await loadRouteInfo()
    71→            }
    72→        }
    73→    }
    74→
    75→    // MARK: - Map Header
    76→    private var mapHeader: some View {
    77→        Map {
    78→            Marker(gym.name, coordinate: gym.coordinate)
    79→                .tint(.orange)
    80→
    81→            // Show route if available
    82→            if let route = directionsService.route {
    83→                MapPolyline(route.polyline)
    84→                    .stroke(.blue, lineWidth: 4)
    85→            }
    86→        }
    87→        .frame(height: 200)
    88→        .allowsHitTesting(false)
    89→    }
    90→
    91→    // MARK: - Header Section
    92→    private var headerSection: some View {
    93→        VStack(alignment: .leading, spacing: 8) {
    94→            // Distance badge
    95→            HStack {
    96→                Label(gym.formattedDistance, systemImage: "location.fill")
    97→                    .font(.subheadline)
    98→                    .padding(.horizontal, 10)
    99→                    .padding(.vertical, 4)
   100→                    .background(Color.blue.opacity(0.1), in: Capsule())
   101→                    .foregroundStyle(.blue)
   102→
   103→                Spacer()
   104→            }
   105→
   106→            Text(gym.address)
   107→                .font(.subheadline)
   108→                .foregroundStyle(.secondary)
   109→
   110→            if let hours = gym.openingHours {
   111→                Label(hours, systemImage: "clock")
   112→                    .font(.subheadline)
   113→                    .foregroundStyle(.secondary)
   114→            }
   115→        }
   116→    }
   117→
   118→    // MARK: - Route Info Section
   119→    private func routeInfoSection(_ info: RouteInfo) -> some View {
   120→        HStack(spacing: 20) {
   121→            // Travel time
   122→            VStack {
   123→                Image(systemName: info.transportIcon)
   124→                    .font(.title2)
   125→                    .foregroundStyle(.blue)
   126→                Text(info.formattedTravelTime)
   127→                    .font(.headline)
   128→                Text(info.formattedDistance)
   129→                    .font(.caption)
   130→                    .foregroundStyle(.secondary)
   131→            }
   132→            .frame(maxWidth: .infinity)
   133→            .padding()
   134→            .background(Color.blue.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
   135→
   136→            // Transport selector
   137→            VStack(alignment: .leading, spacing: 8) {
   138→                Text("Transporte")
   139→                    .font(.caption)
   140→                    .foregroundStyle(.secondary)
   141→
   142→                HStack(spacing: 8) {
   143→                    transportButton(.automobile, icon: "car.fill")
   144→                    transportButton(.walking, icon: "figure.walk")
   145→                    transportButton(.transit, icon: "bus.fill")
   146→                }
   147→            }
   148→        }
   149→    }
   150→
   151→    private func transportButton(_ type: MKDirectionsTransportType, icon: String) -> some View {
   152→        Button {
   153→            selectedTransport = type
   154→            Task { await loadRouteInfo() }
   155→        } label: {
   156→            Image(systemName: icon)
   157→                .font(.title3)
   158→                .frame(width: 44, height: 44)
   159→                .background(selectedTransport == type ? Color.orange : Color.gray.opacity(0.2), in: Circle())
   160→                .foregroundStyle(selectedTransport == type ? .white : .primary)
   161→        }
   162→    }
   163→
   164→    // MARK: - Quick Actions
   165→    private var quickActionsSection: some View {
   166→        HStack(spacing: 12) {
   167→            // Open in Maps
   168→            Button {
   169→                gym.openInMaps(mode: transportMode)
   170→            } label: {
   171→                Label("Ir", systemImage: "arrow.triangle.turn.up.right.diamond.fill")
   172→                    .frame(maxWidth: .infinity)
   173→            }
   174→            .buttonStyle(.borderedProminent)
   175→            .tint(.blue)
   176→
   177→            // Call
   178→            if gym.phone != nil {
   179→                Button {
   180→                    gym.call()
   181→                } label: {
   182→                    Label("Ligar", systemImage: "phone.fill")
   183→                        .frame(maxWidth: .infinity)
   184→                }
   185→                .buttonStyle(.bordered)
   186→                .tint(.green)
   187→            }
   188→
   189→            // Share
   190→            Button {
   191→                gym.share()
   192→            } label: {
   193→                Image(systemName: "square.and.arrow.up")
   194→                    .frame(width: 44, height: 44)
   195→            }
   196→            .buttonStyle(.bordered)
   197→        }
   198→    }
   199→
   200→    private var transportMode: String {
   201→        switch selectedTransport {
   202→        case .walking: return MKLaunchOptionsDirectionsModeWalking
   203→        case .transit: return MKLaunchOptionsDirectionsModeTransit
   204→        default: return MKLaunchOptionsDirectionsModeDriving
   205→        }
   206→    }
   207→
   208→    // MARK: - Contact Section
   209→    private var contactSection: some View {
   210→        VStack(alignment: .leading, spacing: 12) {
   211→            Text("Contato")
   212→                .font(.headline)
   213→
   214→            if let phone = gym.phone {
   215→                Button {
   216→                    gym.call()
   217→                } label: {
   218→                    Label(phone, systemImage: "phone.fill")
   219→                        .foregroundStyle(.primary)
   220→                }
   221→            }
   222→
   223→            if let website = gym.website {
   224→                Button {
   225→                    gym.openWebsite()
   226→                } label: {
   227→                    Label("Visitar site", systemImage: "globe")
   228→                }
   229→            }
   230→        }
   231→    }
   232→
   233→    // MARK: - Amenities Section
   234→    private var amenitiesSection: some View {
   235→        VStack(alignment: .leading, spacing: 12) {
   236→            Text("Comodidades")
   237→                .font(.headline)
   238→
   239→            LazyVGrid(columns: [
   240→                GridItem(.flexible()),
   241→                GridItem(.flexible()),
   242→                GridItem(.flexible())
   243→            ], spacing: 12) {
   244→                ForEach(gym.amenities, id: \.self) { amenity in
   245→                    VStack(spacing: 6) {
   246→                        Image(systemName: amenity.icon)
   247→                            .font(.title2)
   248→                            .foregroundStyle(.orange)
   249→
   250→                        Text(amenity.displayName)
   251→                            .font(.caption)
   252→                            .multilineTextAlignment(.center)
   253→                    }
   254→                    .frame(maxWidth: .infinity)
   255→                    .padding(.vertical, 12)
   256→                    .background(Color.orange.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
   257→                }
   258→            }
   259→        }
   260→    }
   261→
   262→    // MARK: - Directions Section
   263→    private var directionsSection: some View {
   264→        VStack(alignment: .leading, spacing: 12) {
   265→            Text("Como chegar")
   266→                .font(.headline)
   267→
   268→            VStack(spacing: 8) {
   269→                directionButton(
   270→                    title: "Dirigindo",
   271→                    icon: "car.fill",
   272→                    action: { gym.openDrivingDirections() }
   273→                )
   274→
   275→                directionButton(
   276→                    title: "Caminhando",
   277→                    icon: "figure.walk",
   278→                    action: { gym.openWalkingDirections() }
   279→                )
   280→
   281→                directionButton(
   282→                    title: "Transporte público",
   283→                    icon: "bus.fill",
   284→                    action: { gym.openTransitDirections() }
   285→                )
   286→            }
   287→        }
   288→    }
   289→
   290→    private func directionButton(title: String, icon: String, action: @escaping () -> Void) -> some View {
   291→        Button(action: action) {
   292→            HStack {
   293→                Image(systemName: icon)
   294→                    .frame(width: 30)
   295→                Text(title)
   296→                Spacer()
   297→                Image(systemName: "arrow.up.right")
   298→                    .font(.caption)
   299→                    .foregroundStyle(.secondary)
   300→            }
   301→            .padding()
   302→            .background(Color.gray.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
   303→        }
   304→        .foregroundStyle(.primary)
   305→    }
   306→
   307→    // MARK: - Load Route Info
   308→    private func loadRouteInfo() async {
   309→        guard let userLocation = locationService.currentLocation else { return }
   310→
   311→        routeInfo = await directionsService.getRouteInfo(
   312→            from: userLocation.coordinate,
   313→            to: gym,
   314→            transportType: selectedTransport
   315→        )
   316→    }
   317→}
   318→
   319→#Preview {
   320→    GymDetailView(gym: Gym(
   321→        id: "1",
   322→        name: "SmartFit Paulista",
   323→        address: "Av. Paulista, 1000",
   324→        latitude: -23.5629,
   325→        longitude: -46.6544,
   326→        rating: nil,
   327→        priceRange: nil,
   328→        amenities: [.weights, .cardio, .lockers],
   329→        openingHours: "6h - 23h",
   330→        phone: "(11) 3000-0000",
   331→        website: "https://smartfit.com.br",
   332→        imageURL: nil,
   333→        distance: 850,
   334→        mapItem: nil
   335→    ))
   336→    .environmentObject(LocationService())
   337→}
   338→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI
import MapKit

struct GymDetailView: View {
    let gym: Gym

    @EnvironmentObject var locationService: LocationService
    @StateObject private var favoritesService = FavoritesService()
    @StateObject private var directionsService = DirectionsService()
    @Environment(\.dismiss) private var dismiss

    @State private var routeInfo: RouteInfo?
    @State private var selectedTransport: MKDirectionsTransportType = .automobile
    @State private var showingDirectionsSheet = false

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 0) {
                    // Map header
                    mapHeader

                    VStack(alignment: .leading, spacing: 20) {
                        // Header
                        headerSection

                        // Route info (if available)
                        if let routeInfo = routeInfo {
                            routeInfoSection(routeInfo)
                        }

                        Divider()

                        // Quick Actions
                        quickActionsSection

                        Divider()

                        // Contact Info
                        if gym.phone != nil || gym.website != nil {
                            contactSection
                            Divider()
                        }

                        // Amenities
                        if !gym.amenities.isEmpty {
                            amenitiesSection
                            Divider()
                        }

                        // Directions
                        directionsSection
                    }
                    .padding()
                }
            }
            .navigationTitle(gym.name)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        favoritesService.toggleFavorite(gym.id)
                    } label: {
                        Image(systemName: favoritesService.isFavorite(gym.id) ? "heart.fill" : "heart")
                            .foregroundStyle(favoritesService.isFavorite(gym.id) ? .red : .primary)
                    }
                }
            }
            .task {
                await loadRouteInfo()
            }
        }
    }

    // MARK: - Map Header
    private var mapHeader: some View {
        Map {
            Marker(gym.name, coordinate: gym.coordinate)
                .tint(.orange)

            // Show route if available
            if let route = directionsService.route {
                MapPolyline(route.polyline)
                    .stroke(.blue, lineWidth: 4)
            }
        }
        .frame(height: 200)
        .allowsHitTesting(false)
    }

    // MARK: - Header Section
    private var headerSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            // Distance badge
            HStack {
                Label(gym.formattedDistance, systemImage: "location.fill")
                    .font(.subheadline)
                    .padding(.horizontal, 10)
                    .padding(.vertical, 4)
                    .background(Color.blue.opacity(0.1), in: Capsule())
                    .foregroundStyle(.blue)

                Spacer()
            }

            Text(gym.address)
                .font(.subheadline)
                .foregroundStyle(.secondary)

            if let hours = gym.openingHours {
                Label(hours, systemImage: "clock")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
    }

    // MARK: - Route Info Section
    private func routeInfoSection(_ info: RouteInfo) -> some View {
        HStack(spacing: 20) {
            // Travel time
            VStack {
                Image(systemName: info.transportIcon)
                    .font(.title2)
                    .foregroundStyle(.blue)
                Text(info.formattedTravelTime)
                    .font(.headline)
                Text(info.formattedDistance)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            .frame(maxWidth: .infinity)
            .padding()
            .background(Color.blue.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))

            // Transport selector
            VStack(alignment: .leading, spacing: 8) {
                Text("Transporte")
                    .font(.caption)
                    .foregroundStyle(.secondary)

                HStack(spacing: 8) {
                    transportButton(.automobile, icon: "car.fill")
                    transportButton(.walking, icon: "figure.walk")
                    transportButton(.transit, icon: "bus.fill")
                }
            }
        }
    }

    private func transportButton(_ type: MKDirectionsTransportType, icon: String) -> some View {
        Button {
            selectedTransport = type
            Task { await loadRouteInfo() }
        } label: {
            Image(systemName: icon)
                .font(.title3)
                .frame(width: 44, height: 44)
                .background(selectedTransport == type ? Color.orange : Color.gray.opacity(0.2), in: Circle())
                .foregroundStyle(selectedTransport == type ? .white : .primary)
        }
    }

    // MARK: - Quick Actions
    private var quickActionsSection: some View {
        HStack(spacing: 12) {
            // Open in Maps
            Button {
                gym.openInMaps(mode: transportMode)
            } label: {
                Label("Ir", systemImage: "arrow.triangle.turn.up.right.diamond.fill")
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .tint(.blue)

            // Call
            if gym.phone != nil {
                Button {
                    gym.call()
                } label: {
                    Label("Ligar", systemImage: "phone.fill")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.bordered)
                .tint(.green)
            }

            // Share
            Button {
                gym.share()
            } label: {
                Image(systemName: "square.and.arrow.up")
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.bordered)
        }
    }

    private var transportMode: String {
        switch selectedTransport {
        case .walking: return MKLaunchOptionsDirectionsModeWalking
        case .transit: return MKLaunchOptionsDirectionsModeTransit
        default: return MKLaunchOptionsDirectionsModeDriving
        }
    }

    // MARK: - Contact Section
    private var contactSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Contato")
                .font(.headline)

            if let phone = gym.phone {
                Button {
                    gym.call()
                } label: {
                    Label(phone, systemImage: "phone.fill")
                        .foregroundStyle(.primary)
                }
            }

            if let website = gym.website {
                Button {
                    gym.openWebsite()
                } label: {
                    Label("Visitar site", systemImage: "globe")
                }
            }
        }
    }

    // MARK: - Amenities Section
    private var amenitiesSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Comodidades")
                .font(.headline)

            LazyVGrid(columns: [
                GridItem(.flexible()),
                GridItem(.flexible()),
                GridItem(.flexible())
            ], spacing: 12) {
                ForEach(gym.amenities, id: \.self) { amenity in
                    VStack(spacing: 6) {
                        Image(systemName: amenity.icon)
                            .font(.title2)
                            .foregroundStyle(.orange)

                        Text(amenity.displayName)
                            .font(.caption)
                            .multilineTextAlignment(.center)
                    }
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 12)
                    .background(Color.orange.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
                }
            }
        }
    }

    // MARK: - Directions Section
    private var directionsSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Como chegar")
                .font(.headline)

            VStack(spacing: 8) {
                directionButton(
                    title: "Dirigindo",
                    icon: "car.fill",
                    action: { gym.openDrivingDirections() }
                )

                directionButton(
                    title: "Caminhando",
                    icon: "figure.walk",
                    action: { gym.openWalkingDirections() }
                )

                directionButton(
                    title: "Transporte público",
                    icon: "bus.fill",
                    action: { gym.openTransitDirections() }
                )
            }
        }
    }

    private func directionButton(title: String, icon: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            HStack {
                Image(systemName: icon)
                    .frame(width: 30)
                Text(title)
                Spacer()
                Image(systemName: "arrow.up.right")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            .padding()
            .background(Color.gray.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
        }
        .foregroundStyle(.primary)
    }

    // MARK: - Load Route Info
    private func loadRouteInfo() async {
        guard let userLocation = locationService.currentLocation else { return }

        routeInfo = await directionsService.getRouteInfo(
            from: userLocation.coordinate,
            to: gym,
            transportType: selectedTransport
        )
    }
}

#Preview {
    GymDetailView(gym: Gym(
        id: "1",
        name: "SmartFit Paulista",
        address: "Av. Paulista, 1000",
        latitude: -23.5629,
        longitude: -46.6544,
        rating: nil,
        priceRange: nil,
        amenities: [.weights, .cardio, .lockers],
        openingHours: "6h - 23h",
        phone: "(11) 3000-0000",
        website: "https://smartfit.com.br",
        imageURL: nil,
        distance: 850,
        mapItem: nil
    ))
    .environmentObject(LocationService())
}


     1→import SwiftUI
     2→
     3→struct FilterView: View {
     4→    @Binding var filter: GymFilter
     5→    @Environment(\.dismiss) private var dismiss
     6→
     7→    var body: some View {
     8→        NavigationStack {
     9→            Form {
    10→                // Distance
    11→                Section("Distância Máxima") {
    12→                    VStack(alignment: .leading) {
    13→                        HStack {
    14→                            Text("Raio de busca")
    15→                            Spacer()
    16→                            Text(filter.formattedMaxDistance)
    17→                                .foregroundStyle(.secondary)
    18→                        }
    19→                        Slider(value: $filter.maxDistance, in: 1000...10000, step: 500)
    20→                    }
    21→                }
    22→
    23→                // Amenities
    24→                Section("Comodidades") {
    25→                    LazyVGrid(columns: [
    26→                        GridItem(.flexible()),
    27→                        GridItem(.flexible())
    28→                    ], spacing: 8) {
    29→                        ForEach(Gym.Amenity.allCases, id: \.self) { amenity in
    30→                            AmenityChip(
    31→                                amenity: amenity,
    32→                                isSelected: filter.amenities.contains(amenity)
    33→                            ) {
    34→                                if filter.amenities.contains(amenity) {
    35→                                    filter.amenities.remove(amenity)
    36→                                } else {
    37→                                    filter.amenities.insert(amenity)
    38→                                }
    39→                            }
    40→                        }
    41→                    }
    42→                    .padding(.vertical, 8)
    43→                }
    44→
    45→                // Reset
    46→                Section {
    47→                    Button("Limpar Filtros", role: .destructive) {
    48→                        filter.reset()
    49→                    }
    50→                    .frame(maxWidth: .infinity)
    51→                }
    52→            }
    53→            .navigationTitle("Filtros")
    54→            .navigationBarTitleDisplayMode(.inline)
    55→            .toolbar {
    56→                ToolbarItem(placement: .topBarTrailing) {
    57→                    Button("Aplicar") {
    58→                        dismiss()
    59→                    }
    60→                    .fontWeight(.semibold)
    61→                }
    62→
    63→                ToolbarItem(placement: .topBarLeading) {
    64→                    Button("Cancelar") {
    65→                        dismiss()
    66→                    }
    67→                }
    68→            }
    69→        }
    70→    }
    71→}
    72→
    73→// MARK: - Amenity Chip
    74→struct AmenityChip: View {
    75→    let amenity: Gym.Amenity
    76→    let isSelected: Bool
    77→    let action: () -> Void
    78→
    79→    var body: some View {
    80→        Button(action: action) {
    81→            HStack(spacing: 4) {
    82→                Image(systemName: amenity.icon)
    83→                    .font(.caption)
    84→                Text(amenity.displayName)
    85→                    .font(.caption)
    86→            }
    87→            .padding(.horizontal, 10)
    88→            .padding(.vertical, 8)
    89→            .frame(maxWidth: .infinity)
    90→            .background(isSelected ? Color.orange : Color.gray.opacity(0.2), in: Capsule())
    91→            .foregroundStyle(isSelected ? .white : .primary)
    92→        }
    93→        .buttonStyle(.plain)
    94→    }
    95→}
    96→
    97→#Preview {
    98→    FilterView(filter: .constant(GymFilter()))
    99→}
   100→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

struct FilterView: View {
    @Binding var filter: GymFilter
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        NavigationStack {
            Form {
                // Distance
                Section("Distância Máxima") {
                    VStack(alignment: .leading) {
                        HStack {
                            Text("Raio de busca")
                            Spacer()
                            Text(filter.formattedMaxDistance)
                                .foregroundStyle(.secondary)
                        }
                        Slider(value: $filter.maxDistance, in: 1000...10000, step: 500)
                    }
                }

                // Amenities
                Section("Comodidades") {
                    LazyVGrid(columns: [
                        GridItem(.flexible()),
                        GridItem(.flexible())
                    ], spacing: 8) {
                        ForEach(Gym.Amenity.allCases, id: \.self) { amenity in
                            AmenityChip(
                                amenity: amenity,
                                isSelected: filter.amenities.contains(amenity)
                            ) {
                                if filter.amenities.contains(amenity) {
                                    filter.amenities.remove(amenity)
                                } else {
                                    filter.amenities.insert(amenity)
                                }
                            }
                        }
                    }
                    .padding(.vertical, 8)
                }

                // Reset
                Section {
                    Button("Limpar Filtros", role: .destructive) {
                        filter.reset()
                    }
                    .frame(maxWidth: .infinity)
                }
            }
            .navigationTitle("Filtros")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Aplicar") {
                        dismiss()
                    }
                    .fontWeight(.semibold)
                }

                ToolbarItem(placement: .topBarLeading) {
                    Button("Cancelar") {
                        dismiss()
                    }
                }
            }
        }
    }
}

// MARK: - Amenity Chip
struct AmenityChip: View {
    let amenity: Gym.Amenity
    let isSelected: Bool
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            HStack(spacing: 4) {
                Image(systemName: amenity.icon)
                    .font(.caption)
                Text(amenity.displayName)
                    .font(.caption)
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 8)
            .frame(maxWidth: .infinity)
            .background(isSelected ? Color.orange : Color.gray.opacity(0.2), in: Capsule())
            .foregroundStyle(isSelected ? .white : .primary)
        }
        .buttonStyle(.plain)
    }
}

#Preview {
    FilterView(filter: .constant(GymFilter()))
}


     1→import SwiftUI
     2→import MapKit
     3→
     4→struct MapView: View {
     5→    @EnvironmentObject var locationService: LocationService
     6→    @StateObject private var viewModel = GymsViewModel()
     7→    @StateObject private var favoritesService = FavoritesService()
     8→
     9→    @State private var cameraPosition: MapCameraPosition = .automatic
    10→    @State private var selectedGym: Gym?
    11→    @State private var showingDetail = false
    12→    @State private var hasCenteredOnUser = false
    13→
    14→    var body: some View {
    15→        NavigationStack {
    16→            ZStack {
    17→                mapContent
    18→
    19→                // Loading overlay
    20→                if viewModel.isLoading {
    21→                    VStack {
    22→                        HStack {
    23→                            Spacer()
    24→                            HStack(spacing: 8) {
    25→                                ProgressView()
    26→                                    .scaleEffect(0.8)
    27→                                Text("Buscando academias...")
    28→                                    .font(.caption)
    29→                            }
    30→                            .padding(.horizontal, 12)
    31→                            .padding(.vertical, 8)
    32→                            .background(.regularMaterial, in: Capsule())
    33→                            Spacer()
    34→                        }
    35→                        .padding(.top, 8)
    36→                        Spacer()
    37→                    }
    38→                }
    39→
    40→                // Gym count badge
    41→                if !viewModel.isLoading && viewModel.hasSearched {
    42→                    VStack {
    43→                        HStack {
    44→                            Spacer()
    45→                            Text("\(viewModel.gyms.count) academias")
    46→                                .font(.caption)
    47→                                .padding(.horizontal, 12)
    48→                                .padding(.vertical, 6)
    49→                                .background(.regularMaterial, in: Capsule())
    50→                            Spacer()
    51→                        }
    52→                        .padding(.top, 8)
    53→                        Spacer()
    54→                    }
    55→                }
    56→
    57→                if let gym = selectedGym {
    58→                    VStack {
    59→                        Spacer()
    60→                        GymQuickCard(
    61→                            gym: gym,
    62→                            distance: locationService.formattedDistance(to: gym.coordinate),
    63→                            isFavorite: favoritesService.isFavorite(gym.id),
    64→                            onFavorite: { favoritesService.toggleFavorite(gym.id) },
    65→                            onDetails: { showingDetail = true },
    66→                            onClose: { selectedGym = nil }
    67→                        )
    68→                        .padding()
    69→                    }
    70→                    .transition(.move(edge: .bottom))
    71→                }
    72→            }
    73→            .navigationTitle("Academias")
    74→            .navigationBarTitleDisplayMode(.inline)
    75→            .toolbar {
    76→                ToolbarItem(placement: .topBarTrailing) {
    77→                    Button {
    78→                        centerOnUser()
    79→                    } label: {
    80→                        Image(systemName: "location.fill")
    81→                    }
    82→                }
    83→
    84→                ToolbarItem(placement: .topBarTrailing) {
    85→                    Button {
    86→                        Task { await viewModel.refresh() }
    87→                    } label: {
    88→                        Image(systemName: "arrow.clockwise")
    89→                    }
    90→                    .disabled(viewModel.isLoading)
    91→                }
    92→            }
    93→            .sheet(isPresented: $showingDetail) {
    94→                if let gym = selectedGym {
    95→                    GymDetailView(gym: gym)
    96→                }
    97→            }
    98→            .onAppear {
    99→                viewModel.setLocationService(locationService)
   100→                locationService.requestPermission()
   101→            }
   102→            .onChange(of: locationService.currentLocation) { _, newLocation in
   103→                // Center on user first time location is available
   104→                if !hasCenteredOnUser, let location = newLocation {
   105→                    hasCenteredOnUser = true
   106→                    cameraPosition = .region(MKCoordinateRegion(
   107→                        center: location.coordinate,
   108→                        span: MKCoordinateSpan(latitudeDelta: 0.03, longitudeDelta: 0.03)
   109→                    ))
   110→                }
   111→            }
   112→        }
   113→    }
   114→
   115→    @ViewBuilder
   116→    private var mapContent: some View {
   117→        Map(position: $cameraPosition) {
   118→            UserAnnotation()
   119→
   120→            ForEach(viewModel.gyms) { gym in
   121→                Marker(gym.name, coordinate: gym.coordinate)
   122→                    .tint(.orange)
   123→            }
   124→        }
   125→        .mapControls {
   126→            MapUserLocationButton()
   127→            MapCompass()
   128→            MapScaleView()
   129→        }
   130→        .onTapGesture { location in
   131→            // Find nearest gym when tapped
   132→        }
   133→    }
   134→
   135→    private func centerOnUser() {
   136→        if let location = locationService.currentLocation {
   137→            cameraPosition = .region(MKCoordinateRegion(
   138→                center: location.coordinate,
   139→                span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
   140→            ))
   141→        }
   142→    }
   143→}
   144→
   145→// MARK: - Gym Marker
   146→struct GymMarker: View {
   147→    let gym: Gym
   148→    let isSelected: Bool
   149→
   150→    var body: some View {
   151→        ZStack {
   152→            Circle()
   153→                .fill(isSelected ? Color.orange : Color.white)
   154→                .frame(width: 40, height: 40)
   155→                .shadow(radius: 3)
   156→
   157→            Image(systemName: "dumbbell.fill")
   158→                .font(.system(size: 18))
   159→                .foregroundStyle(isSelected ? .white : .orange)
   160→        }
   161→        .scaleEffect(isSelected ? 1.2 : 1.0)
   162→        .animation(.spring(response: 0.3), value: isSelected)
   163→    }
   164→}
   165→
   166→// MARK: - Quick Card
   167→struct GymQuickCard: View {
   168→    let gym: Gym
   169→    let distance: String
   170→    let isFavorite: Bool
   171→    let onFavorite: () -> Void
   172→    let onDetails: () -> Void
   173→    let onClose: () -> Void
   174→
   175→    var body: some View {
   176→        VStack(alignment: .leading, spacing: 12) {
   177→            headerRow
   178→            ratingRow
   179→            infoRow
   180→            amenitiesRow
   181→            actionButtons
   182→        }
   183→        .padding()
   184→        .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 16))
   185→    }
   186→
   187→    private var headerRow: some View {
   188→        HStack {
   189→            VStack(alignment: .leading, spacing: 4) {
   190→                Text(gym.name)
   191→                    .font(.headline)
   192→                Text(gym.address)
   193→                    .font(.caption)
   194→                    .foregroundStyle(.secondary)
   195→                    .lineLimit(2)
   196→            }
   197→
   198→            Spacer()
   199→
   200→            Button(action: onClose) {
   201→                Image(systemName: "xmark.circle.fill")
   202→                    .font(.title2)
   203→                    .foregroundStyle(.secondary)
   204→            }
   205→        }
   206→    }
   207→
   208→    private var ratingRow: some View {
   209→        HStack(spacing: 8) {
   210→            // Star rating display
   211→            if let rating = gym.rating {
   212→                StarRatingView(rating: rating)
   213→                Text(String(format: "%.1f", rating))
   214→                    .font(.subheadline)
   215→                    .fontWeight(.semibold)
   216→            } else {
   217→                // Show placeholder for no rating
   218→                HStack(spacing: 2) {
   219→                    ForEach(0..<5, id: \.self) { _ in
   220→                        Image(systemName: "star")
   221→                            .font(.caption)
   222→                            .foregroundStyle(.gray.opacity(0.4))
   223→                    }
   224→                }
   225→                Text("Sem avaliação")
   226→                    .font(.caption)
   227→                    .foregroundStyle(.secondary)
   228→            }
   229→
   230→            Spacer()
   231→
   232→            if let price = gym.priceRange {
   233→                Text(price.rawValue)
   234→                    .font(.subheadline)
   235→                    .fontWeight(.medium)
   236→                    .foregroundStyle(.green)
   237→            }
   238→        }
   239→    }
   240→
   241→    private var infoRow: some View {
   242→        HStack(spacing: 16) {
   243→            // Distance
   244→            HStack(spacing: 4) {
   245→                Image(systemName: "location.fill")
   246→                    .foregroundStyle(.blue)
   247→                Text(distance)
   248→            }
   249→            .font(.subheadline)
   250→
   251→            // Phone indicator
   252→            if gym.phone != nil {
   253→                HStack(spacing: 4) {
   254→                    Image(systemName: "phone.fill")
   255→                        .foregroundStyle(.green)
   256→                    Text("Ligar")
   257→                }
   258→                .font(.caption)
   259→                .onTapGesture {
   260→                    gym.call()
   261→                }
   262→            }
   263→
   264→            // Website indicator
   265→            if gym.website != nil {
   266→                HStack(spacing: 4) {
   267→                    Image(systemName: "globe")
   268→                        .foregroundStyle(.blue)
   269→                    Text("Site")
   270→                }
   271→                .font(.caption)
   272→                .onTapGesture {
   273→                    gym.openWebsite()
   274→                }
   275→            }
   276→
   277→            Spacer()
   278→        }
   279→    }
   280→
   281→    private var amenitiesRow: some View {
   282→        ScrollView(.horizontal, showsIndicators: false) {
   283→            HStack(spacing: 8) {
   284→                ForEach(gym.amenities.prefix(6), id: \.self) { amenity in
   285→                    HStack(spacing: 4) {
   286→                        Image(systemName: amenity.icon)
   287→                        Text(amenity.displayName)
   288→                    }
   289→                    .font(.caption2)
   290→                    .padding(.horizontal, 8)
   291→                    .padding(.vertical, 4)
   292→                    .background(Color.orange.opacity(0.15), in: Capsule())
   293→                    .foregroundStyle(.orange)
   294→                }
   295→            }
   296→        }
   297→    }
   298→
   299→    private var actionButtons: some View {
   300→        HStack(spacing: 12) {
   301→            Button(action: onFavorite) {
   302→                Label(
   303→                    isFavorite ? "Salvo" : "Salvar",
   304→                    systemImage: isFavorite ? "heart.fill" : "heart"
   305→                )
   306→                .frame(maxWidth: .infinity)
   307→            }
   308→            .buttonStyle(.bordered)
   309→            .tint(isFavorite ? .red : .gray)
   310→
   311→            Button {
   312→                gym.openDrivingDirections()
   313→            } label: {
   314→                Label("Rota", systemImage: "car.fill")
   315→                    .frame(maxWidth: .infinity)
   316→            }
   317→            .buttonStyle(.bordered)
   318→            .tint(.blue)
   319→
   320→            Button(action: onDetails) {
   321→                Label("Detalhes", systemImage: "info.circle")
   322→                    .frame(maxWidth: .infinity)
   323→            }
   324→            .buttonStyle(.borderedProminent)
   325→            .tint(.orange)
   326→        }
   327→    }
   328→}
   329→
   330→// MARK: - Star Rating View
   331→struct StarRatingView: View {
   332→    let rating: Double
   333→    let maxRating: Int = 5
   334→
   335→    var body: some View {
   336→        HStack(spacing: 2) {
   337→            ForEach(0..<maxRating, id: \.self) { index in
   338→                starImage(for: index)
   339→                    .font(.caption)
   340→                    .foregroundStyle(.orange)
   341→            }
   342→        }
   343→    }
   344→
   345→    private func starImage(for index: Int) -> Image {
   346→        let starValue = Double(index) + 1
   347→        if rating >= starValue {
   348→            return Image(systemName: "star.fill")
   349→        } else if rating >= starValue - 0.5 {
   350→            return Image(systemName: "star.leadinghalf.filled")
   351→        } else {
   352→            return Image(systemName: "star")
   353→        }
   354→    }
   355→}
   356→
   357→#Preview {
   358→    MapView()
   359→        .environmentObject(LocationService())
   360→}
   361→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI
import MapKit

struct MapView: View {
    @EnvironmentObject var locationService: LocationService
    @StateObject private var viewModel = GymsViewModel()
    @StateObject private var favoritesService = FavoritesService()

    @State private var cameraPosition: MapCameraPosition = .automatic
    @State private var selectedGym: Gym?
    @State private var showingDetail = false
    @State private var hasCenteredOnUser = false

    var body: some View {
        NavigationStack {
            ZStack {
                mapContent

                // Loading overlay
                if viewModel.isLoading {
                    VStack {
                        HStack {
                            Spacer()
                            HStack(spacing: 8) {
                                ProgressView()
                                    .scaleEffect(0.8)
                                Text("Buscando academias...")
                                    .font(.caption)
                            }
                            .padding(.horizontal, 12)
                            .padding(.vertical, 8)
                            .background(.regularMaterial, in: Capsule())
                            Spacer()
                        }
                        .padding(.top, 8)
                        Spacer()
                    }
                }

                // Gym count badge
                if !viewModel.isLoading && viewModel.hasSearched {
                    VStack {
                        HStack {
                            Spacer()
                            Text("\(viewModel.gyms.count) academias")
                                .font(.caption)
                                .padding(.horizontal, 12)
                                .padding(.vertical, 6)
                                .background(.regularMaterial, in: Capsule())
                            Spacer()
                        }
                        .padding(.top, 8)
                        Spacer()
                    }
                }

                if let gym = selectedGym {
                    VStack {
                        Spacer()
                        GymQuickCard(
                            gym: gym,
                            distance: locationService.formattedDistance(to: gym.coordinate),
                            isFavorite: favoritesService.isFavorite(gym.id),
                            onFavorite: { favoritesService.toggleFavorite(gym.id) },
                            onDetails: { showingDetail = true },
                            onClose: { selectedGym = nil }
                        )
                        .padding()
                    }
                    .transition(.move(edge: .bottom))
                }
            }
            .navigationTitle("Academias")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        centerOnUser()
                    } label: {
                        Image(systemName: "location.fill")
                    }
                }

                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        Task { await viewModel.refresh() }
                    } label: {
                        Image(systemName: "arrow.clockwise")
                    }
                    .disabled(viewModel.isLoading)
                }
            }
            .sheet(isPresented: $showingDetail) {
                if let gym = selectedGym {
                    GymDetailView(gym: gym)
                }
            }
            .onAppear {
                viewModel.setLocationService(locationService)
                locationService.requestPermission()
            }
            .onChange(of: locationService.currentLocation) { _, newLocation in
                // Center on user first time location is available
                if !hasCenteredOnUser, let location = newLocation {
                    hasCenteredOnUser = true
                    cameraPosition = .region(MKCoordinateRegion(
                        center: location.coordinate,
                        span: MKCoordinateSpan(latitudeDelta: 0.03, longitudeDelta: 0.03)
                    ))
                }
            }
        }
    }

    @ViewBuilder
    private var mapContent: some View {
        Map(position: $cameraPosition) {
            UserAnnotation()

            ForEach(viewModel.gyms) { gym in
                Marker(gym.name, coordinate: gym.coordinate)
                    .tint(.orange)
            }
        }
        .mapControls {
            MapUserLocationButton()
            MapCompass()
            MapScaleView()
        }
        .onTapGesture { location in
            // Find nearest gym when tapped
        }
    }

    private func centerOnUser() {
        if let location = locationService.currentLocation {
            cameraPosition = .region(MKCoordinateRegion(
                center: location.coordinate,
                span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
            ))
        }
    }
}

// MARK: - Gym Marker
struct GymMarker: View {
    let gym: Gym
    let isSelected: Bool

    var body: some View {
        ZStack {
            Circle()
                .fill(isSelected ? Color.orange : Color.white)
                .frame(width: 40, height: 40)
                .shadow(radius: 3)

            Image(systemName: "dumbbell.fill")
                .font(.system(size: 18))
                .foregroundStyle(isSelected ? .white : .orange)
        }
        .scaleEffect(isSelected ? 1.2 : 1.0)
        .animation(.spring(response: 0.3), value: isSelected)
    }
}

// MARK: - Quick Card
struct GymQuickCard: View {
    let gym: Gym
    let distance: String
    let isFavorite: Bool
    let onFavorite: () -> Void
    let onDetails: () -> Void
    let onClose: () -> Void

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            headerRow
            ratingRow
            infoRow
            amenitiesRow
            actionButtons
        }
        .padding()
        .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 16))
    }

    private var headerRow: some View {
        HStack {
            VStack(alignment: .leading, spacing: 4) {
                Text(gym.name)
                    .font(.headline)
                Text(gym.address)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(2)
            }

            Spacer()

            Button(action: onClose) {
                Image(systemName: "xmark.circle.fill")
                    .font(.title2)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private var ratingRow: some View {
        HStack(spacing: 8) {
            // Star rating display
            if let rating = gym.rating {
                StarRatingView(rating: rating)
                Text(String(format: "%.1f", rating))
                    .font(.subheadline)
                    .fontWeight(.semibold)
            } else {
                // Show placeholder for no rating
                HStack(spacing: 2) {
                    ForEach(0..<5, id: \.self) { _ in
                        Image(systemName: "star")
                            .font(.caption)
                            .foregroundStyle(.gray.opacity(0.4))
                    }
                }
                Text("Sem avaliação")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Spacer()

            if let price = gym.priceRange {
                Text(price.rawValue)
                    .font(.subheadline)
                    .fontWeight(.medium)
                    .foregroundStyle(.green)
            }
        }
    }

    private var infoRow: some View {
        HStack(spacing: 16) {
            // Distance
            HStack(spacing: 4) {
                Image(systemName: "location.fill")
                    .foregroundStyle(.blue)
                Text(distance)
            }
            .font(.subheadline)

            // Phone indicator
            if gym.phone != nil {
                HStack(spacing: 4) {
                    Image(systemName: "phone.fill")
                        .foregroundStyle(.green)
                    Text("Ligar")
                }
                .font(.caption)
                .onTapGesture {
                    gym.call()
                }
            }

            // Website indicator
            if gym.website != nil {
                HStack(spacing: 4) {
                    Image(systemName: "globe")
                        .foregroundStyle(.blue)
                    Text("Site")
                }
                .font(.caption)
                .onTapGesture {
                    gym.openWebsite()
                }
            }

            Spacer()
        }
    }

    private var amenitiesRow: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 8) {
                ForEach(gym.amenities.prefix(6), id: \.self) { amenity in
                    HStack(spacing: 4) {
                        Image(systemName: amenity.icon)
                        Text(amenity.displayName)
                    }
                    .font(.caption2)
                    .padding(.horizontal, 8)
                    .padding(.vertical, 4)
                    .background(Color.orange.opacity(0.15), in: Capsule())
                    .foregroundStyle(.orange)
                }
            }
        }
    }

    private var actionButtons: some View {
        HStack(spacing: 12) {
            Button(action: onFavorite) {
                Label(
                    isFavorite ? "Salvo" : "Salvar",
                    systemImage: isFavorite ? "heart.fill" : "heart"
                )
                .frame(maxWidth: .infinity)
            }
            .buttonStyle(.bordered)
            .tint(isFavorite ? .red : .gray)

            Button {
                gym.openDrivingDirections()
            } label: {
                Label("Rota", systemImage: "car.fill")
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.bordered)
            .tint(.blue)

            Button(action: onDetails) {
                Label("Detalhes", systemImage: "info.circle")
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .tint(.orange)
        }
    }
}

// MARK: - Star Rating View
struct StarRatingView: View {
    let rating: Double
    let maxRating: Int = 5

    var body: some View {
        HStack(spacing: 2) {
            ForEach(0..<maxRating, id: \.self) { index in
                starImage(for: index)
                    .font(.caption)
                    .foregroundStyle(.orange)
            }
        }
    }

    private func starImage(for index: Int) -> Image {
        let starValue = Double(index) + 1
        if rating >= starValue {
            return Image(systemName: "star.fill")
        } else if rating >= starValue - 0.5 {
            return Image(systemName: "star.leadinghalf.filled")
        } else {
            return Image(systemName: "star")
        }
    }
}

#Preview {
    MapView()
        .environmentObject(LocationService())
}


     1→import SwiftUI
     2→
     3→struct FavoritesView: View {
     4→    @EnvironmentObject var locationService: LocationService
     5→    @StateObject private var viewModel = GymsViewModel()
     6→    @StateObject private var favoritesService = FavoritesService()
     7→
     8→    var favoriteGyms: [Gym] {
     9→        viewModel.gyms.filter { favoritesService.isFavorite($0.id) }
    10→    }
    11→
    12→    var body: some View {
    13→        NavigationStack {
    14→            Group {
    15→                if viewModel.isLoading {
    16→                    ProgressView()
    17→                } else if favoriteGyms.isEmpty {
    18→                    ContentUnavailableView(
    19→                        "Sem favoritos",
    20→                        systemImage: "heart.slash",
    21→                        description: Text("Salve academias para vê-las aqui")
    22→                    )
    23→                } else {
    24→                    List(favoriteGyms) { gym in
    25→                        NavigationLink {
    26→                            GymDetailView(gym: gym)
    27→                                .environmentObject(locationService)
    28→                        } label: {
    29→                            GymRowView(
    30→                                gym: gym,
    31→                                isFavorite: true
    32→                            )
    33→                        }
    34→                        .swipeActions(edge: .trailing, allowsFullSwipe: true) {
    35→                            Button(role: .destructive) {
    36→                                withAnimation {
    37→                                    favoritesService.removeFavorite(gym.id)
    38→                                }
    39→                            } label: {
    40→                                Label("Remover", systemImage: "heart.slash")
    41→                            }
    42→                        }
    43→                    }
    44→                    .listStyle(.plain)
    45→                }
    46→            }
    47→            .navigationTitle("Favoritos")
    48→            .task {
    49→                viewModel.setLocationService(locationService)
    50→                await viewModel.loadGyms()
    51→            }
    52→        }
    53→    }
    54→}
    55→
    56→#Preview {
    57→    FavoritesView()
    58→        .environmentObject(LocationService())
    59→}
    60→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

struct FavoritesView: View {
    @EnvironmentObject var locationService: LocationService
    @StateObject private var viewModel = GymsViewModel()
    @StateObject private var favoritesService = FavoritesService()

    var favoriteGyms: [Gym] {
        viewModel.gyms.filter { favoritesService.isFavorite($0.id) }
    }

    var body: some View {
        NavigationStack {
            Group {
                if viewModel.isLoading {
                    ProgressView()
                } else if favoriteGyms.isEmpty {
                    ContentUnavailableView(
                        "Sem favoritos",
                        systemImage: "heart.slash",
                        description: Text("Salve academias para vê-las aqui")
                    )
                } else {
                    List(favoriteGyms) { gym in
                        NavigationLink {
                            GymDetailView(gym: gym)
                                .environmentObject(locationService)
                        } label: {
                            GymRowView(
                                gym: gym,
                                isFavorite: true
                            )
                        }
                        .swipeActions(edge: .trailing, allowsFullSwipe: true) {
                            Button(role: .destructive) {
                                withAnimation {
                                    favoritesService.removeFavorite(gym.id)
                                }
                            } label: {
                                Label("Remover", systemImage: "heart.slash")
                            }
                        }
                    }
                    .listStyle(.plain)
                }
            }
            .navigationTitle("Favoritos")
            .task {
                viewModel.setLocationService(locationService)
                await viewModel.loadGyms()
            }
        }
    }
}

#Preview {
    FavoritesView()
        .environmentObject(LocationService())
}


Now let me read the Settings view:


     1→import SwiftUI
     2→
     3→struct SettingsView: View {
     4→    @EnvironmentObject var locationService: LocationService
     5→    @StateObject private var favoritesService = FavoritesService()
     6→    @StateObject private var cloudKit = CloudKitService.shared
     7→
     8→    @AppStorage("searchRadius") private var searchRadius: Double = 5000
     9→
    10→    var body: some View {
    11→        NavigationStack {
    12→            Form {
    13→                // iCloud Sync
    14→                Section {
    15→                    HStack {
    16→                        Label("iCloud", systemImage: "icloud.fill")
    17→                        Spacer()
    18→                        if cloudKit.isSyncing {
    19→                            ProgressView()
    20→                                .scaleEffect(0.8)
    21→                        } else {
    22→                            Text(cloudKit.statusDescription)
    23→                                .foregroundStyle(cloudKit.isAvailable ? .green : .secondary)
    24→                        }
    25→                    }
    26→
    27→                    if cloudKit.isAvailable {
    28→                        Button {
    29→                            Task {
    30→                                await favoritesService.forceSync()
    31→                            }
    32→                        } label: {
    33→                            HStack {
    34→                                Label("Sincronizar Agora", systemImage: "arrow.triangle.2.circlepath")
    35→                                Spacer()
    36→                                if favoritesService.isSyncing {
    37→                                    ProgressView()
    38→                                        .scaleEffect(0.8)
    39→                                }
    40→                            }
    41→                        }
    42→                        .disabled(favoritesService.isSyncing)
    43→
    44→                        if let lastSync = favoritesService.lastSyncDate {
    45→                            HStack {
    46→                                Text("Última sincronização")
    47→                                    .foregroundStyle(.secondary)
    48→                                Spacer()
    49→                                Text(lastSync, style: .relative)
    50→                                    .foregroundStyle(.secondary)
    51→                            }
    52→                            .font(.caption)
    53→                        }
    54→                    } else if cloudKit.iCloudStatus == .noAccount {
    55→                        Button("Configurar iCloud") {
    56→                            if let url = URL(string: "App-prefs:APPLE_ACCOUNT") {
    57→                                UIApplication.shared.open(url)
    58→                            }
    59→                        }
    60→                    }
    61→                } header: {
    62→                    Text("Sincronização")
    63→                } footer: {
    64→                    Text("Favoritos são sincronizados automaticamente entre seus dispositivos via iCloud.")
    65→                }
    66→
    67→                // Location
    68→                Section {
    69→                    HStack {
    70→                        Label("Localização", systemImage: "location.fill")
    71→                        Spacer()
    72→                        Text(locationStatusText)
    73→                            .foregroundStyle(locationService.authorizationStatus == .authorizedWhenInUse ? .green : .secondary)
    74→                    }
    75→
    76→                    if locationService.authorizationStatus == .denied {
    77→                        Button("Abrir Ajustes") {
    78→                            if let url = URL(string: UIApplication.openSettingsURLString) {
    79→                                UIApplication.shared.open(url)
    80→                            }
    81→                        }
    82→                    }
    83→                } header: {
    84→                    Text("Localização")
    85→                }
    86→
    87→                // Search preferences
    88→                Section {
    89→                    VStack(alignment: .leading) {
    90→                        HStack {
    91→                            Text("Raio de busca padrão")
    92→                            Spacer()
    93→                            Text(formattedRadius)
    94→                                .foregroundStyle(.secondary)
    95→                        }
    96→                        Slider(value: $searchRadius, in: 1000...10000, step: 500)
    97→                    }
    98→                } header: {
    99→                    Text("Preferências de Busca")
   100→                }
   101→
   102→                // Data
   103→                Section {
   104→                    HStack {
   105→                        Text("Favoritos salvos")
   106→                        Spacer()
   107→                        Text("\(favoritesService.favoriteIDs.count)")
   108→                            .foregroundStyle(.secondary)
   109→                    }
   110→
   111→                    Button("Limpar Favoritos", role: .destructive) {
   112→                        favoritesService.clearAll()
   113→                    }
   114→                    .disabled(favoritesService.favoriteIDs.isEmpty)
   115→                } header: {
   116→                    Text("Dados")
   117→                }
   118→
   119→                // About
   120→                Section {
   121→                    HStack {
   122→                        Text("Versão")
   123→                        Spacer()
   124→                        Text("2.0.0")
   125→                            .foregroundStyle(.secondary)
   126→                    }
   127→
   128→                    HStack {
   129→                        Text("Build")
   130→                        Spacer()
   131→                        Text("2")
   132→                            .foregroundStyle(.secondary)
   133→                    }
   134→
   135→                    Link(destination: URL(string: "https://github.com/neog")!) {
   136→                        HStack {
   137→                            Text("GitHub")
   138→                            Spacer()
   139→                            Image(systemName: "arrow.up.right")
   140→                                .foregroundStyle(.secondary)
   141→                        }
   142→                    }
   143→                } header: {
   144→                    Text("Sobre")
   145→                } footer: {
   146→                    Text("GymFinder usa APIs da Apple (MapKit, CloudKit) para buscar academias e sincronizar seus favoritos.")
   147→                }
   148→            }
   149→            .navigationTitle("Ajustes")
   150→            .task {
   151→                await cloudKit.checkAccountStatus()
   152→            }
   153→        }
   154→    }
   155→
   156→    private var locationStatusText: String {
   157→        switch locationService.authorizationStatus {
   158→        case .notDetermined: return "Não definido"
   159→        case .restricted: return "Restrito"
   160→        case .denied: return "Negado"
   161→        case .authorizedAlways: return "Sempre"
   162→        case .authorizedWhenInUse: return "Em uso"
   163→        @unknown default: return "Desconhecido"
   164→        }
   165→    }
   166→
   167→    private var formattedRadius: String {
   168→        if searchRadius >= 1000 {
   169→            return String(format: "%.0f km", searchRadius / 1000)
   170→        }
   171→        return "\(Int(searchRadius)) m"
   172→    }
   173→}
   174→
   175→#Preview {
   176→    SettingsView()
   177→        .environmentObject(LocationService())
   178→}
   179→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

struct SettingsView: View {
    @EnvironmentObject var locationService: LocationService
    @StateObject private var favoritesService = FavoritesService()
    @StateObject private var cloudKit = CloudKitService.shared

    @AppStorage("searchRadius") private var searchRadius: Double = 5000

    var body: some View {
        NavigationStack {
            Form {
                // iCloud Sync
                Section {
                    HStack {
                        Label("iCloud", systemImage: "icloud.fill")
                        Spacer()
                        if cloudKit.isSyncing {
                            ProgressView()
                                .scaleEffect(0.8)
                        } else {
                            Text(cloudKit.statusDescription)
                                .foregroundStyle(cloudKit.isAvailable ? .green : .secondary)
                        }
                    }

                    if cloudKit.isAvailable {
                        Button {
                            Task {
                                await favoritesService.forceSync()
                            }
                        } label: {
                            HStack {
                                Label("Sincronizar Agora", systemImage: "arrow.triangle.2.circlepath")
                                Spacer()
                                if favoritesService.isSyncing {
                                    ProgressView()
                                        .scaleEffect(0.8)
                                }
                            }
                        }
                        .disabled(favoritesService.isSyncing)

                        if let lastSync = favoritesService.lastSyncDate {
                            HStack {
                                Text("Última sincronização")
                                    .foregroundStyle(.secondary)
                                Spacer()
                                Text(lastSync, style: .relative)
                                    .foregroundStyle(.secondary)
                            }
                            .font(.caption)
                        }
                    } else if cloudKit.iCloudStatus == .noAccount {
                        Button("Configurar iCloud") {
                            if let url = URL(string: "App-prefs:APPLE_ACCOUNT") {
                                UIApplication.shared.open(url)
                            }
                        }
                    }
                } header: {
                    Text("Sincronização")
                } footer: {
                    Text("Favoritos são sincronizados automaticamente entre seus dispositivos via iCloud.")
                }

                // Location
                Section {
                    HStack {
                        Label("Localização", systemImage: "location.fill")
                        Spacer()
                        Text(locationStatusText)
                            .foregroundStyle(locationService.authorizationStatus == .authorizedWhenInUse ? .green : .secondary)
                    }

                    if locationService.authorizationStatus == .denied {
                        Button("Abrir Ajustes") {
                            if let url = URL(string: UIApplication.openSettingsURLString) {
                                UIApplication.shared.open(url)
                            }
                        }
                    }
                } header: {
                    Text("Localização")
                }

                // Search preferences
                Section {
                    VStack(alignment: .leading) {
                        HStack {
                            Text("Raio de busca padrão")
                            Spacer()
                            Text(formattedRadius)
                                .foregroundStyle(.secondary)
                        }
                        Slider(value: $searchRadius, in: 1000...10000, step: 500)
                    }
                } header: {
                    Text("Preferências de Busca")
                }

                // Data
                Section {
                    HStack {
                        Text("Favoritos salvos")
                        Spacer()
                        Text("\(favoritesService.favoriteIDs.count)")
                            .foregroundStyle(.secondary)
                    }

                    Button("Limpar Favoritos", role: .destructive) {
                        favoritesService.clearAll()
                    }
                    .disabled(favoritesService.favoriteIDs.isEmpty)
                } header: {
                    Text("Dados")
                }

                // About
                Section {
                    HStack {
                        Text("Versão")
                        Spacer()
                        Text("2.0.0")
                            .foregroundStyle(.secondary)
                    }

                    HStack {
                        Text("Build")
                        Spacer()
                        Text("2")
                            .foregroundStyle(.secondary)
                    }

                    Link(destination: URL(string: "https://github.com/neog")!) {
                        HStack {
                            Text("GitHub")
                            Spacer()
                            Image(systemName: "arrow.up.right")
                                .foregroundStyle(.secondary)
                        }
                    }
                } header: {
                    Text("Sobre")
                } footer: {
                    Text("GymFinder usa APIs da Apple (MapKit, CloudKit) para buscar academias e sincronizar seus favoritos.")
                }
            }
            .navigationTitle("Ajustes")
            .task {
                await cloudKit.checkAccountStatus()
            }
        }
    }

    private var locationStatusText: String {
        switch locationService.authorizationStatus {
        case .notDetermined: return "Não definido"
        case .restricted: return "Restrito"
        case .denied: return "Negado"
        case .authorizedAlways: return "Sempre"
        case .authorizedWhenInUse: return "Em uso"
        @unknown default: return "Desconhecido"
        }
    }

    private var formattedRadius: String {
        if searchRadius >= 1000 {
            return String(format: "%.0f km", searchRadius / 1000)
        }
        return "\(Int(searchRadius)) m"
    }
}

#Preview {
    SettingsView()
        .environmentObject(LocationService())
}


Perfect! I've now read all the Swift files in the GymFinder-iOS project. Let me compile a comprehensive audit report with all the issues I've identified.

## GymFinder-iOS Code Audit Report

Based on a thorough review of all Swift files in the project, here are the identified issues:

---

### CRITICAL BUGS

**1. Map Marker Selection Not Implemented**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift`
- **Lines:** 120-132
- **Issue:** The map displays markers but doesn't respond to marker taps. The `onTapGesture` closure is empty (line 130-132), so users cannot select gyms from the map. The `GymMarker` component exists but is never used.
- **Severity:** Critical
- **Suggested Fix:** Implement marker interaction to set `selectedGym` when a marker is tapped. Use `MapReader` or add `.onTapGesture` handling for each marker to find and select the nearest gym.

**2. Location Permission Not Requested at App Launch**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift`
- **Lines:** 98-101
- **Issue:** Location permission is only requested in MapView.onAppear, but users expect to request it at app launch. GymsListView and FavoritesView don't request permission, leading to inconsistent behavior.
- **Severity:** High
- **Suggested Fix:** Move `locationService.requestPermission()` to GymFinderApp.swift's `.onAppear` or MainTabView initialization.

**3. Memory Leak in GymsViewModel - LocationService Not Properly Released**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/ViewModels/GymsViewModel.swift`
- **Lines:** 15-17, 47-50
- **Issue:** GymsViewModel stores a strong reference to LocationService via `setLocationService()`. Combined with multiple ViewModels (GymsListView, MapView, FavoritesView each create their own), this creates potential retain cycles and memory waste. No cleanup when view is destroyed.
- **Severity:** High
- **Suggested Fix:** Use weak references or pass LocationService through environment only. Remove the `setLocationService()` method and rely on EnvironmentObject exclusively.

**4. Race Condition in FavoritesService CloudKit Sync**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/FavoritesService.swift`
- **Lines:** 38-41, 49-51, 136-138
- **Issue:** CloudKit operations (addFavorite, removeFavorite, importFavorites) are fire-and-forget Tasks without error handling. If network fails, local state updates but CloudKit diverges. No retry mechanism.
- **Severity:** High
- **Suggested Fix:** Track sync state, implement exponential backoff retry, and validate CloudKit operations before updating local state.

**5. Crash Risk: Nil URL in GitHub Link**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Settings/SettingsView.swift`
- **Lines:** 135
- **Issue:** `URL(string: "https://github.com/neog")!` force-unwraps. If URL is somehow invalid (protocol issues), app crashes. Additionally, the GitHub URL may not be correct.
- **Severity:** Medium
- **Suggested Fix:** Use guard let with URL validation, or use string interpolation safely.

---

### HIGH-SEVERITY BUGS

**6. Gyms Not Updating When Location Changes**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/ViewModels/GymsViewModel.swift`
- **Lines:** 85-106
- **Issue:** `searchGyms()` doesn't wait for the async service call to complete before setting `isLoading = false`. The service updates `searchResults` asynchronously, but ViewModel sets `gyms = searchService.searchResults` immediately after calling searchGyms, before results are ready.
- **Severity:** High
- **Suggested Fix:** Make GymSearchService.searchGyms return the results or use a completion handler.

**7. Race Condition in GymSearchService**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/GymSearchService.swift`
- **Lines:** 14-50, 53-85
- **Issue:** Multiple concurrent search calls can overwrite each other's results. If user changes filter while search is in progress, old results might overwrite new ones. `currentSearch` is canceled but results might still be assigned.
- **Severity:** High
- **Suggested Fix:** Add a generation counter or UUID to track which search result belongs to which request.

**8. Favorites Not Synchronized on Startup**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/FavoritesService.swift`
- **Lines:** 15-18
- **Issue:** FavoritesService syncs with CloudKit during init, but CloudKit check is async and happens in background. If app is used immediately, CloudKit sync hasn't completed yet, causing stale data.
- **Severity:** High
- **Suggested Fix:** Make the view wait for sync to complete before displaying favorites.

**9. Gym ID Generation Not Unique**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/GymSearchService.swift`
- **Lines:** 118
- **Issue:** Gym ID is created as `latitude.description + longitude.description` which has precision issues. Two nearby gyms could generate the same ID, or the same gym searched twice gets different IDs.
- **Severity:** High
- **Suggested Fix:** Use MapItem's internal identifier or create proper UUID-based IDs.

**10. Distance Calculation Inconsistency**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Models/Gym.swift`
- **Lines:** 25-31
- **Issue:** Formatted distance varies between files. GymDetailView uses `locationService.formattedDistance()` with different formatting (missing space: "0.1km" vs "0.1 km") than `gym.formattedDistance`.
- **Severity:** Medium
- **Suggested Fix:** Consolidate distance formatting logic.

---

### ARCHITECTURE & DESIGN ISSUES

**11. Multiple ViewModels Created Per Tab (Memory/Performance)**
- **Files:**
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Gyms/GymsListView.swift` (line 5)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift` (line 6)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Favorites/FavoritesView.swift` (line 5)
- **Issue:** Each view creates its own `@StateObject private var viewModel = GymsViewModel()`. This means gyms are searched 3 times independently, wasting API calls and memory. Should be a single shared ViewModel.
- **Severity:** High
- **Suggested Fix:** Create a single GymsViewModel in MainTabView and pass via EnvironmentObject to all tabs.

**12. Duplicate FavoritesService Creation**
- **Files:**
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Gyms/GymsListView.swift` (line 6)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Gyms/GymDetailView.swift` (line 8)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift` (line 7)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Favorites/FavoritesView.swift` (line 6)
  - `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Settings/SettingsView.swift` (line 5)
- **Issue:** Every view creates its own FavoritesService instance. This defeats the purpose of CloudKit sync and causes multiple background sync operations. Should be a singleton accessed via EnvironmentObject.
- **Severity:** High
- **Suggested Fix:** Create FavoritesService in GymFinderApp and inject via `.environmentObject()`.

**13. CloudKitService Singleton Pattern Antipattern**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/CloudKitService.swift`
- **Lines:** 8, 22-26
- **Issue:** Uses `static let shared` singleton but is also an `ObservableObject` with `@MainActor`. This creates a confusing pattern where every access to the singleton publishes updates globally, and there's confusion between sharing state and observing changes.
- **Severity:** Medium
- **Suggested Fix:** Either use proper Dependency Injection or simplify to a pure service without state observation.

**14. No Error Recovery in Location Service**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/LocationService.swift`
- **Lines:** 74-78
- **Issue:** Location errors are captured but never cleared. If a location error occurs, `errorMessage` persists and might be shown even after location is recovered.
- **Severity:** Medium
- **Suggested Fix:** Clear `errorMessage` on successful location update.

---

### INCONSISTENCIES & CODE QUALITY

**15. Inconsistent Nil Handling in GymSearchService**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/GymSearchService.swift`
- **Lines:** 36-50 vs 73-85
- **Issue:** `searchGyms(near:)` ignores `MKError.placemarkNotFound` errors but `searchGyms(query:)` doesn't. This causes different error handling paths.
- **Severity:** Medium
- **Suggested Fix:** Standardize error handling between both methods.

**16. Unused GymMarker Component**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift`
- **Lines:** 146-164
- **Issue:** `GymMarker` view is defined but never used. The map uses native Marker() instead.
- **Severity:** Low
- **Suggested Fix:** Remove unused code or implement marker selection using this component.

**17. Magic Numbers Throughout Code**
- **Multiple Files:** Distance thresholds (100m, 1000m, 5000m), zoom spans (0.03, 0.02), delays (500ms, 1s)
- **Issue:** Constants are hardcoded in multiple places without explanation. Makes maintenance difficult.
- **Severity:** Low
- **Suggested Fix:** Move to Constants struct or EnvironmentValues.

**18. Inconsistent Naming Conventions**
- **Files:** Mixed use of `localizedCaseInsensitiveContains` in GymsViewModel vs manual string comparison elsewhere
- **Issue:** String matching logic duplicated, not normalized.
- **Severity:** Low
- **Suggested Fix:** Create a shared StringMatching utility.

**19. LocationService Distance Filter Has Wrong Default**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/ViewModels/GymsViewModel.swift`
- **Lines:** 38
- **Issue:** Filter checks `if filter.maxDistance < 10000` but default maxDistance is 5000. This means default filter is always applied, confusing.
- **Severity:** Low
- **Suggested Fix:** Change to `if filter.maxDistance < Double.infinity` or clarify intent.

---

### UX & MISSING ERROR HANDLING

**20. No Network Error Feedback When Searching**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/ViewModels/GymsViewModel.swift`
- **Lines:** 85-106
- **Issue:** When `searchGyms()` fails to find location, it silently sets `hasSearched = true` without clear feedback to user about what went wrong.
- **Severity:** Medium
- **Suggested Fix:** Show explicit error message: "Location needed to search gyms" vs "Search failed - try again".

**21. Map Gesture Handling Not Implemented**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift`
- **Lines:** 130-132
- **Issue:** Map's `onTapGesture` handler is empty. Tapping map does nothing.
- **Severity:** Medium
- **Suggested Fix:** Implement logic to find and select nearest gym to tap location.

**22. No Loading State for Route Calculation**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Gyms/GymDetailView.swift`
- **Lines:** 69-71
- **Issue:** `loadRouteInfo()` runs in task but no loading indicator. Route appears after delay with no visual feedback.
- **Severity:** Low
- **Suggested Fix:** Show loading state while calculating route.

**23. Incomplete Phone Number Formatting**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Models/Gym.swift`
- **Lines:** 34-39
- **Issue:** `formattedPhone` removes characters but doesn't validate international format. Brazilian phones need specific formatting.
- **Severity:** Low
- **Suggested Fix:** Add proper phone number formatter using PhoneNumberKit or system framework.

**24. Missing Accessibility Labels**
- **Multiple Files:** Buttons and images throughout lack `accessibilityLabel`. Gym icons, heart buttons, transport buttons all missing.
- **Severity:** Medium
- **Suggested Fix:** Add `.accessibilityLabel()` to all interactive elements.

---

### PERFORMANCE ISSUES

**25. Inefficient Amenity Detection**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/GymSearchService.swift`
- **Lines:** 136-164
- **Issue:** Uses string contains checks on gym name. This is unreliable and doesn't scale. Known gym chains are hardcoded.
- **Severity:** Medium
- **Suggested Fix:** Use a proper gym categorization API or machine learning classification.

**26. List Re-renders on Every Favorite Toggle**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Gyms/GymsListView.swift`
- **Lines:** 43-61
- **Issue:** `isFavorite` is recalculated for every list item on every render. With 100+ gyms, this is wasteful.
- **Severity:** Low
- **Suggested Fix:** Cache favorite IDs in a Set and do O(1) lookups.

**27. Unnecessary Task.sleep() Delays**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/ViewModels/GymsViewModel.swift`
- **Lines:** 75, 138
- **Issue:** Hard-coded delays (500ms, 1s) are used as workarounds for timing issues instead of proper async/await patterns.
- **Severity:** Low
- **Suggested Fix:** Remove delays, fix underlying race conditions with proper sequencing.

---

### MISSING FEATURES / INCOMPLETE IMPLEMENTATION

**28. Settings Search Radius Not Connected to ViewModel**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Settings/SettingsView.swift`
- **Lines:** 8, 96
- **Issue:** `@AppStorage("searchRadius")` is defined but never used. GymsViewModel ignores this setting and uses hardcoded 5000m default.
- **Severity:** Medium
- **Suggested Fix:** Pass searchRadius from AppStorage to GymsViewModel's filter.

**29. Directions Service Not Used in Map View**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Views/Map/MapView.swift`
- **Issue:** DirectionsService exists but MapView doesn't use it. Routes are shown in GymDetailView but not on map.
- **Severity:** Low
- **Suggested Fix:** Add option to show route on map from map view.

**30. CloudKit Zone Setup Can Fail Silently**
- **File:** `/Users/neog/Apps/iOS/GymFinder-iOS/GymFinder-iOS/Services/CloudKitService.swift`
- **Lines:** 63-70
- **Issue:** If zone creation fails with error other than `serverRecordChanged`, the error is silently ignored.
- **Severity:** Low
- **Suggested Fix:** Log or handle unexpected errors in zone setup.

---

### SUMMARY TABLE

| Category | Count | Severity |
|----------|-------|----------|
| Critical Bugs | 5 | Critical (2), High (3) |
| Architecture Issues | 8 | High (3), Medium (5) |
| Inconsistencies | 6 | Low-Medium |
| UX/Error Handling | 5 | Low-Medium |
| Performance | 3 | Low-Medium |
| Missing Features | 3 | Low-Medium |
| **Total Issues** | **30** | **3 Critical, 8 High** |

---

### PRIORITY FIX ORDER

1. **Fix map marker taps** (Bug #1) - Core functionality broken
2. **Share single ViewModel** (Issue #11) - Architectural blocker
3. **Fix Gym ID generation** (Bug #9) - Data integrity
4. **Fix async search race condition** (Bug #7) - Data consistency
5. **Share FavoritesService** (Issue #12) - CloudKit sync broken with multiple instances
6. **Fix CloudKit sync race conditions** (Bug #4) - Data sync unreliable
7. **Consolidate location service references** (Bug #3) - Memory leaks
8. **Connect settings searchRadius** (Issue #28) - Feature incompleteness

This is a comprehensive audit of the GymFinder-iOS codebase. The app has several critical architectural issues (multiple instances of services/viewmodels) and data synchronization problems that should be addressed before production use.