diff --git a/SodaLive/Sources/App/AppStep.swift b/SodaLive/Sources/App/AppStep.swift index 2633128..0643c4e 100644 --- a/SodaLive/Sources/App/AppStep.swift +++ b/SodaLive/Sources/App/AppStep.swift @@ -143,4 +143,6 @@ enum AppStep { case searchChannel case contentMain(startTab: ContentMainTab) + + case completedSeriesAll } diff --git a/SodaLive/Sources/Content/ContentApi.swift b/SodaLive/Sources/Content/ContentApi.swift index f2ebb4a..7c2d757 100644 --- a/SodaLive/Sources/Content/ContentApi.swift +++ b/SodaLive/Sources/Content/ContentApi.swift @@ -45,6 +45,7 @@ enum ContentApi { case getContentMainSeries case getRecommendSeriesListByGenre(genreId: Int) case getRecommendSeriesByCreator(creatorId: Int) + case getCompletedSeries(page: Int, size: Int) case getContentMainContent case getContentMainNewContentOfTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType) @@ -175,6 +176,9 @@ extension ContentApi: TargetType { case .getRecommendSeriesByCreator: return "/v2/audio-content/main/series/recommend-series-by-creator" + case .getCompletedSeries: + return "/v2/audio-content/main/series/completed-rank" + case .getContentMainContent: return "/v2/audio-content/main/content" @@ -233,7 +237,7 @@ extension ContentApi: TargetType { case .getContentMainHome, .getPopularContentByCreator, .getContentMainSeries, .getRecommendSeriesListByGenre, .getRecommendSeriesByCreator, .getContentMainContent, .getContentMainNewContentOfTheme, .getDailyContentRanking, .getRecommendContentByTag, .getContentMainAlarm, .getContentMainAlarmAll, .getContentMainAsmr, .getPopularAsmrContentByCreator, .getContentMainReplay, .getPopularReplayContentByCreator, - .getContentMainFree, .getIntroduceCreatorList, .getNewFreeContentOfTheme, .getPopularFreeContentByCreator: + .getContentMainFree, .getIntroduceCreatorList, .getNewFreeContentOfTheme, .getPopularFreeContentByCreator, .getCompletedSeries: return .get case .likeContent, .modifyAudioContent, .modifyComment, .unpinContent: @@ -437,6 +441,13 @@ extension ContentApi: TargetType { case .getPopularAsmrContentByCreator(let creatorId), .getPopularReplayContentByCreator(let creatorId), .getPopularFreeContentByCreator(let creatorId): let parameters = ["creatorId": creatorId] return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) + + case .getCompletedSeries(let page, let size): + let parameters = [ + "page": page - 1, + "size": size + ] + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) } } diff --git a/SodaLive/Sources/Content/Main/V2/Series/Completed/CompletedSeriesView.swift b/SodaLive/Sources/Content/Main/V2/Series/Completed/CompletedSeriesView.swift new file mode 100644 index 0000000..0f94f08 --- /dev/null +++ b/SodaLive/Sources/Content/Main/V2/Series/Completed/CompletedSeriesView.swift @@ -0,0 +1,86 @@ +// +// CompletedSeriesView.swift +// SodaLive +// +// Created by klaus on 2/22/25. +// + +import SwiftUI + +struct CompletedSeriesView: View { + + @StateObject var viewModel = CompletedSeriesViewModel() + + private let columns = [ + GridItem(.flexible()), + GridItem(.flexible()), + GridItem(.flexible()) + ] + + var body: some View { + BaseView(isLoading: $viewModel.isLoading) { + VStack(spacing: 13.3) { + DetailNavigationBar(title: "완결 시리즈") + + HStack(alignment: .center, spacing: 0) { + Text("전체") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.graye2) + + Text("\(viewModel.totalCount)") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.mainRed) + .padding(.leading, 6.7) + + Text("개") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.graye2) + + Spacer() + } + .padding(.horizontal, 13.3) + + ScrollView(.vertical, showsIndicators: false) { + LazyVGrid(columns: columns, spacing: 13.3) { + ForEach(0..() + + @Published var errorMessage = "" + @Published var isShowPopup = false + @Published var isLoading = false + + @Published var rankCompleteSeriesList: [SeriesListItem] = [] + @Published var totalCount = 0 + + var isLast = false + var page = 1 + private let size = 20 + + func getCompletedSeries() { + if !isLast && !isLoading { + isLoading = true + + repository.getCompletedSeries(page: page, size: size) + .sink { result in + switch result { + case .finished: + DEBUG_LOG("finish") + case .failure(let error): + ERROR_LOG(error.localizedDescription) + } + } receiveValue: { [unowned self] response in + let responseData = response.data + + do { + let jsonDecoder = JSONDecoder() + let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) + + if let data = decoded.data, decoded.success { + page += 1 + + if (data.items.count > 0) { + self.totalCount = data.totalCount + self.rankCompleteSeriesList = data.items + } else { + isLast = true + } + } else { + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + } + + self.isShowPopup = true + } + } catch { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.isShowPopup = true + } + + self.isLoading = false + } + .store(in: &subscription) + } + } +} diff --git a/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesRepository.swift b/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesRepository.swift index ddb0db2..f9a6fd2 100644 --- a/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesRepository.swift +++ b/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesRepository.swift @@ -24,4 +24,8 @@ final class ContentMainTabSeriesRepository { func getRecommendSeriesByCreator(creatorId: Int) -> AnyPublisher { return api.requestPublisher(.getRecommendSeriesByCreator(creatorId: creatorId)) } + + func getCompletedSeries(page: Int, size: Int) -> AnyPublisher { + return api.requestPublisher(.getCompletedSeries(page: page, size: size)) + } } diff --git a/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesView.swift b/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesView.swift index 2b5d77c..e495e04 100644 --- a/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesView.swift +++ b/SodaLive/Sources/Content/Main/V2/Series/ContentMainTabSeriesView.swift @@ -52,7 +52,10 @@ struct ContentMainTabSeriesView: View { if !viewModel.rankCompleteSeriesList.isEmpty { ContentMainCompletedSeriesView( itemList: viewModel.rankCompleteSeriesList, - onClickMore: {} + onClickMore: { + AppState.shared + .setAppStep(step: .completedSeriesAll) + } ) .padding(.top, 30) } diff --git a/SodaLive/Sources/ContentView.swift b/SodaLive/Sources/ContentView.swift index ed17303..2d41142 100644 --- a/SodaLive/Sources/ContentView.swift +++ b/SodaLive/Sources/ContentView.swift @@ -218,6 +218,9 @@ struct ContentView: View { case .contentMain(let startTab): ContentMainViewV2(selectedTab: startTab) + case .completedSeriesAll: + CompletedSeriesView() + default: EmptyView() .frame(width: 0, height: 0, alignment: .topLeading)