feat: implemented karaoke mode for synchronized lyrics

This commit is contained in:
CappielloAntonio 2024-02-18 16:29:42 +01:00
parent 28fef53590
commit 733102a8a4
4 changed files with 88 additions and 0 deletions

View file

@ -50,8 +50,11 @@ public class PlayerLyricsFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
bind = InnerFragmentPlayerLyricsBinding.inflate(inflater, container, false);
View view = bind.getRoot();
playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class);
initOverlay();
return view;
}
@ -93,6 +96,12 @@ public class PlayerLyricsFragment extends Fragment {
bind = null;
}
private void initOverlay() {
bind.syncLyricsTapButton.setOnClickListener(view -> {
playerBottomSheetViewModel.changeSyncLyricsState();
});
}
private void initializeBrowser() {
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
}
@ -134,25 +143,31 @@ public class PlayerLyricsFragment extends Fragment {
private void setPanelContent(String lyrics, LyricsList lyricsList) {
playerBottomSheetViewModel.getLiveDescription().observe(getViewLifecycleOwner(), description -> {
if (bind != null) {
bind.nowPlayingSongLyricsSrollView.smoothScrollTo(0, 0);
if (lyrics != null && !lyrics.trim().equals("")) {
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(lyrics));
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
bind.syncLyricsTapButton.setVisibility(View.GONE);
} else if (lyricsList != null && lyricsList.getStructuredLyrics() != null) {
setSyncLirics(lyricsList);
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
bind.syncLyricsTapButton.setVisibility(View.VISIBLE);
} else if (description != null && !description.trim().equals("")) {
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(description));
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
bind.syncLyricsTapButton.setVisibility(View.GONE);
} else {
bind.nowPlayingSongLyricsTextView.setVisibility(View.GONE);
bind.emptyDescriptionImageView.setVisibility(View.VISIBLE);
bind.titleEmptyDescriptionLabel.setVisibility(View.VISIBLE);
bind.syncLyricsTapButton.setVisibility(View.GONE);
}
}
});
@ -228,6 +243,10 @@ public class PlayerLyricsFragment extends Fragment {
spannableString.setSpan(new ForegroundColorSpan(requireContext().getResources().getColor(R.color.lyricsTextColor, null)), startingPosition, endingPosition, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
bind.nowPlayingSongLyricsTextView.setText(spannableString);
if (playerBottomSheetViewModel.getSyncLyricsState()) {
bind.nowPlayingSongLyricsSrollView.smoothScrollTo(0, getScroll(lines, toHighlight));
}
}
}
}
@ -245,4 +264,27 @@ public class PlayerLyricsFragment extends Fragment {
return start;
}
private int getLineCount(List<Line> lines, Line toHighlight) {
int start = 0;
for (Line line : lines) {
if (line != toHighlight) {
bind.tempLyricsLineTextView.setText(line.getValue());
start = start + bind.tempLyricsLineTextView.getLineCount();
} else {
break;
}
}
return start;
}
private int getScroll(List<Line> lines, Line toHighlight) {
int lineHeight = bind.nowPlayingSongLyricsTextView.getLineHeight();
int lineCount = getLineCount(lines, toHighlight);
int scrollViewHeight = bind.nowPlayingSongLyricsSrollView.getHeight();
return lineHeight * lineCount < scrollViewHeight / 2 ? 0 : lineHeight * lineCount - scrollViewHeight / 2 + lineHeight;
}
}

View file

@ -50,6 +50,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
private final MutableLiveData<Child> liveMedia = new MutableLiveData<>(null);
private final MutableLiveData<ArtistID3> liveArtist = new MutableLiveData<>(null);
private final MutableLiveData<List<Child>> instantMix = new MutableLiveData<>(null);
private boolean lyricsSyncState = true;
public PlayerBottomSheetViewModel(@NonNull Application application) {
@ -210,4 +211,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
return false;
}
public void changeSyncLyricsState() {
lyricsSyncState = !lyricsSyncState;
}
public boolean getSyncLyricsState() {
return lyricsSyncState;
}
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@color/titleTextColor"
android:pathData="M160,800L160,720L269,720Q218,676 189,614Q160,552 160,480Q160,368 228,282.5Q296,197 400,170L400,254Q330,279 285,340.5Q240,402 240,480Q240,534 261.5,579.5Q283,625 320,658L320,560L400,560L400,800L160,800ZM720,480Q720,429 699.5,384.5Q679,340 640,302L640,400L560,400L560,160L800,160L800,240L691,240Q750,293 774.5,353.5Q799,414 800,480L720,480ZM640,880Q623,880 611.5,868.5Q600,857 600,840L600,720Q600,703 611.5,691.5Q623,680 640,680L640,680L640,640Q640,607 663.5,583.5Q687,560 720,560Q753,560 776.5,583.5Q800,607 800,640L800,680L800,680Q817,680 828.5,691.5Q840,703 840,720L840,840Q840,857 828.5,868.5Q817,880 800,880L640,880ZM680,680L760,680L760,640Q760,623 748.5,611.5Q737,600 720,600Q703,600 691.5,611.5Q680,623 680,640L680,680Z"/>
</vector>

View file

@ -50,4 +50,32 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.core.widget.NestedScrollView>
<Button
android:id="@+id/sync_lyrics_tap_button"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="16dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="64dp"
android:alpha="0.7"
android:visibility="visible"
app:icon="@drawable/ic_lyrics_sync_lock"
app:layout_constraintEnd_toEndOf="@+id/now_playing_song_lyrics_sroll_view"
app:layout_constraintBottom_toBottomOf="@+id/now_playing_song_lyrics_sroll_view" />
<TextView
android:id="@+id/temp_lyrics_line_text_view"
style="@style/BodyLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="invisible"/>
</androidx.constraintlayout.widget.ConstraintLayout>