From 3d8817275c1c245b13adf7aae2bd38ae7f1a1666 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Mon, 6 Jan 2025 14:34:42 +0900 Subject: [PATCH] =?UTF-8?q?=EC=98=A4=EB=94=94=EC=85=98=20=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20-=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive/Sources/Audition/AuditionApi.swift | 52 ++++++++++++ .../Sources/Audition/AuditionItemView.swift | 49 +++++++++++ .../Sources/Audition/AuditionRepository.swift | 19 +++++ SodaLive/Sources/Audition/AuditionView.swift | 80 ++++++++++++++++- .../Sources/Audition/AuditionViewModel.swift | 85 +++++++++++++++++++ .../Audition/GetAuditionListResponse.swift | 19 +++++ 6 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 SodaLive/Sources/Audition/AuditionApi.swift create mode 100644 SodaLive/Sources/Audition/AuditionItemView.swift create mode 100644 SodaLive/Sources/Audition/AuditionRepository.swift create mode 100644 SodaLive/Sources/Audition/AuditionViewModel.swift create mode 100644 SodaLive/Sources/Audition/GetAuditionListResponse.swift diff --git a/SodaLive/Sources/Audition/AuditionApi.swift b/SodaLive/Sources/Audition/AuditionApi.swift new file mode 100644 index 0000000..c93864c --- /dev/null +++ b/SodaLive/Sources/Audition/AuditionApi.swift @@ -0,0 +1,52 @@ +// +// AuditionApi.swift +// SodaLive +// +// Created by klaus on 1/5/25. +// + +import Foundation +import Moya + +enum AuditionApi { + case getAuditionList(page: Int, size: Int) +} + +extension AuditionApi: TargetType { + var baseURL: URL { + return URL(string: BASE_URL)! + } + + var path: String { + switch self { + + case .getAuditionList: + return "/audition" + } + } + + var method: Moya.Method { + switch self { + + case .getAuditionList: + return .get + } + } + + var task: Moya.Task { + switch self { + + case .getAuditionList(let page, let size): + let parameters = [ + "page": page - 1, + "size": size + ] as [String : Any] + + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) + } + } + + var headers: [String : String]? { + return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"] + } +} diff --git a/SodaLive/Sources/Audition/AuditionItemView.swift b/SodaLive/Sources/Audition/AuditionItemView.swift new file mode 100644 index 0000000..a2c64d3 --- /dev/null +++ b/SodaLive/Sources/Audition/AuditionItemView.swift @@ -0,0 +1,49 @@ +// +// AuditionItemView.swift +// SodaLive +// +// Created by klaus on 1/6/25. +// + +import SwiftUI +import Kingfisher + +struct AuditionItemView: View { + + let item: GetAuditionListItem + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + ZStack { + KFImage(URL(string: item.imageUrl)) + .cancelOnDisappear(true) + .downsampling(size: CGSize(width: 1000, height: 530)) + .resizable() + .aspectRatio(1000/530, contentMode: .fit) + .frame(maxWidth: .infinity) + .overlay( + Color.black + .opacity(item.isOff ? 0.7 : 0.0) + ) + } + .frame(maxWidth: .infinity) + + Text(item.title) + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color.grayee) + .lineLimit(1) + .truncationMode(.tail) + } + } +} + +#Preview { + AuditionItemView( + item: GetAuditionListItem( + id: 1, + title: "[원작] 성인식", + imageUrl: "https://test-cf.sodalive.net/audition/production/3/audition-aa934579-c01a-4da2-89fd-cce70d51c612-4267-1735908116928", + isOff: false + ) + ) +} diff --git a/SodaLive/Sources/Audition/AuditionRepository.swift b/SodaLive/Sources/Audition/AuditionRepository.swift new file mode 100644 index 0000000..c714f05 --- /dev/null +++ b/SodaLive/Sources/Audition/AuditionRepository.swift @@ -0,0 +1,19 @@ +// +// AuditionRepository.swift +// SodaLive +// +// Created by klaus on 1/5/25. +// + +import Foundation +import CombineMoya +import Combine +import Moya + +final class AuditionRepository { + private let api = MoyaProvider() + + func getAuditionList(page: Int, size: Int) -> AnyPublisher { + return api.requestPublisher(.getAuditionList(page: page, size: size)) + } +} diff --git a/SodaLive/Sources/Audition/AuditionView.swift b/SodaLive/Sources/Audition/AuditionView.swift index 61e6656..dbfab7f 100644 --- a/SodaLive/Sources/Audition/AuditionView.swift +++ b/SodaLive/Sources/Audition/AuditionView.swift @@ -8,8 +8,86 @@ import SwiftUI struct AuditionView: View { + + @StateObject var viewModel = AuditionViewModel() + var body: some View { - Text("오디션") + BaseView(isLoading: $viewModel.isLoading) { + VStack(spacing: 0) { + HomeNavigationBar(title: "오디션") {} + + ScrollView(.vertical, showsIndicators: false) { + LazyVStack(alignment: .leading, spacing: 16.7) { + ForEach(0..() + + @Published var errorMessage = "" + @Published var isShowPopup = false + @Published var isLoading = false + + @Published var auditionList = [GetAuditionListItem]() + @Published var inProgressCount = 0 + @Published var completedCount = 0 + + @Published var firstIsOffIndex = -1 + + var page = 1 + var isLast = false + private let pageSize = 10 + + func getAuditionList() { + if !isLast && !isLoading { + isLoading = true + + DEBUG_LOG("호출됨") + + repository.getAuditionList(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 + let responseData = response.data + + do { + let jsonDecoder = JSONDecoder() + let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) + + if let data = decoded.data, decoded.success { + if page == 1 { + self.auditionList.removeAll() + } + + self.inProgressCount = data.inProgressCount + self.completedCount = data.completedCount + + if !data.items.isEmpty { + page += 1 + self.auditionList.append(contentsOf: data.items) + self.firstIsOffIndex = self.auditionList.firstIndex(where: { $0.isOff }) ?? -1 + } 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/Audition/GetAuditionListResponse.swift b/SodaLive/Sources/Audition/GetAuditionListResponse.swift new file mode 100644 index 0000000..f34482b --- /dev/null +++ b/SodaLive/Sources/Audition/GetAuditionListResponse.swift @@ -0,0 +1,19 @@ +// +// GetAuditionListResponse.swift +// SodaLive +// +// Created by klaus on 1/5/25. +// + +struct GetAuditionListResponse: Decodable { + let inProgressCount: Int + let completedCount: Int + let items: [GetAuditionListItem] +} + +struct GetAuditionListItem: Decodable { + let id: Int + let title: String + let imageUrl: String + let isOff: Bool +}