Skip to content

Commit

Permalink
๐ŸŽจ#298: ์ฝ”๋“œ๋ฆฌ๋ทฐ ๋ฐ˜์˜
Browse files Browse the repository at this point in the history
  • Loading branch information
wendoei committed Dec 15, 2024
1 parent 5e7c2e2 commit 4e4158a
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 51 deletions.
12 changes: 12 additions & 0 deletions StreetDrop/StreetDrop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@
F4AA84E12C1F732800CADB1A /* DateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AA84E02C1F732800CADB1A /* DateManager.swift */; };
F4AEE56A2D0E169100B65191 /* DefaultFetchingSearchPlaceholderUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AEE5692D0E140C00B65191 /* DefaultFetchingSearchPlaceholderUseCase.swift */; };
F4AEE56C2D0E1C7200B65191 /* FetchingSearchPlaceholderUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AEE56B2D0E1C6600B65191 /* FetchingSearchPlaceholderUseCase.swift */; };
F4AEE5712D0E4ECA00B65191 /* RecommendSectionDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AEE5702D0E4EC300B65191 /* RecommendSectionDTO.swift */; };
F4BDF78F2C1DC57500CC6EE6 /* SettingHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4BDF78E2C1DC57500CC6EE6 /* SettingHeaderView.swift */; };
F4C996A12C1E15CD00FF7B9A /* NoticeListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C996A02C1E15CC00FF7B9A /* NoticeListViewController.swift */; };
F4C996A32C1E1B3400FF7B9A /* NoticeListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C996A22C1E1B3400FF7B9A /* NoticeListCell.swift */; };
Expand Down Expand Up @@ -541,6 +542,7 @@
F4AA84E02C1F732800CADB1A /* DateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateManager.swift; sourceTree = "<group>"; };
F4AEE5692D0E140C00B65191 /* DefaultFetchingSearchPlaceholderUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingSearchPlaceholderUseCase.swift; sourceTree = "<group>"; };
F4AEE56B2D0E1C6600B65191 /* FetchingSearchPlaceholderUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingSearchPlaceholderUseCase.swift; sourceTree = "<group>"; };
F4AEE5702D0E4EC300B65191 /* RecommendSectionDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendSectionDTO.swift; sourceTree = "<group>"; };
F4BDF78E2C1DC57500CC6EE6 /* SettingHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingHeaderView.swift; sourceTree = "<group>"; };
F4C996A02C1E15CC00FF7B9A /* NoticeListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeListViewController.swift; sourceTree = "<group>"; };
F4C996A22C1E1B3400FF7B9A /* NoticeListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeListCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1036,6 +1038,7 @@
18F76FAE2A050110006CF9EF /* DataMapping */ = {
isa = PBXGroup;
children = (
F4AEE56F2D0E4EBB00B65191 /* RecommendMusic */,
F4AA84D72C1F030300CADB1A /* Notice */,
1876F03B2A66E01C0064B887 /* MyLevel */,
1876F03A2A66E0170064B887 /* MyLikeList */,
Expand Down Expand Up @@ -1571,6 +1574,14 @@
path = Notice;
sourceTree = "<group>";
};
F4AEE56F2D0E4EBB00B65191 /* RecommendMusic */ = {
isa = PBXGroup;
children = (
F4AEE5702D0E4EC300B65191 /* RecommendSectionDTO.swift */,
);
path = RecommendMusic;
sourceTree = "<group>";
};
F4C9969D2C1E159600FF7B9A /* Notice */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2004,6 +2015,7 @@
18683FDC2A348B15005A94AC /* DefaultMainRepository.swift in Sources */,
1876F03F2A66E4E30064B887 /* MyLikeListResponseDTO+Mapping.swift in Sources */,
6A7D73DD2BB14015009340E3 /* GradientProgressBar.swift in Sources */,
F4AEE5712D0E4ECA00B65191 /* RecommendSectionDTO.swift in Sources */,
B46578C32B00BC060024B066 /* LeftAlignedCollectionViewFlowLayout.swift in Sources */,
F47C1B982CCD242B00C2D546 /* RecommendSection.swift in Sources */,
C41BD2E92A38467A0090EF2B /* UIImageView+ImageCache.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// RecommendSectionDTO.swift
// StreetDrop
//
// Created by jihye kim on 14/12/2024.
//

struct RecommendSectionResponse: Decodable {
let data: [RecommendSectionDTO]
}

struct PromptOfTheDayResponse: Decodable {
let sentence: String?
}

struct RecommendSectionDTO: Decodable {
// Header
let title: String
let description: String?

// Content
let type: ContentType
let content: Content

enum ContentType: String, Decodable {
case basic
case keyword

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(String.self)
self = ContentType(rawValue: rawValue.lowercased()) ?? .basic
}
}

struct Content: Decodable {
let basic: [MusicContentDTO]?
let keyword: [KeywordContentDTO]?
}

struct MusicContentDTO: Decodable {
let albumName: String
let artistName: String
let songName: String
let durationTime: String
let albumImage: String
let albumThumbnailImage: String
let genre: [String]
}

struct KeywordContentDTO: Decodable {
let artistName: String
let albumImage: String
let albumThumbnailImage: String
}
}
30 changes: 8 additions & 22 deletions StreetDrop/StreetDrop/Domain/Entity/RecommendSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,7 @@
// Created by jihye kim on 26/10/2024.
//

struct RecommendSectionResponse: Decodable {
let data: [RecommendSectionDTO]
}

struct PromptOfTheDayResponse: Decodable {
let sentence: String?
}

struct RecommendSectionDTO: Decodable {
struct RecommendSectionEntity {
// Header
let title: String
let description: String?
Expand All @@ -22,23 +14,17 @@ struct RecommendSectionDTO: Decodable {
let type: ContentType
let content: Content

enum ContentType: String, Decodable {
enum ContentType: String {
case basic
case keyword

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(String.self)
self = ContentType(rawValue: rawValue.lowercased()) ?? .basic
}
}

struct Content: Decodable {
let basic: [MusicContent]?
let keyword: [KeywordContent]?
struct Content {
var basic: [MusicContentEntity]?
var keyword: [KeywordContentEntity]?
}

struct MusicContent: Decodable {
struct MusicContentEntity {
let albumName: String
let artistName: String
let songName: String
Expand All @@ -48,7 +34,7 @@ struct RecommendSectionDTO: Decodable {
let genre: [String]
}

struct KeywordContent: Decodable {
struct KeywordContentEntity {
let artistName: String
let albumImage: String
let albumThumbnailImage: String
Expand All @@ -57,7 +43,7 @@ struct RecommendSectionDTO: Decodable {

// MARK: Conversion

extension RecommendSectionDTO {
extension RecommendSectionEntity {
typealias HeaderInfo = RecommendMusicSectionModel.Header
typealias Item = RecommendMusicSectionModel.Item

Expand Down
49 changes: 47 additions & 2 deletions StreetDrop/StreetDrop/Domain/UseCase/RecommendMusicUsecase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import RxSwift

protocol RecommendMusicUsecase {
func getPromptOfTheDay() -> Single<String?>
func getRecommendSections() -> Single<[RecommendSectionDTO]>
func getRecommendSections() -> Single<[RecommendSectionEntity]>
}

final class DefaultRecommendMusicUsecase: RecommendMusicUsecase {
Expand All @@ -25,7 +25,52 @@ final class DefaultRecommendMusicUsecase: RecommendMusicUsecase {
recommendMusicRepository.fetchPromptOfTheDay()
}

func getRecommendSections() -> Single<[RecommendSectionDTO]> {
func getRecommendSections() -> Single<[RecommendSectionEntity]> {
recommendMusicRepository.fetchRecommendSectionList()
.map { dtoList in
dtoList.map { self.recommendSectionEntity(from: $0) }
}
}
}

// MARK: Conversion

extension DefaultRecommendMusicUsecase {
private func recommendSectionEntity(from dto: RecommendSectionDTO) -> RecommendSectionEntity {
typealias Entity = RecommendSectionEntity
let convertedType = Entity.ContentType(rawValue: dto.type.rawValue) ?? .basic

let convertedContent: Entity.Content
switch convertedType {
case .basic:
let basicContent = dto.content.basic?.map {
Entity.MusicContentEntity(
albumName: $0.albumName,
artistName: $0.artistName,
songName: $0.songName,
durationTime: $0.durationTime,
albumImage: $0.albumImage,
albumThumbnailImage: $0.albumThumbnailImage,
genre: $0.genre
)
}
convertedContent = Entity.Content(basic: basicContent)
case .keyword:
let keywordContent = dto.content.keyword?.map {
RecommendSectionEntity.KeywordContentEntity(
artistName: $0.artistName,
albumImage: $0.albumImage,
albumThumbnailImage: $0.albumThumbnailImage
)
}
convertedContent = Entity.Content(keyword: keywordContent)
}

return Entity(
title: dto.title,
description: dto.description,
type: convertedType,
content: convertedContent
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import UIKit

class GuideDetailView: UIView {
final class GuideDetailView: UIView {
private lazy var speechBubblePointImageView: UIImageView = {
let speechBubblePointImage = UIImage(named: "speechBubblePoint")
let imageView = UIImageView(image: speechBubblePointImage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import UIKit

import SnapKit

class RecentSearchesHeaderView: UICollectionReusableView {
final class RecentSearchesHeaderView: UICollectionReusableView {
static var reuseIdentifier: String {
return String(describing: Self.self)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import RxRelay
import RxSwift
import SnapKit

class RecommendHeaderView: UICollectionReusableView {
final class RecommendHeaderView: UICollectionReusableView {
static var reuseIdentifier: String {
return String(describing: Self.self)
}

let titleLabel = UILabel()
let arrowIconImageView = UIImageView()
let infoIconButton = UIButton()
private let titleLabel = UILabel()
private let arrowIconImageView = UIImageView()
private let infoIconButton = UIButton()
private let disposeBag: DisposeBag = DisposeBag()
private let infoGuideView = GuideDetailView()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import UIKit

import Kingfisher

class RecommendKeywordCell: UICollectionViewCell {
final class RecommendKeywordCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
configureUI()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ extension SearchingMusicViewController {
group.interItemSpacing = .fixed(16)

let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
section.orthogonalScrollingBehavior = .groupPaging
section.interGroupSpacing = 16
section.contentInsets = NSDirectionalEdgeInsets(
top: 20, leading: 24, bottom: 48, trailing: 24
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protocol SearchingMusicViewModel: ViewModel {
}

final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
private let model: SearchMusicUsecase
private let searchMusicUsecase: SearchMusicUsecase
private let recommendMusicUseCase: RecommendMusicUsecase
private let searchPlaceholderUseCase: FetchingSearchPlaceholderUseCase
let location: CLLocation
Expand All @@ -42,17 +42,17 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
let recentMusicQueries = PublishRelay<[String]>()
let selectedMusic = PublishRelay<Music>()
let promptOfTheDay = PublishRelay<String>()
let recommendSections = PublishRelay<[RecommendSectionDTO]>()
let recommendSections = PublishRelay<[RecommendSectionEntity]>()
let recommendSectionModels = PublishRelay<[RecommendMusicSectionModel]>()
}

init(
model: SearchMusicUsecase = DefaultSearchingMusicUsecase(),
searchMusicUsecase: SearchMusicUsecase = DefaultSearchingMusicUsecase(),
recommendMusicUseCase: RecommendMusicUsecase = DefaultRecommendMusicUsecase(),
searchPlaceholderUseCase: FetchingSearchPlaceholderUseCase = DefaultFetchingSearchPlaceholderUseCase(),
location: CLLocation
) {
self.model = model
self.searchMusicUsecase = searchMusicUsecase
self.recommendMusicUseCase = recommendMusicUseCase
self.searchPlaceholderUseCase = searchPlaceholderUseCase
self.location = location
Expand All @@ -64,7 +64,7 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
input.viewDidLoadEvent
.subscribe(onNext: { [weak self] in
guard let self else { return }
self.model.getRecentSearches()
self.searchMusicUsecase.getRecentSearches()
.subscribe { result in
switch result {
case .success(let queries):
Expand Down Expand Up @@ -106,7 +106,7 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
.bind { [weak self] keyword in
if !keyword.isEmpty {
self?.searchMusic(output: output, keyword: keyword)
self?.model.saveRecentSearch(keyword: keyword)
self?.searchMusicUsecase.saveRecentSearch(keyword: keyword)
}
}
.disposed(by: disposedBag)
Expand All @@ -120,7 +120,7 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
input.keywordQueryDidPressEvent
.bind { [weak self] keywordQuery in
self?.searchMusic(output: output, keyword: keywordQuery)
self?.model.saveRecentSearch(keyword: keywordQuery)
self?.searchMusicUsecase.saveRecentSearch(keyword: keywordQuery)
}
.disposed(by: disposedBag)

Expand All @@ -142,10 +142,10 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
guard let self else { return }

Task {
await self.model.deleteRecentSearch(keyword: keyword)
await self.searchMusicUsecase.deleteRecentSearch(keyword: keyword)

do {
let recentQueries = try await self.model.getRecentSearches().value
let recentQueries = try await self.searchMusicUsecase.getRecentSearches().value
output.recentMusicQueries.accept(recentQueries)
} catch {
output.recentMusicQueries.accept([])
Expand All @@ -158,7 +158,7 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
}

func searchMusic(output: Output, keyword: String) {
model.searchMusic(keyword: keyword)
searchMusicUsecase.searchMusic(keyword: keyword)
.subscribe { result in
switch result {
case .success(let musicList):
Expand All @@ -174,7 +174,7 @@ final class DefaultSearchingMusicViewModel: SearchingMusicViewModel {
}

func fetchCurrentLocationVillageName() {
self.model.getVillageName(
self.searchMusicUsecase.getVillageName(
latitude: self.location.coordinate.latitude,
longitude: self.location.coordinate.longitude
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,11 @@ extension NoticeListViewController: UICollectionViewDelegate {

extension NoticeListViewController {
func bindAction() {
Observable.merge(
self.backButton.rx.tap.asObservable()
)
.bind { _ in
self.navigationController?.popViewController(animated: true)
}
.disposed(by: disposeBag)
self.backButton.rx.tap
.bind(with: self) { owner, _ in
owner.navigationController?.popViewController(animated: true)
}
.disposed(by: disposeBag)
}

func bindViewModel() {
Expand Down

0 comments on commit 4e4158a

Please sign in to comment.