feat: toggle player bitrate visibility on touch (#466)

* feat: touch player chip to toggle bitrate visibility

* feat: player bitrate visibility is remembered

* fix: player landscape layout not grouping chip with textview

* feat: touch bitrate to toggle its visibility

This catches the edge case where the the chip is not reachable due to insuficient horizontal space

---------

Co-authored-by: eddyizm <eddyizm@gmail.com>
This commit is contained in:
Tom 2026-03-02 00:48:15 -03:00 committed by GitHub
parent 0487f3bb9b
commit c9cf86acb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 98 additions and 40 deletions

View file

@ -8,9 +8,11 @@ import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
@ -33,6 +35,10 @@ import androidx.media3.session.SessionToken;
import androidx.navigation.NavController;
import androidx.navigation.NavOptions;
import androidx.navigation.fragment.NavHostFragment;
import androidx.transition.ChangeBounds;
import androidx.transition.Slide;
import androidx.transition.TransitionManager;
import androidx.transition.TransitionSet;
import androidx.viewpager2.widget.ViewPager2;
import com.cappielloantonio.tempo.R;
@ -56,7 +62,6 @@ import com.google.android.material.elevation.SurfaceColors;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -314,7 +319,7 @@ public class PlayerControllerFragment extends Fragment {
if (!samplingRate.trim().isEmpty()) items.add(samplingRate);
String mediaQuality = TextUtils.join("", items);
playerMediaBitrate.setVisibility(View.VISIBLE);
playerMediaBitrate.setVisibility(Preferences.getBitrateVisible() ? View.VISIBLE : View.GONE);
playerMediaBitrate.setText(isLocal ? mediaQuality : mediaQuality);
}
}
@ -335,7 +340,25 @@ public class PlayerControllerFragment extends Fragment {
TrackInfoDialog dialog = new TrackInfoDialog(mediaMetadata);
dialog.show(activity.getSupportFragmentManager(), null);
});
playerMediaExtension.setOnClickListener( v -> toggleBitrateVisibility() );
playerMediaBitrate.setOnClickListener(v -> toggleBitrateVisibility() );
}
private void toggleBitrateVisibility() {
ViewGroup parent = (ViewGroup) playerMediaBitrate.getParent();
TransitionSet transition = new TransitionSet()
.addTransition(new Slide(Gravity.START))
.addTransition(new ChangeBounds())
.setDuration(500)
.setInterpolator(new AccelerateDecelerateInterpolator());
TransitionManager.beginDelayedTransition(parent, transition);
playerMediaBitrate.setVisibility(Preferences.getBitrateVisible() ? View.GONE : View.VISIBLE);
Preferences.setBitrateVisible(!Preferences.getBitrateVisible());
}
private void updateAssetLinkChips(MediaMetadata mediaMetadata) {
if (assetLinkChipGroup == null) return;
String mediaType = mediaMetadata.extras != null ? mediaMetadata.extras.getString("type", Constants.MEDIA_TYPE_MUSIC) : Constants.MEDIA_TYPE_MUSIC;

View file

@ -25,6 +25,7 @@ object Preferences {
private const val IN_USE_SERVER_ADDRESS = "in_use_server_address"
private const val NEXT_SERVER_SWITCH = "next_server_switch"
private const val PLAYBACK_SPEED = "playback_speed"
private const val BITRATE_VISIBLE = "bitrate_visible"
private const val SKIP_SILENCE = "skip_silence"
private const val SHUFFLE_MODE = "shuffle_mode"
private const val REPEAT_MODE = "repeat_mode"
@ -292,6 +293,16 @@ object Preferences {
App.getInstance().preferences.edit().putFloat(PLAYBACK_SPEED, playbackSpeed).apply()
}
@JvmStatic
fun getBitrateVisible(): Boolean {
return App.getInstance().preferences.getBoolean(BITRATE_VISIBLE, true)
}
@JvmStatic
fun setBitrateVisible(bitrateVisible: Boolean) {
App.getInstance().preferences.edit().putBoolean(BITRATE_VISIBLE, bitrateVisible).apply()
}
@JvmStatic
fun isSkipSilenceMode(): Boolean {
return App.getInstance().preferences.getBoolean(SKIP_SILENCE, false)

View file

@ -24,30 +24,42 @@
app:layout_constraintStart_toEndOf="@+id/vertical_guideline"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.chip.Chip
android:id="@+id/player_media_extension"
style="@style/Widget.Material3.Chip.Suggestion"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/player_media_quality_sector_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:clickable="false"
android:text="Unknown"
app:chipStrokeWidth="0dp"
android:layout_marginVertical="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/player_media_bitrate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"/>
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/player_media_bitrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="@id/player_media_extension"
app:layout_constraintBottom_toBottomOf="@id/player_media_extension"
app:layout_constraintStart_toEndOf="@id/player_media_extension"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/player_media_bitrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="@id/player_media_extension"
app:layout_constraintBottom_toBottomOf="@id/player_media_extension"
app:layout_constraintStart_toEndOf="@id/player_media_extension"
app:layout_constraintEnd_toEndOf="parent"/>
<com.google.android.material.chip.Chip
android:id="@+id/player_media_extension"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:checked="true"
android:focusable="true"
android:text="Unknown"
app:chipStrokeWidth="0dp"
app:chipBackgroundColor="@color/material_dynamic_secondary40"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/player_media_bitrate"
app:layout_constraintHorizontal_chainStyle="packed"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageButton
android:id="@+id/player_info_track"

View file

@ -33,30 +33,42 @@
app:layout_constraintBottom_toBottomOf="parent"
app:tint="?attr/colorOnPrimaryContainer" />
<com.google.android.material.chip.Chip
android:id="@+id/player_media_extension"
style="@style/Widget.Material3.Chip.Suggestion"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/player_media_quality_sector_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:clickable="false"
android:text="Unknown"
app:chipStrokeWidth="0dp"
android:layout_marginVertical="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/player_media_bitrate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"/>
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/player_media_bitrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="@id/player_media_extension"
app:layout_constraintBottom_toBottomOf="@id/player_media_extension"
app:layout_constraintStart_toEndOf="@id/player_media_extension"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/player_media_bitrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="@id/player_media_extension"
app:layout_constraintBottom_toBottomOf="@id/player_media_extension"
app:layout_constraintStart_toEndOf="@id/player_media_extension"
app:layout_constraintEnd_toEndOf="parent"/>
<com.google.android.material.chip.Chip
android:id="@+id/player_media_extension"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:checked="true"
android:focusable="true"
android:text="Unknown"
app:chipStrokeWidth="0dp"
app:chipBackgroundColor="@color/material_dynamic_secondary40"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/player_media_bitrate"
app:layout_constraintHorizontal_chainStyle="packed"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageButton
android:id="@+id/player_info_track"