diff options
Diffstat (limited to 'app/src')
42 files changed, 420 insertions, 99 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index e6be70f7..9e18b47a 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -93,6 +93,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo private SlidingUpPanelLayout slideUpPanel; private SlidingUpPanelLayout.PanelSlideListener panelSlideListener; + private boolean isPanelClosing = false; private NowPlayingFragment nowPlayingFragment; private SubsonicFragment secondaryFragment; private Toolbar mainToolbar; @@ -195,6 +196,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo @Override public void onPanelCollapsed(View panel) { + isPanelClosing = false; bottomBar.setVisibility(View.VISIBLE); nowPlayingToolbar.setVisibility(View.GONE); nowPlayingFragment.setPrimaryFragment(false); @@ -204,6 +206,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo @Override public void onPanelExpanded(View panel) { + isPanelClosing = false; currentFragment.stopActionMode(); // Disable custom view before switching @@ -341,6 +344,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo super.onNewIntent(intent); if(currentFragment != null && intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) { + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + closeNowPlaying(); + } + if(currentFragment instanceof SearchFragment) { String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY); boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false); @@ -483,7 +490,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo @Override public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) { - if(slideUpPanel != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + if(slideUpPanel != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && !isPanelClosing) { secondaryFragment = fragment; nowPlayingFragment.setPrimaryFragment(false); secondaryFragment.setPrimaryFragment(true); @@ -573,6 +580,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo @Override public void closeNowPlaying() { slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + isPanelClosing = true; } private SubsonicFragment getNewFragment(String fragmentType) { diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java index d4613994..5b3dc289 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java @@ -16,13 +16,18 @@ package github.daneren2005.dsub.adapter; import android.content.Context; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import java.util.List; +import github.daneren2005.dsub.R; import github.daneren2005.dsub.service.DownloadFile; +import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.FastScroller; import github.daneren2005.dsub.view.SongView; import github.daneren2005.dsub.view.UpdateView; @@ -33,6 +38,7 @@ public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements public DownloadFileAdapter(Context context, List<DownloadFile> entries, OnItemClickedListener onItemClickedListener) { super(context, entries); this.onItemClickedListener = onItemClickedListener; + this.checkable = true; } @Override @@ -43,7 +49,7 @@ public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements @Override public void onBindViewHolder(UpdateView.UpdateViewHolder holder, DownloadFile item, int viewType) { SongView songView = (SongView) holder.getUpdateView(); - songView.setObject(item.getSong(), false); + songView.setObject(item.getSong(), Util.isBatchMode(context)); songView.setDownloadFile(item); } @@ -56,4 +62,21 @@ public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements public String getTextToShowInBubble(int position) { return null; } + + @Override + public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { + if(Util.isOffline(context)) { + menuInflater.inflate(R.menu.multiselect_nowplaying_offline, menu); + } else { + menuInflater.inflate(R.menu.multiselect_nowplaying, menu); + } + + if(!selected.isEmpty()) { + MenuItem starItem = menu.findItem(R.id.menu_star); + if(starItem != null) { + boolean isStarred = selected.get(0).getSong().isStarred(); + starItem.setTitle(isStarred ? R.string.common_unstar : R.string.common_star); + } + } + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java index 2c4f75dc..6c1c14da 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java @@ -26,6 +26,7 @@ import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicDirectory.Entry; import github.daneren2005.dsub.domain.ServerInfo; +import github.daneren2005.dsub.fragments.MainFragment; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.ImageLoader; @@ -88,6 +89,10 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter { this.type = type; this.extra = extra; this.size = size; + + if(super.getItemCount() < size) { + allLoaded = true; + } } public void loadMore() { @@ -110,7 +115,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter { appendCachedData(newData); loading = false; - if(newData.isEmpty()) { + if(newData.size() < size) { allLoaded = true; notifyDataSetChanged(); } @@ -126,6 +131,8 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter { result = service.getAlbumList(type, extra, size, offset, false, context, null); } else if("genres".equals(type) || "genres-songs".equals(type)) { result = service.getSongsByGenre(extra, size, offset, context, null); + }else if(type.indexOf(MainFragment.SONGS_LIST_PREFIX) != -1) { + result = service.getSongList(type, size, offset, context, null); } else { result = service.getAlbumList(type, size, offset, false, context, null); } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java index 8f1f1c38..473366fe 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java @@ -100,6 +100,9 @@ public class MainAdapter extends SectionAdapter<Integer> { } else if("videos".equals(header)) { display = context.getResources().getString(R.string.main_videos); checkBox.setVisibility(View.GONE); + } else if("songs".equals(header)) { + display = context.getResources().getString(R.string.search_songs); + checkBox.setVisibility(View.GONE); } else { display = header; checkBox.setVisibility(View.GONE); diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SimilarArtistAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SimilarArtistAdapter.java new file mode 100644 index 00000000..2234d4cd --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SimilarArtistAdapter.java @@ -0,0 +1,53 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2016 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.ViewGroup; + +import java.util.List; + +import github.daneren2005.dsub.domain.Artist; +import github.daneren2005.dsub.view.ArtistView; +import github.daneren2005.dsub.view.UpdateView; + +public class SimilarArtistAdapter extends SectionAdapter<Artist> { + public static int VIEW_TYPE_ARTIST = 4; + + public SimilarArtistAdapter(Context context, List<Artist> artists, OnItemClickedListener onItemClickedListener) { + super(context, artists); + this.onItemClickedListener = onItemClickedListener; + } + public SimilarArtistAdapter(Context context, List<String> headers, List<List<Artist>> sections, OnItemClickedListener onItemClickedListener) { + super(context, headers, sections); + this.onItemClickedListener = onItemClickedListener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new ArtistView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Artist item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Artist item) { + return VIEW_TYPE_ARTIST; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/domain/Artist.java b/app/src/main/java/github/daneren2005/dsub/domain/Artist.java index 56e8f92e..9d4cbe29 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/Artist.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/Artist.java @@ -30,6 +30,8 @@ import java.util.List; */ public class Artist implements Serializable { private static final String TAG = Artist.class.getSimpleName(); + public static final String ROOT_ID = "-1"; + public static final String MISSING_ID = "-2"; private String id; private String name; @@ -38,6 +40,14 @@ public class Artist implements Serializable { private Integer rating; private int closeness; + public Artist() { + + } + public Artist(String id, String name) { + this.id = id; + this.name = name; + } + public String getId() { return id; } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java index f048587b..65ed99b9 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java @@ -46,6 +46,11 @@ import javax.net.ssl.HttpsURLConnection; public class MainFragment extends SelectRecyclerFragment<Integer> { private static final String TAG = MainFragment.class.getSimpleName(); + public static final String SONGS_LIST_PREFIX = "songs-"; + public static final String SONGS_NEWEST = SONGS_LIST_PREFIX + "newest"; + public static final String SONGS_TOP_PLAYED = SONGS_LIST_PREFIX + "topPlayed"; + public static final String SONGS_RECENT = SONGS_LIST_PREFIX + "recent"; + public static final String SONGS_FREQUENT = SONGS_LIST_PREFIX + "frequent"; public MainFragment() { super(); @@ -124,6 +129,22 @@ public class MainFragment extends SelectRecyclerFragment<Integer> { sections.add(albums); headers.add("albums"); + if(ServerInfo.isMadsonic6(context)) { + List<Integer> songs = new ArrayList<>(); + + songs.add(R.string.main_songs_newest); + if(ServerInfo.checkServerVersion(context, "2.0.1")) { + songs.add(R.string.main_songs_top_played); + } + songs.add(R.string.main_songs_recent); + if(ServerInfo.checkServerVersion(context, "2.0.1")) { + songs.add(R.string.main_songs_frequent); + } + + sections.add(songs); + headers.add("songs"); + } + if(ServerInfo.checkServerVersion(context, "1.8")) { List<Integer> videos = Arrays.asList(R.string.main_videos); sections.add(videos); @@ -383,6 +404,14 @@ public class MainFragment extends SelectRecyclerFragment<Integer> { showAlbumList("alphabeticalByName"); } else if(item == R.string.main_videos) { showVideos(); + } else if (item == R.string.main_songs_newest) { + showAlbumList(SONGS_NEWEST); + } else if (item == R.string.main_songs_top_played) { + showAlbumList(SONGS_TOP_PLAYED); + } else if (item == R.string.main_songs_recent) { + showAlbumList(SONGS_RECENT); + } else if (item == R.string.main_songs_frequent) { + showAlbumList(SONGS_FREQUENT); } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java index d77f476f..5de9c595 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -457,6 +457,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis mediaRouteButton.setRouteSelector(downloadService.getRemoteSelector()); } } + + if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_BATCH_MODE, false)) { + menu.findItem(R.id.menu_batch_mode).setChecked(true); + } } @Override @@ -474,7 +478,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis menuInflater.inflate(R.menu.nowplaying_context_offline, menu); } else { menuInflater.inflate(R.menu.nowplaying_context, menu); - menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star); + menu.findItem(R.id.song_menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star); } if (downloadFile.getSong().getParent() == null) { @@ -620,9 +624,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } createNewPlaylist(entries, true); return true; - case R.id.menu_star: - UpdateHelper.toggleStarred(context, song.getSong()); - return true; case R.id.menu_rate: UpdateHelper.setRating(context, song.getSong()); return true; @@ -634,11 +635,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis startTimer(); } return true; - case R.id.menu_add_playlist: - songs = new ArrayList<Entry>(1); - songs.add(song.getSong()); - addToPlaylist(songs); - return true; case R.id.menu_info: displaySongInfo(song.getSong()); return true; @@ -663,7 +659,18 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis // Any failed condition will get here Util.toast(context, "Failed to start equalizer. Try restarting."); return true; - } default: + }case R.id.menu_batch_mode: + if(Util.isBatchMode(context)) { + Util.setBatchMode(context, false); + songListAdapter.notifyDataSetChanged(); + } else { + Util.setBatchMode(context, true); + songListAdapter.notifyDataSetChanged(); + } + context.supportInvalidateOptionsMenu(); + + return true; + default: return false; } } @@ -1158,11 +1165,23 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) { this.currentPlaying = currentPlaying; + setupSubtitle(currentPlayingIndex); + } + + private void setupSubtitle(int currentPlayingIndex) { if (currentPlaying != null) { Entry song = currentPlaying.getSong(); songTitleTextView.setText(song.getTitle()); getImageLoader().loadImage(albumArtImageView, song, true, true); - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); + + DownloadService downloadService = getDownloadService(); + if(downloadService.isShufflePlayEnabled()) { + setSubtitle(context.getResources().getString(R.string.download_playerstate_playing_shuffle)); + } else if(downloadService.isArtistRadio()) { + setSubtitle(context.getResources().getString(R.string.download_playerstate_playing_artist_radio)); + } else { + setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); + } } else { songTitleTextView.setText(null); getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); @@ -1199,10 +1218,11 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis scrollWhenLoaded = false; } - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); if(this.currentPlaying != currentPlaying) { onSongChanged(currentPlaying, currentPlayingIndex); onMetadataUpdate(currentPlaying != null ? currentPlaying.getSong() : null, DownloadService.METADATA_UPDATED_ALL); + } else { + setupSubtitle(currentPlayingIndex); } } @@ -1356,4 +1376,18 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis break; } } + + @Override + protected List<Entry> getSelectedEntries() { + List<DownloadFile> selected = getCurrentAdapter().getSelected(); + List<Entry> entries = new ArrayList<>(); + + for(DownloadFile downloadFile: selected) { + if(downloadFile.getSong() != null) { + entries.add(downloadFile.getSong()); + } + } + + return entries; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java index d21b82e0..5c659a6a 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java @@ -130,7 +130,7 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_search: + case R.id.menu_global_search: context.startSearch(currentQuery, false, null, false); return true; } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index 4209cfd6..718ad5c5 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -387,16 +387,17 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section } else { List<Entry> songs = new ArrayList<Entry>(); - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, true)) { - Iterator it = entries.listIterator(entries.indexOf(entry)); - while(it.hasNext()) { - songs.add((Entry) it.next()); + if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, true) && (albumListType == null || "starred".equals(albumListType))) { + for(Entry song: entries) { + if(!song.isDirectory() && !song.isVideo()) { + songs.add(song); + } } + playNow(songs, entry, 0); } else { songs.add(entry); + playNow(songs); } - - playNow(songs); } } @@ -580,6 +581,14 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section setTitle(albumListExtra); } else if("alphabeticalByName".equals(albumListType)) { setTitle(R.string.main_albums_alphabetical); + } if (MainFragment.SONGS_NEWEST.equals(albumListType)) { + setTitle(R.string.main_songs_newest); + } else if (MainFragment.SONGS_TOP_PLAYED.equals(albumListType)) { + setTitle(R.string.main_songs_top_played); + } else if (MainFragment.SONGS_RECENT.equals(albumListType)) { + setTitle(R.string.main_songs_recent); + } else if (MainFragment.SONGS_FREQUENT.equals(albumListType)) { + setTitle(R.string.main_songs_frequent); } new LoadTask(true) { @@ -596,6 +605,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section } } else if("genres".equals(albumListType) || "genres-songs".equals(albumListType)) { result = service.getSongsByGenre(albumListExtra, size, 0, context, this); + } else if(albumListType.indexOf(MainFragment.SONGS_LIST_PREFIX) != -1) { + result = service.getSongList(albumListType, size, 0, context, this); } else { result = service.getAlbumList(albumListType, size, 0, refresh, context, this); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java index 93e3a93a..a41b9d6f 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java @@ -15,14 +15,16 @@ package github.daneren2005.dsub.fragments; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import github.daneren2005.dsub.R; -import github.daneren2005.dsub.adapter.ArtistAdapter; import github.daneren2005.dsub.adapter.SectionAdapter; +import github.daneren2005.dsub.adapter.SimilarArtistAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.MusicDirectory; @@ -35,6 +37,8 @@ import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UpdateView; import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -52,18 +56,6 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - super.onCreateOptionsMenu(menu, menuInflater); - if(!primaryFragment) { - return; - } - - if(info.getMissingArtists().isEmpty()) { - menu.removeItem(R.id.menu_show_missing); - } - } - - @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_play_now: @@ -72,9 +64,6 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { case R.id.menu_shuffle: playAll(true); return true; - case R.id.menu_show_missing: - showMissingArtists(); - break; } return super.onOptionsItemSelected(item); @@ -82,8 +71,10 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { @Override public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Artist> updateView, Artist item) { - onCreateContextMenuSupport(menu, menuInflater, updateView, item); - recreateContextMenu(menu); + if(!Artist.MISSING_ID.equals(item.getId())) { + onCreateContextMenuSupport(menu, menuInflater, updateView, item); + recreateContextMenu(menu); + } } @Override @@ -93,14 +84,21 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { @Override public void onItemClicked(UpdateView<Artist> updateView, Artist artist) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - - replaceFragment(fragment); + if(Artist.MISSING_ID.equals(artist.getId())) { + String url = "http://www.last.fm/music/" + URLEncoder.encode(artist.getName()); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + startActivity(intent); + } else { + SubsonicFragment fragment = new SelectDirectoryFragment(); + Bundle args = new Bundle(); + args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); + args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); + args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); + fragment.setArguments(args); + + replaceFragment(fragment); + } } @Override @@ -109,8 +107,22 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { } @Override - public SectionAdapter getAdapter(List<Artist> objects) { - return new ArtistAdapter(context, objects, this); + public SectionAdapter getAdapter(List<Artist> artists) { + if(info.getMissingArtists().isEmpty()) { + return new SimilarArtistAdapter(context, artists, this); + } else { + List<String> headers = new ArrayList<>(); + headers.add(null); + headers.add(context.getResources().getString(R.string.menu_similar_artists_missing)); + + List<Artist> missingArtists = new ArrayList<>(); + for(String artistName: info.getMissingArtists()) { + Artist artist = new Artist(Artist.MISSING_ID, artistName); + missingArtists.add(artist); + } + + return new SimilarArtistAdapter(context, headers, Arrays.asList(artists, missingArtists), this); + } } @Override @@ -124,16 +136,6 @@ public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { return R.string.menu_similar_artists; } - private void showMissingArtists() { - StringBuilder b = new StringBuilder(); - - for(String name: info.getMissingArtists()) { - b.append("<h3><a href=\"https://www.google.com/#q=" + URLEncoder.encode(name) + "\">" + name + "</a></h3> "); - } - - Util.showHTMLDialog(context, R.string.menu_similar_artists, b.toString()); - } - private void playAll(final boolean shuffle) { new RecursiveLoader(context) { @Override diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java index bc2418eb..0cb433c2 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -326,6 +326,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR public boolean onContextItemSelected(MenuItem menuItem, Object selectedItem) { Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null; Entry entry = selectedItem instanceof Entry ? (Entry) selectedItem : null; + if(selectedItem instanceof DownloadFile) { + entry = ((DownloadFile) selectedItem).getSong(); + } List<Entry> songs = new ArrayList<Entry>(1); songs.add(entry); diff --git a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java index aa353def..35d419bb 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/AutoMediaBrowserService.java @@ -58,6 +58,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { private static final String PODCAST_PREFIX = "po-"; private static final String ALBUM_TYPE_PREFIX = "ty-"; private static final String MUSIC_DIRECTORY_PREFIX = "md-"; + private static final int MAX_DOUBLE_LINE_ITEMS = 9; private DownloadService downloadService; private Handler handler = new Handler(); @@ -194,7 +195,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { albumListType = "newest"; } - return musicService.getAlbumList(albumListType, 40, 0, true, downloadService, null); + return musicService.getAlbumList(albumListType, MAX_DOUBLE_LINE_ITEMS, 0, true, downloadService, null); } @Override @@ -286,6 +287,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { protected void done(MusicDirectory podcasts) { List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>(); + int i = 0; for(Entry entry: podcasts.getChildren(false, true)) { PodcastEpisode podcast = (PodcastEpisode) entry; Bundle podcastExtras = new Bundle(); @@ -294,12 +296,16 @@ public class AutoMediaBrowserService extends MediaBrowserService { MediaDescription description = new MediaDescription.Builder() .setTitle(podcast.getTitle()) - .setSubtitle(Util.formatDate(downloadService, podcast.getDate())) + .setSubtitle(Util.formatDate(downloadService, podcast.getDate(), false)) .setMediaId(PODCAST_PREFIX + podcast.getId()) .setExtras(podcastExtras) .build(); mediaItems.add(new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)); + i++; + if(i >= MAX_DOUBLE_LINE_ITEMS) { + break; + } } result.sendResult(mediaItems); @@ -364,7 +370,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { .setExtras(shuffleExtras); mediaItems.add(new MediaBrowser.MediaItem(shuffle.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); - /*Bundle playLastExtras = new Bundle(); + Bundle playLastExtras = new Bundle(); playLastExtras.putString(idConstant, id); playLastExtras.putBoolean(Constants.INTENT_EXTRA_PLAY_LAST, true); @@ -372,7 +378,7 @@ public class AutoMediaBrowserService extends MediaBrowserService { playLast.setTitle(downloadService.getString(R.string.menu_play_last)) .setMediaId("playLast-" + id) .setExtras(playLastExtras); - mediaItems.add(new MediaBrowser.MediaItem(playLast.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE));*/ + mediaItems.add(new MediaBrowser.MediaItem(playLast.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE)); result.sendResult(mediaItems); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java index 49cb217d..52268d82 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java @@ -72,6 +72,7 @@ public class CachedMusicService implements MusicService { private static final int TTL_MUSIC_DIR = 5 * 60; // Five minutes public static final int CACHE_UPDATE_LIST = 1; public static final int CACHE_UPDATE_METADATA = 2; + private static final int CACHED_LAST_FM = 24 * 60; private final RESTMusicService musicService; private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<Boolean>(120, TimeUnit.SECONDS); @@ -667,6 +668,11 @@ public class CachedMusicService implements MusicService { } @Override + public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + return musicService.getSongList(type, size, offset, context, progressListener); + } + + @Override public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { return musicService.getRandomSongs(size, artistId, context, progressListener); } @@ -1147,12 +1153,22 @@ public class CachedMusicService implements MusicService { String cacheName = getCacheName(context, "artistInfo", id); ArtistInfo info = null; if(!refresh) { - info = FileUtil.deserialize(context, cacheName, ArtistInfo.class); + info = FileUtil.deserialize(context, cacheName, ArtistInfo.class, CACHED_LAST_FM); } if(info == null && allowNetwork) { - info = musicService.getArtistInfo(id, refresh, allowNetwork, context, progressListener); - FileUtil.serialize(context, info, cacheName); + try { + info = musicService.getArtistInfo(id, refresh, allowNetwork, context, progressListener); + FileUtil.serialize(context, info, cacheName); + } catch(Exception e) { + Log.w(TAG, "Failed to refresh Artist Info"); + info = FileUtil.deserialize(context, cacheName, ArtistInfo.class); + + // Nothing ever cached, throw error further upstream + if(info == null) { + throw e; + } + } } return info; diff --git a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java index 670ea7d2..bc54f486 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java @@ -503,7 +503,7 @@ public class ChromeCastController extends RemoteController { try { Cast.CastApi.setMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace(), mediaPlayer); - } catch (IOException e) { + } catch (Exception e) { Log.e(TAG, "Exception while creating channel", e); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java index ac8b44d6..7044410b 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java @@ -379,7 +379,8 @@ public class DownloadFile implements BufferFile { return "DownloadFile (" + song + ")"; } - @Override + // Don't do this. Causes infinite loop if two instances of same song + /*@Override public boolean equals(Object o) { if (this == o) { return true; @@ -390,7 +391,7 @@ public class DownloadFile implements BufferFile { DownloadFile downloadFile = (DownloadFile) o; return Util.equals(this.getSong(), downloadFile.getSong()); - } + }*/ private class DownloadTask extends SilentBackgroundTask<Void> { private MusicService musicService; diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index a4f88ee2..3e771d70 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -601,6 +601,9 @@ public class DownloadService extends Service { } editor.commit(); } + public boolean isArtistRadio() { + return artistRadio; + } public synchronized void shuffle() { Collections.shuffle(downloadList); diff --git a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java index 2972bb7c..876b45fd 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java @@ -94,6 +94,8 @@ public interface MusicService { MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception; diff --git a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java index a1657f39..3048a0db 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java @@ -588,6 +588,11 @@ public class OfflineMusicService implements MusicService { } @Override + public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException(ERRORMSG); + } + + @Override public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException(ERRORMSG); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java index 4a6e5108..a7a68205 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -72,7 +72,8 @@ import android.util.Log; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.*; -import github.daneren2005.dsub.service.parser.AlbumListParser; +import github.daneren2005.dsub.fragments.MainFragment; +import github.daneren2005.dsub.service.parser.EntryListParser; import github.daneren2005.dsub.service.parser.ArtistInfoParser; import github.daneren2005.dsub.service.parser.BookmarkParser; import github.daneren2005.dsub.service.parser.ChatMessageParser; @@ -571,7 +572,7 @@ public class RESTMusicService implements MusicService { Reader reader = getReader(context, progressListener, method, null, names, values, true); try { - return new AlbumListParser(context, getInstance(context)).parse(reader, progressListener); + return new EntryListParser(context, getInstance(context)).parse(reader, progressListener); } finally { Util.close(reader); } @@ -637,13 +638,49 @@ public class RESTMusicService implements MusicService { Reader reader = getReader(context, progressListener, method, null, names, values, true); try { - return new AlbumListParser(context, instance).parse(reader, progressListener); + return new EntryListParser(context, instance).parse(reader, progressListener); } finally { Util.close(reader); } } - @Override + @Override + public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + List<String> names = new ArrayList<String>(); + List<Object> values = new ArrayList<Object>(); + + names.add("size"); + values.add(size); + names.add("offset"); + values.add(offset); + + String method; + switch(type) { + case MainFragment.SONGS_NEWEST: + method = "getNewaddedSongs"; + break; + case MainFragment.SONGS_TOP_PLAYED: + method = "getTopplayedSongs"; + break; + case MainFragment.SONGS_RECENT: + method = "getLastplayedSongs"; + break; + case MainFragment.SONGS_FREQUENT: + method = "getMostplayedSongs"; + break; + default: + method = "getNewaddedSongs"; + } + + Reader reader = getReader(context, progressListener, method, null, names, values, true); + try { + return new EntryListParser(context, getInstance(context)).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + + @Override public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.11", "Artist radio is not supported"); diff --git a/app/src/main/java/github/daneren2005/dsub/service/parser/AlbumListParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/EntryListParser.java index 213cc6b3..f91aaae1 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/parser/AlbumListParser.java +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/EntryListParser.java @@ -29,9 +29,9 @@ import java.io.Reader; /** * @author Sindre Mehus */ -public class AlbumListParser extends MusicDirectoryEntryParser { +public class EntryListParser extends MusicDirectoryEntryParser { - public AlbumListParser(Context context, int instance) { + public EntryListParser(Context context, int instance) { super(context, instance); } @@ -50,6 +50,9 @@ public class AlbumListParser extends MusicDirectoryEntryParser { entry.setDirectory(true); } dir.addChild(entry); + } else if ("song".equals(name)) { + MusicDirectory.Entry entry = parseEntry(""); + dir.addChild(entry); } else if ("error".equals(name)) { handleError(); } diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index bfb85492..00682947 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -169,6 +169,7 @@ public final class Constants { public static final String PREFERENCES_KEY_COLOR_ACTION_BAR = "colorActionBar"; public static final String PREFERENCES_KEY_SHUFFLE_BY_ALBUM = "shuffleByAlbum"; public static final String PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER = "neverResumePlayQueue"; + public static final String PREFERENCES_KEY_BATCH_MODE = "batchMode"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index bf4af20d..98bbe1df 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -107,6 +107,7 @@ public final class Util { private static DecimalFormat BYTE_LOCALIZED_FORMAT = null; private static SimpleDateFormat DATE_FORMAT_SHORT = new SimpleDateFormat("MMM d h:mm a"); private static SimpleDateFormat DATE_FORMAT_LONG = new SimpleDateFormat("MMM d, yyyy h:mm a"); + private static SimpleDateFormat DATE_FORMAT_NO_TIME = new SimpleDateFormat("MMM d, yyyy"); private static int CURRENT_YEAR = new Date().getYear(); public static final String EVENT_META_CHANGED = "github.daneren2005.dsub.EVENT_META_CHANGED"; @@ -376,6 +377,12 @@ public final class Util { int cacheSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CACHE_SIZE, "-1")); return cacheSize == -1 ? Integer.MAX_VALUE : cacheSize; } + public static boolean isBatchMode(Context context) { + return Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_BATCH_MODE, false); + } + public static void setBatchMode(Context context, boolean batchMode) { + Util.getPreferences(context).edit().putBoolean(Constants.PREFERENCES_KEY_BATCH_MODE, batchMode).commit(); + } public static String getRestUrl(Context context, String method) { return getRestUrl(context, method, true); @@ -901,26 +908,38 @@ public final class Util { } public static String formatDate(Context context, String dateString) { + return formatDate(context, dateString, true); + } + public static String formatDate(Context context, String dateString, boolean includeTime) { try { + dateString = dateString.replace(' ', 'T'); boolean isDateNormalized = ServerInfo.checkServerVersion(context, "1.11"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); if (isDateNormalized) { dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } - return formatDate(dateFormat.parse(dateString)); + return formatDate(dateFormat.parse(dateString), includeTime); } catch(ParseException e) { + Log.e(TAG, "Failed to parse date string", e); return dateString; } } public static String formatDate(Date date) { + return formatDate(date, true); + } + public static String formatDate(Date date, boolean includeTime) { if(date == null) { return "Never"; } else { - if(date.getYear() != CURRENT_YEAR) { - return DATE_FORMAT_LONG.format(date); + if(includeTime) { + if (date.getYear() != CURRENT_YEAR) { + return DATE_FORMAT_LONG.format(date); + } else { + return DATE_FORMAT_SHORT.format(date); + } } else { - return DATE_FORMAT_SHORT.format(date); + return DATE_FORMAT_NO_TIME.format(date); } } } diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java index bad9c0f6..47c77cac 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java @@ -415,7 +415,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } } - downloadService.download(entries, false, true, false, shuffle, startIndex, startPosition); + downloadService.download(entries, false, !append, false, shuffle, startIndex, startPosition); } private void noResults() { diff --git a/app/src/main/java/github/daneren2005/dsub/view/SongView.java b/app/src/main/java/github/daneren2005/dsub/view/SongView.java index c7634b34..2c0580af 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/SongView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/SongView.java @@ -106,8 +106,7 @@ public class SongView extends UpdateView2<MusicDirectory.Entry, Boolean> { if(artist.length() != 0) { artist.append(" - "); } - int index = date.indexOf(" "); - artist.append(date.substring(0, index != -1 ? index : date.length())); + artist.append(Util.formatDate(context, date, false)); } } else if(song.getArtist() != null) { diff --git a/app/src/main/res/menu/drawer_menu.xml b/app/src/main/res/menu/drawer_menu.xml index b3e70cfa..21d324a9 100644 --- a/app/src/main/res/menu/drawer_menu.xml +++ b/app/src/main/res/menu/drawer_menu.xml @@ -3,7 +3,7 @@ xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/multiselect_nowplaying.xml b/app/src/main/res/menu/multiselect_nowplaying.xml new file mode 100644 index 00000000..9d361bf0 --- /dev/null +++ b/app/src/main/res/menu/multiselect_nowplaying.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:compat="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/menu_download" + android:title="@string/common.download" + android:icon="?attr/download" + compat:showAsAction="ifRoom|withText"/> + + <item + android:id="@+id/menu_delete" + android:title="@string/menu.delete_cache" + android:icon="?attr/remove" + compat:showAsAction="ifRoom|withText"/> + + <item + android:id="@+id/menu_cache" + android:title="@string/common.pin"/> + + <item + android:id="@+id/menu_add_playlist" + android:title="@string/menu.add_playlist"/> + + <item + android:id="@+id/menu_star" + android:title="@string/common.star"/> +</menu> diff --git a/app/src/main/res/menu/multiselect_nowplaying_offline.xml b/app/src/main/res/menu/multiselect_nowplaying_offline.xml new file mode 100644 index 00000000..044836c6 --- /dev/null +++ b/app/src/main/res/menu/multiselect_nowplaying_offline.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:compat="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/menu_delete" + android:title="@string/menu.delete_cache" + android:icon="?attr/remove" + compat:showAsAction="ifRoom|withText"/> +</menu> diff --git a/app/src/main/res/menu/nowplaying.xml b/app/src/main/res/menu/nowplaying.xml index 60255692..9c198e9a 100644 --- a/app/src/main/res/menu/nowplaying.xml +++ b/app/src/main/res/menu/nowplaying.xml @@ -33,6 +33,11 @@ android:title="@string/equalizer.label" android:checkable="true"/> + <item + android:id="@+id/menu_batch_mode" + android:title="@string/download.batch_mode" + android:checkable="true"/> + <item android:id="@+id/menu_screen_on_off" android:title="@string/download.menu_screen_on" diff --git a/app/src/main/res/menu/nowplaying_context.xml b/app/src/main/res/menu/nowplaying_context.xml index 60d6288e..06f4afcb 100644 --- a/app/src/main/res/menu/nowplaying_context.xml +++ b/app/src/main/res/menu/nowplaying_context.xml @@ -26,7 +26,7 @@ <group android:id="@+id/hide_star"> <item - android:id="@+id/menu_star" + android:id="@+id/song_menu_star" android:title="@string/common.star"/> </group> @@ -44,7 +44,7 @@ <group android:id="@+id/server_1.8"> <item - android:id="@+id/menu_add_playlist" + android:id="@+id/song_menu_add_playlist" android:title="@string/menu.add_playlist"/> </group> </menu> diff --git a/app/src/main/res/menu/nowplaying_context_offline.xml b/app/src/main/res/menu/nowplaying_context_offline.xml index 5f8009ff..14c95ab6 100644 --- a/app/src/main/res/menu/nowplaying_context_offline.xml +++ b/app/src/main/res/menu/nowplaying_context_offline.xml @@ -22,7 +22,7 @@ <group android:id="@+id/hide_star"> <item - android:id="@+id/menu_star" + android:id="@+id/song_menu_star" android:title="@string/common.star"/> </group> </menu> diff --git a/app/src/main/res/menu/nowplaying_offline.xml b/app/src/main/res/menu/nowplaying_offline.xml index bba5ba00..d1f6f706 100644 --- a/app/src/main/res/menu/nowplaying_offline.xml +++ b/app/src/main/res/menu/nowplaying_offline.xml @@ -25,6 +25,11 @@ android:id="@+id/menu_equalizer" android:title="@string/equalizer.label" android:checkable="true"/> + + <item + android:id="@+id/menu_batch_mode" + android:title="@string/download.batch_mode" + android:checkable="true"/> <item android:id="@+id/menu_screen_on_off" diff --git a/app/src/main/res/menu/similar_artists.xml b/app/src/main/res/menu/similar_artists.xml index f6c30fb2..2557381e 100644 --- a/app/src/main/res/menu/similar_artists.xml +++ b/app/src/main/res/menu/similar_artists.xml @@ -13,8 +13,4 @@ android:icon="?attr/shuffle" android:title="@string/menu.shuffle" compat:showAsAction="ifRoom|withText"/> - - <item - android:id="@+id/menu_show_missing" - android:title="@string/menu.show_missing"/> </menu>
\ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 13453ae6..3ab30895 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -106,7 +106,6 @@ <string name="menu.rate">Setze Bewertung</string> <string name="menu.top_tracks">Last.FM Top Medien</string> <string name="menu.similar_artists">Ähnliche Künstler</string> - <string name="menu.show_missing">Zeige fehlende</string> <string name="menu.start_radio">Starte Radio</string> <string name="menu.first_level_artist">Erste Ebene sind Künstler</string> diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f56e939e..47f7ce7f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -96,7 +96,6 @@ <string name="menu.rate">Establecer valoración</string> <string name="menu.top_tracks">Tp Tracks de Last.FM</string> <string name="menu.similar_artists">Artistas similares</string> - <string name="menu.show_missing">Mostrar los que faltan</string> <string name="menu.start_radio">Iniciar radio</string> <string name="playlist.label">Listas de reproducción</string> diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index ea8d3eeb..11302cd3 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -111,7 +111,6 @@ <string name="menu.rate">Értékelés</string> <string name="menu.top_tracks">Last.fm legjobb dalok</string> <string name="menu.similar_artists">Hasonló előadók</string> - <string name="menu.show_missing">Hiányzó megjelenítése</string> <string name="menu.start_radio">Rádió indítása</string> <string name="menu.first_level_artist">Részletes megjelenítés</string> diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4bf21c67..545e9505 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -109,7 +109,6 @@ <string name="menu.rate">Bepaal rating</string> <string name="menu.top_tracks">Laatste .FM Top Nummers</string> <string name="menu.similar_artists">Gelijke artiesten</string> - <string name="menu.show_missing">Toon missende</string> <string name="menu.start_radio">Start radio</string> <string name="menu.first_level_artist">Eerste niveau artiesten</string> diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 03b65571..75042859 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -110,7 +110,6 @@ <string name="menu.rate">Classificar</string> <string name="menu.top_tracks">Top faixas do Last.FM</string> <string name="menu.similar_artists">Artistas semelhantes</string> - <string name="menu.show_missing">Mostrar os que faltam</string> <string name="menu.start_radio">Iniciar rádio</string> <string name="menu.first_level_artist">Artistas no primeiro nível</string> diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 38add733..8288d155 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -111,7 +111,6 @@ <string name="menu.rate">Sätt betyg </string> <string name="menu.top_tracks">Last.FM topp spår</string> <string name="menu.similar_artists">Liknande artister</string> - <string name="menu.show_missing">Visa saknade</string> <string name="menu.start_radio">Starta radio</string> <string name="menu.first_level_artist">Första steget artister</string> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index d97a3b21..c8553dc0 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -37,6 +37,7 @@ <attr name="rating_good" format="reference"/> <attr name="radio" format="reference"/> <attr name="star_outline" format="reference"/> + <attr name="download" format="reference"/> <attr name="drawerItemsIcons" format="reference"/> <attr name="drawerHome" format="reference"/> <attr name="drawerLibrary" format="reference"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5d0aacd7..b7efff1a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,6 +76,10 @@ <string name="main.albums_alphabetical">Alphabetically</string> <string name="main.videos">Videos</string> <string name="main.songs_genres">@string/main.albums_genres</string> + <string name="main.songs_newest">@string/main.albums_newest</string> + <string name="main.songs_top_played">Top Played</string> + <string name="main.songs_recent">@string/main.albums_recent</string> + <string name="main.songs_frequent">@string/main.albums_frequent</string> <string name="main.back_confirm">Press back again to exit</string> <string name="main.scan_complete">Completed scan of Server</string> <string name="main.artist">Artist</string> @@ -111,7 +115,7 @@ <string name="menu.rate">Set Rating</string> <string name="menu.top_tracks">Last.FM Top Tracks</string> <string name="menu.similar_artists">Similar Artists</string> - <string name="menu.show_missing">Show missing</string> + <string name="menu.similar_artists.missing">Missing Artists</string> <string name="menu.start_radio">Start Radio</string> <string name="menu.first_level_artist">First level artists</string> @@ -186,7 +190,8 @@ <string name="download.playerstate_downloading">Downloading - %s</string> <string name="download.playerstate_mobile_disabled">Waiting for WiFi network to download</string> <string name="download.playerstate_buffering">Buffering</string> - <string name="download.playerstate_playing_shuffle">Playing shuffle</string> + <string name="download.playerstate_playing_shuffle">Shuffle mode</string> + <string name="download.playerstate_playing_artist_radio">Artist radio</string> <string name="download.menu_show_album">Show Album</string> <string name="download.menu_lyrics">Lyrics</string> <string name="download.menu_remove_all">Remove all</string> @@ -227,6 +232,7 @@ <string name="download.restore_play_queue">continue from where you left off on another device at</string> <string name="download.thumbs_up">Thumbs Up</string> <string name="download.thumbs_down">Thumbs Down</string> + <string name="download.batch_mode">Batch Mode</string> <string name="sync.new_podcasts">New podcasts available</string> <string name="sync.new_playlists">New songs in playlists</string> diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 790d91de..4915c012 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -38,6 +38,7 @@ <item name="rating_good">@drawable/ic_action_rating_good_light</item> <item name="radio">@drawable/ic_menu_radio_dark</item> <item name="star_outline">@drawable/ic_toggle_star_outline_light</item> + <item name="download">@drawable/ic_menu_download_dark</item> <item name="drawerHome">@drawable/main_offline_light</item> <item name="drawerLibrary">@drawable/ic_menu_library_light</item> <item name="drawerPlaylists">@drawable/ic_menu_playlist_light</item> @@ -103,6 +104,7 @@ <item name="rating_good">@drawable/ic_action_rating_good_dark</item> <item name="radio">@drawable/ic_menu_radio_dark</item> <item name="star_outline">@drawable/ic_toggle_star_outline_dark</item> + <item name="download">@drawable/ic_menu_download_dark</item> <item name="drawerHome">@drawable/main_offline_dark</item> <item name="drawerLibrary">@drawable/ic_menu_library_dark</item> <item name="drawerPlaylists">@drawable/ic_menu_playlist_dark</item> @@ -190,6 +192,7 @@ <item name="add_person">@drawable/ic_menu_add_person_light</item> <item name="password">@drawable/ic_menu_password_light</item> <item name="radio">@drawable/ic_menu_radio_light</item> + <item name="download">@drawable/ic_menu_download_light</item> <item name="actionModeBackground">@color/background_material_light</item> <item name="actionModeStyle">@style/LightActionMode</item> <item name="actionModeCloseButtonStyle">@style/DarkCloseButton</item> |