parent
638d00ffc3
commit
62904d96b1
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// CategoryApi.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2/7/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Moya
|
||||||
|
|
||||||
|
enum CategoryApi {
|
||||||
|
case getCategoryList(creatorId: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension CategoryApi: TargetType {
|
||||||
|
var baseURL: URL {
|
||||||
|
return URL(string: BASE_URL)!
|
||||||
|
}
|
||||||
|
|
||||||
|
var path: String {
|
||||||
|
switch self {
|
||||||
|
case .getCategoryList:
|
||||||
|
return "/category"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var method: Moya.Method {
|
||||||
|
switch self {
|
||||||
|
case .getCategoryList:
|
||||||
|
return .get
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var task: Moya.Task {
|
||||||
|
switch self {
|
||||||
|
case .getCategoryList(let creatorId):
|
||||||
|
let parameters = ["creatorId": creatorId] as [String : Any]
|
||||||
|
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers: [String : String]? {
|
||||||
|
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// ContentListCategoryView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2/7/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentListCategoryView: View {
|
||||||
|
let categoryList: [GetCategoryListResponse]
|
||||||
|
let selectCategory: (Int) -> Void
|
||||||
|
|
||||||
|
@Binding var selectedCategory: String
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
ForEach(0..<categoryList.count, id: \.self) { index in
|
||||||
|
let category = categoryList[index]
|
||||||
|
Text(category.category)
|
||||||
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
|
.foregroundColor(Color(hex: selectedCategory == category.category ? "3bb9f1" : "777777"))
|
||||||
|
.padding(.horizontal, 13.3)
|
||||||
|
.padding(.vertical, 9.3)
|
||||||
|
.border(
|
||||||
|
Color(hex: selectedCategory == category.category ? "3bb9f1" : "eeeeee"),
|
||||||
|
width: 0.5
|
||||||
|
)
|
||||||
|
.cornerRadius(16.7)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: CGFloat(16.7))
|
||||||
|
.stroke(lineWidth: 0.5)
|
||||||
|
.foregroundColor(Color(hex: selectedCategory == category.category ? "3bb9f1" : "eeeeee"))
|
||||||
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
if selectedCategory != category.category {
|
||||||
|
selectedCategory = category.category
|
||||||
|
selectCategory(category.categoryId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
|
||||||
|
ContentListCategoryView(
|
||||||
|
categoryList: [
|
||||||
|
GetCategoryListResponse(categoryId: 0, category: "전체"),
|
||||||
|
GetCategoryListResponse(categoryId: 1, category: "test"),
|
||||||
|
GetCategoryListResponse(categoryId: 0, category: "test2")
|
||||||
|
],
|
||||||
|
selectCategory: { _ in },
|
||||||
|
selectedCategory: .constant("전체")
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// GetCategoryListResponse.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 2/7/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct GetCategoryListResponse: Decodable {
|
||||||
|
let categoryId: Int
|
||||||
|
let category: String
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import Foundation
|
||||||
import Moya
|
import Moya
|
||||||
|
|
||||||
enum ContentApi {
|
enum ContentApi {
|
||||||
case getAudioContentList(userId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort)
|
case getAudioContentList(userId: Int, categoryId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort)
|
||||||
case getAudioContentDetail(audioContentId: Int)
|
case getAudioContentDetail(audioContentId: Int)
|
||||||
case likeContent(request: PutAudioContentLikeRequest)
|
case likeContent(request: PutAudioContentLikeRequest)
|
||||||
case registerComment(request: RegisterAudioContentCommentRequest)
|
case registerComment(request: RegisterAudioContentCommentRequest)
|
||||||
|
@ -152,9 +152,10 @@ extension ContentApi: TargetType {
|
||||||
|
|
||||||
var task: Moya.Task {
|
var task: Moya.Task {
|
||||||
switch self {
|
switch self {
|
||||||
case .getAudioContentList(let userId, let page, let size, let sort):
|
case .getAudioContentList(let userId, let categoryId, let page, let size, let sort):
|
||||||
let parameters = [
|
let parameters = [
|
||||||
"creator-id": userId,
|
"creator-id": userId,
|
||||||
|
"category-id": categoryId,
|
||||||
"page": page - 1,
|
"page": page - 1,
|
||||||
"size": size,
|
"size": size,
|
||||||
"sort-type": sort
|
"sort-type": sort
|
||||||
|
|
|
@ -35,6 +35,15 @@ struct ContentListView: View {
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
.background(Color.black)
|
.background(Color.black)
|
||||||
|
|
||||||
|
if !viewModel.categoryList.isEmpty {
|
||||||
|
ContentListCategoryView(
|
||||||
|
categoryList: viewModel.categoryList,
|
||||||
|
selectCategory: { viewModel.selectCategory(categoryId: $0) },
|
||||||
|
selectedCategory: $viewModel.selectedCategory
|
||||||
|
)
|
||||||
|
.padding(.horizontal, 13.3)
|
||||||
|
}
|
||||||
|
|
||||||
if userId == UserDefaults.int(forKey: .userId) {
|
if userId == UserDefaults.int(forKey: .userId) {
|
||||||
Text("새로운 콘텐츠 등록하기")
|
Text("새로운 콘텐츠 등록하기")
|
||||||
.font(.custom(Font.bold.rawValue, size: 15))
|
.font(.custom(Font.bold.rawValue, size: 15))
|
||||||
|
@ -132,12 +141,14 @@ struct ContentListView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, 13.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.userId = userId
|
viewModel.userId = userId
|
||||||
|
viewModel.getCategoryList()
|
||||||
viewModel.getAudioContentList()
|
viewModel.getAudioContentList()
|
||||||
}
|
}
|
||||||
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .bottom, autohideIn: 2) {
|
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .bottom, autohideIn: 2) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ final class ContentListViewModel: ObservableObject {
|
||||||
@Published var isShowPopup = false
|
@Published var isShowPopup = false
|
||||||
@Published var isLoading = false
|
@Published var isLoading = false
|
||||||
|
|
||||||
|
@Published var categoryList: [GetCategoryListResponse] = []
|
||||||
@Published var audioContentList: [GetAudioContentListItem] = []
|
@Published var audioContentList: [GetAudioContentListItem] = []
|
||||||
@Published var totalCount = 0
|
@Published var totalCount = 0
|
||||||
@Published var sort = Sort.NEWEST {
|
@Published var sort = Sort.NEWEST {
|
||||||
|
@ -32,18 +33,20 @@ final class ContentListViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var scrollToTop = false
|
@Published var scrollToTop = false
|
||||||
|
@Published var selectedCategory: String = "전체"
|
||||||
|
|
||||||
var userId = 0
|
var userId = 0
|
||||||
var page = 1
|
var page = 1
|
||||||
var isLast = false
|
var isLast = false
|
||||||
private let pageSize = 10
|
private let pageSize = 10
|
||||||
|
private var categoryId = 0
|
||||||
|
|
||||||
func getAudioContentList() {
|
func getAudioContentList() {
|
||||||
if (!isLast && !isLoading) {
|
if (!isLast && !isLoading) {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
repository
|
repository
|
||||||
.getAudioContentList(userId: userId, page: page, size: pageSize, sort: sort)
|
.getAudioContentList(userId: userId, categoryId: categoryId, page: page, size: pageSize, sort: sort)
|
||||||
.sink { result in
|
.sink { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .finished:
|
case .finished:
|
||||||
|
@ -64,11 +67,11 @@ final class ContentListViewModel: ObservableObject {
|
||||||
self.scrollToTop.toggle()
|
self.scrollToTop.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !data.items.isEmpty {
|
page += 1
|
||||||
page += 1
|
self.totalCount = data.totalCount
|
||||||
self.totalCount = data.totalCount
|
self.audioContentList.append(contentsOf: data.items)
|
||||||
self.audioContentList.append(contentsOf: data.items)
|
|
||||||
} else {
|
if data.items.isEmpty {
|
||||||
isLast = true
|
isLast = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,4 +93,53 @@ final class ContentListViewModel: ObservableObject {
|
||||||
.store(in: &subscription)
|
.store(in: &subscription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCategoryList() {
|
||||||
|
repository.getCategoryList(creatorId: userId)
|
||||||
|
.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<[GetCategoryListResponse]>.self, from: responseData)
|
||||||
|
|
||||||
|
if let data = decoded.data, decoded.success {
|
||||||
|
categoryList.removeAll()
|
||||||
|
|
||||||
|
if !data.isEmpty {
|
||||||
|
categoryList.append(GetCategoryListResponse(categoryId: 0, category: "전체"))
|
||||||
|
categoryList.append(contentsOf: data)
|
||||||
|
}
|
||||||
|
} 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectCategory(categoryId: Int) {
|
||||||
|
self.categoryId = categoryId
|
||||||
|
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
getAudioContentList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,10 @@ import Moya
|
||||||
|
|
||||||
final class ContentRepository {
|
final class ContentRepository {
|
||||||
private let api = MoyaProvider<ContentApi>()
|
private let api = MoyaProvider<ContentApi>()
|
||||||
|
private let categoryApi = MoyaProvider<CategoryApi>()
|
||||||
|
|
||||||
func getAudioContentList(userId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort) -> AnyPublisher<Response, MoyaError> {
|
func getAudioContentList(userId: Int, categoryId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.getAudioContentList(userId: userId, page: page, size: size, sort: sort))
|
return api.requestPublisher(.getAudioContentList(userId: userId, categoryId: categoryId, page: page, size: size, sort: sort))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAudioContentDetail(audioContentId: Int) -> AnyPublisher<Response, MoyaError> {
|
func getAudioContentDetail(audioContentId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
|
@ -120,4 +121,8 @@ final class ContentRepository {
|
||||||
func unpinContent(contentId: Int) -> AnyPublisher<Response, MoyaError> {
|
func unpinContent(contentId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.unpinContent(contentId: contentId))
|
return api.requestPublisher(.unpinContent(contentId: contentId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCategoryList(creatorId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
|
return categoryApi.requestPublisher(.getCategoryList(creatorId: creatorId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue