From 1853526b9b113209265af166f5d708ad5849be6f Mon Sep 17 00:00:00 2001 From: ufuoma_isaac Date: Sun, 29 Dec 2024 16:40:20 +0100 Subject: [PATCH] Integrate some Artist Endpoints (#109) * 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 Co-authored-by: Ejemudaro Ufuoma Isaac --- app/build.gradle.kts | 1 + .../domain/manager/ArtistDomainManager.kt | 43 ++++++++++ .../domain/manager/UserDomainManager.kt | 14 ++- .../spotifystats/domain/mapper/AlbumMapper.kt | 25 ++++++ .../domain/mapper/ArtistMapper.kt | 2 +- .../domain/mapper/ArtistTopTracksMapper.kt | 28 ++++++ .../domain/mapper/RelatedArtistMapper.kt | 25 ++++++ .../domain/mapper/SeveralArtistsMapper.kt | 25 ++++++ .../spotifystats/domain/model/Album.kt | 13 +++ .../spotifystats/domain/model/ArtistTrack.kt | 18 ++++ .../domain/model/RelatedArtist.kt | 12 +++ .../spotifystats/network/di/ApiModule.kt | 14 +++ .../spotifystats/network/di/NetworkModule.kt | 6 ++ .../spotifystats/network/dto/AlbumDto.kt | 26 ++++++ .../network/dto/ArtistTopTracksDto.kt | 8 ++ .../network/dto/ArtistTrackDto.kt | 26 ++++++ .../network/dto/RelatedArtistDto.kt | 24 ++++++ .../network/dto/SeveralArtistsDto.kt | 8 ++ .../spotifystats/network/dto/TopAlbumDto.kt | 10 ++- .../spotifystats/network/service/ArtistApi.kt | 28 ++++++ .../spotifystats/network/service/UserApi.kt | 7 +- .../ui/scene/artist/ArtistScreen.kt | 5 +- .../ui/scene/artist/ArtistUiState.kt | 7 +- .../ui/scene/artist/ArtistViewModel.kt | 85 +++++++++++++++++-- gradle/wrapper/gradle-wrapper.properties | 3 +- 25 files changed, 441 insertions(+), 22 deletions(-) create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/manager/ArtistDomainManager.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/mapper/AlbumMapper.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistTopTracksMapper.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/mapper/RelatedArtistMapper.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/mapper/SeveralArtistsMapper.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/model/Album.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/model/ArtistTrack.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/domain/model/RelatedArtist.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/dto/AlbumDto.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTopTracksDto.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTrackDto.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/dto/RelatedArtistDto.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/dto/SeveralArtistsDto.kt create mode 100644 app/src/main/java/com/efedaniel/spotifystats/network/service/ArtistApi.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e731b3f6..20e9efe1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/manager/ArtistDomainManager.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/manager/ArtistDomainManager.kt new file mode 100644 index 00000000..fc3901e5 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/manager/ArtistDomainManager.kt @@ -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 = artistApi + .getArtist(id) + .map(artistMapper::dtoToDomain) + + fun getArtistAlbum(id: String): Single> = artistApi + .getArtistAlbum(id) + .map(PaginatedResponse::items) + .map(albumMapper::dtoListToDomainList) + + fun getArtistTopTracks(id: String): Single> = artistApi + .getArtistTopTracks(id) + .map { it.track } + .map { artistTrackMapper.dtoListToDomainList(it) } + + fun getSeveralArtists(ids: List): Single> = artistApi + .getSeveralArtist(ids) + .map (SeveralArtistsDto::artists) + .map {severalArtistsMapper.dtoListToDomainList(it)} +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/manager/UserDomainManager.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/manager/UserDomainManager.kt index def650fa..94f308e0 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/domain/manager/UserDomainManager.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/manager/UserDomainManager.kt @@ -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 = userApi @@ -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 = userApi - .getArtist(id) - .map(artistMapper::dtoToDomain) } \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/AlbumMapper.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/AlbumMapper.kt new file mode 100644 index 00000000..b6703597 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/AlbumMapper.kt @@ -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 + ) = dtos.map { albumDto -> + dtoToDomain(dto = albumDto) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistMapper.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistMapper.kt index 86bf50aa..4b63e701 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistMapper.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistMapper.kt @@ -14,4 +14,4 @@ class ArtistMapper @Inject constructor() { name = dto.name, popularity = dto.popularity ) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistTopTracksMapper.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistTopTracksMapper.kt new file mode 100644 index 00000000..958f3e75 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/ArtistTopTracksMapper.kt @@ -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 + ) = dtos.map { artistTrackDto -> + dtoToDomain(dto = artistTrackDto) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/RelatedArtistMapper.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/RelatedArtistMapper.kt new file mode 100644 index 00000000..1607adf2 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/RelatedArtistMapper.kt @@ -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 + ) = dtos.mapIndexed { index, relatedArtistDto -> + dtoToDomain(dto = relatedArtistDto) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/SeveralArtistsMapper.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/SeveralArtistsMapper.kt new file mode 100644 index 00000000..22a43a23 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/mapper/SeveralArtistsMapper.kt @@ -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 + ) = dtos.map { artistDto -> + dtoToDomain(dto = artistDto) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/model/Album.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/model/Album.kt new file mode 100644 index 00000000..80bef054 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/model/Album.kt @@ -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?, + val spotifyUrl: String, + val uri: String?, +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/model/ArtistTrack.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/model/ArtistTrack.kt new file mode 100644 index 00000000..713a09c5 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/model/ArtistTrack.kt @@ -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?, + val album: AlbumDto? +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/domain/model/RelatedArtist.kt b/app/src/main/java/com/efedaniel/spotifystats/domain/model/RelatedArtist.kt new file mode 100644 index 00000000..41768d1b --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/domain/model/RelatedArtist.kt @@ -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 = emptyList(), // Fixme: Change to ImmutableList + val imageUrl: String? = null, + val name: String = "", + val popularity: Int = 0, + val followersDto: FollowersDto? = null, +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/di/ApiModule.kt b/app/src/main/java/com/efedaniel/spotifystats/network/di/ApiModule.kt index 0b5c56bf..28fdd099 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/network/di/ApiModule.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/network/di/ApiModule.kt @@ -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 @@ -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 @@ -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 @@ -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 = diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/di/NetworkModule.kt b/app/src/main/java/com/efedaniel/spotifystats/network/di/NetworkModule.kt index a055f54f..e7b4d5ee 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/network/di/NetworkModule.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/network/di/NetworkModule.kt @@ -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 @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/AlbumDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/AlbumDto.kt new file mode 100644 index 00000000..52779421 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/AlbumDto.kt @@ -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, + @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, + @SerializedName("total_tracks") + val totalTracks: Int, +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTopTracksDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTopTracksDto.kt new file mode 100644 index 00000000..0ac73bdb --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTopTracksDto.kt @@ -0,0 +1,8 @@ +package com.efedaniel.spotifystats.network.dto + +import com.google.gson.annotations.SerializedName + +data class ArtistTopTracksDto( + @SerializedName("tracks") + val track: List, +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTrackDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTrackDto.kt new file mode 100644 index 00000000..91ea42a0 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/ArtistTrackDto.kt @@ -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?, +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/RelatedArtistDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/RelatedArtistDto.kt new file mode 100644 index 00000000..4a85628e --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/RelatedArtistDto.kt @@ -0,0 +1,24 @@ +package com.efedaniel.spotifystats.network.dto + +import com.google.gson.annotations.SerializedName + +data class RelatedArtistDto( + @SerializedName("id") + val id: String, + @SerializedName("external_urls") + val externalUrls: ExternalUrls, + @SerializedName("genres") + val genres: List, + @SerializedName("images") + val images: List, + @SerializedName("name") + val name: String, + @SerializedName("popularity") + val popularity: Int, + @SerializedName("followers") + val followers: FollowersDto, + @SerializedName("type") + val type: String, + @SerializedName("uri") + val uri: String +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/SeveralArtistsDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/SeveralArtistsDto.kt new file mode 100644 index 00000000..c033924c --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/SeveralArtistsDto.kt @@ -0,0 +1,8 @@ +package com.efedaniel.spotifystats.network.dto + +import com.google.gson.annotations.SerializedName + +data class SeveralArtistsDto( + @SerializedName("artists") + val artists : List +) diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/dto/TopAlbumDto.kt b/app/src/main/java/com/efedaniel/spotifystats/network/dto/TopAlbumDto.kt index 80ad9d24..48344534 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/network/dto/TopAlbumDto.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/network/dto/TopAlbumDto.kt @@ -3,8 +3,16 @@ package com.efedaniel.spotifystats.network.dto import com.google.gson.annotations.SerializedName data class TopAlbumDto( + @SerializedName("id") + val id: String, @SerializedName("images") val images: List, @SerializedName("name") - val name: String + val name: String, + @SerializedName("artist") + val artists: List, + @SerializedName("external_urls") + val externalUrls: ExternalUrls, + @SerializedName("uri") + val uri: String ) \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/service/ArtistApi.kt b/app/src/main/java/com/efedaniel/spotifystats/network/service/ArtistApi.kt new file mode 100644 index 00000000..b2237426 --- /dev/null +++ b/app/src/main/java/com/efedaniel/spotifystats/network/service/ArtistApi.kt @@ -0,0 +1,28 @@ +package com.efedaniel.spotifystats.network.service + +import com.efedaniel.spotifystats.network.dto.AlbumDto +import com.efedaniel.spotifystats.network.dto.ArtistDto +import com.efedaniel.spotifystats.network.dto.ArtistTopTracksDto +import com.efedaniel.spotifystats.network.dto.PaginatedResponse +import com.efedaniel.spotifystats.network.dto.SeveralArtistsDto +import com.efedaniel.spotifystats.network.dto.TopArtistDto +import com.efedaniel.spotifystats.network.dto.TopTrackDto +import io.reactivex.rxjava3.core.Single +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface ArtistApi { + + @GET("artists/{id}") + fun getArtist(@Path("id") id: String): Single + + @GET("artists/{id}/albums") + fun getArtistAlbum(@Path("id") id: String): Single> + + @GET("artists/{id}/top-tracks") + fun getArtistTopTracks(@Path("id") id: String): Single + + @GET("artists") + fun getSeveralArtist( @Query("ids") ids: List): Single +} \ No newline at end of file diff --git a/app/src/main/java/com/efedaniel/spotifystats/network/service/UserApi.kt b/app/src/main/java/com/efedaniel/spotifystats/network/service/UserApi.kt index d8431e1b..74689d56 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/network/service/UserApi.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/network/service/UserApi.kt @@ -1,16 +1,11 @@ package com.efedaniel.spotifystats.network.service -import com.efedaniel.spotifystats.network.dto.ArtistDto import com.efedaniel.spotifystats.network.dto.UserResponse import io.reactivex.rxjava3.core.Single import retrofit2.http.GET -import retrofit2.http.Path interface UserApi { @GET("me") fun getCurrentUser(): Single - - @GET("artists/{id}") - fun getArtist(@Path("id") id: String): Single -} \ No newline at end of file +} diff --git a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistScreen.kt b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistScreen.kt index 31970232..544749ce 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistScreen.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistScreen.kt @@ -1,7 +1,6 @@ package com.efedaniel.spotifystats.ui.scene.artist import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith @@ -34,7 +33,9 @@ fun ArtistScreen( modifier: Modifier = Modifier, viewModel: ArtistViewModel = hiltViewModel(), ) { - LaunchedEffect(key1 = id) { viewModel.fetchArtist(id) } + LaunchedEffect(key1 = id) { + viewModel.fetchArtistInformation(id) + } AnimatedContent( targetState = viewModel.state.screenState, diff --git a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistUiState.kt b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistUiState.kt index 5de87188..0c06529c 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistUiState.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistUiState.kt @@ -2,10 +2,15 @@ package com.efedaniel.spotifystats.ui.scene.artist import androidx.compose.runtime.Immutable import com.efedaniel.spotifystats.core.ScreenState +import com.efedaniel.spotifystats.domain.model.Album import com.efedaniel.spotifystats.domain.model.Artist +import com.efedaniel.spotifystats.domain.model.ArtistTrack @Immutable data class ArtistUiState( val screenState: ScreenState = ScreenState.SUCCESS, - val artist: Artist = Artist() + val artist: Artist = Artist(), + val album: List = emptyList(), + val tracks: List = emptyList(), + val severalArtist: List = emptyList() ) diff --git a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistViewModel.kt b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistViewModel.kt index 1ad971f4..040e713b 100644 --- a/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistViewModel.kt +++ b/app/src/main/java/com/efedaniel/spotifystats/ui/scene/artist/ArtistViewModel.kt @@ -7,7 +7,7 @@ import com.efedaniel.spotifystats.core.BaseViewModel import com.efedaniel.spotifystats.core.ScreenState.ERROR import com.efedaniel.spotifystats.core.ScreenState.LOADING import com.efedaniel.spotifystats.core.ScreenState.SUCCESS -import com.efedaniel.spotifystats.domain.manager.UserDomainManager +import com.efedaniel.spotifystats.domain.manager.ArtistDomainManager import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.kotlin.addTo import io.reactivex.rxjava3.kotlin.subscribeBy @@ -16,15 +16,27 @@ import javax.inject.Inject @HiltViewModel class ArtistViewModel @Inject constructor( - private val userDomainManager: UserDomainManager, + private val artistDomainManager: ArtistDomainManager, ): BaseViewModel() { var state by mutableStateOf(ArtistUiState(screenState = LOADING)) private set - fun fetchArtist(id: String?) { - userDomainManager - .getArtist(id.orEmpty()) + fun fetchArtistInformation(id: String?) { + id ?: kotlin.run { + state = ArtistUiState(screenState = ERROR) + Timber.e("The ID should not be null") + return + } + + fetchArtist(id) + fetchArtistAlbums(id) + fetchArtistTopTracks(id) + } + + fun fetchArtist(id: String) { + artistDomainManager + .getArtist(id) .doOnSubscribe { state = state.copy(screenState = LOADING) } .subscribeBy( onSuccess = { @@ -34,7 +46,68 @@ class ArtistViewModel @Inject constructor( ) }, onError = { - state = ArtistUiState(screenState = ERROR,) + state = ArtistUiState(screenState = ERROR) + Timber.e("There was an error") + Timber.e(it) + } + ) + .addTo(disposables) + } + + fun fetchArtistAlbums(id: String) { + artistDomainManager.getArtistAlbum(id) + .doOnSubscribe { state = state.copy(screenState = LOADING) } + .subscribe({ albumList -> + state = state.copy( + screenState = SUCCESS, + album = albumList + ) + Timber.d(albumList.toString()) + + }, { error -> + state = state.copy(screenState = ERROR,) + Timber.e("There was an error") + Timber.e(error) + + }) + .addTo(disposables) + } + + fun fetchArtistTopTracks(id: String?) { + artistDomainManager + .getArtistTopTracks(id.orEmpty()) + .doOnSubscribe { state = state.copy(screenState = LOADING) } + .subscribeBy ( + onSuccess = { topTracks -> + state = state.copy( + screenState = SUCCESS, + tracks = topTracks ) + Timber.d(topTracks.toString()) + }, + onError = { + state = state.copy(screenState = ERROR,) + Timber.e("There was an error") + Timber.e(it) + } + ) + .addTo(disposables) + } + + // TODO @ufuoma remove this + fun fetchSeveralArtists(id: List) { + artistDomainManager + .getSeveralArtists(id) + .doOnSubscribe { state = state.copy(screenState = LOADING) } + .subscribeBy( + onSuccess = { artists -> + state = state.copy( + screenState = SUCCESS, + severalArtist = artists + ) + Timber.d(artists.toString()) + }, + onError = { + state = state.copy(screenState = ERROR,) Timber.e("There was an error") Timber.e(it) } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b415..5ce119eb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ +#Mon Aug 05 06:32:54 WAT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME