Skip to content

Commit

Permalink
Merge pull request #1322 from wakmusic/1316-music-detail-artist-or-cr…
Browse files Browse the repository at this point in the history
…edit

🔀 :: (#1316) 음악 상세에서 아티스트 이름 클릭 시 크레딧 혹은 아티스트 상세로 이동
  • Loading branch information
baekteun authored Nov 1, 2024
2 parents 3739097 + f290b21 commit 8f3200a
Show file tree
Hide file tree
Showing 18 changed files with 163 additions and 9 deletions.
6 changes: 6 additions & 0 deletions Projects/App/Sources/Application/AppComponent+Artist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public extension AppComponent {
}
}

var findArtistIDUseCase: any FindArtistIDUseCase {
shared {
FindArtistIDUseCaseImpl(artistRepository: artistRepository)
}
}

// MARK: Artist Detail > Artist Music
var artistMusicComponent: ArtistMusicComponent {
ArtistMusicComponent(parent: self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public protocol RemoteArtistDataSource {
func fetchArtistSongList(id: String, sort: ArtistSongSortType, page: Int) -> Single<[ArtistSongListEntity]>
func fetchArtistSubscriptionStatus(id: String) -> Single<ArtistSubscriptionStatusEntity>
func subscriptionArtist(id: String, on: Bool) -> Completable
func findArtistID(name: String) -> Single<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public protocol ArtistRepository {
func fetchArtistSongList(id: String, sort: ArtistSongSortType, page: Int) -> Single<[ArtistSongListEntity]>
func fetchArtistSubscriptionStatus(id: String) -> Single<ArtistSubscriptionStatusEntity>
func subscriptionArtist(id: String, on: Bool) -> Completable
func findArtistID(name: String) -> Single<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import RxSwift

public protocol FindArtistIDUseCase {
func execute(name: String) -> Single<String>
}
15 changes: 13 additions & 2 deletions Projects/Domains/ArtistDomain/Sources/API/ArtistAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum ArtistAPI {
case fetchArtistSongList(id: String, sort: ArtistSongSortType, page: Int)
case fetchSubscriptionStatus(id: String)
case subscriptionArtist(id: String, on: Bool)
case findArtistID(name: String)
}

extension ArtistAPI: WMAPI {
Expand All @@ -29,6 +30,8 @@ extension ArtistAPI: WMAPI {
return "/\(id)/subscription"
case let .subscriptionArtist(id, _):
return "/\(id)/subscription"
case let .findArtistID(name):
return "/find"
}
}

Expand All @@ -37,7 +40,8 @@ extension ArtistAPI: WMAPI {
case .fetchArtistList,
.fetchArtistDetail,
.fetchArtistSongList,
.fetchSubscriptionStatus:
.fetchSubscriptionStatus,
.findArtistID:
return .get
case let .subscriptionArtist(_, on):
return on ? .post : .delete
Expand All @@ -59,12 +63,19 @@ extension ArtistAPI: WMAPI {
],
encoding: URLEncoding.queryString
)
case let .findArtistID(name):
return .requestParameters(
parameters: [
"name": name
],
encoding: URLEncoding.queryString
)
}
}

public var jwtTokenType: JwtTokenType {
switch self {
case .fetchArtistList, .fetchArtistDetail, .fetchArtistSongList:
case .fetchArtistList, .fetchArtistDetail, .fetchArtistSongList, .findArtistID:
return .none
case .fetchSubscriptionStatus, .subscriptionArtist:
return .accessToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ public final class RemoteArtistDataSourceImpl: BaseRemoteDataSource<ArtistAPI>,
request(.subscriptionArtist(id: id, on: on))
.asCompletable()
}

public func findArtistID(name: String) -> Single<String> {
request(.findArtistID(name: name))
.map(FindArtistIDResponseDTO.self)
.map { $0.id }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ public final class ArtistRepositoryImpl: ArtistRepository {
public func subscriptionArtist(id: String, on: Bool) -> Completable {
remoteArtistDataSource.subscriptionArtist(id: id, on: on)
}

public func findArtistID(name: String) -> Single<String> {
remoteArtistDataSource.findArtistID(name: name)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

struct FindArtistIDResponseDTO: Decodable {
let id: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ArtistDomainInterface
import RxSwift

public struct FindArtistIDUseCaseImpl: FindArtistIDUseCase {
private let artistRepository: any ArtistRepository

public init(
artistRepository: any ArtistRepository
) {
self.artistRepository = artistRepository
}

public func execute(name: String) -> Single<String> {
return artistRepository.findArtistID(name: name)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ArtistDomainInterface
import RxSwift

public final class FindArtistIDUseCaseSpy: FindArtistIDUseCase {
public private(set) var callCount = 0
public var handler: ((String) -> Single<String>) = { _ in .never() }
public func execute(name: String) -> Single<String> {
callCount += 1
return handler(name)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@testable import ArtistDomainTesting
import ArtistFeatureInterface
import BaseFeature
import BaseFeatureInterface
import Inject
Expand Down Expand Up @@ -48,6 +50,11 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
.just(.init(status: "", likes: 0))
}

let findArtistIDUseCase = FindArtistIDUseCaseSpy()
findArtistIDUseCase.handler = { _ in
.just("fgSXAKsq-Vo")
}

let reactor = MusicDetailReactor(
songIDs: [
"fgSXAKsq-Vo",
Expand All @@ -58,7 +65,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
selectedID: "DPEtmqvaKqY",
fetchSongUseCase: fetchSongUseCase,
addLikeSongUseCase: addLikeSongUseCase,
cancelLikeSongUseCase: cancelLikeSongUseCase
cancelLikeSongUseCase: cancelLikeSongUseCase,
findArtistIDUseCase: findArtistIDUseCase
)
let viewController = Inject.ViewControllerHost(
UINavigationController(
Expand All @@ -70,6 +78,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
containSongsFactory: DummyContainSongsFactory(),
textPopupFactory: DummyTextPopupFactory(),
karaokeFactory: DummyKaraokeFactory(),
artistDetailFactory: DummyArtistDetailFactory(),
playlistPresenterGlobalState: DummyPlaylistPresenterGlobalState()
)
)
Expand Down Expand Up @@ -129,3 +138,9 @@ final class DummyKaraokeFactory: KaraokeFactory {
UIViewController()
}
}

final class DummyArtistDetailFactory: ArtistDetailFactory {
func makeView(artistID: String) -> UIViewController {
UIViewController()
}
}
10 changes: 7 additions & 3 deletions Projects/Features/MusicDetailFeature/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ let project = Project.module(
.feature(target: .LyricHighlightingFeature, type: .interface),
.feature(target: .SongCreditFeature, type: .interface),
.feature(target: .SignInFeature, type: .interface),
.feature(target: .ArtistFeature, type: .interface),
.domain(target: .SongsDomain, type: .interface),
.domain(target: .LikeDomain, type: .interface)
.domain(target: .LikeDomain, type: .interface),
.domain(target: .ArtistDomain, type: .interface)
]),
.tests(module: .feature(.MusicDetailFeature), dependencies: [
.feature(target: .MusicDetailFeature),
.domain(target: .SongsDomain, type: .testing),
.domain(target: .LikeDomain, type: .testing)
.domain(target: .LikeDomain, type: .testing),
.domain(target: .ArtistDomain, type: .testing)
]),
.demo(module: .feature(.MusicDetailFeature), dependencies: [
.feature(target: .MusicDetailFeature),
.domain(target: .SongsDomain, type: .testing),
.domain(target: .LikeDomain, type: .testing)
.domain(target: .LikeDomain, type: .testing),
.domain(target: .ArtistDomain, type: .testing)
])
]
)
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import ArtistDomainInterface
import ArtistFeatureInterface
import BaseFeature
import BaseFeatureInterface
import LikeDomainInterface
Expand All @@ -17,9 +19,11 @@ public protocol MusicDetailDependency: Dependency {
var containSongsFactory: any ContainSongsFactory { get }
var karaokeFactory: any KaraokeFactory { get }
var textPopupFactory: any TextPopupFactory { get }
var artistDetailFactory: any ArtistDetailFactory { get }
var playlistPresenterGlobalState: any PlayListPresenterGlobalStateProtocol { get }
var addLikeSongUseCase: any AddLikeSongUseCase { get }
var cancelLikeSongUseCase: any CancelLikeSongUseCase { get }
var findArtistIDUseCase: any FindArtistIDUseCase { get }
}

public final class MusicDetailComponent: Component<MusicDetailDependency>, MusicDetailFactory {
Expand All @@ -29,7 +33,8 @@ public final class MusicDetailComponent: Component<MusicDetailDependency>, Music
selectedID: selectedID,
fetchSongUseCase: dependency.fetchSongUseCase,
addLikeSongUseCase: dependency.addLikeSongUseCase,
cancelLikeSongUseCase: dependency.cancelLikeSongUseCase
cancelLikeSongUseCase: dependency.cancelLikeSongUseCase,
findArtistIDUseCase: dependency.findArtistIDUseCase
)

let viewController = MusicDetailViewController(
Expand All @@ -40,6 +45,7 @@ public final class MusicDetailComponent: Component<MusicDetailDependency>, Music
containSongsFactory: dependency.containSongsFactory,
textPopupFactory: dependency.textPopupFactory,
karaokeFactory: dependency.karaokeFactory,
artistDetailFactory: dependency.artistDetailFactory,
playlistPresenterGlobalState: dependency.playlistPresenterGlobalState
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ArtistDomainInterface
import BaseFeature
import Foundation
import Kingfisher
Expand Down Expand Up @@ -30,6 +31,7 @@ final class MusicDetailReactor: Reactor {
case musicPickButtonDidTap
case playListButtonDidTap
case dismissButtonDidTap
case didTapArtistLabel
}

enum Mutation {
Expand All @@ -48,6 +50,7 @@ final class MusicDetailReactor: Reactor {
case textPopup(text: String, completion: () -> Void)
case signin
case karaoke(ky: Int?, tj: Int?)
case artist(artistID: String)
}

struct State {
Expand All @@ -71,6 +74,7 @@ final class MusicDetailReactor: Reactor {
private let fetchSongUseCase: any FetchSongUseCase
private let addLikeSongUseCase: any AddLikeSongUseCase
private let cancelLikeSongUseCase: any CancelLikeSongUseCase
private let findArtistIDUseCase: any FindArtistIDUseCase
private var shouldRefreshLikeList = false

private var pendingLikeRequests: [String: LikeRequest] = [:]
Expand All @@ -83,7 +87,8 @@ final class MusicDetailReactor: Reactor {
selectedID: String,
fetchSongUseCase: any FetchSongUseCase,
addLikeSongUseCase: any AddLikeSongUseCase,
cancelLikeSongUseCase: any CancelLikeSongUseCase
cancelLikeSongUseCase: any CancelLikeSongUseCase,
findArtistIDUseCase: any FindArtistIDUseCase
) {
let selectedIndex = songIDs.firstIndex(of: selectedID) ?? 0
self.initialState = .init(
Expand All @@ -94,6 +99,7 @@ final class MusicDetailReactor: Reactor {
self.fetchSongUseCase = fetchSongUseCase
self.addLikeSongUseCase = addLikeSongUseCase
self.cancelLikeSongUseCase = cancelLikeSongUseCase
self.findArtistIDUseCase = findArtistIDUseCase

let urls = [
songIDs[safe: selectedIndex - 1],
Expand Down Expand Up @@ -133,6 +139,8 @@ final class MusicDetailReactor: Reactor {
return playListButtonDidTap()
case .dismissButtonDidTap:
return navigateMutation(navigate: .dismiss)
case .didTapArtistLabel:
return didTapArtistLabel()
}
}

Expand Down Expand Up @@ -416,6 +424,25 @@ private extension MusicDetailReactor {
LogManager.analytics(log)
return navigateMutation(navigate: .playlist(id: song.videoID))
}

func didTapArtistLabel() -> Observable<Mutation> {
guard let selectedSong = currentState.selectedSong else { return .empty() }
let artists = selectedSong.artistString.components(separatedBy: ",")

if artists.count == 1, let artistName = artists.first {
return findArtistIDUseCase.execute(name: artistName)
.asObservable()
.flatMap {
return Observable.concat(
.just(Mutation.navigate(.artist(artistID: $0))),
.just(.navigate(nil))
)
}
.catchAndReturn(.navigate(.credit(id: selectedSong.videoID)))
} else {
return navigateMutation(navigate: .credit(id: selectedSong.videoID))
}
}
}

// MARK: - Private Methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ private protocol MusicDetailActionProtocol {
var playlistButtonDidTap: Observable<Void> { get }
var creditButtonDidTap: Observable<Void> { get }
var dismissButtonDidTap: Observable<Void> { get }
var didTapArtistLabel: Observable<Void> { get }
}

final class MusicDetailView: UIView {
Expand Down Expand Up @@ -256,4 +257,5 @@ extension Reactive: MusicDetailActionProtocol where Base: MusicDetailView {
var playlistButtonDidTap: Observable<Void> { base.musicToolbarView.rx.playlistButtonDidTap }
var creditButtonDidTap: Observable<Void> { base.creditButton.rx.tap.asObservable() }
var dismissButtonDidTap: Observable<Void> { base.dismissButton.rx.tap.asObservable() }
var didTapArtistLabel: Observable<Void> { base.musicControlView.rx.didTapArtistLabel }
}
Loading

0 comments on commit 8f3200a

Please sign in to comment.