콘텐츠 메인, 라이브 메인, 오디션 메인, 마이페이지

- 로그인 하지 않고 페이지 조회가 되도록 수정
This commit is contained in:
Yu Sung
2025-03-24 18:32:27 +09:00
parent fa94c5447f
commit 80cb19a1c7
32 changed files with 874 additions and 595 deletions

View File

@@ -41,6 +41,7 @@ enum ContentApi {
case getContentMainHome(isAdultContentVisible: Bool, contentType: ContentType)
case getPopularContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainHomeContentRanking(isAdultContentVisible: Bool, contentType: ContentType, sortType: String)
case getContentMainSeries(isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendSeriesListByGenre(genreId: Int, isAdultContentVisible: Bool, contentType: ContentType)
@@ -168,6 +169,9 @@ extension ContentApi: TargetType {
case .getPopularContentByCreator:
return "/v2/audio-content/main/home/popular-content-by-creator"
case .getContentMainHomeContentRanking:
return "/v2/audio-content/main/home/content/ranking"
case .getContentMainSeries:
return "/v2/audio-content/main/series"
@@ -238,7 +242,7 @@ extension ContentApi: TargetType {
case .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList, .getCurationList, .getAudioContentByTheme:
return .get
case .getContentMainHome, .getPopularContentByCreator, .getContentMainSeries, .getRecommendSeriesListByGenre, .getRecommendSeriesByCreator, .getContentMainContent,
case .getContentMainHome, .getPopularContentByCreator, .getContentMainHomeContentRanking, .getContentMainSeries, .getRecommendSeriesListByGenre, .getRecommendSeriesByCreator, .getContentMainContent,
.getContentMainNewContentOfTheme, .getDailyContentRanking, .getRecommendContentByTag, .getContentMainAlarm, .getContentMainAlarmAll,
.getContentMainAsmr, .getPopularAsmrContentByCreator, .getContentMainReplay, .getPopularReplayContentByCreator,
.getContentMainFree, .getIntroduceCreatorList, .getNewFreeContentOfTheme, .getPopularFreeContentByCreator, .getCompletedSeries, .getContentMainContentPopularContentByCreator:
@@ -439,6 +443,15 @@ extension ContentApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainHomeContentRanking(let isAdultContentVisible, let contentType, let sortType):
let parameters = [
"sort-type": sortType,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendSeriesByCreator(let creatorId, let isAdultContentVisible, let contentType):
let parameters = [
"creatorId": creatorId,

View File

@@ -11,6 +11,8 @@ import Kingfisher
struct ContentMainTabRankContentView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let rows = [
GridItem(.fixed(60), alignment: .leading),
GridItem(.fixed(60), alignment: .leading),
@@ -92,9 +94,13 @@ struct ContentMainTabRankContentView: View {
.frame(width: screenSize().width * 0.66, alignment: .leading)
.contentShape(Rectangle())
.onTapGesture {
AppState
.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}

View File

@@ -10,6 +10,8 @@ import Kingfisher
struct ContentByChannelView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let title: String
let creatorList: [ContentCreatorResponse]
let contentList: [GetAudioContentRankingItem]
@@ -111,15 +113,23 @@ struct ContentByChannelView: View {
.foregroundColor(.gray77)
}
.onTapGesture {
AppState
.shared
.setAppStep(step: .creatorDetail(userId: content.creatorId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: content.creatorId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
.onTapGesture {
AppState
.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}

View File

@@ -31,4 +31,14 @@ class ContentMainTabHomeRepository {
)
)
}
func getContentRanking(sortType: String = "매출") -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getContentMainHomeContentRanking(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
sortType: sortType
)
)
}
}

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct ContentMainTabHomeView: View {
@StateObject var viewModel = ContentMainTabHomeViewModel()
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
@@ -29,10 +30,12 @@ struct ContentMainTabHomeView: View {
Spacer()
Image("ic_content_keep")
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_content_keep")
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
}
}
.padding(.horizontal, 13.3)
@@ -45,153 +48,156 @@ struct ContentMainTabHomeView: View {
.padding(.horizontal, 13.3)
}
if viewModel.bannerList.count > 0 {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
viewModel.bannerList.count > 0 {
ContentMainBannerViewV2(bannerList: viewModel.bannerList)
.padding(.top, 30)
.padding(.horizontal, 13.3)
}
HStack(spacing: 0) {
Image("ic_title_search_black")
Text("채널명을 입력해 보세요")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.gray55)
.keyboardType(.default)
.padding(.horizontal, 13.3)
Spacer()
}
.padding(.horizontal, 21.3)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color.gray22)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.strokeBorder(lineWidth: 1)
.foregroundColor(Color.graybb)
)
.padding(.top, 30)
.padding(.horizontal, 13.3)
.onTapGesture {
UserDefaults.set("", forKey: .searchChannel)
AppState.shared.setAppStep(step: .searchChannel)
}
VStack(spacing: 13.3) {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_series",
title: "시리즈",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .SERIES
)
)
}
)
.frame(maxWidth: .infinity)
Image("ic_title_search_black")
ContentMainTabCategoryView(
imageName: "ic_category_content",
title: "단편",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .CONTENT
)
)
}
)
.frame(maxWidth: .infinity)
Text("채널명을 입력해 보세요")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.gray55)
.keyboardType(.default)
.padding(.horizontal, 13.3)
ContentMainTabCategoryView(
imageName: "ic_category_alarm",
title: "모닝콜",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ALARM
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_asmr",
title: "ASMR",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ASMR
)
)
}
)
.frame(maxWidth: .infinity)
Spacer()
}
.padding(.horizontal, 21.3)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color.gray22)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.strokeBorder(lineWidth: 1)
.foregroundColor(Color.graybb)
)
.padding(.top, 30)
.padding(.horizontal, 13.3)
.onTapGesture {
UserDefaults.set("", forKey: .searchChannel)
AppState.shared.setAppStep(step: .searchChannel)
}
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_replay",
title: "다시듣기",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .REPLAY
VStack(spacing: 13.3) {
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_series",
title: "시리즈",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .SERIES
)
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_free",
title: "무료",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .FREE
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_content",
title: "단편",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .CONTENT
)
)
)
}
)
.frame(maxWidth: .infinity)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_alarm",
title: "모닝콜",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ALARM
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_asmr",
title: "ASMR",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ASMR
)
)
}
)
.frame(maxWidth: .infinity)
}
ContentMainTabCategoryView(
imageName: "ic_category_audio_book",
title: "오디오북",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_toon",
title: "오디오툰",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_replay",
title: "다시듣기",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .REPLAY
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_free",
title: "무료",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .FREE
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_book",
title: "오디오북",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_toon",
title: "오디오툰",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
}
}
.padding(.vertical, 13.3)
.background(Color.gray22)
.cornerRadius(5.3)
.padding(.top, 30)
.padding(.horizontal, 13.3)
}
.padding(.vertical, 13.3)
.background(Color.gray22)
.cornerRadius(5.3)
.padding(.top, 30)
.padding(.horizontal, 13.3)
if let response = viewModel.rankCreatorResponse {
ContentMainTabHomeRankCreatorView(response: response)
@@ -210,7 +216,11 @@ struct ContentMainTabHomeView: View {
title: "인기 단편",
isMore: true,
onClickMore: {
AppState.shared.setAppStep(step: .contentRankingAll)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .contentRankingAll)
} else {
AppState.shared.setAppStep(step: .login)
}
},
sortList: !viewModel.rankSortTypeList.isEmpty ?
viewModel.rankSortTypeList :
@@ -221,7 +231,8 @@ struct ContentMainTabHomeView: View {
.padding(.top, 30)
}
if viewModel.eventBannerList.count > 0 {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
viewModel.eventBannerList.count > 0 {
SectionEventBannerView(items: viewModel.eventBannerList)
.padding(.top, 30)
}

View File

@@ -11,7 +11,6 @@ import Combine
final class ContentMainTabHomeViewModel: ObservableObject {
private let repository = ContentMainTabHomeRepository()
private let contentRepository = ContentRepository()
private var subscription = Set<AnyCancellable>()
@Published var errorMessage = ""
@@ -77,7 +76,7 @@ final class ContentMainTabHomeViewModel: ObservableObject {
func getContentRanking(sort: String = "매출") {
isLoading = true
contentRepository.getContentRanking(page: 1, size: 12, sortType: sort)
repository.getContentRanking(sortType: sort)
.sink { result in
switch result {
case .finished:
@@ -90,10 +89,10 @@ final class ContentMainTabHomeViewModel: ObservableObject {
do {
let jsonDecoder = JSONDecoder()
let decoded = try jsonDecoder.decode(ApiResponse<GetAudioContentRanking>.self, from: responseData)
let decoded = try jsonDecoder.decode(ApiResponse<[GetAudioContentRankingItem]>.self, from: responseData)
if let data = decoded.data, decoded.success {
self.rankContentList = data.items
self.rankContentList = data
} else {
if let message = decoded.message {
self.errorMessage = message

View File

@@ -10,6 +10,8 @@ import Kingfisher
struct ContentMainTabHomeRankCreatorView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let response: GetExplorerSectionResponse
let rankingCrawns = ["ic_crown_1", "ic_crown_2", "ic_crown_3"]
@@ -121,8 +123,13 @@ struct ContentMainTabHomeRankCreatorView: View {
}
.contentShape(Rectangle())
.onTapGesture {
AppState.shared
.setAppStep(step: .creatorDetail(userId: creator.id))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: creator.id))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}