콘텐츠 메인 - 숏플, 라이브 다시 듣기 추가
This commit is contained in:
		
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_can_gray.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_can_gray.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |   "images" : [ | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "filename" : "ic_card_can_gray.png", | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "info" : { | ||||||
|  |     "author" : "xcode", | ||||||
|  |     "version" : 1 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_can_gray.imageset/ic_card_can_gray.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_can_gray.imageset/ic_card_can_gray.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 552 B | 
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_time_small_gray.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_time_small_gray.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |   "images" : [ | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "filename" : "ic_card_time_small_gray.png", | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "info" : { | ||||||
|  |     "author" : "xcode", | ||||||
|  |     "version" : 1 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_time_small_gray.imageset/ic_card_time_small_gray.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_card_time_small_gray.imageset/ic_card_time_small_gray.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 543 B | 
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_short_play.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_short_play.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |   "images" : [ | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "filename" : "ic_short_play.png", | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "info" : { | ||||||
|  |     "author" : "xcode", | ||||||
|  |     "version" : 1 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_short_play.imageset/ic_short_play.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_short_play.imageset/ic_short_play.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_thumb_play_blue.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/ic_thumb_play_blue.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |   "images" : [ | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "filename" : "ic_thumb_play_blue.png", | ||||||
|  |       "idiom" : "universal", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "info" : { | ||||||
|  |     "author" : "xcode", | ||||||
|  |     "version" : 1 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_thumb_play_blue.imageset/ic_thumb_play_blue.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/ic_thumb_play_blue.imageset/ic_thumb_play_blue.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.9 KiB | 
| @@ -119,4 +119,6 @@ enum AppStep { | |||||||
|     case creatorCommunityModify(postId: Int, onSuccess: () -> Void) |     case creatorCommunityModify(postId: Int, onSuccess: () -> Void) | ||||||
|      |      | ||||||
|     case canCoupon |     case canCoupon | ||||||
|  |      | ||||||
|  |     case contentAllByTheme(themeId: Int) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										111
									
								
								SodaLive/Sources/Content/All/ByTheme/ContentAllByThemeView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								SodaLive/Sources/Content/All/ByTheme/ContentAllByThemeView.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | // | ||||||
|  | //  ContentAllByThemeView.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 2/14/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import SwiftUI | ||||||
|  |  | ||||||
|  | struct ContentAllByThemeView: View { | ||||||
|  |     @StateObject var viewModel = ContentAllByThemeViewModel() | ||||||
|  |      | ||||||
|  |     let themeId: Int | ||||||
|  |      | ||||||
|  |     let columns = [ | ||||||
|  |         GridItem(.flexible(), alignment: .top), | ||||||
|  |         GridItem(.flexible(), alignment: .top), | ||||||
|  |         GridItem(.flexible(), alignment: .top) | ||||||
|  |     ] | ||||||
|  |      | ||||||
|  |     var body: some View { | ||||||
|  |         NavigationView { | ||||||
|  |             BaseView(isLoading: $viewModel.isLoading) { | ||||||
|  |                 VStack(alignment: .leading, spacing: 0) { | ||||||
|  |                     DetailNavigationBar(title: viewModel.theme) | ||||||
|  |                      | ||||||
|  |                     HStack(spacing: 13.3) { | ||||||
|  |                         Spacer() | ||||||
|  |                          | ||||||
|  |                         Text("최신순") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor( | ||||||
|  |                                 Color(hex: "e2e2e2") | ||||||
|  |                                     .opacity(viewModel.sort == .NEWEST ? 1 : 0.5) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 if viewModel.sort != .NEWEST { | ||||||
|  |                                     viewModel.sort = .NEWEST | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                          | ||||||
|  |                         Text("높은 가격순") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor( | ||||||
|  |                                 Color(hex: "e2e2e2") | ||||||
|  |                                     .opacity(viewModel.sort == .PRICE_HIGH ? 1 : 0.5) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 if viewModel.sort != .PRICE_HIGH { | ||||||
|  |                                     viewModel.sort = .PRICE_HIGH | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                          | ||||||
|  |                         Text("낮은 가격순") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor( | ||||||
|  |                                 Color(hex: "e2e2e2") | ||||||
|  |                                     .opacity(viewModel.sort == .PRICE_LOW ? 1 : 0.5) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 if viewModel.sort != .PRICE_LOW { | ||||||
|  |                                     viewModel.sort = .PRICE_LOW | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                     } | ||||||
|  |                     .padding(.vertical, 13.3) | ||||||
|  |                     .padding(.horizontal, 20) | ||||||
|  |                     .background(Color(hex: "161616")) | ||||||
|  |                     .padding(.top, 13.3) | ||||||
|  |                      | ||||||
|  |                     HStack(spacing: 0) { | ||||||
|  |                         Text("전체") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor(Color(hex: "e2e2e2")) | ||||||
|  |                          | ||||||
|  |                         Text("\(viewModel.totalCount)") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor(Color(hex: "ff5c49")) | ||||||
|  |                             .padding(.leading, 8) | ||||||
|  |                          | ||||||
|  |                         Text("개") | ||||||
|  |                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|  |                             .foregroundColor(Color(hex: "e2e2e2")) | ||||||
|  |                             .padding(.leading, 2) | ||||||
|  |                          | ||||||
|  |                         Spacer() | ||||||
|  |                     } | ||||||
|  |                     .padding(.vertical, 13.3) | ||||||
|  |                     .padding(.horizontal, 20) | ||||||
|  |                      | ||||||
|  |                     ScrollView(.vertical, showsIndicators: false) { | ||||||
|  |                         LazyVGrid(columns: columns, spacing: 13.3) { | ||||||
|  |                             ForEach(0..<viewModel.contentList.count, id: \.self) { index in | ||||||
|  |                                 ContentNewAllItemView(item: viewModel.contentList[index]) | ||||||
|  |                                     .onAppear { | ||||||
|  |                                         if index == viewModel.contentList.count - 1 { | ||||||
|  |                                             viewModel.getContentList() | ||||||
|  |                                         } | ||||||
|  |                                     } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 .onAppear { | ||||||
|  |                     viewModel.themeId = themeId | ||||||
|  |                     viewModel.getContentList() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,96 @@ | |||||||
|  | // | ||||||
|  | //  ContentAllByThemeViewModel.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 2/14/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import Foundation | ||||||
|  | import Combine | ||||||
|  |  | ||||||
|  | final class ContentAllByThemeViewModel: ObservableObject { | ||||||
|  |     enum Sort: String { | ||||||
|  |         case NEWEST, PRICE_HIGH, PRICE_LOW | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private let repository = ContentRepository() | ||||||
|  |     private var subscription = Set<AnyCancellable>() | ||||||
|  |      | ||||||
|  |     @Published var errorMessage = "" | ||||||
|  |     @Published var isShowPopup = false | ||||||
|  |     @Published var isLoading = false | ||||||
|  |      | ||||||
|  |     @Published var theme = "" | ||||||
|  |     @Published var totalCount = 0 | ||||||
|  |     @Published var sort = Sort.NEWEST { | ||||||
|  |         didSet { | ||||||
|  |             page = 1 | ||||||
|  |             isLast = false | ||||||
|  |             getContentList() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     @Published var contentList: [GetAudioContentMainItem] = [] | ||||||
|  |      | ||||||
|  |     var themeId = 0 | ||||||
|  |     var page = 1 | ||||||
|  |     var isLast = false | ||||||
|  |     private let pageSize = 10 | ||||||
|  |      | ||||||
|  |     func getContentList() { | ||||||
|  |         if (!isLast && !isLoading) { | ||||||
|  |             isLoading = true | ||||||
|  |              | ||||||
|  |             repository.getAudioContentByTheme( | ||||||
|  |                 themeId: themeId, | ||||||
|  |                 page: page, | ||||||
|  |                 size: pageSize, | ||||||
|  |                 sort: sort | ||||||
|  |             ) | ||||||
|  |             .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<GetContentByThemeResponse>.self, from: responseData) | ||||||
|  |                      | ||||||
|  |                     if let data = decoded.data, decoded.success { | ||||||
|  |                         if page == 1 { | ||||||
|  |                             self.contentList.removeAll() | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         if !data.items.isEmpty { | ||||||
|  |                             page += 1 | ||||||
|  |                             self.theme = data.theme | ||||||
|  |                             self.totalCount = data.totalCount | ||||||
|  |                             self.contentList.append(contentsOf: data.items) | ||||||
|  |                         } 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,14 @@ | |||||||
|  | // | ||||||
|  | //  GetContentByThemeResponse.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 2/14/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import Foundation | ||||||
|  |  | ||||||
|  | struct GetContentByThemeResponse: Decodable { | ||||||
|  |     let theme: String | ||||||
|  |     let totalCount: Int | ||||||
|  |     let items: [GetAudioContentMainItem] | ||||||
|  | } | ||||||
| @@ -36,6 +36,7 @@ enum ContentApi { | |||||||
|     case getContentRankingSortType |     case getContentRankingSortType | ||||||
|     case pinContent(contentId: Int) |     case pinContent(contentId: Int) | ||||||
|     case unpinContent(contentId: Int) |     case unpinContent(contentId: Int) | ||||||
|  |     case getAudioContentByTheme(themeId: Int, page: Int, size: Int, sort: ContentAllByThemeViewModel.Sort) | ||||||
| } | } | ||||||
|  |  | ||||||
| extension ContentApi: TargetType { | extension ContentApi: TargetType { | ||||||
| @@ -125,6 +126,9 @@ extension ContentApi: TargetType { | |||||||
|              |              | ||||||
|         case .unpinContent(let contentId): |         case .unpinContent(let contentId): | ||||||
|             return  "/audio-content/unpin-at-the-top/\(contentId)" |             return  "/audio-content/unpin-at-the-top/\(contentId)" | ||||||
|  |              | ||||||
|  |         case .getAudioContentByTheme(let themeId, _, _, _): | ||||||
|  |             return "/audio-content/theme/\(themeId)/content" | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -136,7 +140,7 @@ extension ContentApi: TargetType { | |||||||
|                 .getContentRankingSortType: |                 .getContentRankingSortType: | ||||||
|             return .get |             return .get | ||||||
|              |              | ||||||
|         case .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList, .getCurationList: |         case .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList, .getCurationList, .getAudioContentByTheme: | ||||||
|             return .get |             return .get | ||||||
|              |              | ||||||
|         case .likeContent, .modifyAudioContent, .modifyComment, .unpinContent: |         case .likeContent, .modifyAudioContent, .modifyComment, .unpinContent: | ||||||
| @@ -271,6 +275,15 @@ extension ContentApi: TargetType { | |||||||
|              |              | ||||||
|         case .pinContent, .unpinContent: |         case .pinContent, .unpinContent: | ||||||
|             return .requestPlain |             return .requestPlain | ||||||
|  |              | ||||||
|  |         case .getAudioContentByTheme(_, let page, let size, let sort): | ||||||
|  |             let parameters = [ | ||||||
|  |                 "page": page - 1, | ||||||
|  |                 "size": size, | ||||||
|  |                 "sort-type": sort | ||||||
|  |             ] as [String : Any] | ||||||
|  |              | ||||||
|  |             return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|   | |||||||
| @@ -125,4 +125,8 @@ final class ContentRepository { | |||||||
|     func getCategoryList(creatorId: Int) -> AnyPublisher<Response, MoyaError> { |     func getCategoryList(creatorId: Int) -> AnyPublisher<Response, MoyaError> { | ||||||
|         return categoryApi.requestPublisher(.getCategoryList(creatorId: creatorId)) |         return categoryApi.requestPublisher(.getCategoryList(creatorId: creatorId)) | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     func getAudioContentByTheme(themeId: Int, page: Int, size: Int, sort: ContentAllByThemeViewModel.Sort) -> AnyPublisher<Response, MoyaError> { | ||||||
|  |         return api.requestPublisher(.getAudioContentByTheme(themeId: themeId, page: page, size: size, sort: sort)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -35,11 +35,60 @@ struct ContentMainView: View { | |||||||
|                             .padding(.horizontal, 13.3) |                             .padding(.horizontal, 13.3) | ||||||
|                          |                          | ||||||
|                         ContentMainBannerView() |                         ContentMainBannerView() | ||||||
|                             .padding(.bottom, 40) |                             .padding(.bottom, 26.7) | ||||||
|                             .padding(.horizontal, 13.3) |                             .padding(.horizontal, 13.3) | ||||||
|                          |                          | ||||||
|  |                         HStack(spacing: 13.3) { | ||||||
|  |                             VStack(spacing: 2.7) { | ||||||
|  |                                 HStack(spacing: 2.7) { | ||||||
|  |                                     Image("ic_short_play") | ||||||
|  |                                      | ||||||
|  |                                     Text("숏플") | ||||||
|  |                                         .font(.custom(Font.bold.rawValue, size: 14.7)) | ||||||
|  |                                         .foregroundColor(Color(hex: "dd158d")) | ||||||
|  |                                 } | ||||||
|  |                                  | ||||||
|  |                                 Text("짧지만 꼴릿한 이야기") | ||||||
|  |                                     .font(.custom(Font.light.rawValue, size: 10)) | ||||||
|  |                                     .foregroundColor(Color(hex: "dd158d")) | ||||||
|  |                             } | ||||||
|  |                             .padding(.vertical, 10) | ||||||
|  |                             .frame(maxWidth: .infinity) | ||||||
|  |                             .background(Color(hex: "ffecf7")) | ||||||
|  |                             .cornerRadius(2.6) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 AppState.shared.setAppStep( | ||||||
|  |                                     step: .contentAllByTheme(themeId: 11) | ||||||
|  |                                 ) | ||||||
|  |                             } | ||||||
|  |                              | ||||||
|  |                             VStack(spacing: 2.7) { | ||||||
|  |                                 HStack(spacing: 2.7) { | ||||||
|  |                                     Image("ic_thumb_play_blue") | ||||||
|  |                                      | ||||||
|  |                                     Text("라이브 다시듣기") | ||||||
|  |                                         .font(.custom(Font.bold.rawValue, size: 14.7)) | ||||||
|  |                                         .foregroundColor(Color(hex: "0057ff")) | ||||||
|  |                                 } | ||||||
|  |                                  | ||||||
|  |                                 Text("놓쳤던 라이브 다시듣기") | ||||||
|  |                                     .font(.custom(Font.light.rawValue, size: 10)) | ||||||
|  |                                     .foregroundColor(Color(hex: "0057ff")) | ||||||
|  |                             } | ||||||
|  |                             .padding(.vertical, 10) | ||||||
|  |                             .frame(maxWidth: .infinity) | ||||||
|  |                             .background(Color(hex: "ecf9ff")) | ||||||
|  |                             .cornerRadius(2.6) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 AppState.shared.setAppStep( | ||||||
|  |                                     step: .contentAllByTheme(themeId: 7) | ||||||
|  |                                 ) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         .padding(.bottom, 40) | ||||||
|  |                         .padding(.horizontal, 13.3) | ||||||
|  |                          | ||||||
|                         ContentMainMyStashView() |                         ContentMainMyStashView() | ||||||
|                             .padding(.bottom, 40) |  | ||||||
|                             .padding(.horizontal, 13.3) |                             .padding(.horizontal, 13.3) | ||||||
|                          |                          | ||||||
|                         ContentMainNewContentView() |                         ContentMainNewContentView() | ||||||
|   | |||||||
| @@ -39,6 +39,7 @@ struct ContentMainMyStashView: View { | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                 .padding(.bottom, 40) | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             if viewModel.isLoading { |             if viewModel.isLoading { | ||||||
|   | |||||||
| @@ -175,6 +175,9 @@ struct ContentView: View { | |||||||
|             case .canCoupon: |             case .canCoupon: | ||||||
|                 CanCouponView() |                 CanCouponView() | ||||||
|                  |                  | ||||||
|  |             case .contentAllByTheme(let themeId): | ||||||
|  |                 ContentAllByThemeView(themeId: themeId) | ||||||
|  |                  | ||||||
|             default: |             default: | ||||||
|                 EmptyView() |                 EmptyView() | ||||||
|                     .frame(width: 0, height: 0, alignment: .topLeading) |                     .frame(width: 0, height: 0, alignment: .topLeading) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Yu Sung
					Yu Sung