Implementation of the display of song lyrics where present

This commit is contained in:
CappielloAntonio 2021-12-19 16:48:43 +01:00
parent 12ce97836d
commit 40cbf289af
8 changed files with 148 additions and 14 deletions

4
.idea/misc.xml generated
View file

@ -30,6 +30,7 @@
<entry key="app/src/main/res/drawable/ic_graphic_eq.xml" value="0.28055555555555556" /> <entry key="app/src/main/res/drawable/ic_graphic_eq.xml" value="0.28055555555555556" />
<entry key="app/src/main/res/drawable/ic_home.xml" value="0.28055555555555556" /> <entry key="app/src/main/res/drawable/ic_home.xml" value="0.28055555555555556" />
<entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.2814814814814815" /> <entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.2814814814814815" />
<entry key="app/src/main/res/drawable/ic_lyrics.xml" value="0.17314814814814813" />
<entry key="app/src/main/res/drawable/ic_more_vert.xml" value="0.28055555555555556" /> <entry key="app/src/main/res/drawable/ic_more_vert.xml" value="0.28055555555555556" />
<entry key="app/src/main/res/drawable/ic_pause.xml" value="0.28055555555555556" /> <entry key="app/src/main/res/drawable/ic_pause.xml" value="0.28055555555555556" />
<entry key="app/src/main/res/drawable/ic_play.xml" value="0.27685185185185185" /> <entry key="app/src/main/res/drawable/ic_play.xml" value="0.27685185185185185" />
@ -107,11 +108,12 @@
<entry key="app/src/main/res/layout/item_placeholder_year.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/layout/item_placeholder_year.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/layout/item_player_now_playing_song.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/layout/item_player_now_playing_song.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/layout/item_player_queue_song.xml" value="0.1" /> <entry key="app/src/main/res/layout/item_player_queue_song.xml" value="0.1" />
<entry key="app/src/main/res/layout/player_body_bottom_sheet.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/layout/player_body_bottom_sheet.xml" value="0.8" />
<entry key="app/src/main/res/layout/player_header_bottom_sheet.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/layout/player_header_bottom_sheet.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/menu/bottom_nav_menu.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/menu/bottom_nav_menu.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/menu/login_page_menu.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/menu/login_page_menu.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/menu/main_page_menu.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/menu/main_page_menu.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/menu/player_page_menu.xml" value="0.5178753830439223" />
<entry key="app/src/main/res/menu/playlist_page_menu.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/menu/playlist_page_menu.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/menu/toolbar_menu.xml" value="0.3229166666666667" /> <entry key="app/src/main/res/menu/toolbar_menu.xml" value="0.3229166666666667" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.28055555555555556" /> <entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.28055555555555556" />

View file

@ -264,4 +264,27 @@ public class SongRepository {
return song; return song;
} }
public MutableLiveData<String> getSongLyrics(Song song) {
MutableLiveData<String> lyrics = new MutableLiveData<>(null);
App.getSubsonicClientInstance(application, false)
.getMediaRetrievalClient()
.getLyrics(song.getArtistName(), song.getTitle())
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(@NonNull Call<SubsonicResponse> call, @NonNull Response<SubsonicResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getLyrics() != null) {
lyrics.setValue(response.body().getLyrics().getContent());
}
}
@Override
public void onFailure(@NonNull Call<SubsonicResponse> call, @NonNull Throwable t) {
}
});
return lyrics;
}
} }

View file

@ -1,11 +1,12 @@
package com.cappielloantonio.play.subsonic.models; package com.cappielloantonio.play.subsonic.models;
import com.tickaroo.tikxml.annotation.Attribute; import com.tickaroo.tikxml.annotation.Attribute;
import com.tickaroo.tikxml.annotation.TextContent;
import com.tickaroo.tikxml.annotation.Xml; import com.tickaroo.tikxml.annotation.Xml;
@Xml @Xml(name = "lyrics")
public class Lyrics { public class Lyrics {
@Attribute(name = "value") @TextContent
protected String content; protected String content;
@Attribute @Attribute
protected String artist; protected String artist;

View file

@ -30,6 +30,7 @@ public class SubsonicResponse {
private InternetRadioStations internetRadioStations; private InternetRadioStations internetRadioStations;
private NewestPodcasts newestPodcasts; private NewestPodcasts newestPodcasts;
private Podcasts podcasts; private Podcasts podcasts;
@Element(name = "lyrics")
private Lyrics lyrics; private Lyrics lyrics;
@Element(name = "songsByGenre") @Element(name = "songsByGenre")
private Songs songsByGenre; private Songs songsByGenre;

View file

@ -75,6 +75,7 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE
playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class); playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
init(); init();
initLyricsView();
initQueueSlideView(); initQueueSlideView();
initQueueRecyclerView(); initQueueRecyclerView();
initFavoriteButtonClick(); initFavoriteButtonClick();
@ -122,10 +123,25 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE
} }
private void init() { private void init() {
bodyBind.playerMoveDownBottomSheet.setOnClickListener(new View.OnClickListener() { bodyBind.playerMoveDownBottomSheet.setOnClickListener(view -> activity.collapseBottomSheet());
@Override }
public void onClick(View 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() { private void initFavoriteButtonClick() {
bodyBind.buttonFavorite.setOnClickListener(v -> playerBottomSheetViewModel.setFavorite(requireContext() )); bodyBind.buttonFavorite.setOnClickListener(v -> playerBottomSheetViewModel.setFavorite(requireContext()));
bodyBind.buttonFavorite.setOnLongClickListener(v -> { bodyBind.buttonFavorite.setOnLongClickListener(v -> {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable("song_object", playerBottomSheetViewModel.getCurrentSong()); bundle.putParcelable("song_object", playerBottomSheetViewModel.getCurrentSong());
@ -301,6 +317,9 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE
} }
private void setSongInfo(Song song) { private void setSongInfo(Song song) {
setLyricsTextViewVisibility(false);
playerBottomSheetViewModel.refreshSongLyrics(requireActivity(), song);
bodyBind.playerSongTitleLabel.setText(MusicUtil.getReadableString(song.getTitle())); bodyBind.playerSongTitleLabel.setText(MusicUtil.getReadableString(song.getTitle()));
bodyBind.playerArtistNameLabel.setText(MusicUtil.getReadableString(song.getArtistName())); bodyBind.playerArtistNameLabel.setText(MusicUtil.getReadableString(song.getArtistName()));
@ -316,6 +335,16 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE
bodyBind.buttonFavorite.setChecked(song.isFavorite()); 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() { protected void updatePlayPauseState() {
headerBind.playerHeaderButton.setChecked(!MusicPlayerRemote.isPlaying()); headerBind.playerHeaderButton.setChecked(!MusicPlayerRemote.isPlaying());
} }

View file

@ -5,7 +5,9 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.model.Artist; import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Queue; import com.cappielloantonio.play.model.Queue;
@ -27,6 +29,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
private final ArtistRepository artistRepository; private final ArtistRepository artistRepository;
private final QueueRepository queueRepository; private final QueueRepository queueRepository;
private final MutableLiveData<String> songLyrics = new MutableLiveData<>(null);
private final LiveData<List<Queue>> queueSong; private final LiveData<List<Queue>> queueSong;
public PlayerBottomSheetViewModel(@NonNull Application application) { public PlayerBottomSheetViewModel(@NonNull Application application) {
@ -77,4 +80,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
Song song = getCurrentSong(); Song song = getCurrentSong();
return artistRepository.getArtist(song.getArtistId()); return artistRepository.getArtist(song.getArtistId());
} }
public LiveData<String> getLyrics() {
return songLyrics;
}
public void refreshSongLyrics(LifecycleOwner owner, Song song) {
songRepository.getSongLyrics(song).observe(owner, songLyrics::postValue);
}
} }

View file

@ -33,8 +33,8 @@
android:layout_height="32dp" android:layout_height="32dp"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp" 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" />
<TextView <TextView
style="@style/ToolbarTextView" style="@style/ToolbarTextView"
@ -51,8 +51,8 @@
android:id="@+id/player_song_cover_view_pager" android:id="@+id/player_song_cover_view_pager"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginStart="24dp" android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp" android:layout_marginEnd="24dp"
app:layout_constraintDimensionRatio="H,1:1" app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
@ -63,8 +63,8 @@
android:id="@+id/player_big_timer" android:id="@+id/player_big_timer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_song_cover_view_pager"> app:layout_constraintTop_toBottomOf="@+id/player_song_cover_view_pager">
@ -148,7 +148,7 @@
app:layout_constraintTop_toBottomOf="@+id/player_song_title_label" /> app:layout_constraintTop_toBottomOf="@+id/player_song_title_label" />
<View <View
android:id="@+id/player_divider" android:id="@+id/player_divider_top"
style="@style/Divider" style="@style/Divider"
android:layout_marginStart="18dp" android:layout_marginStart="18dp"
android:layout_marginEnd="18dp" android:layout_marginEnd="18dp"
@ -156,6 +156,70 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_artist_name_label" /> app:layout_constraintTop_toBottomOf="@+id/player_artist_name_label" />
<androidx.cardview.widget.CardView
android:id="@+id/player_song_lyrics_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_divider_top">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<TextView
android:id="@+id/player_song_lyrics_label"
style="@style/HeadlineTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:text="@string/player_song_lyrics_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/player_song_lyrics_label_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="20dp"
android:text="@string/player_show_lyrics_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/player_song_lyrics_label"/>
<TextView
android:id="@+id/player_song_lyrics_text_view"
style="@style/SubheadTextView"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_song_lyrics_label"/>
<View
android:id="@+id/player_divider_bottom"
style="@style/Divider"
android:layout_marginTop="12dp"
android:layout_marginStart="18dp"
android:layout_marginEnd="18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_song_lyrics_text_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/player_queue_recycler_view" android:id="@+id/player_queue_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -165,5 +229,5 @@
android:paddingBottom="18dp" android:paddingBottom="18dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_divider" /> app:layout_constraintTop_toBottomOf="@+id/player_song_lyrics_cardview" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -111,6 +111,9 @@
<string name="menu_settings_button">Settings</string> <string name="menu_settings_button">Settings</string>
<string name="menu_unpin_button">Unpin</string> <string name="menu_unpin_button">Unpin</string>
<string name="player_bottom_sheet_title">Now playing</string> <string name="player_bottom_sheet_title">Now playing</string>
<string name="player_hide_lyrics_button">Hide</string>
<string name="player_show_lyrics_button">Show</string>
<string name="player_song_lyrics_label">Lyrics</string>
<string name="playing_notification_description">The playing notification provides actions for play/pause etc.</string> <string name="playing_notification_description">The playing notification provides actions for play/pause etc.</string>
<string name="playing_notification_name">Playing Notification</string> <string name="playing_notification_name">Playing Notification</string>
<string name="playlist_catalogue_title">Playlist Catalogue</string> <string name="playlist_catalogue_title">Playlist Catalogue</string>