Code refactor

main
Hemanth S 2020-09-06 16:33:24 +05:30
parent 332c2dc69b
commit 8eb7859f30
6 changed files with 104 additions and 74 deletions

View File

@ -55,12 +55,13 @@ private val roomModule = module {
factory { factory {
get<RetroDatabase>().playCountDao() get<RetroDatabase>().playCountDao()
} }
factory { factory {
get<RetroDatabase>().historyDao() get<RetroDatabase>().historyDao()
} }
single { single {
RealRoomRepository(get(), get(), get()) RealRoomRepository(get(), get(), get(), get())
} bind RoomRepository::class } bind RoomRepository::class
} }
private val mainModule = module { private val mainModule = module {

View File

@ -16,7 +16,7 @@ import java.util.*
private const val BASE_QUERY_ARTIST = "search/artist" private const val BASE_QUERY_ARTIST = "search/artist"
private const val BASE_URL = "https://api.deezer.com/" private const val BASE_URL = "https://api.deezer.com/"
interface DeezerApiService { interface DeezerService {
@GET("$BASE_QUERY_ARTIST&limit=1") @GET("$BASE_QUERY_ARTIST&limit=1")
fun getArtistImage( fun getArtistImage(
@ -26,7 +26,7 @@ interface DeezerApiService {
companion object { companion object {
operator fun invoke( operator fun invoke(
client: okhttp3.Call.Factory client: okhttp3.Call.Factory
): DeezerApiService { ): DeezerService {
return Retrofit.Builder() return Retrofit.Builder()
.baseUrl(BASE_URL) .baseUrl(BASE_URL)
.callFactory(client) .callFactory(client)

View File

@ -104,7 +104,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
adapter = songAdapter adapter = songAdapter
layoutManager = linearLayoutManager() layoutManager = linearLayoutManager()
} }
repository.historySong().observe(viewLifecycleOwner, Observer { repository.observableHistorySongs().observe(viewLifecycleOwner, Observer {
val songs = it.map { historyEntity -> historyEntity.toSong() } val songs = it.map { historyEntity -> historyEntity.toSong() }
songAdapter.swapDataSet(songs) songAdapter.swapDataSet(songs)
}) })

View File

@ -16,7 +16,7 @@ package code.name.monkey.retromusic.glide.artistimage
import android.content.Context import android.content.Context
import code.name.monkey.retromusic.deezer.Data 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.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
@ -38,7 +38,7 @@ class ArtistImage(val artistName: String)
class ArtistImageFetcher( class ArtistImageFetcher(
private val context: Context, private val context: Context,
private val deezerApiService: DeezerApiService, private val deezerService: DeezerService,
val model: ArtistImage, val model: ArtistImage,
val urlLoader: ModelLoader<GlideUrl, InputStream>, val urlLoader: ModelLoader<GlideUrl, InputStream>,
val width: Int, val width: Int,
@ -66,7 +66,7 @@ class ArtistImageFetcher(
PreferenceUtil.isAllowedToDownloadMetadata() PreferenceUtil.isAllowedToDownloadMetadata()
) { ) {
val artists = model.artistName.split(",") val artists = model.artistName.split(",")
val response = deezerApiService.getArtistImage(artists[0]).execute() val response = deezerService.getArtistImage(artists[0]).execute()
if (!response.isSuccessful) { if (!response.isSuccessful) {
throw IOException("Request failed with code: " + response.code()) throw IOException("Request failed with code: " + response.code())
@ -106,7 +106,7 @@ class ArtistImageFetcher(
class ArtistImageLoader( class ArtistImageLoader(
val context: Context, val context: Context,
private val deezerApiService: DeezerApiService, private val deezerService: DeezerService,
private val urlLoader: ModelLoader<GlideUrl, InputStream> private val urlLoader: ModelLoader<GlideUrl, InputStream>
) : StreamModelLoader<ArtistImage> { ) : StreamModelLoader<ArtistImage> {
@ -115,7 +115,7 @@ class ArtistImageLoader(
width: Int, width: Int,
height: Int height: Int
): DataFetcher<InputStream> { ): DataFetcher<InputStream> {
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 val context: Context
) : ModelLoaderFactory<ArtistImage, InputStream> { ) : ModelLoaderFactory<ArtistImage, InputStream> {
private var deezerApiService: DeezerApiService private var deezerService: DeezerService
private var okHttpFactory: OkHttpUrlLoader.Factory private var okHttpFactory: OkHttpUrlLoader.Factory
init { init {
@ -134,8 +134,8 @@ class Factory(
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build() .build()
) )
deezerApiService = DeezerApiService.invoke( deezerService = DeezerService.invoke(
DeezerApiService.createDefaultOkHttpClient(context) DeezerService.createDefaultOkHttpClient(context)
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
@ -156,7 +156,7 @@ class Factory(
): ModelLoader<ArtistImage, InputStream> { ): ModelLoader<ArtistImage, InputStream> {
return ArtistImageLoader( return ArtistImageLoader(
context!!, context!!,
deezerApiService, deezerService,
okHttpFactory.build(context, factories) okHttpFactory.build(context, factories)
) )
} }

View File

@ -1,12 +1,14 @@
package code.name.monkey.retromusic.network package code.name.monkey.retromusic.network
import android.content.Context
import code.name.monkey.retromusic.App 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 com.google.gson.Gson
import okhttp3.Cache import okhttp3.Cache
import okhttp3.ConnectionPool
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.koin.dsl.module import org.koin.dsl.module
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
@ -16,50 +18,22 @@ import java.util.concurrent.TimeUnit
private const val TIMEOUT: Long = 700 private const val TIMEOUT: Long = 700
val networkModule = module { val networkModule = module {
factory {
provideHttpClient(get(), get())
}
factory {
provideCacheControlInterceptor()
}
factory { factory {
provideDefaultCache() provideDefaultCache()
} }
factory { factory {
provideLastFmService(get()) provideOkHttp(get(), get())
} }
single { 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? { fun provideDefaultCache(): Cache? {
@ -69,3 +43,55 @@ fun provideDefaultCache(): Cache? {
} }
return null 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)
}

View File

@ -22,6 +22,7 @@ import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist
import code.name.monkey.retromusic.network.LastFMService 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.Result.*
import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.network.model.LastFmArtist import code.name.monkey.retromusic.network.model.LastFmArtist
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -153,9 +154,10 @@ class RealRepository(
cache: String? cache: String?
): Result<LastFmArtist> { ): Result<LastFmArtist> {
return try { return try {
Result.Success(lastFMService.artistInfo(name, lang, cache)) Success(lastFMService.artistInfo(name, lang, cache))
} catch (e: Exception) { } catch (e: Exception) {
Result.Error println(e)
Error
} }
} }
@ -165,15 +167,16 @@ class RealRepository(
): Result<LastFmAlbum> { ): Result<LastFmAlbum> {
return try { return try {
val lastFmAlbum = lastFMService.albumInfo(artist, album) val lastFmAlbum = lastFMService.albumInfo(artist, album)
Result.Success(lastFmAlbum) Success(lastFmAlbum)
} catch (e: Exception) { } catch (e: Exception) {
Result.Error println(e)
Error
} }
} }
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
override suspend fun homeSectionsFlow(): Flow<Result<List<Home>>> { override suspend fun homeSectionsFlow(): Flow<Result<List<Home>>> {
val homes = MutableStateFlow<Result<List<Home>>>(value = Result.Loading) val homes = MutableStateFlow<Result<List<Home>>>(value = Loading)
val homeSections = mutableListOf<Home>() val homeSections = mutableListOf<Home>()
val sections = listOf( val sections = listOf(
topArtistsHome(), topArtistsHome(),
@ -191,9 +194,9 @@ class RealRepository(
} }
} }
if (homeSections.isEmpty()) { if (homeSections.isEmpty()) {
homes.value = Result.Error homes.value = Error
} else { } else {
homes.value = Result.Success(homeSections) homes.value = Success(homeSections)
} }
return homes return homes
} }
@ -350,52 +353,52 @@ class RealRepository(
} }
override fun songsFlow(): Flow<Result<List<Song>>> = flow { override fun songsFlow(): Flow<Result<List<Song>>> = flow {
emit(Result.Loading) emit(Loading)
val data = songRepository.songs() val data = songRepository.songs()
if (data.isEmpty()) { if (data.isEmpty()) {
emit(Result.Error) emit(Error)
} else { } else {
emit(Result.Success(data)) emit(Success(data))
} }
} }
override fun albumsFlow(): Flow<Result<List<Album>>> = flow { override fun albumsFlow(): Flow<Result<List<Album>>> = flow {
emit(Result.Loading) emit(Loading)
val data = albumRepository.albums() val data = albumRepository.albums()
if (data.isEmpty()) { if (data.isEmpty()) {
emit(Result.Error) emit(Error)
} else { } else {
emit(Result.Success(data)) emit(Success(data))
} }
} }
override fun artistsFlow(): Flow<Result<List<Artist>>> = flow { override fun artistsFlow(): Flow<Result<List<Artist>>> = flow {
emit(Result.Loading) emit(Loading)
val data = artistRepository.artists() val data = artistRepository.artists()
if (data.isEmpty()) { if (data.isEmpty()) {
emit(Result.Error) emit(Error)
} else { } else {
emit(Result.Success(data)) emit(Success(data))
} }
} }
override fun playlistsFlow(): Flow<Result<List<Playlist>>> = flow { override fun playlistsFlow(): Flow<Result<List<Playlist>>> = flow {
emit(Result.Loading) emit(Loading)
val data = playlistRepository.playlists() val data = playlistRepository.playlists()
if (data.isEmpty()) { if (data.isEmpty()) {
emit(Result.Error) emit(Error)
} else { } else {
emit(Result.Success(data)) emit(Success(data))
} }
} }
override fun genresFlow(): Flow<Result<List<Genre>>> = flow { override fun genresFlow(): Flow<Result<List<Genre>>> = flow {
emit(Result.Loading) emit(Loading)
val data = genreRepository.genres() val data = genreRepository.genres()
if (data.isEmpty()) { if (data.isEmpty()) {
emit(Result.Error) emit(Error)
} else { } else {
emit(Result.Success(data)) emit(Success(data))
} }
} }
} }