콘텐츠 메인 - Api 분리
This commit is contained in:
parent
77a145d61c
commit
c09920942c
|
@ -22,8 +22,11 @@ enum ContentApi {
|
||||||
case getAudioContentCommentReplyList(commentId: Int, page: Int, size: Int)
|
case getAudioContentCommentReplyList(commentId: Int, page: Int, size: Int)
|
||||||
case deleteAudioContent(audioContentId: Int)
|
case deleteAudioContent(audioContentId: Int)
|
||||||
case modifyAudioContent(parameters: [MultipartFormData])
|
case modifyAudioContent(parameters: [MultipartFormData])
|
||||||
case getMain
|
case getNewContentUploadCreatorList
|
||||||
|
case getMainBannerList
|
||||||
|
case getMainOrderList
|
||||||
case getNewContentOfTheme(theme: String)
|
case getNewContentOfTheme(theme: String)
|
||||||
|
case getCurationList(page: Int, size: Int)
|
||||||
case donation(request: AudioContentDonationRequest)
|
case donation(request: AudioContentDonationRequest)
|
||||||
case modifyComment(request: ModifyCommentRequest)
|
case modifyComment(request: ModifyCommentRequest)
|
||||||
case getNewContentThemeList
|
case getNewContentThemeList
|
||||||
|
@ -79,12 +82,21 @@ extension ContentApi: TargetType {
|
||||||
case .modifyAudioContent:
|
case .modifyAudioContent:
|
||||||
return "/audio-content"
|
return "/audio-content"
|
||||||
|
|
||||||
case .getMain:
|
case .getNewContentUploadCreatorList:
|
||||||
return "/audio-content/main"
|
return "/audio-content/main/new-content-upload-creator"
|
||||||
|
|
||||||
|
case .getMainBannerList:
|
||||||
|
return "/audio-content/main/banner-list"
|
||||||
|
|
||||||
|
case .getMainOrderList:
|
||||||
|
return "/audio-content/main/order-list"
|
||||||
|
|
||||||
case .getNewContentOfTheme:
|
case .getNewContentOfTheme:
|
||||||
return "/audio-content/main/new"
|
return "/audio-content/main/new"
|
||||||
|
|
||||||
|
case .getCurationList:
|
||||||
|
return "/audio-content/main/curation-list"
|
||||||
|
|
||||||
case .donation:
|
case .donation:
|
||||||
return "/audio-content/donation"
|
return "/audio-content/donation"
|
||||||
|
|
||||||
|
@ -111,11 +123,14 @@ extension ContentApi: TargetType {
|
||||||
var method: Moya.Method {
|
var method: Moya.Method {
|
||||||
switch self {
|
switch self {
|
||||||
case .getAudioContentList, .getAudioContentDetail, .getOrderList, .getAudioContentThemeList,
|
case .getAudioContentList, .getAudioContentDetail, .getOrderList, .getAudioContentThemeList,
|
||||||
.getAudioContentCommentList, .getAudioContentCommentReplyList, .getMain, .getNewContentOfTheme,
|
.getAudioContentCommentList, .getAudioContentCommentReplyList, .getNewContentOfTheme,
|
||||||
.getNewContentThemeList, .getNewContentAllOfTheme, .getAudioContentListByCurationId, .getContentRanking,
|
.getNewContentThemeList, .getNewContentAllOfTheme, .getAudioContentListByCurationId, .getContentRanking,
|
||||||
.getContentRankingSortType:
|
.getContentRankingSortType:
|
||||||
return .get
|
return .get
|
||||||
|
|
||||||
|
case .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList, .getCurationList:
|
||||||
|
return .get
|
||||||
|
|
||||||
case .likeContent, .modifyAudioContent, .modifyComment:
|
case .likeContent, .modifyAudioContent, .modifyComment:
|
||||||
return .put
|
return .put
|
||||||
|
|
||||||
|
@ -163,7 +178,7 @@ extension ContentApi: TargetType {
|
||||||
case .addAllPlaybackTracking(let request):
|
case .addAllPlaybackTracking(let request):
|
||||||
return .requestJSONEncodable(request)
|
return .requestJSONEncodable(request)
|
||||||
|
|
||||||
case .getAudioContentThemeList, .getMain:
|
case .getAudioContentThemeList, .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList:
|
||||||
return .requestPlain
|
return .requestPlain
|
||||||
|
|
||||||
case .uploadAudioContent(let parameters):
|
case .uploadAudioContent(let parameters):
|
||||||
|
@ -236,6 +251,14 @@ extension ContentApi: TargetType {
|
||||||
|
|
||||||
case .getContentRankingSortType:
|
case .getContentRankingSortType:
|
||||||
return .requestPlain
|
return .requestPlain
|
||||||
|
|
||||||
|
case .getCurationList(let page, let size):
|
||||||
|
let parameters = [
|
||||||
|
"page": page - 1,
|
||||||
|
"size": size
|
||||||
|
] as [String : Any]
|
||||||
|
|
||||||
|
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,14 +65,26 @@ final class ContentRepository {
|
||||||
return api.requestPublisher(.modifyAudioContent(parameters: parameters))
|
return api.requestPublisher(.modifyAudioContent(parameters: parameters))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMain() -> AnyPublisher<Response, MoyaError> {
|
func getNewContentUploadCreatorList() -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.getMain)
|
return api.requestPublisher(.getNewContentUploadCreatorList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMainBannerList() -> AnyPublisher<Response, MoyaError> {
|
||||||
|
return api.requestPublisher(.getMainBannerList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMainOrderList() -> AnyPublisher<Response, MoyaError> {
|
||||||
|
return api.requestPublisher(.getMainOrderList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewContentOfTheme(theme: String) -> AnyPublisher<Response, MoyaError> {
|
func getNewContentOfTheme(theme: String) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.getNewContentOfTheme(theme: theme))
|
return api.requestPublisher(.getNewContentOfTheme(theme: theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCurationList(page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
|
return api.requestPublisher(.getCurationList(page: page, size: size))
|
||||||
|
}
|
||||||
|
|
||||||
func donation(contentId: Int, can: Int, comment: String) -> AnyPublisher<Response, MoyaError> {
|
func donation(contentId: Int, can: Int, comment: String) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.donation(request: AudioContentDonationRequest(contentId: contentId, donationCan: can, comment: comment)))
|
return api.requestPublisher(.donation(request: AudioContentDonationRequest(contentId: contentId, donationCan: can, comment: comment)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
//
|
||||||
|
// ContentMainBannerView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/08/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct ContentMainBannerView: View {
|
||||||
|
|
||||||
|
@StateObject private var viewModel = ContentMainBannerViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
if !viewModel.bannerList.isEmpty {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
TabView(selection: $viewModel.currentIndex) {
|
||||||
|
ForEach(0..<viewModel.bannerList.count, id: \.self) { index in
|
||||||
|
let item = viewModel.bannerList[index]
|
||||||
|
if let url = item.thumbnailImageUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
|
||||||
|
KFImage(URL(string: url))
|
||||||
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
.frame(
|
||||||
|
width: screenSize().width - 26.7,
|
||||||
|
height: (screenSize().width - 26.7) * 0.53
|
||||||
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
switch item.type {
|
||||||
|
case .EVENT:
|
||||||
|
AppState.shared.setAppStep(step: .eventDetail(event: item.eventItem!))
|
||||||
|
case .CREATOR:
|
||||||
|
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId!))
|
||||||
|
case .LINK:
|
||||||
|
if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cornerRadius(4.7)
|
||||||
|
} else {
|
||||||
|
KFImage(URL(string: item.thumbnailImageUrl))
|
||||||
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
.frame(
|
||||||
|
width: screenSize().width - 26.7,
|
||||||
|
height: (screenSize().width - 26.7) * 0.53
|
||||||
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
switch item.type {
|
||||||
|
case .EVENT:
|
||||||
|
AppState.shared.setAppStep(step: .eventDetail(event: item.eventItem!))
|
||||||
|
case .CREATOR:
|
||||||
|
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId!))
|
||||||
|
case .LINK:
|
||||||
|
if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cornerRadius(4.7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
||||||
|
.frame(
|
||||||
|
width: screenSize().width - 26.7,
|
||||||
|
height: (screenSize().width - 26.7) * 0.53
|
||||||
|
)
|
||||||
|
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
ForEach(0..<viewModel.bannerList.count, id: \.self) { index in
|
||||||
|
Capsule()
|
||||||
|
.foregroundColor(index == viewModel.currentIndex ? Color(hex: "9970ff") : Color(hex: "909090"))
|
||||||
|
.frame(
|
||||||
|
width: index == viewModel.currentIndex ? 18 : 6,
|
||||||
|
height: 6
|
||||||
|
)
|
||||||
|
.tag(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, 13.3)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
viewModel.timer.upstream.connect().cancel()
|
||||||
|
}
|
||||||
|
.onReceive(viewModel.timer) { _ in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
withAnimation {
|
||||||
|
if viewModel.currentIndex == viewModel.bannerList.count - 1 {
|
||||||
|
viewModel.currentIndex = 0
|
||||||
|
} else {
|
||||||
|
viewModel.currentIndex += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ActivityIndicatorView()
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.getBannerList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentMainBannerView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ContentMainBannerView()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
//
|
||||||
|
// ContentMainBannerViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainBannerViewModel: ObservableObject {
|
||||||
|
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var currentIndex = 0
|
||||||
|
@Published var timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
|
||||||
|
|
||||||
|
@Published var bannerList = [GetAudioContentBannerResponse]()
|
||||||
|
|
||||||
|
func getBannerList() {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getMainBannerList()
|
||||||
|
.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<[GetAudioContentBannerResponse]>.self, from: responseData)
|
||||||
|
self.isLoading = false
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.bannerList.removeAll()
|
||||||
|
self.bannerList.append(contentsOf: data)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,114 +0,0 @@
|
||||||
//
|
|
||||||
// ContentMainBannerView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2023/08/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Kingfisher
|
|
||||||
|
|
||||||
struct ContentMainBannerView: View {
|
|
||||||
|
|
||||||
let items: [GetAudioContentBannerResponse]
|
|
||||||
@State private var currentIndex = 0
|
|
||||||
@State private var timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
TabView(selection: $currentIndex) {
|
|
||||||
ForEach(0..<items.count, id: \.self) { index in
|
|
||||||
let item = items[index]
|
|
||||||
if let url = item.thumbnailImageUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
|
|
||||||
KFImage(URL(string: url))
|
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(
|
|
||||||
width: screenSize().width - 26.7,
|
|
||||||
height: (screenSize().width - 26.7) * 0.53
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
switch item.type {
|
|
||||||
case .EVENT:
|
|
||||||
AppState.shared.setAppStep(step: .eventDetail(event: item.eventItem!))
|
|
||||||
case .CREATOR:
|
|
||||||
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId!))
|
|
||||||
case .LINK:
|
|
||||||
if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.cornerRadius(4.7)
|
|
||||||
} else {
|
|
||||||
KFImage(URL(string: item.thumbnailImageUrl))
|
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(
|
|
||||||
width: screenSize().width - 26.7,
|
|
||||||
height: (screenSize().width - 26.7) * 0.53
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
switch item.type {
|
|
||||||
case .EVENT:
|
|
||||||
AppState.shared.setAppStep(step: .eventDetail(event: item.eventItem!))
|
|
||||||
case .CREATOR:
|
|
||||||
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId!))
|
|
||||||
case .LINK:
|
|
||||||
if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.cornerRadius(4.7)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
|
|
||||||
.frame(
|
|
||||||
width: screenSize().width - 26.7,
|
|
||||||
height: (screenSize().width - 26.7) * 0.53
|
|
||||||
)
|
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
|
||||||
ForEach(0..<items.count, id: \.self) { index in
|
|
||||||
Capsule()
|
|
||||||
.foregroundColor(index == currentIndex ? Color(hex: "9970ff") : Color(hex: "909090"))
|
|
||||||
.frame(
|
|
||||||
width: index == currentIndex ? 18 : 6,
|
|
||||||
height: 6
|
|
||||||
)
|
|
||||||
.tag(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.top, 13.3)
|
|
||||||
}
|
|
||||||
.frame(width: screenSize().width - 26.7)
|
|
||||||
.onAppear {
|
|
||||||
timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
|
|
||||||
}
|
|
||||||
.onDisappear {
|
|
||||||
timer.upstream.connect().cancel()
|
|
||||||
}
|
|
||||||
.onReceive(timer) { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
withAnimation {
|
|
||||||
if currentIndex == items.count - 1 {
|
|
||||||
currentIndex = 0
|
|
||||||
} else {
|
|
||||||
currentIndex += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentMainBannerView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentMainBannerView(
|
|
||||||
items: [
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
//
|
|
||||||
// ContentMainCurationView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2023/08/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentMainCurationView: View {
|
|
||||||
|
|
||||||
let items: [GetAudioContentCurationResponse]
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
LazyVStack(spacing: 40) {
|
|
||||||
ForEach(0..<items.count, id: \.self) {
|
|
||||||
ContentMainCurationItemView(item: items[$0])
|
|
||||||
.padding(.horizontal, 13.3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// ContentMainMyStashView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2023/08/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentMainMyStashView: View {
|
|
||||||
|
|
||||||
let items: [GetAudioContentMainItem]
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 13.3) {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("내 보관함")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Text("전체보기")
|
|
||||||
.font(.custom(Font.light.rawValue, size: 11.3))
|
|
||||||
.foregroundColor(Color(hex: "bbbbbb"))
|
|
||||||
.onTapGesture {
|
|
||||||
AppState.shared.setAppStep(step: .orderListAll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
LazyHStack(alignment: .top, spacing: 13.3) {
|
|
||||||
ForEach(0..<items.count, id: \.self) { index in
|
|
||||||
let item = items[index]
|
|
||||||
ContentMainItemView(item: item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentMainMyStashView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentMainMyStashView(
|
|
||||||
items: [
|
|
||||||
GetAudioContentMainItem(
|
|
||||||
contentId: 1,
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
title: "테스트",
|
|
||||||
creatorId: 7,
|
|
||||||
creatorProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
creatorNickname: "유저1"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
//
|
|
||||||
// ContentMainNewContentCreatorView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2023/08/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentMainNewContentCreatorView: View {
|
|
||||||
|
|
||||||
let items: [GetNewContentUploadCreator]
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
LazyHStack(spacing: 21.3) {
|
|
||||||
ForEach(0..<items.count, id: \.self) { index in
|
|
||||||
let item = items[index]
|
|
||||||
ContentMainNewContentCreatorItemView(item: item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentMainNewContentCreatorView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentMainNewContentCreatorView(
|
|
||||||
items: [
|
|
||||||
GetNewContentUploadCreator(
|
|
||||||
creatorId: 1,
|
|
||||||
creatorNickname: "수다친구1",
|
|
||||||
creatorProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png"
|
|
||||||
),
|
|
||||||
GetNewContentUploadCreator(
|
|
||||||
creatorId: 2,
|
|
||||||
creatorNickname: "수다친구2",
|
|
||||||
creatorProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png"
|
|
||||||
),
|
|
||||||
GetNewContentUploadCreator(
|
|
||||||
creatorId: 3,
|
|
||||||
creatorNickname: "수다친구3",
|
|
||||||
creatorProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
//
|
|
||||||
// ContentMainNewContentView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2023/08/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentMainNewContentView: View {
|
|
||||||
|
|
||||||
let themes: [String]
|
|
||||||
let items: [GetAudioContentMainItem]
|
|
||||||
|
|
||||||
let selectTheme: (String) -> Void
|
|
||||||
@Binding var selectedTheme: String
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("새로운 콘텐츠")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Image("ic_forward")
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 20, height: 20)
|
|
||||||
.onTapGesture {
|
|
||||||
AppState.shared.setAppStep(step: .newContentAll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentMainNewContentThemeView(themes: themes, selectTheme: selectTheme, selectedTheme: $selectedTheme)
|
|
||||||
.padding(.vertical, 16.7)
|
|
||||||
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
HStack(alignment: .top, spacing: 13.3) {
|
|
||||||
ForEach(0..<items.count, id: \.self) {
|
|
||||||
ContentMainItemView(item: items[$0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentMainNewContentView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentMainNewContentView(
|
|
||||||
themes: ["전체", "테마1", "테마2"],
|
|
||||||
items: [
|
|
||||||
GetAudioContentMainItem(
|
|
||||||
contentId: 1,
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
title: "테스트",
|
|
||||||
creatorId: 7,
|
|
||||||
creatorProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
creatorNickname: "유저1"
|
|
||||||
)
|
|
||||||
],
|
|
||||||
selectTheme: { _ in },
|
|
||||||
selectedTheme: .constant("전체")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,7 +19,7 @@ struct ContentMainView: View {
|
||||||
RefreshableScrollView(
|
RefreshableScrollView(
|
||||||
refreshing: $viewModel.isLoading,
|
refreshing: $viewModel.isLoading,
|
||||||
action: {
|
action: {
|
||||||
viewModel.getMain()
|
viewModel.refresh()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
LazyVStack(alignment: .leading, spacing: 0) {
|
LazyVStack(alignment: .leading, spacing: 0) {
|
||||||
|
@ -29,46 +29,28 @@ struct ContentMainView: View {
|
||||||
.padding(.bottom, 26.7)
|
.padding(.bottom, 26.7)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
|
|
||||||
if viewModel.newContentUploadCreatorList.count > 0 {
|
if !viewModel.isLoading {
|
||||||
ContentMainNewContentCreatorView(items: viewModel.newContentUploadCreatorList)
|
ContentMainNewContentCreatorView()
|
||||||
.padding(.bottom, 26.7)
|
.padding(.bottom, 26.7)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
}
|
|
||||||
|
|
||||||
if viewModel.bannerList.count > 0 {
|
ContentMainBannerView()
|
||||||
ContentMainBannerView(items: viewModel.bannerList)
|
|
||||||
.padding(.bottom, 40)
|
.padding(.bottom, 40)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
}
|
|
||||||
|
|
||||||
if viewModel.orderList.count > 0 {
|
ContentMainMyStashView()
|
||||||
ContentMainMyStashView(items: viewModel.orderList)
|
|
||||||
.padding(.bottom, 40)
|
.padding(.bottom, 40)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
}
|
|
||||||
|
|
||||||
ContentMainNewContentView(
|
ContentMainNewContentView()
|
||||||
themes: viewModel.themeList,
|
|
||||||
items: viewModel.newContentList,
|
|
||||||
selectTheme: { viewModel.selectedTheme = $0 },
|
|
||||||
selectedTheme: $viewModel.selectedTheme
|
|
||||||
)
|
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
|
|
||||||
if let contentRanking = viewModel.contentRanking {
|
ContentMainRankingView()
|
||||||
ContentMainRankingView(
|
|
||||||
sorts: viewModel.contentRankingSortList,
|
|
||||||
item: contentRanking,
|
|
||||||
selectSort: { viewModel.selectedContentRankingSort = $0 },
|
|
||||||
selectedSort: $viewModel.selectedContentRankingSort
|
|
||||||
)
|
|
||||||
.padding(.top, 40)
|
.padding(.top, 40)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.animation(nil)
|
.animation(nil)
|
||||||
}
|
|
||||||
|
|
||||||
if viewModel.curationList.count > 0 {
|
ContentMainCurationView()
|
||||||
ContentMainCurationView(items: viewModel.curationList)
|
|
||||||
.padding(.top, 40)
|
.padding(.top, 40)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 20)
|
||||||
}
|
}
|
||||||
|
@ -100,28 +82,6 @@ struct ContentMainView: View {
|
||||||
LoadingView()
|
LoadingView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) {
|
|
||||||
GeometryReader { geo in
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Text(viewModel.errorMessage)
|
|
||||||
.padding(.vertical, 13.3)
|
|
||||||
.padding(.horizontal, 6.7)
|
|
||||||
.frame(width: geo.size.width - 66.7, alignment: .center)
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
|
||||||
.background(Color(hex: "9970ff"))
|
|
||||||
.foregroundColor(Color.white)
|
|
||||||
.multilineTextAlignment(.leading)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.cornerRadius(20)
|
|
||||||
.padding(.top, 66.7)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
viewModel.getMain()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,165 +10,13 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
final class ContentMainViewModel: ObservableObject {
|
final class ContentMainViewModel: ObservableObject {
|
||||||
|
|
||||||
private let repository = ContentRepository()
|
|
||||||
private var subscription = Set<AnyCancellable>()
|
|
||||||
|
|
||||||
@Published var errorMessage = ""
|
|
||||||
@Published var isShowPopup = false
|
|
||||||
@Published var isLoading = false
|
@Published var isLoading = false
|
||||||
|
|
||||||
@Published var newContentUploadCreatorList = [GetNewContentUploadCreator]()
|
func refresh() {
|
||||||
@Published var newContentList = [GetAudioContentMainItem]()
|
|
||||||
@Published var bannerList = [GetAudioContentBannerResponse]()
|
|
||||||
@Published var orderList = [GetAudioContentMainItem]()
|
|
||||||
@Published var themeList = [String]()
|
|
||||||
@Published var curationList = [GetAudioContentCurationResponse]()
|
|
||||||
@Published var contentRankingSortList = [String]()
|
|
||||||
@Published var contentRanking: GetAudioContentRanking? = nil
|
|
||||||
|
|
||||||
@Published var selectedTheme = "전체" {
|
|
||||||
didSet {
|
|
||||||
getNewContentOfTheme()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Published var selectedContentRankingSort = "매출" {
|
|
||||||
didSet {
|
|
||||||
getContentRanking()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMain() {
|
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
repository.getMain()
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [unowned self] in
|
||||||
.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<GetAudioContentMainResponse>.self, from: responseData)
|
|
||||||
self.isLoading = false
|
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success {
|
|
||||||
self.newContentUploadCreatorList.removeAll()
|
|
||||||
self.newContentList.removeAll()
|
|
||||||
self.bannerList.removeAll()
|
|
||||||
self.orderList.removeAll()
|
|
||||||
self.curationList.removeAll()
|
|
||||||
self.themeList.removeAll()
|
|
||||||
self.contentRankingSortList.removeAll()
|
|
||||||
|
|
||||||
self.newContentUploadCreatorList.append(contentsOf: data.newContentUploadCreatorList)
|
|
||||||
self.newContentList.append(contentsOf: data.newContentList)
|
|
||||||
self.bannerList.append(contentsOf: data.bannerList)
|
|
||||||
self.orderList.append(contentsOf: data.orderList)
|
|
||||||
self.curationList.append(contentsOf: data.curationList)
|
|
||||||
self.contentRanking = data.contentRanking
|
|
||||||
self.contentRankingSortList.append(contentsOf: data.contentRankingSortTypeList)
|
|
||||||
|
|
||||||
self.themeList.append("전체")
|
|
||||||
self.themeList.append(contentsOf: data.themeList)
|
|
||||||
} else {
|
|
||||||
if let message = decoded.message {
|
|
||||||
self.errorMessage = message
|
|
||||||
} else {
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
}
|
|
||||||
|
|
||||||
self.isShowPopup = true
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
print(error)
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
self.isShowPopup = true
|
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &subscription)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNewContentOfTheme() {
|
|
||||||
repository.getNewContentOfTheme(theme: selectedTheme == "전체" ? "" : selectedTheme)
|
|
||||||
.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<[GetAudioContentMainItem]>.self, from: responseData)
|
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success {
|
|
||||||
self.newContentList.removeAll()
|
|
||||||
self.newContentList.append(contentsOf: 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getContentRanking() {
|
|
||||||
isLoading = true
|
|
||||||
|
|
||||||
repository.getContentRanking(page: 1, size: 12, sortType: selectedContentRankingSort)
|
|
||||||
.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<GetAudioContentRanking>.self, from: responseData)
|
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success {
|
|
||||||
self.contentRanking = 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// ContentMainCurationView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/08/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentMainCurationView: View {
|
||||||
|
|
||||||
|
@StateObject private var viewModel = ContentMainCurationViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
if !viewModel.curationList.isEmpty {
|
||||||
|
LazyVStack(spacing: 40) {
|
||||||
|
ForEach(0..<viewModel.curationList.count, id: \.self) { index in
|
||||||
|
ContentMainCurationItemView(item: viewModel.curationList[index])
|
||||||
|
.padding(.horizontal, 13.3)
|
||||||
|
.onAppear {
|
||||||
|
if index == viewModel.curationList.count - 1 {
|
||||||
|
viewModel.getCurationList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ActivityIndicatorView()
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.page = 1
|
||||||
|
viewModel.isLast = false
|
||||||
|
viewModel.getCurationList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
//
|
||||||
|
// ContentMainCurationViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainCurationViewModel: ObservableObject {
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var curationList = [GetAudioContentCurationResponse]()
|
||||||
|
|
||||||
|
var isLast = false
|
||||||
|
var page = 1
|
||||||
|
private let size = 10
|
||||||
|
|
||||||
|
func getCurationList() {
|
||||||
|
if !isLoading && !isLast {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getCurationList(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
|
||||||
|
self.isLoading = false
|
||||||
|
let responseData = response.data
|
||||||
|
|
||||||
|
do {
|
||||||
|
let jsonDecoder = JSONDecoder()
|
||||||
|
let decoded = try jsonDecoder.decode(ApiResponse<[GetAudioContentCurationResponse]>.self, from: responseData)
|
||||||
|
self.isLoading = false
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
if page == 1 {
|
||||||
|
self.curationList.removeAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.isEmpty {
|
||||||
|
page += 1
|
||||||
|
self.curationList.append(contentsOf: data)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// ContentMainNewContentView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/08/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentMainNewContentView: View {
|
||||||
|
|
||||||
|
@StateObject private var viewModel = ContentMainNewContentViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 16.7) {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Text("새로운 콘텐츠")
|
||||||
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Image("ic_forward")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.onTapGesture {
|
||||||
|
AppState.shared.setAppStep(step: .newContentAll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !viewModel.themeList.isEmpty {
|
||||||
|
ContentMainNewContentThemeView(
|
||||||
|
themes: viewModel.themeList,
|
||||||
|
selectTheme: { theme in
|
||||||
|
viewModel.selectedTheme = theme
|
||||||
|
},
|
||||||
|
selectedTheme: $viewModel.selectedTheme
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !viewModel.newContentList.isEmpty {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
HStack(alignment: .top, spacing: 13.3) {
|
||||||
|
ForEach(0..<viewModel.newContentList.count, id: \.self) {
|
||||||
|
ContentMainItemView(item: viewModel.newContentList[$0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ActivityIndicatorView()
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.getThemeList()
|
||||||
|
viewModel.getNewContentOfTheme()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentMainNewContentView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ContentMainNewContentView()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
//
|
||||||
|
// ContentMainNewContentViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainNewContentViewModel: ObservableObject {
|
||||||
|
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var themeList = [String]()
|
||||||
|
@Published var newContentList = [GetAudioContentMainItem]()
|
||||||
|
|
||||||
|
@Published var selectedTheme = "전체" {
|
||||||
|
didSet {
|
||||||
|
newContentList.removeAll()
|
||||||
|
getNewContentOfTheme()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getThemeList() {
|
||||||
|
repository.getNewContentThemeList()
|
||||||
|
.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<[String]>.self, from: responseData)
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.themeList.append("전체")
|
||||||
|
self.themeList.append(contentsOf: 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNewContentOfTheme() {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getNewContentOfTheme(theme: selectedTheme == "전체" ? "" : selectedTheme)
|
||||||
|
.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<[GetAudioContentMainItem]>.self, from: responseData)
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.newContentList.removeAll()
|
||||||
|
self.newContentList.append(contentsOf: 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// ContentMainNewContentCreatorView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/08/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentMainNewContentCreatorView: View {
|
||||||
|
|
||||||
|
@StateObject private var viewModel = ContentMainNewContentCreatorViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
if !viewModel.newContentUploadCreatorList.isEmpty {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack(spacing: 21.3) {
|
||||||
|
ForEach(0..<viewModel.newContentUploadCreatorList.count, id: \.self) { index in
|
||||||
|
let item = viewModel.newContentUploadCreatorList[index]
|
||||||
|
ContentMainNewContentCreatorItemView(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ActivityIndicatorView()
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.getNewContentUploadCreatorList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentMainNewContentCreatorView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ContentMainNewContentCreatorView()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// ContentMainNewContentCreatorViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainNewContentCreatorViewModel: ObservableObject {
|
||||||
|
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var newContentUploadCreatorList = [GetNewContentUploadCreator]()
|
||||||
|
|
||||||
|
func getNewContentUploadCreatorList() {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getNewContentUploadCreatorList()
|
||||||
|
.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<[GetNewContentUploadCreator]>.self, from: responseData)
|
||||||
|
self.isLoading = false
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.newContentUploadCreatorList.removeAll()
|
||||||
|
self.newContentUploadCreatorList.append(contentsOf: data)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// ContentMainMyStashView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/08/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentMainMyStashView: View {
|
||||||
|
|
||||||
|
@StateObject private var viewModel = ContentMainMyStashViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
if !viewModel.orderList.isEmpty {
|
||||||
|
VStack(alignment: .leading, spacing: 13.3) {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Text("내 보관함")
|
||||||
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text("전체보기")
|
||||||
|
.font(.custom(Font.light.rawValue, size: 11.3))
|
||||||
|
.foregroundColor(Color(hex: "bbbbbb"))
|
||||||
|
.onTapGesture {
|
||||||
|
AppState.shared.setAppStep(step: .orderListAll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack(alignment: .top, spacing: 13.3) {
|
||||||
|
ForEach(0..<viewModel.orderList.count, id: \.self) { index in
|
||||||
|
let item = viewModel.orderList[index]
|
||||||
|
ContentMainItemView(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ActivityIndicatorView()
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.getOrderList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentMainMyStashView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ContentMainMyStashView()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// ContentMainMyStashViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainMyStashViewModel: ObservableObject {
|
||||||
|
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var orderList = [GetAudioContentMainItem]()
|
||||||
|
|
||||||
|
func getOrderList() {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getMainOrderList()
|
||||||
|
.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<[GetAudioContentMainItem]>.self, from: responseData)
|
||||||
|
self.isLoading = false
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.orderList.removeAll()
|
||||||
|
self.orderList.append(contentsOf: data)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,11 +10,7 @@ import Kingfisher
|
||||||
|
|
||||||
struct ContentMainRankingView: View {
|
struct ContentMainRankingView: View {
|
||||||
|
|
||||||
let sorts: [String]
|
@StateObject private var viewModel = ContentMainRankingViewModel()
|
||||||
let item: GetAudioContentRanking
|
|
||||||
|
|
||||||
let selectSort: (String) -> Void
|
|
||||||
@Binding var selectedSort: String
|
|
||||||
|
|
||||||
let rows = [
|
let rows = [
|
||||||
GridItem(.fixed(60), alignment: .leading),
|
GridItem(.fixed(60), alignment: .leading),
|
||||||
|
@ -23,7 +19,7 @@ struct ContentMainRankingView: View {
|
||||||
]
|
]
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 16.7) {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Text("인기 콘텐츠")
|
Text("인기 콘텐츠")
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
|
@ -38,7 +34,7 @@ struct ContentMainRankingView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
Text("\(item.startDate) ~ \(item.endDate)")
|
Text("\(viewModel.dateString)")
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
|
@ -49,15 +45,19 @@ struct ContentMainRankingView: View {
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
.background(Color(hex: "222222"))
|
.background(Color(hex: "222222"))
|
||||||
.padding(.top, 13.3)
|
|
||||||
|
|
||||||
ContentMainRankingSortView(sorts: sorts, selectSort: selectSort, selectedSort: $selectedSort)
|
if !viewModel.contentRankingSortList.isEmpty {
|
||||||
.padding(.vertical, 16.7)
|
ContentMainRankingSortView(
|
||||||
|
sorts: viewModel.contentRankingSortList,
|
||||||
|
selectSort: { viewModel.selectedContentRankingSort = $0 },
|
||||||
|
selectedSort: $viewModel.selectedContentRankingSort
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
LazyHGrid(rows: rows, spacing: 13.3) {
|
LazyHGrid(rows: rows, spacing: 13.3) {
|
||||||
ForEach(0..<item.items.count, id: \.self) { index in
|
ForEach(0..<viewModel.contentRankingItemList.count, id: \.self) { index in
|
||||||
let content = item.items[index]
|
let content = viewModel.contentRankingItemList[index]
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
KFImage(URL(string: content.coverImageUrl))
|
KFImage(URL(string: content.coverImageUrl))
|
||||||
.resizable()
|
.resizable()
|
||||||
|
@ -91,63 +91,17 @@ struct ContentMainRankingView: View {
|
||||||
}
|
}
|
||||||
.frame(height: 207)
|
.frame(height: 207)
|
||||||
}
|
}
|
||||||
.padding(.top, 13.3)
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onAppear {
|
||||||
|
viewModel.getContentRankingSortType()
|
||||||
|
viewModel.getContentRanking()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentMainRankingView_Previews: PreviewProvider {
|
struct ContentMainRankingView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ContentMainRankingView(
|
ContentMainRankingView()
|
||||||
sorts: ["매출", "후원", "댓글"],
|
|
||||||
item: GetAudioContentRanking(
|
|
||||||
startDate: "2023년 10월 2일",
|
|
||||||
endDate: "10월 9일",
|
|
||||||
items: [
|
|
||||||
GetAudioContentRankingItem(
|
|
||||||
contentId: 10,
|
|
||||||
title: "sdffsfddfs",
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/audio_content_cover/27/27-cover-77e3a23f-23f2-467c-867f-3e6b7e08060c-9136-1696424061456",
|
|
||||||
themeStr: "커버곡",
|
|
||||||
price: 10,
|
|
||||||
duration: "00:30:20",
|
|
||||||
creatorId: 1,
|
|
||||||
creatorNickname: "ㄹㄴ어ㅏㅣㅇㄴ런아ㅣ"
|
|
||||||
),
|
|
||||||
GetAudioContentRankingItem(
|
|
||||||
contentId: 10,
|
|
||||||
title: "sdffsfddfs",
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/audio_content_cover/27/27-cover-77e3a23f-23f2-467c-867f-3e6b7e08060c-9136-1696424061456",
|
|
||||||
themeStr: "커버곡",
|
|
||||||
price: 10,
|
|
||||||
duration: "00:30:20",
|
|
||||||
creatorId: 1,
|
|
||||||
creatorNickname: "ㄹㄴ어ㅏㅣㅇㄴ런아ㅣ"
|
|
||||||
),
|
|
||||||
GetAudioContentRankingItem(
|
|
||||||
contentId: 10,
|
|
||||||
title: "sdffsfddfs",
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/audio_content_cover/27/27-cover-77e3a23f-23f2-467c-867f-3e6b7e08060c-9136-1696424061456",
|
|
||||||
themeStr: "커버곡",
|
|
||||||
price: 10,
|
|
||||||
duration: "00:30:20",
|
|
||||||
creatorId: 1,
|
|
||||||
creatorNickname: "ㄹㄴ어ㅏㅣㅇㄴ런아ㅣ"
|
|
||||||
),
|
|
||||||
GetAudioContentRankingItem(
|
|
||||||
contentId: 10,
|
|
||||||
title: "sdffsfddfs",
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/audio_content_cover/27/27-cover-77e3a23f-23f2-467c-867f-3e6b7e08060c-9136-1696424061456",
|
|
||||||
themeStr: "커버곡",
|
|
||||||
price: 10,
|
|
||||||
duration: "00:30:20",
|
|
||||||
creatorId: 1,
|
|
||||||
creatorNickname: "ㄹㄴ어ㅏㅣㅇㄴ런아ㅣ"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
selectSort: { _ in },
|
|
||||||
selectedSort: .constant("매출")
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
//
|
||||||
|
// ContentMainRankingViewModel.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2023/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
final class ContentMainRankingViewModel: ObservableObject {
|
||||||
|
|
||||||
|
private let repository = ContentRepository()
|
||||||
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@Published var errorMessage = ""
|
||||||
|
@Published var isShowPopup = false
|
||||||
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var dateString = ""
|
||||||
|
@Published var contentRankingSortList = [String]()
|
||||||
|
@Published var contentRankingItemList = [GetAudioContentRankingItem]()
|
||||||
|
|
||||||
|
@Published var selectedContentRankingSort = "매출" {
|
||||||
|
didSet {
|
||||||
|
getContentRanking()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContentRankingSortType() {
|
||||||
|
repository.getContentRankingSortType()
|
||||||
|
.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<[String]>.self, from: responseData)
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
self.contentRankingSortList.removeAll()
|
||||||
|
self.contentRankingSortList.append(contentsOf: 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContentRanking() {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
repository.getContentRanking(page: 1, size: 12, sortType: selectedContentRankingSort)
|
||||||
|
.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<GetAudioContentRanking>.self, from: responseData)
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
dateString = "\(data.startDate)~\(data.endDate)"
|
||||||
|
self.contentRankingItemList.append(contentsOf: data.items)
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue