From 26edcdf4daf7859287b46cf85a70d5b5681a83bd Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 23:26:39 +0530 Subject: [PATCH] WIP Lyrics --- app/build.gradle | 3 +- app/src/debug/res/values/styles.xml | 9 ++-- .../code/name/monkey/retromusic/MainModule.kt | 39 +++++++++++++- .../adapter/album/AlbumCoverPagerAdapter.kt | 6 ++- .../monkey/retromusic/dialogs/LyricsDialog.kt | 51 +++++++++++++++++++ .../retromusic/extensions/DialogExtension.kt | 2 +- .../fragments/search/SearchViewModel.kt | 4 +- .../glide/artistimage/ArtistImageLoader.kt | 4 +- .../{deezer => model}/DeezerResponse.kt | 2 +- .../{deezer => network}/DeezerService.kt | 3 +- .../retromusic/network/LyricsService.kt | 12 +++++ .../retromusic/network/RetrofitClient.kt | 32 ++++-------- .../conversion/LyricsConverterFactory.kt | 51 +++++++++++++++++++ .../retromusic/repository/Repository.kt | 11 +++- .../name/monkey/retromusic/util/MusicUtil.kt | 4 +- app/src/main/res/layout/item_contributor.xml | 1 + app/src/main/res/layout/lyrics_dialog.xml | 33 ++++++++++++ app/src/main/res/values/styles.xml | 6 ++- 18 files changed, 228 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt rename app/src/main/java/code/name/monkey/retromusic/{deezer => model}/DeezerResponse.kt (94%) rename app/src/main/java/code/name/monkey/retromusic/{deezer => network}/DeezerService.kt (95%) create mode 100644 app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt create mode 100644 app/src/main/res/layout/lyrics_dialog.xml diff --git a/app/build.gradle b/app/build.gradle index d928d693..4725b1d8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -161,7 +161,6 @@ dependencies { implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r' - implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod' implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' @@ -169,7 +168,7 @@ dependencies { implementation 'com.r0adkll:slidableactivity:2.1.0' implementation 'com.heinrichreimersoftware:material-intro:1.6' implementation 'com.github.dhaval2404:imagepicker:1.7.1' - + implementation 'org.jsoup:jsoup:1.11.1' implementation 'me.zhanghai.android.fastscroll:library:1.1.0' implementation 'me.jorgecastillo:androidcolorx:0.2.0' diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml index 7f4fe30c..c45bc56a 100644 --- a/app/src/debug/res/values/styles.xml +++ b/app/src/debug/res/values/styles.xml @@ -60,20 +60,23 @@ \ No newline at end of file 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 8d0fafa8..fe513d50 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -14,7 +14,7 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel import code.name.monkey.retromusic.model.Genre -import code.name.monkey.retromusic.network.networkModule +import code.name.monkey.retromusic.network.* import code.name.monkey.retromusic.repository.* import code.name.monkey.retromusic.util.FilePathUtil import kotlinx.coroutines.Dispatchers.IO @@ -25,6 +25,28 @@ import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.bind import org.koin.dsl.module +val networkModule = module { + + factory { + provideDefaultCache() + } + factory { + provideOkHttp(get(), get()) + } + single { + provideLastFmRetrofit(get()) + } + single { + provideDeezerRest(get()) + } + single { + provideLastFmRest(get()) + } + single { + provideLyrics(get()) + } +} + private val roomModule = module { single { @@ -72,7 +94,20 @@ private val mainModule = module { } private val dataModule = module { single { - RealRepository(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) + RealRepository( + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get() + ) } bind Repository::class single { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index 039aa9fe..8cd40e97 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.dialogs.LyricsDialog import code.name.monkey.retromusic.fragments.AlbumCoverStyle import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.glide.RetroMusicColoredTarget @@ -90,14 +91,15 @@ class AlbumCoverPagerAdapter( val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false) albumCover = view.findViewById(R.id.player_image) albumCover.setOnClickListener { - showLyricsDialog() + LyricsDialog().show(childFragmentManager, "LyricsDialog") + //showLyricsDialog() } return view } private fun showLyricsDialog() { lifecycleScope.launch(Dispatchers.IO) { - val data = MusicUtil.getLyrics(song) + val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found" withContext(Dispatchers.Main) { MaterialAlertDialogBuilder( requireContext(), diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt new file mode 100644 index 00000000..d1f5f022 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt @@ -0,0 +1,51 @@ +package code.name.monkey.retromusic.dialogs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.network.Result +import code.name.monkey.retromusic.repository.Repository +import kotlinx.android.synthetic.main.lyrics_dialog.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.android.ext.android.inject + +class LyricsDialog : DialogFragment() { + override fun getTheme(): Int { + return R.style.MaterialAlertDialogTheme + } + + private val repository by inject() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.lyrics_dialog, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + lifecycleScope.launch(IO) { + val result: Result = repository.lyrics( + MusicPlayerRemote.currentSong.artistName, + MusicPlayerRemote.currentSong.title + ) + withContext(Main) { + when (result) { + is Result.Error -> println("Error") + is Result.Loading -> println("Loading") + is Result.Success -> lyricsText.text = result.data + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt index d2c38310..c56a4045 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt @@ -8,7 +8,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder fun DialogFragment.materialDialog(title: Int): MaterialAlertDialogBuilder { return MaterialAlertDialogBuilder( requireContext(), - R.style.ThemeOverlay_MaterialComponents_Dialog_Alert + R.style.MaterialAlertDialogTheme ).setTitle(title) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt index eecff933..50681023 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt @@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.repository.RealRepository import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class SearchViewModel(private val realRepository: RealRepository) : ViewModel() { private val results = MutableLiveData>() @@ -17,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel() fun search(query: String?) = viewModelScope.launch(IO) { val result = realRepository.search(query) - withContext(Main) { results.postValue(result) } + results.value = result } } \ No newline at end of file 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 f9792c42..43d23120 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 @@ -15,8 +15,8 @@ package code.name.monkey.retromusic.glide.artistimage import android.content.Context -import code.name.monkey.retromusic.deezer.Data -import code.name.monkey.retromusic.deezer.DeezerService +import code.name.monkey.retromusic.model.Data +import code.name.monkey.retromusic.network.DeezerService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Priority diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt similarity index 94% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt rename to app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt index b029ab53..929a9d13 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt @@ -1,4 +1,4 @@ -package code.name.monkey.retromusic.deezer +package code.name.monkey.retromusic.model import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt similarity index 95% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt rename to app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt index 327f6848..1ea0c16c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt @@ -1,6 +1,7 @@ -package code.name.monkey.retromusic.deezer +package code.name.monkey.retromusic.network import android.content.Context +import code.name.monkey.retromusic.model.DeezerResponse import okhttp3.Cache import okhttp3.Interceptor import okhttp3.OkHttpClient diff --git a/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt new file mode 100644 index 00000000..0a0e0490 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.network + +import retrofit2.http.GET +import retrofit2.http.Headers +import retrofit2.http.Query + +interface LyricsRestService { + + @Headers("Cache-Control: public") + @GET("/lyrics") + suspend fun getLyrics(@Query("artist") artist: String, @Query("title") title: String): String +} \ No newline at end of file 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 2121c812..df75072d 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 @@ -3,39 +3,17 @@ package code.name.monkey.retromusic.network import android.content.Context import code.name.monkey.retromusic.App import code.name.monkey.retromusic.BuildConfig -import code.name.monkey.retromusic.deezer.DeezerService +import code.name.monkey.retromusic.network.conversion.LyricsConverterFactory import com.google.gson.Gson import okhttp3.Cache import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import org.koin.dsl.module import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.util.concurrent.TimeUnit -private const val TIMEOUT: Long = 700 - -val networkModule = module { - - factory { - provideDefaultCache() - } - factory { - provideOkHttp(get(), get()) - } - single { - provideLastFmRetrofit(get()) - } - single { - provideDeezerRest(get()) - } - single { - provideLastFmRest(get()) - } -} - fun provideDefaultCache(): Cache? { val cacheDir = File(App.getContext().cacheDir.absolutePath, "/okhttp-lastfm/") if (cacheDir.mkdirs() || cacheDir.isDirectory) { @@ -94,4 +72,12 @@ fun provideDeezerRest(retrofit: Retrofit): DeezerService { .baseUrl("https://api.deezer.com/") .build() return newBuilder.create(DeezerService::class.java) +} + +fun provideLyrics(retrofit: Retrofit): LyricsRestService { + val newBuilder = retrofit.newBuilder() + .baseUrl("https://makeitpersonal.co") + .addConverterFactory(LyricsConverterFactory()) + .build() + return newBuilder.create(LyricsRestService::class.java) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt new file mode 100644 index 00000000..474e81c9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Naman Dwivedi. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ +package code.name.monkey.retromusic.network.conversion + +import okhttp3.MediaType +import okhttp3.RequestBody +import okhttp3.ResponseBody +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.Type + +class LyricsConverterFactory : Converter.Factory() { + + override fun responseBodyConverter( + type: Type?, + annotations: Array?, + retrofit: Retrofit? + ): Converter? { + return if (String::class.java == type) { + Converter { value -> value.string() } + } else null + } + + override fun requestBodyConverter( + type: Type?, + parameterAnnotations: Array?, + methodAnnotations: Array?, + retrofit: Retrofit? + ): Converter<*, RequestBody>? { + + return if (String::class.java == type) { + Converter { value -> RequestBody.create(MEDIA_TYPE, value) } + } else null + } + + companion object { + private val MEDIA_TYPE = MediaType.parse("text/plain") + } +} \ 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 4dd683a1..32ca1ffe 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 @@ -21,6 +21,7 @@ import code.name.monkey.retromusic.db.* 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.LyricsRestService import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.Result.* import code.name.monkey.retromusic.network.model.LastFmAlbum @@ -94,6 +95,7 @@ interface Repository { suspend fun checkSongExistInPlayCount(songId: Int): List suspend fun playCountSongs(): List suspend fun blackListPaths(): List + suspend fun lyrics(artist: String, title: String): Result } class RealRepository( @@ -107,9 +109,16 @@ class RealRepository( private val playlistRepository: PlaylistRepository, private val searchRepository: RealSearchRepository, private val topPlayedRepository: TopPlayedRepository, - private val roomRepository: RoomRepository + private val roomRepository: RoomRepository, + private val lyricsRestService: LyricsRestService ) : Repository { + override suspend fun lyrics(artist: String, title: String): Result = try { + Success(lyricsRestService.getLyrics(artist, title)) + } catch (e: Exception) { + Error + } + override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index a3bbf776..8659a0ba 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -111,7 +111,7 @@ object MusicUtil : KoinComponent { } fun getLyrics(song: Song): String? { - var lyrics: String? = null + var lyrics: String? = "No lyrics found" val file = File(song.data) try { lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) @@ -151,7 +151,7 @@ object MusicUtil : KoinComponent { } false } - if (files != null && files.size > 0) { + if (files != null && files.isNotEmpty()) { for (f in files) { try { val newLyrics = diff --git a/app/src/main/res/layout/item_contributor.xml b/app/src/main/res/layout/item_contributor.xml index ef73b468..d7ba8832 100644 --- a/app/src/main/res/layout/item_contributor.xml +++ b/app/src/main/res/layout/item_contributor.xml @@ -32,6 +32,7 @@ android:scaleType="centerCrop" app:civ_border="false" app:civ_shadow="false" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:retroCornerSize="21dp" diff --git a/app/src/main/res/layout/lyrics_dialog.xml b/app/src/main/res/layout/lyrics_dialog.xml new file mode 100644 index 00000000..27fa8a95 --- /dev/null +++ b/app/src/main/res/layout/lyrics_dialog.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c0eb21c3..3c37bd74 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -215,14 +215,16 @@