import SwiftUI struct ContentView: View { @EnvironmentObject var appState: AppState @State private var showMenu = false var body: some View { NavigationStack { ZStack { VStack(spacing: 10) { HStack(spacing: 10) { RouteView() WeatherView() } if let sightId = appState.sightId { SightView(sightId: sightId) } else { Text("Выберите маршрут, чтобы увидеть достопримечательность") .foregroundColor(.gray) .padding() } } .padding() // Плавающая кнопка в правом нижнем углу VStack { Spacer() HStack { Spacer() Button(action: { withAnimation(.spring()) { showMenu.toggle() } }) { Image(systemName: "line.3.horizontal") .font(.system(size: 24, weight: .bold)) .foregroundColor(.white) .padding() .background(Color.blue) .clipShape(Circle()) .shadow(radius: 5) } .padding(.trailing, 20) // .padding(.bottom, -20) // Убираем отрицательный паддинг .padding(.bottom, -20) // Добавляем паддинг, чтобы кнопка не перекрывалась } } // Используем кастомное BottomMenu if showMenu { // Используем Binding для двусторонней связи BottomMenu(isPresented: $showMenu) .transition(.move(edge: .bottom)) // Добавляем игнорирование safe area сверху, если BottomMenu // должно полностью закрывать контент, но обычно для // BottomSheet это не требуется, GeometryReader в BottomMenu // уже делает нужное растяжение. } } } .task { await fetchRoutes() } .preferredColorScheme(.light) } private func fetchRoutes() async { guard let url = URL(string: "https://white-nights.krbl.ru/services/content/route") else { return } do { let (data, _) = try await URLSession.shared.data(from: url) let routes = try JSONDecoder().decode([Route].self, from: data) appState.allRoutes = routes if let firstRoute = routes.first { appState.selectedRoute = firstRoute } } catch { print("Ошибка загрузки маршрутов: \(error)") } } }