mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 13:21:13 +00:00
- Added support for genres and playlists
- Fixed some deep linking issues from transport controls in the main window - Various other small cleanups and polish
This commit is contained in:
parent
2e765da9fc
commit
375e0d0e28
@ -31,6 +31,30 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
|
||||
.putExtra(EXTRA_CATEGORY_ID, categoryId);
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context,
|
||||
final String categoryName,
|
||||
long categoryId,
|
||||
final String categoryValue)
|
||||
{
|
||||
final Intent intent = getStartIntent(context, categoryName, categoryId);
|
||||
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
intent.putExtra(
|
||||
AlbumBrowseActivity.EXTRA_TITLE,
|
||||
context.getString(R.string.albums_by_title, categoryValue));
|
||||
}
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context,
|
||||
final String categoryName,
|
||||
final JSONObject categoryJson)
|
||||
{
|
||||
final String value = categoryJson.optString(Messages.Key.VALUE);
|
||||
final long categoryId = categoryJson.optLong(Messages.Key.ID);
|
||||
return getStartIntent(context, categoryName, categoryId, value);
|
||||
}
|
||||
|
||||
private WebSocketService wss;
|
||||
private Adapter adapter;
|
||||
@ -123,18 +147,12 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
|
||||
};
|
||||
|
||||
private View.OnClickListener onItemClickListener = (View view) -> {
|
||||
JSONObject album = (JSONObject) view.getTag();
|
||||
long id = album.optLong(Key.ID);
|
||||
String title = album.optString(Key.TITLE, "");
|
||||
final JSONObject album = (JSONObject) view.getTag();
|
||||
final long id = album.optLong(Key.ID);
|
||||
final String title = album.optString(Key.TITLE, "");
|
||||
|
||||
final Intent intent = TrackListActivity.getStartIntent(
|
||||
AlbumBrowseActivity.this, Messages.Category.ALBUM, id);
|
||||
|
||||
if (Strings.notEmpty(title)) {
|
||||
intent.putExtra(
|
||||
TrackListActivity.EXTRA_TITLE,
|
||||
getString(R.string.songs_from_category, title));
|
||||
}
|
||||
AlbumBrowseActivity.this, Messages.Category.ALBUM, id, title);
|
||||
|
||||
startActivityForResult(intent, Navigation.RequestCode.ALBUM_TRACKS_ACTIVITY);
|
||||
};
|
||||
|
@ -19,20 +19,28 @@ import java.util.Map;
|
||||
|
||||
public class CategoryBrowseActivity extends WebSocketActivityBase implements Filterable {
|
||||
private static final String EXTRA_CATEGORY = "extra_category";
|
||||
private static final String EXTRA_DEEP_LINK_TYPE = "extra_deep_link_type";
|
||||
|
||||
public interface DeepLink {
|
||||
int TRACKS = 0;
|
||||
int ALBUMS = 1;
|
||||
}
|
||||
|
||||
private static final Map<String, String> CATEGORY_NAME_TO_ID = new HashMap<>();
|
||||
private static final Map<String, Integer> CATEGORY_NAME_TO_TITLE = new HashMap<>();
|
||||
|
||||
static {
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Key.ALBUM_ARTIST, Messages.Key.ALBUM_ARTIST_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Key.GENRE, Messages.Key.GENRE_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Key.ARTIST, Messages.Key.ARTIST_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Key.ALBUM, Messages.Key.ALBUM_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Category.ALBUM_ARTIST, Messages.Key.ALBUM_ARTIST_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Category.GENRE, Messages.Key.GENRE_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Category.ARTIST, Messages.Key.ARTIST_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Category.ALBUM, Messages.Key.ALBUM_ID);
|
||||
CATEGORY_NAME_TO_ID.put(Messages.Category.PLAYLISTS, Messages.Key.ALBUM_ID);
|
||||
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Key.ALBUM_ARTIST, R.string.artists_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Key.GENRE, R.string.genres_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Key.ARTIST, R.string.artists_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Key.ALBUM, R.string.albums_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Category.ALBUM_ARTIST, R.string.artists_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Category.GENRE, R.string.genres_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Category.ARTIST, R.string.artists_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Category.ALBUM, R.string.albums_title);
|
||||
CATEGORY_NAME_TO_TITLE.put(Messages.Category.PLAYLISTS, R.string.playlists_title);
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context, final String category) {
|
||||
@ -40,16 +48,24 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
|
||||
.putExtra(EXTRA_CATEGORY, category);
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context, final String category, int deepLinkType) {
|
||||
return new Intent(context, CategoryBrowseActivity.class)
|
||||
.putExtra(EXTRA_CATEGORY, category)
|
||||
.putExtra(EXTRA_DEEP_LINK_TYPE, deepLinkType);
|
||||
}
|
||||
|
||||
private String category;
|
||||
private Adapter adapter;
|
||||
private String filter;
|
||||
private TransportFragment transport;
|
||||
private int deepLinkType;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
this.category = getIntent().getStringExtra(EXTRA_CATEGORY);
|
||||
this.deepLinkType = getIntent().getIntExtra(EXTRA_DEEP_LINK_TYPE, DeepLink.ALBUMS);
|
||||
this.adapter = new Adapter();
|
||||
|
||||
setContentView(R.layout.recycler_view_activity);
|
||||
@ -68,7 +84,9 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
Views.initSearchMenu(this, menu, this);
|
||||
if (!Messages.Category.PLAYLISTS.equals(category)) { /* bleh */
|
||||
Views.initSearchMenu(this, menu, this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -127,37 +145,37 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
|
||||
|
||||
private View.OnClickListener onItemClickListener = (View view) -> {
|
||||
final JSONObject entry = (JSONObject) view.getTag();
|
||||
final long categoryId = entry.optLong(Messages.Key.ID);
|
||||
final String value = entry.optString(Messages.Key.VALUE);
|
||||
|
||||
final Intent intent = AlbumBrowseActivity.getStartIntent(this, category, categoryId);
|
||||
|
||||
if (Strings.notEmpty(value)) {
|
||||
intent.putExtra(
|
||||
AlbumBrowseActivity.EXTRA_TITLE,
|
||||
getString(R.string.albums_by_title, value));
|
||||
if (deepLinkType == DeepLink.ALBUMS) {
|
||||
navigateToAlbums(entry);
|
||||
}
|
||||
else {
|
||||
navigateToTracks(entry);
|
||||
}
|
||||
|
||||
startActivityForResult(intent, Navigation.RequestCode.ALBUM_BROWSE_ACTIVITY);
|
||||
};
|
||||
|
||||
private View.OnLongClickListener onItemLongClickListener = (View view) -> {
|
||||
final JSONObject entry = (JSONObject) view.getTag();
|
||||
/* if we deep link to albums by default, long press will get to
|
||||
tracks. if we deep link to tracks, just ignore */
|
||||
if (deepLinkType == DeepLink.ALBUMS) {
|
||||
navigateToTracks((JSONObject) view.getTag());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private void navigateToAlbums(final JSONObject entry) {
|
||||
final Intent intent = AlbumBrowseActivity.getStartIntent(this, category, entry);
|
||||
startActivityForResult(intent, Navigation.RequestCode.ALBUM_BROWSE_ACTIVITY);
|
||||
}
|
||||
|
||||
private void navigateToTracks(final JSONObject entry) {
|
||||
final long categoryId = entry.optLong(Messages.Key.ID);
|
||||
final String value = entry.optString(Messages.Key.VALUE);
|
||||
|
||||
final Intent intent = TrackListActivity.getStartIntent(this, category, categoryId);
|
||||
|
||||
if (Strings.notEmpty(value)) {
|
||||
intent.putExtra(
|
||||
TrackListActivity.EXTRA_TITLE,
|
||||
getString(R.string.songs_from_category, value));
|
||||
}
|
||||
|
||||
final Intent intent = TrackListActivity.getStartIntent(this, category, categoryId, value);
|
||||
startActivityForResult(intent, Navigation.RequestCode.CATEGORY_TRACKS_ACTIVITY);
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private final TextView title;
|
||||
@ -182,7 +200,11 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
|
||||
titleColor = R.color.theme_green;
|
||||
}
|
||||
|
||||
title.setText(entry.optString(Messages.Key.VALUE, "-"));
|
||||
/* note optString only does a null check! */
|
||||
String value = entry.optString(Messages.Key.VALUE, "");
|
||||
value = Strings.empty(value) ? getString(R.string.unknown_value) : value;
|
||||
|
||||
title.setText(value);
|
||||
title.setTextColor(getResources().getColor(titleColor));
|
||||
|
||||
itemView.setTag(entry);
|
||||
|
@ -33,7 +33,6 @@ import java.util.Map;
|
||||
|
||||
public class MainActivity extends WebSocketActivityBase {
|
||||
private static Map<TransportModel.RepeatMode, Integer> REPEAT_TO_STRING_ID;
|
||||
private static final int ARTIFICIAL_ARTWORK_DELAY_MILLIS = 0;
|
||||
|
||||
private WebSocketService wss = null;
|
||||
private TransportModel model = new TransportModel();
|
||||
@ -44,15 +43,15 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
private TextView notPlayingOrDisconnected;
|
||||
private View connected;
|
||||
private CheckBox shuffleCb, muteCb, repeatCb;
|
||||
private ImageView albumArtImageView;
|
||||
private View mainTrackMetadataWithAlbumArt, mainTrackMetadataNoAlbumArt;
|
||||
private View disconnectedOverlay;
|
||||
private Handler handler = new Handler();
|
||||
private ViewPropertyAnimator metadataAnim1, metadataAnim2;
|
||||
|
||||
/* ugh, artwork related */
|
||||
private enum DisplayMode { Artwork, NoArtwork, Stopped }
|
||||
private View mainTrackMetadataWithAlbumArt, mainTrackMetadataNoAlbumArt;
|
||||
private ViewPropertyAnimator metadataAnim1, metadataAnim2;
|
||||
private AlbumArtModel albumArtModel = new AlbumArtModel();
|
||||
private ImageView albumArtImageView;
|
||||
|
||||
static {
|
||||
REPEAT_TO_STRING_ID = new HashMap<>();
|
||||
@ -107,10 +106,21 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.action_settings) {
|
||||
startActivity(SettingsActivity.getStartIntent(this));
|
||||
return true;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_settings:
|
||||
startActivity(SettingsActivity.getStartIntent(this));
|
||||
return true;
|
||||
|
||||
case R.id.action_genres:
|
||||
startActivity(CategoryBrowseActivity.getStartIntent(this, Messages.Category.GENRE));
|
||||
return true;
|
||||
|
||||
case R.id.action_playlists:
|
||||
startActivity(CategoryBrowseActivity.getStartIntent(
|
||||
this, Messages.Category.PLAYLISTS, CategoryBrowseActivity.DeepLink.TRACKS));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@ -306,7 +316,7 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
final boolean stopped = (model.getPlaybackState() == TransportModel.PlaybackState.Stopped);
|
||||
notPlayingOrDisconnected.setVisibility(stopped ? View.VISIBLE : View.GONE);
|
||||
|
||||
final boolean stateIsValidForArtwork = !stopped && connected;
|
||||
final boolean stateIsValidForArtwork = !stopped && connected && model.isValid();
|
||||
|
||||
this.connected.setVisibility((connected && stopped) ? View.VISIBLE : View.GONE);
|
||||
this.disconnectedOverlay.setVisibility(connected ? View.GONE : View.VISIBLE);
|
||||
@ -369,17 +379,19 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
metadataAnim2.cancel();
|
||||
}
|
||||
|
||||
if (mode == DisplayMode.Artwork) {
|
||||
if (mode == DisplayMode.Stopped) {
|
||||
albumArtImageView.setImageDrawable(null);
|
||||
metadataAnim1 = Views.animateAlpha(mainTrackMetadataWithAlbumArt, 0.0f);
|
||||
metadataAnim2 = Views.animateAlpha(mainTrackMetadataNoAlbumArt, 0.0f);
|
||||
}
|
||||
else if (mode == DisplayMode.Artwork) {
|
||||
metadataAnim1 = Views.animateAlpha(mainTrackMetadataWithAlbumArt, 1.0f);
|
||||
metadataAnim2 = Views.animateAlpha(mainTrackMetadataNoAlbumArt, 0.0f);
|
||||
}
|
||||
else {
|
||||
albumArtImageView.setImageDrawable(null);
|
||||
|
||||
/* oh god why. hack to make volume % disappear. */
|
||||
float noArtAlpha = (mode == DisplayMode.Stopped) ? 0.0f : 1.0f;
|
||||
metadataAnim2 = Views.animateAlpha(mainTrackMetadataNoAlbumArt, noArtAlpha);
|
||||
metadataAnim1 = Views.animateAlpha(mainTrackMetadataWithAlbumArt, 0.0f);
|
||||
metadataAnim2 = Views.animateAlpha(mainTrackMetadataNoAlbumArt, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,16 +474,18 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
private void navigateToCurrentArtist() {
|
||||
final long artistId = model.getTrackValueLong(TransportModel.Key.ARTIST_ID, -1);
|
||||
if (artistId != -1) {
|
||||
final String artistName = model.getTrackValueString(TransportModel.Key.ARTIST, "");
|
||||
startActivity(AlbumBrowseActivity.getStartIntent(
|
||||
MainActivity.this, Messages.Category.ARTIST, artistId));
|
||||
MainActivity.this, Messages.Category.ARTIST, artistId, artistName));
|
||||
}
|
||||
}
|
||||
|
||||
private void navigateToCurrentAlbum() {
|
||||
final long albumId = model.getTrackValueLong(TransportModel.Key.ALBUM_ID, -1);
|
||||
if (albumId != -1) {
|
||||
final String albumName = model.getTrackValueString(TransportModel.Key.ALBUM, "");
|
||||
startActivity(TrackListActivity.getStartIntent(
|
||||
MainActivity.this, Messages.Category.ALBUM, albumId));
|
||||
MainActivity.this, Messages.Category.ALBUM, albumId, albumName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,13 +494,11 @@ public class MainActivity extends WebSocketActivityBase {
|
||||
}
|
||||
|
||||
private AlbumArtModel.AlbumArtCallback albumArtRetrieved = (model, url) -> {
|
||||
long delay = Math.max(0, ARTIFICIAL_ARTWORK_DELAY_MILLIS - model.getLoadTimeMillis());
|
||||
|
||||
handler.postDelayed(() -> {
|
||||
handler.post(() -> {
|
||||
if (model == albumArtModel) {
|
||||
updateAlbumArt();
|
||||
}
|
||||
}, delay);
|
||||
});
|
||||
};
|
||||
|
||||
private CheckBox.OnCheckedChangeListener muteListener =
|
||||
|
@ -108,5 +108,6 @@ public class Messages {
|
||||
String ARTIST = "artist";
|
||||
String ALBUM_ARTIST = "album_artist";
|
||||
String GENRE = "genre";
|
||||
String PLAYLISTS = "playlists";
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
private void rebindUi() {
|
||||
Views.setTextAndMoveCursorToEnd(this.addressText, prefs.getString("address", "192.168.1.100"));
|
||||
Views.setTextAndMoveCursorToEnd(this.portText, String.format(Locale.ENGLISH, "%d", prefs.getInt("port", 9002)));
|
||||
this.passwordText.setText(prefs.getString("password", ""));
|
||||
Views.setTextAndMoveCursorToEnd(this.passwordText, prefs.getString("password", ""));
|
||||
}
|
||||
|
||||
private void bindEventListeners() {
|
||||
|
@ -26,6 +26,21 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
|
||||
.putExtra(EXTRA_SELECTED_ID, id);
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context,
|
||||
final String type,
|
||||
final long id,
|
||||
final String categoryValue) {
|
||||
final Intent intent = getStartIntent(context, type, id);
|
||||
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
intent.putExtra(
|
||||
TrackListActivity.EXTRA_TITLE,
|
||||
context.getString(R.string.songs_from_category, categoryValue));
|
||||
}
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent getStartIntent(final Context context) {
|
||||
return new Intent(context, TrackListActivity.class);
|
||||
}
|
||||
@ -67,7 +82,9 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
Views.initSearchMenu(this, menu, this);
|
||||
if (!Messages.Category.PLAYLISTS.equals(categoryType)) {
|
||||
Views.initSearchMenu(this, menu, this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,7 @@ public class TransportModel {
|
||||
private double duration;
|
||||
private double currentTime;
|
||||
private JSONObject track = new JSONObject();
|
||||
private boolean valid = false;
|
||||
|
||||
public TransportModel() {
|
||||
reset();
|
||||
@ -135,6 +136,8 @@ public class TransportModel {
|
||||
duration = message.getDoubleOption(Key.PLAYING_DURATION);
|
||||
currentTime = message.getDoubleOption(Key.PLAYING_CURRENT_TIME);
|
||||
track = message.getJsonObjectOption(Key.PLAYING_TRACK, new JSONObject());
|
||||
|
||||
valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -146,6 +149,11 @@ public class TransportModel {
|
||||
queueCount = queuePosition = 0;
|
||||
duration = currentTime = 0.0f;
|
||||
track = new JSONObject();
|
||||
valid = false;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
public PlaybackState getPlaybackState() {
|
||||
@ -156,10 +164,6 @@ public class TransportModel {
|
||||
return repeatMode;
|
||||
}
|
||||
|
||||
public void setRepeatMode(final RepeatMode repeatMode) {
|
||||
this.repeatMode = repeatMode;
|
||||
}
|
||||
|
||||
public boolean isShuffled() {
|
||||
return shuffled;
|
||||
}
|
||||
|
@ -1,8 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_playlists"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/menu_playlists"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_genres"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/menu_genres"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/menu_settings"/>
|
||||
|
||||
</menu>
|
@ -8,6 +8,7 @@
|
||||
<string name="songs_from_category">songs from \'%1$s\'</string>
|
||||
<string name="genres_title">genres</string>
|
||||
<string name="artists_title">artists</string>
|
||||
<string name="playlists_title">playlists</string>
|
||||
<string name="button_pause">pause</string>
|
||||
<string name="button_play">play</string>
|
||||
<string name="button_prev">prev</string>
|
||||
@ -42,4 +43,7 @@
|
||||
<string name="transport_not_playing">not playing</string>
|
||||
<string name="search_hint">search</string>
|
||||
<string name="menu_settings">settings</string>
|
||||
<string name="menu_genres">genres</string>
|
||||
<string name="menu_playlists">playlists</string>
|
||||
<string name="unknown_value"><unknown></string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user