Skip to content

Commit

Permalink
Integrate some Artist Endpoints (#109)
Browse files Browse the repository at this point in the history
* changed the gradle version to 8.6

* added albumDto, album model, Album mapper

* Artist Album in progress

* Artist's ALbum error: service not found

* Fix service definition

* Able to fetch Artist's Album

* Moved artist Api call to ArtistApi class

* Clean up

* Added Artist's tracks and related artist Dtos

* Added the dtos neeed for ArtistTracks and related artists

* in progress

* Unable to fetch Artist Top tracks in ArtistDomainManager

* fetched Album from ArtistTopTracks endpoint

* Not sure if the error has been resolved, phone logs not showing...

* Error has been resolved

* Code clean up

* Several Artist Api endpoint setup

* it works without hitting the top-tracks endpoint

* Issue resolved: I can not hit the top_tracks endpoint without getting error

* issue in ArtistViewModel: trying to debug...

* issue resolved :)

* issue: several_artist endpoint giving me a 400 error

* issue resolved: Several Artist Api error resolved

* PR Reviews

* PR Reviews

---------

Co-authored-by: efedaniel <[email protected]>
Co-authored-by: Ejemudaro Ufuoma Isaac <[email protected]>
  • Loading branch information
3 people authored Dec 29, 2024
1 parent 6ff5a9c commit 1853526
Show file tree
Hide file tree
Showing 25 changed files with 441 additions and 22 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ dependencies {
implementation("io.reactivex.rxjava3:rxjava:3.1.8")
implementation("io.reactivex.rxjava3:rxkotlin:3.0.1")
implementation("io.reactivex.rxjava3:rxandroid:3.0.2")
implementation("com.github.mrmike:ok2curl:0.8.0")

// Timber
implementation("com.jakewharton.timber:timber:5.0.1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.efedaniel.spotifystats.domain.manager

import com.efedaniel.spotifystats.domain.mapper.AlbumMapper
import com.efedaniel.spotifystats.domain.mapper.ArtistMapper
import com.efedaniel.spotifystats.domain.mapper.ArtistTrackMapper
import com.efedaniel.spotifystats.domain.mapper.SeveralArtistsMapper
import com.efedaniel.spotifystats.domain.model.Album
import com.efedaniel.spotifystats.domain.model.Artist
import com.efedaniel.spotifystats.domain.model.ArtistTrack
import com.efedaniel.spotifystats.network.dto.AlbumDto
import com.efedaniel.spotifystats.network.dto.PaginatedResponse
import com.efedaniel.spotifystats.network.dto.SeveralArtistsDto
import com.efedaniel.spotifystats.network.service.ArtistApi
import io.reactivex.rxjava3.core.Single
import javax.inject.Inject

class ArtistDomainManager @Inject constructor(
private val artistApi: ArtistApi,
private val artistMapper: ArtistMapper,
private val albumMapper: AlbumMapper,
private val artistTrackMapper: ArtistTrackMapper,
private val severalArtistsMapper: SeveralArtistsMapper,
) {

fun getArtist(id: String): Single<Artist> = artistApi
.getArtist(id)
.map(artistMapper::dtoToDomain)

fun getArtistAlbum(id: String): Single<List<Album>> = artistApi
.getArtistAlbum(id)
.map(PaginatedResponse<AlbumDto>::items)
.map(albumMapper::dtoListToDomainList)

fun getArtistTopTracks(id: String): Single<List<ArtistTrack>> = artistApi
.getArtistTopTracks(id)
.map { it.track }
.map { artistTrackMapper.dtoListToDomainList(it) }

fun getSeveralArtists(ids: List<String>): Single<List<Artist>> = artistApi
.getSeveralArtist(ids)
.map (SeveralArtistsDto::artists)
.map {severalArtistsMapper.dtoListToDomainList(it)}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
package com.efedaniel.spotifystats.domain.manager

import com.efedaniel.spotifystats.domain.mapper.AlbumMapper
import com.efedaniel.spotifystats.domain.mapper.ArtistMapper
import com.efedaniel.spotifystats.domain.mapper.TopArtistMapper
import com.efedaniel.spotifystats.domain.mapper.TopTrackMapper
import com.efedaniel.spotifystats.domain.mapper.UserMapper
import com.efedaniel.spotifystats.domain.model.Album
import com.efedaniel.spotifystats.domain.model.Artist
import com.efedaniel.spotifystats.domain.model.User
import com.efedaniel.spotifystats.network.dto.AlbumDto
import com.efedaniel.spotifystats.network.dto.PaginatedResponse
import com.efedaniel.spotifystats.network.dto.TopAlbumDto
import com.efedaniel.spotifystats.network.dto.TopArtistDto
import com.efedaniel.spotifystats.network.service.UserApi
import com.efedaniel.spotifystats.persistence.cache.UserCache
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import javax.annotation.Signed
import javax.inject.Inject

class UserDomainManager @Inject constructor(
private val userApi: UserApi,
private val cache: UserCache,
private val userMapper: UserMapper,
private val artistMapper: ArtistMapper,
) {

fun fetchCurrentUser(): Single<User> = userApi
Expand All @@ -27,7 +36,4 @@ class UserDomainManager @Inject constructor(
?.let { Single.just(userMapper.mapEntityToDomain(it)) }
?: Single.error(Exception("User does not exist in cache"))

fun getArtist(id: String): Single<Artist> = userApi
.getArtist(id)
.map(artistMapper::dtoToDomain)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.efedaniel.spotifystats.domain.mapper

import com.efedaniel.spotifystats.domain.model.Album
import com.efedaniel.spotifystats.network.dto.AlbumDto
import javax.inject.Inject

class AlbumMapper @Inject constructor() {

fun dtoToDomain(
dto: AlbumDto,
): Album = Album(
id = dto.id,
name = dto.name,
imageUrl = dto.images.firstOrNull()?.url,
artists = dto.artists,
spotifyUrl = dto.externalUrls.spotify,
uri = dto.uri,
)

fun dtoListToDomainList(
dtos: List<AlbumDto>
) = dtos.map { albumDto ->
dtoToDomain(dto = albumDto)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ class ArtistMapper @Inject constructor() {
name = dto.name,
popularity = dto.popularity
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.efedaniel.spotifystats.domain.mapper

import com.efedaniel.spotifystats.domain.model.ArtistTrack
import com.efedaniel.spotifystats.network.dto.ArtistTrackDto
import javax.inject.Inject

class ArtistTrackMapper @Inject constructor() {

private fun dtoToDomain(
dto: ArtistTrackDto,
) = ArtistTrack(
id = dto.id,
name = dto.name,
imageUrl = dto.images?.firstOrNull()?.url,
popularity = dto.popularity,
isExplicit = dto.explicit,
previewUrl = dto.previewUrl,
uri = dto.uri,
images = dto.images,
album = dto.album,
)

fun dtoListToDomainList(
dtos: List<ArtistTrackDto>
) = dtos.map { artistTrackDto ->
dtoToDomain(dto = artistTrackDto)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.efedaniel.spotifystats.domain.mapper

import com.efedaniel.spotifystats.domain.model.RelatedArtist
import com.efedaniel.spotifystats.network.dto.RelatedArtistDto
import javax.inject.Inject

class RelatedArtistMapper @Inject constructor() {

private fun dtoToDomain(
dto: RelatedArtistDto,
) = RelatedArtist(
id = dto.id,
name = dto.name,
imageUrl = dto.images.firstOrNull()?.url,
popularity = dto.popularity,
followersDto = dto.followers,
genres = dto.genres
)

fun dtoListToDomainList(
dtos: List<RelatedArtistDto>
) = dtos.mapIndexed { index, relatedArtistDto ->
dtoToDomain(dto = relatedArtistDto)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.efedaniel.spotifystats.domain.mapper

import com.efedaniel.spotifystats.domain.model.Artist
import com.efedaniel.spotifystats.network.dto.ArtistDto
import javax.inject.Inject

class SeveralArtistsMapper @Inject constructor() {

fun dtoToDomain(
dto: ArtistDto,
): Artist = Artist(
id = dto.id,
name = dto.name,
imageUrl = dto.images.firstOrNull()?.url,
spotifyUrl = dto.externalUrls.spotify,
genres = dto.genres,
popularity = dto.popularity,
)

fun dtoListToDomainList(
dtos: List<ArtistDto>
) = dtos.map { artistDto ->
dtoToDomain(dto = artistDto)
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/efedaniel/spotifystats/domain/model/Album.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.efedaniel.spotifystats.domain.model

import androidx.compose.runtime.Immutable

@Immutable
data class Album(
val id: String,
val imageUrl: String?,
val name: String,
val artists: List<String>?,
val spotifyUrl: String,
val uri: String?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.efedaniel.spotifystats.domain.model

import androidx.compose.runtime.Immutable
import com.efedaniel.spotifystats.network.dto.AlbumDto
import com.efedaniel.spotifystats.network.dto.ImageDto

@Immutable
data class ArtistTrack(
val id: String,
val name: String,
val imageUrl: String?,
val isExplicit: Boolean?,
val popularity: Int?,
val previewUrl: String?,
val uri: String?,
val images: List<ImageDto>?,
val album: AlbumDto?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.efedaniel.spotifystats.domain.model

import com.efedaniel.spotifystats.network.dto.FollowersDto

data class RelatedArtist(
val id: String = "",
val genres: List<String> = emptyList(), // Fixme: Change to ImmutableList
val imageUrl: String? = null,
val name: String = "",
val popularity: Int = 0,
val followersDto: FollowersDto? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import com.efedaniel.spotifystats.utility.constants.Constants.SPOTIFY_AUTH_BASE_
import com.efedaniel.spotifystats.utility.constants.Constants.SPOTIFY_BASE_URL
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.moczul.ok2curl.CurlInterceptor
import com.moczul.ok2curl.logger.Logger
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -20,6 +22,7 @@ import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import timber.log.Timber
import javax.inject.Named
import javax.inject.Singleton

Expand Down Expand Up @@ -66,10 +69,12 @@ class ApiModule {
@Named("BaseOkHttp") okhttp: OkHttpClient,
tokenAuthenticator: TokenAuthenticator,
errorInterceptor: ErrorInterceptor,
curlInterceptor: CurlInterceptor
): OkHttpClient = okhttp
.newBuilder()
.authenticator(tokenAuthenticator)
// .addInterceptor(errorInterceptor)
.addInterceptor(curlInterceptor)
.build()

@Provides
Expand All @@ -90,6 +95,15 @@ class ApiModule {
HttpLoggingInterceptor()
.also { it.level = BODY }

@Provides
@Singleton
internal fun provideCurlInterceptor(): CurlInterceptor =
CurlInterceptor(object : Logger {
override fun log(message: String) {
Timber.d(message)
}
})

@Provides
@Singleton
internal fun provideConverterFactory(): Converter.Factory =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.efedaniel.spotifystats.network.di

import com.efedaniel.spotifystats.network.service.ArtistApi
import com.efedaniel.spotifystats.network.service.AuthApi
import com.efedaniel.spotifystats.network.service.PlaybackService
import com.efedaniel.spotifystats.network.service.StatsApi
Expand Down Expand Up @@ -36,4 +37,9 @@ class NetworkModule {
@Singleton
internal fun providePlaybackService(retrofit: Retrofit): PlaybackService =
retrofit.create(PlaybackService::class.java)

@Provides
@Singleton
internal fun provideArtistApi(retrofit: Retrofit): ArtistApi =
retrofit.create(ArtistApi::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.efedaniel.spotifystats.network.dto

import com.google.gson.annotations.SerializedName

data class AlbumDto(
@SerializedName("id")
val id: String,
@SerializedName("images")
val images: List<ImageDto>,
@SerializedName("name")
val name: String,
@SerializedName("external_urls")
val externalUrls: ExternalUrls,
@SerializedName("release_date")
val releaseDate: String,
@SerializedName("release_date_precision")
val releaseDatePrecision : String,
@SerializedName("type")
val type: String,
@SerializedName("uri")
val uri: String,
@SerializedName("artist")
val artists: List<String>,
@SerializedName("total_tracks")
val totalTracks: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.efedaniel.spotifystats.network.dto

import com.google.gson.annotations.SerializedName

data class ArtistTopTracksDto(
@SerializedName("tracks")
val track: List<ArtistTrackDto>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.efedaniel.spotifystats.network.dto

import com.google.gson.annotations.SerializedName

data class ArtistTrackDto(
@SerializedName("id")
val id: String,
@SerializedName("name")
val name: String,
@SerializedName("album")
val album: AlbumDto,
@SerializedName("explicit")
val explicit: Boolean,
@SerializedName("popularity")
val popularity: Int,
@SerializedName("preview_url")
val previewUrl: String?,
@SerializedName("uri")
val uri: String,
@SerializedName("external_urls")
val externalUrls: ExternalUrls,
@SerializedName("track_number")
val trackNumber: Int,
@SerializedName("images")
val images: List<ImageDto>?,
)
Loading

0 comments on commit 1853526

Please sign in to comment.