import Foundation import AVKit import Combine @MainActor class SightViewModel: ObservableObject { @Published var sightName: String = "Загрузка..." @Published var allArticles: [Article] = [] @Published var selectedArticle: Article? @Published var articleHeading: String = "" @Published var articleBody: String = "" @Published var mediaState: MediaState = .loading private var sightModel: SightModel? private var selectedLanguage: String = "ru" // по умолчанию enum MediaState { case loading case image(URL) case video(AVPlayer) case error } func setLanguage(_ language: String) { self.selectedLanguage = language } func loadInitialData(sightId: Int) async { do { async let sightModelTask = fetchJSON( from: "https://white-nights.krbl.ru/services/content/sight/\(sightId)?lang=\(selectedLanguage)", type: SightModel.self ) async let articlesTask = fetchJSON( from: "https://white-nights.krbl.ru/services/content/sight/\(sightId)/article?lang=\(selectedLanguage)", type: [Article].self ) let (fetchedSightModel, fetchedArticles) = try await (sightModelTask, articlesTask) self.sightModel = fetchedSightModel self.sightName = fetchedSightModel.name let reviewArticle = Article(id: -1, body: "", heading: "Обзор", isReviewArticle: true) self.allArticles = [reviewArticle] + fetchedArticles selectArticle(reviewArticle) } catch { print("Ошибка начальной загрузки данных: \(error)") self.mediaState = .error } } func selectArticle(_ article: Article) { guard selectedArticle != article else { return } self.selectedArticle = article self.articleHeading = article.heading self.articleBody = article.body Task { await updateMedia(for: article) } } private func updateMedia(for article: Article) async { self.mediaState = .loading if article.isReviewArticle == true { guard let sight = sightModel else { self.mediaState = .error return } if let videoPreviewId = sight.video_preview, let url = URL(string: "https://white-nights.krbl.ru/services/content/media/\(videoPreviewId)/download?lang=\(selectedLanguage)") { let player = AVPlayer(url: url) player.play() self.mediaState = .video(player) } else if let url = URL(string: "https://white-nights.krbl.ru/services/content/media/\(sight.preview_media)/download?lang=\(selectedLanguage)") { self.mediaState = .image(url) } else { self.mediaState = .error } } else { do { let mediaItems = try await fetchJSON( from: "https://white-nights.krbl.ru/services/content/article/\(article.id)/media?lang=\(selectedLanguage)", type: [ArticleMedia].self ) if let firstMedia = mediaItems.first, let url = URL(string: "https://white-nights.krbl.ru/services/content/media/\(firstMedia.id)/download?lang=\(selectedLanguage)") { self.mediaState = .image(url) } else { self.mediaState = .error } } catch { print("Ошибка загрузки медиа для статьи '\(article.heading)': \(error)") self.mediaState = .error } } } private func fetchJSON(from urlString: String, type: T.Type) async throws -> T { guard let url = URL(string: urlString) else { throw URLError(.badURL) } let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode(T.self, from: data) } }