import Foundation import Combine final class CreatorChannelLiveViewModel: ObservableObject { private let repository = CreatorChannelLiveRepository() private var subscription = Set() private let pageSize = 20 @Published var isLoading = false @Published var isLoadingNextPage = false @Published var response: CreatorChannelLiveTabResponse? @Published var liveReplayContents = [CreatorChannelAudioContentResponse]() @Published var selectedSort: ContentSort = .latest @Published var page = 0 @Published var size = 20 @Published var hasNext = false @Published var hasLoaded = false @Published var errorMessage = "" @Published var isShowPopup = false func fetchFirstPage(creatorId: Int) { fetchLive(creatorId: creatorId, page: 0, isNextPage: false) } func fetchNextPageIfNeeded(creatorId: Int, currentItem: CreatorChannelAudioContentResponse) { guard liveReplayContents.last?.audioContentId == currentItem.audioContentId else { return } guard hasNext, isLoadingNextPage == false, isLoading == false else { return } fetchLive(creatorId: creatorId, page: page + 1, isNextPage: true) } func selectSort(_ sort: ContentSort, creatorId: Int) { guard selectedSort != sort else { return } selectedSort = sort fetchFirstPage(creatorId: creatorId) } private func fetchLive(creatorId: Int, page requestPage: Int, isNextPage: Bool) { if isNextPage { isLoadingNextPage = true } else { isLoading = true } repository.getLive(creatorId: creatorId, page: requestPage, size: pageSize, sort: selectedSort) .sink { [weak self] result in guard let self else { return } switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) self.applyFailureState() } } receiveValue: { [weak self] response in guard let self else { return } do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: response.data) if let data = decoded.data, decoded.success { self.applySuccessState(data, isNextPage: isNextPage) } else { self.errorMessage = decoded.message ?? I18n.Common.commonError self.isShowPopup = true } } catch { ERROR_LOG(error.localizedDescription) self.errorMessage = I18n.Common.commonError self.isShowPopup = true } self.hasLoaded = true self.isLoading = false self.isLoadingNextPage = false } .store(in: &subscription) } private func applySuccessState(_ data: CreatorChannelLiveTabResponse, isNextPage: Bool) { response = data page = data.page size = data.size hasNext = data.hasNext if isNextPage { liveReplayContents.append(contentsOf: data.liveReplayContents) } else { liveReplayContents = data.liveReplayContents } } private func applyFailureState() { errorMessage = I18n.Common.commonError isShowPopup = true hasLoaded = true isLoading = false isLoadingNextPage = false } }