diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 16741bc6..8d0fafa8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -55,12 +55,13 @@ private val roomModule = module { factory { get().playCountDao() } + factory { get().historyDao() } single { - RealRoomRepository(get(), get(), get()) + RealRoomRepository(get(), get(), get(), get()) } bind RoomRepository::class } private val mainModule = module { diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt b/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt similarity index 97% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt rename to app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt index fd107234..327f6848 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt @@ -16,7 +16,7 @@ import java.util.* private const val BASE_QUERY_ARTIST = "search/artist" private const val BASE_URL = "https://api.deezer.com/" -interface DeezerApiService { +interface DeezerService { @GET("$BASE_QUERY_ARTIST&limit=1") fun getArtistImage( @@ -26,7 +26,7 @@ interface DeezerApiService { companion object { operator fun invoke( client: okhttp3.Call.Factory - ): DeezerApiService { + ): DeezerService { return Retrofit.Builder() .baseUrl(BASE_URL) .callFactory(client) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt index c71bcceb..6c7230a5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt @@ -104,7 +104,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de adapter = songAdapter layoutManager = linearLayoutManager() } - repository.historySong().observe(viewLifecycleOwner, Observer { + repository.observableHistorySongs().observe(viewLifecycleOwner, Observer { val songs = it.map { historyEntity -> historyEntity.toSong() } songAdapter.swapDataSet(songs) }) diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt index 398916ce..f9792c42 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt @@ -16,7 +16,7 @@ package code.name.monkey.retromusic.glide.artistimage import android.content.Context import code.name.monkey.retromusic.deezer.Data -import code.name.monkey.retromusic.deezer.DeezerApiService +import code.name.monkey.retromusic.deezer.DeezerService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Priority @@ -38,7 +38,7 @@ class ArtistImage(val artistName: String) class ArtistImageFetcher( private val context: Context, - private val deezerApiService: DeezerApiService, + private val deezerService: DeezerService, val model: ArtistImage, val urlLoader: ModelLoader, val width: Int, @@ -66,7 +66,7 @@ class ArtistImageFetcher( PreferenceUtil.isAllowedToDownloadMetadata() ) { val artists = model.artistName.split(",") - val response = deezerApiService.getArtistImage(artists[0]).execute() + val response = deezerService.getArtistImage(artists[0]).execute() if (!response.isSuccessful) { throw IOException("Request failed with code: " + response.code()) @@ -106,7 +106,7 @@ class ArtistImageFetcher( class ArtistImageLoader( val context: Context, - private val deezerApiService: DeezerApiService, + private val deezerService: DeezerService, private val urlLoader: ModelLoader ) : StreamModelLoader { @@ -115,7 +115,7 @@ class ArtistImageLoader( width: Int, height: Int ): DataFetcher { - return ArtistImageFetcher(context, deezerApiService, model, urlLoader, width, height) + return ArtistImageFetcher(context, deezerService, model, urlLoader, width, height) } } @@ -123,7 +123,7 @@ class Factory( val context: Context ) : ModelLoaderFactory { - private var deezerApiService: DeezerApiService + private var deezerService: DeezerService private var okHttpFactory: OkHttpUrlLoader.Factory init { @@ -134,8 +134,8 @@ class Factory( .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .build() ) - deezerApiService = DeezerApiService.invoke( - DeezerApiService.createDefaultOkHttpClient(context) + deezerService = DeezerService.invoke( + DeezerService.createDefaultOkHttpClient(context) .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) @@ -156,7 +156,7 @@ class Factory( ): ModelLoader { return ArtistImageLoader( context!!, - deezerApiService, + deezerService, okHttpFactory.build(context, factories) ) } diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt index affb3823..2121c812 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt @@ -1,12 +1,14 @@ package code.name.monkey.retromusic.network +import android.content.Context import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.Constants.AUDIO_SCROBBLER_URL +import code.name.monkey.retromusic.BuildConfig +import code.name.monkey.retromusic.deezer.DeezerService import com.google.gson.Gson import okhttp3.Cache -import okhttp3.ConnectionPool import okhttp3.Interceptor import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor import org.koin.dsl.module import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @@ -16,50 +18,22 @@ import java.util.concurrent.TimeUnit private const val TIMEOUT: Long = 700 val networkModule = module { - factory { - provideHttpClient(get(), get()) - } - factory { - provideCacheControlInterceptor() - } + factory { provideDefaultCache() } factory { - provideLastFmService(get()) + provideOkHttp(get(), get()) } single { - providerRetrofit(get()) + provideLastFmRetrofit(get()) + } + single { + provideDeezerRest(get()) + } + single { + provideLastFmRest(get()) } -} - -fun provideLastFmService(retrofit: Retrofit): LastFMService = - retrofit.create(LastFMService::class.java) - -fun providerRetrofit(okHttpClient: OkHttpClient.Builder): Retrofit = Retrofit.Builder() - .baseUrl(AUDIO_SCROBBLER_URL) - .callFactory(okHttpClient.build()) - .addConverterFactory(GsonConverterFactory.create(Gson())) - .build() - -fun provideHttpClient( - cache: Cache, - interceptor: Interceptor -): OkHttpClient.Builder = OkHttpClient.Builder() - .connectionPool(ConnectionPool(0, 1, TimeUnit.NANOSECONDS)) - .retryOnConnectionFailure(true) - .connectTimeout(TIMEOUT, TimeUnit.MINUTES) - .writeTimeout(TIMEOUT, TimeUnit.MINUTES) - .readTimeout(TIMEOUT, TimeUnit.MINUTES) - .cache(cache) - .addInterceptor(interceptor) - - -fun provideCacheControlInterceptor(): Interceptor = Interceptor { chain: Interceptor.Chain -> - val modifiedRequest = chain.request().newBuilder() - .addHeader("Cache-Control", "max-age=31536000, max-stale=31536000") - .build() - chain.proceed(modifiedRequest) } fun provideDefaultCache(): Cache? { @@ -69,3 +43,55 @@ fun provideDefaultCache(): Cache? { } return null } + +fun logInterceptor(): Interceptor { + val loggingInterceptor = HttpLoggingInterceptor() + if (BuildConfig.DEBUG) { + loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY + } else { + // disable retrofit log on release + loggingInterceptor.level = HttpLoggingInterceptor.Level.NONE + } + return loggingInterceptor +} + +fun headerInterceptor(context: Context): Interceptor { + return Interceptor { + val original = it.request() + val request = original.newBuilder() + .header("User-Agent", context.packageName) + .addHeader("Content-Type", "application/json; charset=utf-8") + .method(original.method(), original.body()) + .build() + it.proceed(request) + } +} + +fun provideOkHttp(context: Context, cache: Cache): OkHttpClient { + return OkHttpClient.Builder() + .addNetworkInterceptor(logInterceptor()) + .addInterceptor(headerInterceptor(context)) + .connectTimeout(1, TimeUnit.SECONDS) + .readTimeout(1, TimeUnit.SECONDS) + .cache(cache) + .build() +} + +fun provideLastFmRetrofit(client: OkHttpClient): Retrofit { + return Retrofit.Builder() + .baseUrl("https://ws.audioscrobbler.com/2.0/") + .addConverterFactory(GsonConverterFactory.create(Gson())) + .callFactory { request -> client.newCall(request) } + .build() +} + +fun provideLastFmRest(retrofit: Retrofit): LastFMService { + return retrofit.create(LastFMService::class.java) +} + +fun provideDeezerRest(retrofit: Retrofit): DeezerService { + val newBuilder = retrofit.newBuilder() + .baseUrl("https://api.deezer.com/") + .build() + return newBuilder.create(DeezerService::class.java) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index f0af9ecc..4dd683a1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService import code.name.monkey.retromusic.network.Result +import code.name.monkey.retromusic.network.Result.* import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.network.model.LastFmArtist import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -153,9 +154,10 @@ class RealRepository( cache: String? ): Result { return try { - Result.Success(lastFMService.artistInfo(name, lang, cache)) + Success(lastFMService.artistInfo(name, lang, cache)) } catch (e: Exception) { - Result.Error + println(e) + Error } } @@ -165,15 +167,16 @@ class RealRepository( ): Result { return try { val lastFmAlbum = lastFMService.albumInfo(artist, album) - Result.Success(lastFmAlbum) + Success(lastFmAlbum) } catch (e: Exception) { - Result.Error + println(e) + Error } } @ExperimentalCoroutinesApi override suspend fun homeSectionsFlow(): Flow>> { - val homes = MutableStateFlow>>(value = Result.Loading) + val homes = MutableStateFlow>>(value = Loading) val homeSections = mutableListOf() val sections = listOf( topArtistsHome(), @@ -191,9 +194,9 @@ class RealRepository( } } if (homeSections.isEmpty()) { - homes.value = Result.Error + homes.value = Error } else { - homes.value = Result.Success(homeSections) + homes.value = Success(homeSections) } return homes } @@ -350,52 +353,52 @@ class RealRepository( } override fun songsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = songRepository.songs() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun albumsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = albumRepository.albums() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun artistsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = artistRepository.artists() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun playlistsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = playlistRepository.playlists() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun genresFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = genreRepository.genres() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } } \ No newline at end of file