From 40cbf289af85024584437ac831ffc12ee5921c20 Mon Sep 17 00:00:00 2001 From: CappielloAntonio Date: Sun, 19 Dec 2021 16:48:43 +0100 Subject: [PATCH] Implementation of the display of song lyrics where present --- .idea/misc.xml | 4 +- .../play/repository/SongRepository.java | 23 ++++++ .../play/subsonic/models/Lyrics.java | 5 +- .../subsonic/models/SubsonicResponse.java | 1 + .../fragment/PlayerBottomSheetFragment.java | 39 ++++++++-- .../viewmodel/PlayerBottomSheetViewModel.java | 11 +++ .../res/layout/player_body_bottom_sheet.xml | 76 +++++++++++++++++-- app/src/main/res/values/strings.xml | 3 + 8 files changed, 148 insertions(+), 14 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 202a98d4..e4441683 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -30,6 +30,7 @@ + @@ -107,11 +108,12 @@ - + + diff --git a/app/src/main/java/com/cappielloantonio/play/repository/SongRepository.java b/app/src/main/java/com/cappielloantonio/play/repository/SongRepository.java index c7a276f7..a2558826 100644 --- a/app/src/main/java/com/cappielloantonio/play/repository/SongRepository.java +++ b/app/src/main/java/com/cappielloantonio/play/repository/SongRepository.java @@ -264,4 +264,27 @@ public class SongRepository { return song; } + + public MutableLiveData getSongLyrics(Song song) { + MutableLiveData lyrics = new MutableLiveData<>(null); + + App.getSubsonicClientInstance(application, false) + .getMediaRetrievalClient() + .getLyrics(song.getArtistName(), song.getTitle()) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getLyrics() != null) { + lyrics.setValue(response.body().getLyrics().getContent()); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + } + }); + + return lyrics; + } } diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/models/Lyrics.java b/app/src/main/java/com/cappielloantonio/play/subsonic/models/Lyrics.java index 20401b64..edaec4dd 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/models/Lyrics.java +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/models/Lyrics.java @@ -1,11 +1,12 @@ package com.cappielloantonio.play.subsonic.models; import com.tickaroo.tikxml.annotation.Attribute; +import com.tickaroo.tikxml.annotation.TextContent; import com.tickaroo.tikxml.annotation.Xml; -@Xml +@Xml(name = "lyrics") public class Lyrics { - @Attribute(name = "value") + @TextContent protected String content; @Attribute protected String artist; diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/models/SubsonicResponse.java b/app/src/main/java/com/cappielloantonio/play/subsonic/models/SubsonicResponse.java index 97754522..d9916731 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/models/SubsonicResponse.java +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/models/SubsonicResponse.java @@ -30,6 +30,7 @@ public class SubsonicResponse { private InternetRadioStations internetRadioStations; private NewestPodcasts newestPodcasts; private Podcasts podcasts; + @Element(name = "lyrics") private Lyrics lyrics; @Element(name = "songsByGenre") private Songs songsByGenre; diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerBottomSheetFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerBottomSheetFragment.java index 4bd47cea..2a5c6cea 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerBottomSheetFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerBottomSheetFragment.java @@ -75,6 +75,7 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class); init(); + initLyricsView(); initQueueSlideView(); initQueueRecyclerView(); initFavoriteButtonClick(); @@ -122,10 +123,25 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE } private void init() { - bodyBind.playerMoveDownBottomSheet.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - activity.collapseBottomSheet(); + bodyBind.playerMoveDownBottomSheet.setOnClickListener(view -> activity.collapseBottomSheet()); + } + + private void initLyricsView() { + playerBottomSheetViewModel.getLyrics().observe(requireActivity(), lyrics -> { + if (lyrics != null && !lyrics.trim().equals("")) { + bodyBind.playerSongLyricsCardview.setVisibility(View.VISIBLE); + } else { + bodyBind.playerSongLyricsCardview.setVisibility(View.GONE); + } + + bodyBind.playerSongLyricsTextView.setText(MusicUtil.getReadableString(lyrics)); + }); + + bodyBind.playerSongLyricsLabelClickable.setOnClickListener(view -> { + if (bodyBind.playerSongLyricsTextView.getVisibility() == View.INVISIBLE || bodyBind.playerSongLyricsTextView.getVisibility() == View.GONE) { + setLyricsTextViewVisibility(true); + } else { + setLyricsTextViewVisibility(false); } }); } @@ -236,7 +252,7 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE } private void initFavoriteButtonClick() { - bodyBind.buttonFavorite.setOnClickListener(v -> playerBottomSheetViewModel.setFavorite(requireContext() )); + bodyBind.buttonFavorite.setOnClickListener(v -> playerBottomSheetViewModel.setFavorite(requireContext())); bodyBind.buttonFavorite.setOnLongClickListener(v -> { Bundle bundle = new Bundle(); bundle.putParcelable("song_object", playerBottomSheetViewModel.getCurrentSong()); @@ -301,6 +317,9 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE } private void setSongInfo(Song song) { + setLyricsTextViewVisibility(false); + playerBottomSheetViewModel.refreshSongLyrics(requireActivity(), song); + bodyBind.playerSongTitleLabel.setText(MusicUtil.getReadableString(song.getTitle())); bodyBind.playerArtistNameLabel.setText(MusicUtil.getReadableString(song.getArtistName())); @@ -316,6 +335,16 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE bodyBind.buttonFavorite.setChecked(song.isFavorite()); } + private void setLyricsTextViewVisibility(boolean isVisible) { + if(isVisible) { + bodyBind.playerSongLyricsTextView.setVisibility(View.VISIBLE); + bodyBind.playerSongLyricsLabelClickable.setText(R.string.player_hide_lyrics_button); + } else { + bodyBind.playerSongLyricsTextView.setVisibility(View.GONE); + bodyBind.playerSongLyricsLabelClickable.setText(R.string.player_show_lyrics_button); + } + } + protected void updatePlayPauseState() { headerBind.playerHeaderButton.setChecked(!MusicPlayerRemote.isPlaying()); } diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlayerBottomSheetViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlayerBottomSheetViewModel.java index 89883fb6..06ab7b4e 100644 --- a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlayerBottomSheetViewModel.java +++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlayerBottomSheetViewModel.java @@ -5,7 +5,9 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import com.cappielloantonio.play.model.Artist; import com.cappielloantonio.play.model.Queue; @@ -27,6 +29,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel { private final ArtistRepository artistRepository; private final QueueRepository queueRepository; + private final MutableLiveData songLyrics = new MutableLiveData<>(null); private final LiveData> queueSong; public PlayerBottomSheetViewModel(@NonNull Application application) { @@ -77,4 +80,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel { Song song = getCurrentSong(); return artistRepository.getArtist(song.getArtistId()); } + + public LiveData getLyrics() { + return songLyrics; + } + + public void refreshSongLyrics(LifecycleOwner owner, Song song) { + songRepository.getSongLyrics(song).observe(owner, songLyrics::postValue); + } } diff --git a/app/src/main/res/layout/player_body_bottom_sheet.xml b/app/src/main/res/layout/player_body_bottom_sheet.xml index b8a84a25..66296842 100644 --- a/app/src/main/res/layout/player_body_bottom_sheet.xml +++ b/app/src/main/res/layout/player_body_bottom_sheet.xml @@ -33,8 +33,8 @@ android:layout_height="32dp" android:layout_gravity="center_vertical" android:layout_marginEnd="8dp" - android:foreground="?android:attr/selectableItemBackgroundBorderless" - android:background="@drawable/ic_bottom_sheet_down" /> + android:background="@drawable/ic_bottom_sheet_down" + android:foreground="?android:attr/selectableItemBackgroundBorderless" /> @@ -148,7 +148,7 @@ app:layout_constraintTop_toBottomOf="@+id/player_song_title_label" /> + + + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/player_song_lyrics_cardview" /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6155efb8..08e45380 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -111,6 +111,9 @@ Settings Unpin Now playing + Hide + Show + Lyrics The playing notification provides actions for play/pause etc. Playing Notification Playlist Catalogue