mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
feat: implemented karaoke mode for synchronized lyrics
This commit is contained in:
parent
28fef53590
commit
733102a8a4
4 changed files with 88 additions and 0 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
app/src/main/res/drawable/ic_lyrics_sync_lock.xml
Normal file
9
app/src/main/res/drawable/ic_lyrics_sync_lock.xml
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue