Skip to content

Commit

Permalink
Show technical info and track number
Browse files Browse the repository at this point in the history
Optionally show information about current track above slider.
- Technical info, currently bitrate and samplerate
- Current track number and queue length

Add a scroll view around song information lines, which kicks in if it
doesn't fit on screen. E.g. if all options are on, and using a device
with a short screen.
  • Loading branch information
kaaholst committed Jul 16, 2024
1 parent b648caf commit 82cbcab
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 80 deletions.
36 changes: 27 additions & 9 deletions Squeezer/src/main/java/uk/org/ngo/squeezer/NowPlayingActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@


import uk.org.ngo.squeezer.framework.BaseActivity;
import uk.org.ngo.squeezer.model.Player;
import uk.org.ngo.squeezer.service.event.MusicChanged;

public class NowPlayingActivity extends BaseActivity {

/**
* Called when the activity is first created.
*/

private MenuItem menuItemTrackCount;
private MenuItem menuItemTechnicalInfo;
private MenuItem menuItemComposerLine;
private MenuItem menuItemConductorLine;
private MenuItem menuItemClassicalMusicTags;
Expand Down Expand Up @@ -72,6 +76,8 @@ public boolean onCreateOptionsMenu(Menu menu) {
trackInfoMenu = menu.findItem(R.id.menu_nowplaying_trackinfo).getSubMenu();
MenuCompat.setGroupDividerEnabled(trackInfoMenu, true);

menuItemTrackCount = trackInfoMenu.findItem(R.id.menu_item_track_info);
menuItemTechnicalInfo = trackInfoMenu.findItem(R.id.menu_item_technical_info);
menuItemComposerLine = trackInfoMenu.findItem(R.id.menu_item_composer_line);
menuItemConductorLine = trackInfoMenu.findItem(R.id.menu_item_conductor_line);
menuItemClassicalMusicTags = trackInfoMenu.findItem(R.id.menu_item_classical_music_tags);
Expand All @@ -91,33 +97,45 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (itemId == android.R.id.home) {
finish();
return true;
} else if (itemId == R.id.menu_item_track_info) {
Squeezer.getPreferences().showTrackCount(!menuItemTrackCount.isChecked());
refreshTrackInfo();
return true;
} else if (itemId == R.id.menu_item_technical_info) {
Squeezer.getPreferences().showTechnicalInfo(!menuItemTechnicalInfo.isChecked());
refreshTrackInfo();
return true;
} else if (itemId == R.id.menu_item_composer_line) {
Squeezer.getPreferences().addComposerLine(!menuItemComposerLine.isChecked());
updateTrackInfoMenuItems();
// Make sure view is updated to reflect changes
NowPlayingActivity.show(this);
refreshTrackInfo();
return true;
} else if (itemId == R.id.menu_item_conductor_line) {
Squeezer.getPreferences().addConductorLine(!menuItemConductorLine.isChecked());
updateTrackInfoMenuItems();
// Make sure view is updated to reflect changes
NowPlayingActivity.show(this);
refreshTrackInfo();
return true;
} else if (itemId == R.id.menu_item_classical_music_tags) {
Squeezer.getPreferences().displayClassicalMusicTags(!menuItemClassicalMusicTags.isChecked());
updateTrackInfoMenuItems();
// Make sure view is updated to reflect changes
NowPlayingActivity.show(this);
refreshTrackInfo();
return true;
}

return super.onOptionsItemSelected(item);
}

private void refreshTrackInfo() {
updateTrackInfoMenuItems();
Player activePlayer = getActivePlayer();
if (activePlayer != null) {
requireService().getEventBus().post(new MusicChanged(activePlayer, activePlayer.getPlayerState()));
}
}

private void updateTrackInfoMenuItems() {
if (menuItemComposerLine != null) {
Preferences preferences = Squeezer.getPreferences();

menuItemTrackCount.setChecked(preferences.showTrackCount());
menuItemTechnicalInfo.setChecked(preferences.showTechnicalInfo());
menuItemComposerLine.setChecked(preferences.addComposerLine());
menuItemConductorLine.setChecked(preferences.addConductorLine());
menuItemClassicalMusicTags.setChecked(preferences.displayClassicalMusicTags());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public class NowPlayingFragment extends Fragment implements OnCrollerChangeList
private TextView trackText;
private TextView conductorText;
private TextView composerText;
private TextView trackInfo;

private JiveItem albumItem;
private JiveItem artistItem;
Expand Down Expand Up @@ -296,8 +297,10 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
v = inflater.inflate(largeArtwork ? R.layout.now_playing_fragment_full_large_artwork : R.layout.now_playing_fragment_full, container, false);

artistText = v.findViewById(R.id.artistname);
composerText = v.findViewById(R.id.composer);
conductorText = v.findViewById(R.id.conductorname);
albumText = v.findViewById(R.id.albumname);
trackInfo = v.findViewById(R.id.track_info);
shuffleButton = v.findViewById(R.id.shuffle);
repeatButton = v.findViewById(R.id.repeat);
currentTime = v.findViewById(R.id.currenttime);
Expand Down Expand Up @@ -334,7 +337,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
}

trackText = v.findViewById(R.id.trackname);
composerText = v.findViewById(R.id.composer);
playPauseButton = v.findViewById(R.id.pause);

nextButton = v.findViewById(R.id.next);
Expand Down Expand Up @@ -831,6 +833,10 @@ else if (!TextUtils.isEmpty(song.songInfo.getBand())) {
artistText.setSelected(true);
albumText.setSelected(true);

String trackInfoText = formatTrackInfo(preferences, playerState, song);
trackInfo.setText(trackInfoText);
trackInfo.setVisibility(!TextUtils.isEmpty(trackInfoText) ? View.VISIBLE : View.GONE);

requireService().pluginItems(song.moreAction, new IServiceItemListCallback<>() {
@Override
public void onItemsReceived(int count, int start, Map<String, Object> parameters, List<JiveItem> items, Class<JiveItem> dataType) {
Expand Down Expand Up @@ -872,6 +878,20 @@ public Object getClient() {
}
}

private static String formatTrackInfo(Preferences preferences, PlayerState playerState, CurrentPlaylistItem song) {
return Util.joinSkipEmpty(" - ", formatTechnicalInfo(preferences, song), formatTrackCount(preferences, playerState));
}

private static String formatTechnicalInfo(Preferences preferences, CurrentPlaylistItem song) {
return preferences.showTechnicalInfo() ? Util.joinSkipEmpty(" ", song.songInfo.bitRate, song.songInfo.sampleRate) : "";
}

private static String formatTrackCount(Preferences preferences, PlayerState playerState) {
return (preferences.showTrackCount() && playerState.getCurrentPlaylistTracksNum() > 1)
? String.format("%s/%s", playerState.getCurrentPlaylistIndex() + 1, playerState.getCurrentPlaylistTracksNum())
: "";
}

private void updateVolumeInfo() {
if (mFullHeightLayout) {
ISqueezeService.VolumeInfo volumeInfo = requireService().getVolume();
Expand Down
22 changes: 22 additions & 0 deletions Squeezer/src/main/java/uk/org/ngo/squeezer/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ public final class Preferences {
// Preferred maximum info per item for a given list layout
public static final String KEY_MAX_LINES_FORMAT = "squeezer.%s.maxLines";

// Show current track and queue length on now playing screen
public static final String KEY_TRACK_COUNT = "squeezer.show_track_count";

// Show technical info (bitrate, samplerate etc) on now playing screen
public static final String KEY_TECHNICAL_INFO = "squeezer.show_technical_info";

// Add line above track title for showing composer
public static final String KEY_COMPOSER_LINE = "squeezer.add_composer_line";

Expand Down Expand Up @@ -627,6 +633,22 @@ public void setMaxLines(ArtworkListLayout listLayout, int maxLines) {
sharedPreferences.edit().putInt(String.format(KEY_MAX_LINES_FORMAT, listLayout.name()), maxLines).apply();
}

public boolean showTrackCount() {
return sharedPreferences.getBoolean(KEY_TRACK_COUNT, true);
}

public void showTrackCount(boolean b) {
sharedPreferences.edit().putBoolean(Preferences.KEY_TRACK_COUNT, b).apply();
}

public boolean showTechnicalInfo() {
return sharedPreferences.getBoolean(KEY_TECHNICAL_INFO, false);
}

public void showTechnicalInfo(boolean b) {
sharedPreferences.edit().putBoolean(Preferences.KEY_TECHNICAL_INFO, b).apply();
}

public boolean addComposerLine() {
return sharedPreferences.getBoolean(KEY_COMPOSER_LINE, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ private void fillDisplayPreferences(Preferences preferences) {
}

private void fillNowPlayingPreferences(Preferences preferences) {
final SwitchPreferenceCompat trackCount = findPreference(Preferences.KEY_TRACK_COUNT);
trackCount.setChecked(preferences.showTrackCount());

final SwitchPreferenceCompat teachnicalInfo = findPreference(Preferences.KEY_TECHNICAL_INFO);
teachnicalInfo.setChecked(preferences.showTechnicalInfo());

final SwitchPreferenceCompat addComposerLine = findPreference(Preferences.KEY_COMPOSER_LINE);
addComposerLine.setChecked(preferences.addComposerLine());

Expand Down
2 changes: 1 addition & 1 deletion Squeezer/src/main/java/uk/org/ngo/squeezer/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public static String joinSkipEmpty(String separator, Iterable<String> parts) {

StringBuilder sb = new StringBuilder();
for (String part : parts) {
if (part == null) continue;
if (part == null || part.isEmpty()) continue;

if (sb.length() > 0) sb.append(separator);
sb.append(part);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import uk.org.ngo.squeezer.model.Action;
import uk.org.ngo.squeezer.model.DisplayMessage;
import uk.org.ngo.squeezer.model.JiveItem;
import uk.org.ngo.squeezer.model.Player;
import uk.org.ngo.squeezer.screensaver.Screensaver;
import uk.org.ngo.squeezer.service.ISqueezeService;
import uk.org.ngo.squeezer.service.SqueezeService;
Expand Down Expand Up @@ -450,6 +451,13 @@ public void onEventMainThread(AlertEvent alert) {

// Safe accessors

public Player getActivePlayer() {
if (mService == null) {
return null;
}
return mService.getActivePlayer();
}

/**
* Perform the supplied <code>action</code> using parameters in <code>item</code> via
* {@link ISqueezeService#action(JiveItem, Action)}
Expand Down
155 changes: 86 additions & 69 deletions Squeezer/src/main/res/layout/now_playing_include.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,86 +30,103 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:orientation="vertical">

<TextView
android:id="@+id/composer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.ComposerName"
tools:text="Composer" />

<!-- The trackname TextView needs to be wrapped in a LinearLayout.
If you do not do this then changing the contents of any other item in the layout
will cause the layout to reflow, which causes the scrolling marquee text to
reset. Wrapping the trackname TextView in a LinearLayout means that the TextView
will not change size when then the layout is recalculated, and the text continues
to scroll. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/trackname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.SongName"/>
</FrameLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/item"
android:layout_marginTop="4dp"
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
style="@style/SqueezerWidget.List.CoverArt"
android:id="@+id/icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/labels"
android:contentDescription="@string/app_name"
tools:src="@drawable/pending" />

<LinearLayout
android:id="@+id/labels"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintEnd_toStartOf="@+id/context_menu">
android:orientation="vertical">
<TextView
android:id="@+id/albumname"
android:layout_width="wrap_content"
android:id="@+id/composer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.AlbumName"
tools:text="Album" />

<TextView
android:id="@+id/artistname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.ArtistName"
tools:text="Artist" />

<TextView
android:id="@+id/conductorname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.ConductorName"
tools:text="Conductor" />
style="@style/SqueezerWidget.NowPlaying.ComposerName"
tools:text="Composer" />

<!-- The trackname TextView needs to be wrapped in a LinearLayout.
If you do not do this then changing the contents of any other item in the layout
will cause the layout to reflow, which causes the scrolling marquee text to
reset. Wrapping the trackname TextView in a LinearLayout means that the TextView
will not change size when then the layout is recalculated, and the text continues
to scroll. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/trackname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.SongName"/>
</FrameLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/item"
android:layout_marginTop="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
style="@style/SqueezerWidget.List.CoverArt"
android:id="@+id/icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/labels"
android:contentDescription="@string/app_name"
tools:src="@drawable/pending" />

<LinearLayout
android:id="@+id/labels"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintEnd_toStartOf="@+id/context_menu">
<TextView
android:id="@+id/albumname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.AlbumName"
tools:text="Album" />

<TextView
android:id="@+id/artistname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.ArtistName"
tools:text="Artist" />

<TextView
android:id="@+id/conductorname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SqueezerWidget.NowPlaying.ConductorName"
tools:text="Conductor" />
</LinearLayout>

<include
layout="@layout/context_menu_image_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

<include
layout="@layout/context_menu_image_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>
</LinearLayout>

<TextView
android:id="@+id/track_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
tools:text="Track info" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down
Loading

0 comments on commit 82cbcab

Please sign in to comment.