feat(home): 홈 추천 콘텐츠 섹션 추가
This commit is contained in:
@@ -14,12 +14,14 @@ struct ContentItemView: View {
|
||||
|
||||
let item: AudioContentMainItem
|
||||
|
||||
var itemSize: CGFloat = 160
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ZStack(alignment: .top) {
|
||||
DownsampledKFImage(
|
||||
url: URL(string: item.coverImageUrl),
|
||||
size: CGSize(width: 160, height: 160)
|
||||
size: CGSize(width: itemSize, height: itemSize)
|
||||
)
|
||||
.cornerRadius(16)
|
||||
|
||||
@@ -51,7 +53,7 @@ struct ContentItemView: View {
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
.frame(width: 160)
|
||||
.frame(width: itemSize)
|
||||
.onTapGesture {
|
||||
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
AppState.shared.setAppStep(step: .contentDetail(contentId: item.contentId))
|
||||
|
||||
@@ -20,4 +20,5 @@ struct GetHomeResponse: Decodable {
|
||||
let recommendChannelList: [RecommendChannelResponse]
|
||||
let freeContentList: [AudioContentMainItem]
|
||||
let pointAvailableContentList: [AudioContentMainItem]
|
||||
let recommendContentList: [AudioContentMainItem]
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ enum HomeApi {
|
||||
case getHomeData(isAdultContentVisible: Bool, contentType: ContentType)
|
||||
case getLatestContentByTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType)
|
||||
case getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek, isAdultContentVisible: Bool, contentType: ContentType)
|
||||
case getRecommendContents(isAdultContentVisible: Bool, contentType: ContentType)
|
||||
}
|
||||
|
||||
extension HomeApi: TargetType {
|
||||
@@ -29,6 +30,9 @@ extension HomeApi: TargetType {
|
||||
|
||||
case .getDayOfWeekSeriesList:
|
||||
return "/api/home/day-of-week-series"
|
||||
|
||||
case .getRecommendContents:
|
||||
return "/api/home/recommend-contents"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +67,14 @@ extension HomeApi: TargetType {
|
||||
"contentType": contentType
|
||||
] as [String: Any]
|
||||
|
||||
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
|
||||
|
||||
case .getRecommendContents(let isAdultContentVisible, let contentType):
|
||||
let parameters = [
|
||||
"isAdultContentVisible": isAdultContentVisible,
|
||||
"contentType": contentType
|
||||
] as [String: Any]
|
||||
|
||||
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,13 @@ class HomeTabRepository {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func getRecommendContents() -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(
|
||||
.getRecommendContents(
|
||||
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
|
||||
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +327,46 @@ struct HomeTabView: View {
|
||||
}
|
||||
}
|
||||
|
||||
if !viewModel.recommendContentList.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
HStack {
|
||||
Text("추천 콘텐츠")
|
||||
.font(.custom(Font.preBold.rawValue, size: 24))
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image("ic_refresh")
|
||||
.onTapGesture {
|
||||
viewModel.refreshRecommendContents()
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 24)
|
||||
|
||||
let horizontalPadding: CGFloat = 24
|
||||
let gridSpacing: CGFloat = 16
|
||||
let width = (screenSize().width - (horizontalPadding * 2) - gridSpacing) / 2
|
||||
|
||||
LazyVGrid(
|
||||
columns: Array(
|
||||
repeating: GridItem(
|
||||
.flexible(),
|
||||
spacing: gridSpacing,
|
||||
alignment: .topLeading
|
||||
),
|
||||
count: 2
|
||||
),
|
||||
alignment: .leading,
|
||||
spacing: gridSpacing
|
||||
) {
|
||||
ForEach(viewModel.recommendContentList.indices, id: \.self) { idx in
|
||||
ContentItemView(item: viewModel.recommendContentList[idx], itemSize: width)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, horizontalPadding)
|
||||
}
|
||||
}
|
||||
|
||||
Text("""
|
||||
- 회사명 : 주식회사 소다라이브
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ final class HomeTabViewModel: ObservableObject {
|
||||
@Published var recommendChannelList: [RecommendChannelResponse] = []
|
||||
@Published var freeContentList: [AudioContentMainItem] = []
|
||||
@Published var pointAvailableContentList: [AudioContentMainItem] = []
|
||||
@Published var recommendContentList: [AudioContentMainItem] = []
|
||||
|
||||
func fetchData() {
|
||||
isLoading = true
|
||||
@@ -65,6 +66,7 @@ final class HomeTabViewModel: ObservableObject {
|
||||
self.recommendChannelList = data.recommendChannelList
|
||||
self.freeContentList = data.freeContentList
|
||||
self.pointAvailableContentList = data.pointAvailableContentList
|
||||
self.recommendContentList = data.recommendContentList
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
@@ -197,4 +199,42 @@ final class HomeTabViewModel: ObservableObject {
|
||||
}
|
||||
.store(in: &subscription)
|
||||
}
|
||||
|
||||
func refreshRecommendContents() {
|
||||
isLoading = true
|
||||
|
||||
repository.getRecommendContents()
|
||||
.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<[AudioContentMainItem]>.self, from: responseData)
|
||||
|
||||
if let data = decoded.data, decoded.success {
|
||||
self.recommendContentList = 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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user