From e68961bd0d93665ece7154b58fab64d78cf226c7 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Tue, 29 Aug 2023 14:10:16 +0900 Subject: [PATCH] =?UTF-8?q?=ED=9B=84=EC=9B=90=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=EB=B3=B4=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive/Sources/ContentView.swift | 3 + SodaLive/Sources/Explorer/ExplorerApi.swift | 14 +- .../Sources/Explorer/ExplorerRepository.swift | 4 + .../Profile/GetDonationAllResponse.swift | 16 ++ .../Profile/UserProfileDonationAllView.swift | 251 ++++++++++++++++++ .../UserProfileDonationAllViewModel.swift | 79 ++++++ .../Profile/UserProfileDonationView.swift | 4 +- .../Sources/Extensions/IntExtension.swift | 12 + 8 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 SodaLive/Sources/Explorer/Profile/GetDonationAllResponse.swift create mode 100644 SodaLive/Sources/Explorer/Profile/UserProfileDonationAllView.swift create mode 100644 SodaLive/Sources/Explorer/Profile/UserProfileDonationAllViewModel.swift diff --git a/SodaLive/Sources/ContentView.swift b/SodaLive/Sources/ContentView.swift index 2f24eed..b803d1c 100644 --- a/SodaLive/Sources/ContentView.swift +++ b/SodaLive/Sources/ContentView.swift @@ -151,6 +151,9 @@ struct ContentView: View { case .orderListAll: OrderListAllView() + case .userProfileDonationAll(let userId): + UserProfileDonationAllView(userId: userId) + default: EmptyView() .frame(width: 0, height: 0, alignment: .topLeading) diff --git a/SodaLive/Sources/Explorer/ExplorerApi.swift b/SodaLive/Sources/Explorer/ExplorerApi.swift index 40c4904..3ce990f 100644 --- a/SodaLive/Sources/Explorer/ExplorerApi.swift +++ b/SodaLive/Sources/Explorer/ExplorerApi.swift @@ -17,6 +17,7 @@ enum ExplorerApi { case writeCheers(parentCheersId: Int?, creatorId: Int, content: String) case modifyCheers(cheersId: Int, content: String) case writeCreatorNotice(request: PostCreatorNoticeRequest) + case getCreatorProfileDonationRanking(userId: Int, page: Int, size: Int) } extension ExplorerApi: TargetType { @@ -35,6 +36,9 @@ extension ExplorerApi: TargetType { case .getCreatorProfile(let userId): return "/explorer/profile/\(userId)" + case .getCreatorProfileDonationRanking(let userId, _, _): + return "/explorer/profile/\(userId)/donation-rank" + case .getFollowerList(let userId, _, _): return "/explorer/profile/\(userId)/follower-list" @@ -54,7 +58,7 @@ extension ExplorerApi: TargetType { var method: Moya.Method { switch self { - case .getExplorer, .searchChannel, .getCreatorProfile, .getFollowerList, .getCreatorProfileCheers: + case .getExplorer, .searchChannel, .getCreatorProfile, .getFollowerList, .getCreatorProfileCheers, .getCreatorProfileDonationRanking: return .get case .writeCheers, .writeCreatorNotice: @@ -104,6 +108,14 @@ extension ExplorerApi: TargetType { case .writeCreatorNotice(let request): return .requestJSONEncodable(request) + + case .getCreatorProfileDonationRanking(_, let page, let size): + let parameters = [ + "page": page - 1, + "size": size + ] as [String : Any] + + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) } } diff --git a/SodaLive/Sources/Explorer/ExplorerRepository.swift b/SodaLive/Sources/Explorer/ExplorerRepository.swift index a9ceded..5af42bf 100644 --- a/SodaLive/Sources/Explorer/ExplorerRepository.swift +++ b/SodaLive/Sources/Explorer/ExplorerRepository.swift @@ -44,4 +44,8 @@ final class ExplorerRepository { func writeCreatorNotice(notice: String) -> AnyPublisher { return api.requestPublisher(.writeCreatorNotice(request: PostCreatorNoticeRequest(notice: notice))) } + + func getCreatorProfileDonationRanking(userId: Int, page: Int, size: Int) -> AnyPublisher { + return api.requestPublisher(.getCreatorProfileDonationRanking(userId: userId, page: page, size: size)) + } } diff --git a/SodaLive/Sources/Explorer/Profile/GetDonationAllResponse.swift b/SodaLive/Sources/Explorer/Profile/GetDonationAllResponse.swift new file mode 100644 index 0000000..41b929a --- /dev/null +++ b/SodaLive/Sources/Explorer/Profile/GetDonationAllResponse.swift @@ -0,0 +1,16 @@ +// +// GetDonationAllResponse.swift +// SodaLive +// +// Created by klaus on 2023/08/29. +// + +import Foundation + +struct GetDonationAllResponse: Decodable { + let accumulatedCansToday: Int + let accumulatedCansLastWeek: Int + let accumulatedCansThisMonth: Int + let totalCount: Int + let userDonationRanking: [UserDonationRankingResponse] +} diff --git a/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllView.swift b/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllView.swift new file mode 100644 index 0000000..b111bff --- /dev/null +++ b/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllView.swift @@ -0,0 +1,251 @@ +// +// UserProfileDonationAllView.swift +// SodaLive +// +// Created by klaus on 2023/08/29. +// + +import SwiftUI +import Kingfisher + +struct UserProfileDonationAllView: View { + + let userId: Int + @StateObject var viewModel = UserProfileDonationAllViewModel() + + var body: some View { + BaseView(isLoading: $viewModel.isLoading) { + VStack(spacing: 0) { + DetailNavigationBar(title: "후원랭킹 전체보기") + + if userId == UserDefaults.int(forKey: .userId) { + VStack(spacing: 13.3) { + HStack(spacing: 0) { + Text("오늘") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Spacer() + + Text("\(viewModel.accumulatedCansToday.comma())") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Text(" 캔") + .font(.custom(Font.light.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + } + + HStack(spacing: 0) { + Text("지난주") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Spacer() + + Text("\(viewModel.accumulatedCansLastWeek.comma())") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Text(" 캔") + .font(.custom(Font.light.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + } + + HStack(spacing: 0) { + Text("이번 달 어제까지") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Spacer() + + Text("\(viewModel.accumulatedCansThisMonth.comma())") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Text(" 캔") + .font(.custom(Font.light.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + } + } + .padding(.vertical, 13.3) + .padding(.horizontal, 16.7) + .background(Color(hex: "2b2635")) + .cornerRadius(8) + .padding(.top, 13.3) + .padding(.horizontal, 13.3) + } + + HStack(alignment: .center, spacing: 0) { + Text("전체") + .font(.custom(Font.medium.rawValue, size: 14.7)) + .foregroundColor(Color(hex: "eeeeee")) + + Text("\(viewModel.totalCount)") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "9970ff")) + .padding(.leading, 6.7) + + Text("개") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "777777")) + + Spacer() + } + .padding(.top, 13.3) + .padding(.horizontal, 13.3) + + Rectangle() + .frame(width: screenSize().width - 26.7, height: 1) + .foregroundColor(Color(hex: "909090").opacity(0.5)) + .padding(.top, 6.7) + + ScrollView(.vertical, showsIndicators: false) { + LazyVStack(spacing: 0) { + ForEach(0.. 10 ? "\(String(item.nickname.prefix(10)))..." : item.nickname + Text(nickname) + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + + Spacer() + + if let donationCan = item.donationCan, donationCan > 0, withDonationCan { + Text("\(donationCan) 캔") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + } + .padding(.horizontal, isTop3Index(index: index) ? 20 : 0) + .padding(.top, getTopPadding(index: index)) + .padding(.bottom, getBottomPadding(index: index)) + .background(Color(hex: "2b2635").opacity(isTop3Index(index: index) ? 1 : 0)) + .cornerRadius(4.7, corners: cornerRadiusConers(index: index)) + .padding(.horizontal, isTop3Index(index: index) ? 0 : 6.7) + } + + private func isTop3Index(index: Int) -> Bool { + return index == 0 || index == 1 || index == 2 + } + + private func getTopPadding(index: Int) -> CGFloat { + if index == 0 || index == 3 { + return 20 + } else { + return 6.7 + } + } + + private func getBottomPadding(index: Int) -> CGFloat { + if (index == 0 && itemCount == 1) || (index == 1 && itemCount == 2) || index == 2 { + return 20 + } else { + return 6.7 + } + } + + private func cornerRadiusConers(index: Int) -> UIRectCorner { + if (index == 0 && itemCount == 1) { + return [.topLeft, .topRight, .bottomLeft, .bottomRight] + } else if index == 0 { + return [.topLeft, .topRight] + } else if (index == 1 && itemCount == 2) || index == 2 { + return [.bottomLeft, .bottomRight] + } else { + return [] + } + } +} diff --git a/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllViewModel.swift b/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllViewModel.swift new file mode 100644 index 0000000..5234288 --- /dev/null +++ b/SodaLive/Sources/Explorer/Profile/UserProfileDonationAllViewModel.swift @@ -0,0 +1,79 @@ +// +// UserProfileDonationAllViewModel.swift +// SodaLive +// +// Created by klaus on 2023/08/29. +// + +import Foundation +import Combine + +final class UserProfileDonationAllViewModel: ObservableObject { + private var repository = ExplorerRepository() + private var subscription = Set() + + @Published var errorMessage = "" + @Published var isShowPopup = false + @Published var isLoading = false + + @Published var totalCount = 0 + @Published var accumulatedCansToday = 0 + @Published var accumulatedCansLastWeek = 0 + @Published var accumulatedCansThisMonth = 0 + @Published var userDonationRanking: [UserDonationRankingResponse] = [] + + var userId = 0 + var page = 1 + var isLast = false + private let pageSize = 10 + + func getCreatorProfileDonationRanking() { + if (!isLast && !isLoading) { + isLoading = true + + repository.getCreatorProfileDonationRanking(userId: userId, page: page, size: pageSize) + .sink { result in + switch result { + case .finished: + DEBUG_LOG("finish") + case .failure(let error): + ERROR_LOG(error.localizedDescription) + } + } receiveValue: { [unowned self] response in + self.isLoading = false + 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.accumulatedCansToday = data.accumulatedCansToday + self.accumulatedCansLastWeek = data.accumulatedCansLastWeek + self.accumulatedCansThisMonth = data.accumulatedCansThisMonth + + if !data.userDonationRanking.isEmpty { + page += 1 + self.totalCount = data.totalCount + self.userDonationRanking.append(contentsOf: data.userDonationRanking) + } 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 + } + } + .store(in: &subscription) + } + } +} diff --git a/SodaLive/Sources/Explorer/Profile/UserProfileDonationView.swift b/SodaLive/Sources/Explorer/Profile/UserProfileDonationView.swift index 6bae502..69f66f3 100644 --- a/SodaLive/Sources/Explorer/Profile/UserProfileDonationView.swift +++ b/SodaLive/Sources/Explorer/Profile/UserProfileDonationView.swift @@ -32,7 +32,9 @@ struct UserProfileDonationView: View { Text("전체보기") .font(.custom(Font.light.rawValue, size: 11.3)) .foregroundColor(Color(hex: "bbbbbb")) - .onTapGesture {} + .onTapGesture { + AppState.shared.setAppStep(step: .userProfileDonationAll(userId: userId)) + } } ScrollView(.horizontal, showsIndicators: false) { diff --git a/SodaLive/Sources/Extensions/IntExtension.swift b/SodaLive/Sources/Extensions/IntExtension.swift index cdf30f5..cb33551 100644 --- a/SodaLive/Sources/Extensions/IntExtension.swift +++ b/SodaLive/Sources/Extensions/IntExtension.swift @@ -30,3 +30,15 @@ extension Int64 { return timeText.joined(separator: ":") } } + +extension Int { + func comma() -> String { + let numberFormatter = NumberFormatter() + numberFormatter.groupingSeparator = "," + numberFormatter.groupingSize = 3 + numberFormatter.usesGroupingSeparator = true + numberFormatter.decimalSeparator = "." + numberFormatter.numberStyle = .decimal + return numberFormatter.string(from: self as NSNumber)! + } +}