From 47bc905e4d18f4aae6c704d9f0ae7b3ab076db1b Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Sun, 5 Jan 2025 18:18:40 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20-=20=EC=9D=B8=EA=B8=B0=20=ED=81=AC=EB=A6=AC?= =?UTF-8?q?=EC=97=90=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Content/ContentRepository.swift | 5 + .../Content/Main/ContentMainView.swift | 4 + .../ContentMainCreatorRankingView.swift | 150 ++++++++++++++++++ .../ContentMainCreatorRankingViewModel.swift | 54 +++++++ SodaLive/Sources/Explorer/ExplorerApi.swift | 8 +- 5 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 SodaLive/Sources/Content/Main/Ranking/ContentMainCreatorRankingView.swift create mode 100644 SodaLive/Sources/Content/Main/Ranking/ContentMainCreatorRankingViewModel.swift diff --git a/SodaLive/Sources/Content/ContentRepository.swift b/SodaLive/Sources/Content/ContentRepository.swift index dd70e6c..014a01d 100644 --- a/SodaLive/Sources/Content/ContentRepository.swift +++ b/SodaLive/Sources/Content/ContentRepository.swift @@ -13,6 +13,7 @@ import Moya final class ContentRepository { private let api = MoyaProvider() private let categoryApi = MoyaProvider() + private let explorerApi = MoyaProvider() func getAudioContentList(userId: Int, categoryId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort) -> AnyPublisher { return api.requestPublisher(.getAudioContentList(userId: userId, categoryId: categoryId, page: page, size: size, sort: sort)) @@ -168,4 +169,8 @@ final class ContentRepository { ) ) } + + func getCreatorRanking() -> AnyPublisher { + return explorerApi.requestPublisher(.getCreatorRank) + } } diff --git a/SodaLive/Sources/Content/Main/ContentMainView.swift b/SodaLive/Sources/Content/Main/ContentMainView.swift index 03539a3..d866f11 100644 --- a/SodaLive/Sources/Content/Main/ContentMainView.swift +++ b/SodaLive/Sources/Content/Main/ContentMainView.swift @@ -37,6 +37,10 @@ struct ContentMainView: View { .padding(.bottom, 26.7) .padding(.horizontal, 13.3) + ContentMainCreatorRankingView() + .padding(.bottom, 26.7) + .padding(.horizontal, 13.3) + ContentMainRecommendSeriesView() HStack(spacing: 8) { diff --git a/SodaLive/Sources/Content/Main/Ranking/ContentMainCreatorRankingView.swift b/SodaLive/Sources/Content/Main/Ranking/ContentMainCreatorRankingView.swift new file mode 100644 index 0000000..84ececc --- /dev/null +++ b/SodaLive/Sources/Content/Main/Ranking/ContentMainCreatorRankingView.swift @@ -0,0 +1,150 @@ +// +// ContentMainCreatorRankingView.swift +// SodaLive +// +// Created by klaus on 1/5/25. +// + +import SwiftUI +import Kingfisher + +struct ContentMainCreatorRankingView: View { + + @StateObject var viewModel = ContentMainCreatorRankingViewModel() + + let rankingCrawns = ["ic_crown_1", "ic_crown_2", "ic_crown_3"] + let rankingColors = [ + [Color(hex: "ffdc00"), Color(hex: "ffb600")], + [Color(hex: "ffffff"), Color(hex: "9f9f9f")], + [Color(hex: "e6a77a"), Color(hex: "c67e4a")], + [Color(hex: "ffffff").opacity(0), Color(hex: "ffffff").opacity(0)] + ] + + var body: some View { + ZStack { + if let response = viewModel.creatorRankingResponse { + VStack(alignment: .leading, spacing: 13.3) { + VStack(alignment: .leading, spacing: 4) { + if let coloredTitle = response.coloredTitle, let color = response.color { + let titleArray = response.title.components(separatedBy: coloredTitle) + HStack(spacing: 0) { + Text(titleArray[0]) + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color.grayee) + + Text(coloredTitle) + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color(hex: color)) + + if titleArray.count > 1 { + Text(titleArray[1]) + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color.grayee) + } + } + } else { + Text(response.title) + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color.grayee) + } + + if let desc = response.desc { + VStack(spacing: 8) { + Text("\(desc)") + .font(.custom(Font.bold.rawValue, size: 14.7)) + .foregroundColor(Color.grayee) + + Text("※ 인기 크리에이터의 순위는 매주 업데이트됩니다.") + .font(.custom(Font.light.rawValue, size: 13.3)) + .foregroundColor(Color.graybb) + } + .padding(.vertical, 8) + .frame(maxWidth: .infinity) + .background(Color.gray22) + .padding(.top, 13.3) + } + } + .frame(maxWidth: .infinity) + .frame(alignment: .leading) + + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 13.3) { + ForEach(0..() + + @Published var errorMessage = "" + @Published var isShowPopup = false + @Published var creatorRankingResponse: GetExplorerSectionResponse? = nil + + func getCreatorRanking() { + repository.getCreatorRanking() + .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 { + self.creatorRankingResponse = data + } else { + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = "인기 크리에이터를 불러오지 못했습니다. 다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + } + + self.isShowPopup = true + } + } catch { + self.errorMessage = "인기 크리에이터를 불러오지 못했습니다. 다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.isShowPopup = true + } + } + .store(in: &subscription) + } +} diff --git a/SodaLive/Sources/Explorer/ExplorerApi.swift b/SodaLive/Sources/Explorer/ExplorerApi.swift index 6c92a21..ab7549a 100644 --- a/SodaLive/Sources/Explorer/ExplorerApi.swift +++ b/SodaLive/Sources/Explorer/ExplorerApi.swift @@ -9,6 +9,7 @@ import Foundation import Moya enum ExplorerApi { + case getCreatorRank case getExplorer case searchChannel(channel: String) case getCreatorProfile(userId: Int) @@ -27,6 +28,9 @@ extension ExplorerApi: TargetType { var path: String { switch self { + case .getCreatorRank: + return "/explorer/creator-rank" + case .getExplorer: return "/explorer" @@ -58,7 +62,7 @@ extension ExplorerApi: TargetType { var method: Moya.Method { switch self { - case .getExplorer, .searchChannel, .getCreatorProfile, .getFollowerList, .getCreatorProfileCheers, .getCreatorProfileDonationRanking: + case .getExplorer, .searchChannel, .getCreatorProfile, .getFollowerList, .getCreatorProfileCheers, .getCreatorProfileDonationRanking, .getCreatorRank: return .get case .writeCheers, .writeCreatorNotice: @@ -71,7 +75,7 @@ extension ExplorerApi: TargetType { var task: Task { switch self { - case .getExplorer: + case .getExplorer, .getCreatorRank: return .requestPlain case .searchChannel(let channel):