From abe43fa2eb6f5a8fb6734af4cba40dbba5650158 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 12 Oct 2015 18:07:51 -0700 Subject: #480 Add support for starring/rating from auto --- .../dsub/activity/SubsonicFragmentActivity.java | 8 +- .../dsub/fragments/NowPlayingFragment.java | 179 +++++--------- .../dsub/fragments/SelectDirectoryFragment.java | 13 +- .../dsub/fragments/SubsonicFragment.java | 226 +----------------- .../daneren2005/dsub/service/DownloadService.java | 73 ++++++ .../github/daneren2005/dsub/util/UpdateHelper.java | 263 +++++++++++++++++++++ .../dsub/util/compat/RemoteControlClientLP.java | 60 +++-- 7 files changed, 447 insertions(+), 375 deletions(-) create mode 100644 app/src/main/java/github/daneren2005/dsub/util/UpdateHelper.java (limited to 'app/src/main/java/github/daneren2005') 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 8d3bf099..f32c5255 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -819,8 +819,9 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo @Override public void onSongsChanged(List songs, DownloadFile currentPlaying, int currentPlayingIndex) { - if(this.currentPlaying != currentPlaying || currentPlaying == null) { + if(this.currentPlaying != currentPlaying || this.currentPlaying == null) { onSongChanged(currentPlaying, currentPlayingIndex); + onMetadataUpdate(currentPlaying != null ? currentPlaying.getSong() : null, DownloadService.METADATA_UPDATED_ALL); } } @@ -836,4 +837,9 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo startButton.setImageResource(typedArray.getResourceId(0, 0)); typedArray.recycle(); } + + @Override + public void onMetadataUpdate(MusicDirectory.Entry entry, int fieldChange) { + + } } 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 892891d2..a6517bf6 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -61,6 +61,7 @@ import github.daneren2005.dsub.activity.SubsonicFragmentActivity; import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.audiofx.EqualizerController; import github.daneren2005.dsub.domain.Bookmark; +import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RepeatMode; import github.daneren2005.dsub.domain.ServerInfo; @@ -196,24 +197,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis starButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - DownloadFile currentDownload = getDownloadService().getCurrentPlaying(); - if (currentDownload != null) { - final Entry currentSong = currentDownload.getSong(); - toggleStarred(currentSong, new OnStarChange() { - @Override - void starChange(boolean starred) { - if(currentSong.isStarred()) { - starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); - } else { - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); - } else { - starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); - } - } - } - }); - } + getDownloadService().toggleStarred(); } }); } else { @@ -360,37 +344,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(downloadService == null) { return; } - - DownloadFile downloadFile = downloadService.getCurrentPlaying(); - if(downloadFile == null) { - return; - } - Entry entry = downloadFile.getSong(); - - // If rating == 1, already set so unset - if(entry.getRating() == 1) { - setRating(entry, 0); - - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); - } else { - rateBadButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_bad)); - } - } else { - // Immediately skip to the next song - downloadService.next(true); - - // Otherwise set rating to 1 - setRating(entry, 1); - rateBadButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_bad_selected)); - - // Make sure good rating is blank - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); - } else { - rateGoodButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_good)); - } - } + downloadService.toggleRating(1); } }); rateGoodButton.setOnClickListener(new View.OnClickListener() { @@ -400,34 +354,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(downloadService == null) { return; } - - DownloadFile downloadFile = downloadService.getCurrentPlaying(); - if(downloadFile == null) { - return; - } - Entry entry = downloadFile.getSong(); - - // If rating == 5, already set so unset - if(entry.getRating() == 5) { - setRating(entry, 0); - - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); - } else { - rateGoodButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_good)); - } - } else { - // Otherwise set rating to maximum - setRating(entry, 5); - rateGoodButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_good_selected)); - - // Make sure bad rating is blank - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); - } else { - rateBadButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_bad)); - } - } + downloadService.toggleRating(5); } }); @@ -694,10 +621,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis createNewPlaylist(entries, true); return true; case R.id.menu_star: - toggleStarred(song.getSong()); + UpdateHelper.toggleStarred(context, song.getSong()); return true; case R.id.menu_rate: - setRating(song.getSong()); + UpdateHelper.setRating(context, song.getSong()); return true; case R.id.menu_toggle_timer: if(getDownloadService().getSleepTimer()) { @@ -1093,7 +1020,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis MusicService musicService = MusicServiceFactory.getMusicService(context); musicService.createBookmark(currentSong, position, comment, context, null); - new EntryInstanceUpdater(currentSong) { + new UpdateHelper.EntryInstanceUpdater(currentSong) { @Override public void update(Entry found) { found.setBookmark(new Bookmark(position)); @@ -1235,54 +1162,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis Entry song = currentPlaying.getSong(); songTitleTextView.setText(song.getTitle()); getImageLoader().loadImage(albumArtImageView, song, true, true); - if(song.isStarred()) { - starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); - } else { - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); - } else { - starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); - } - } setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); - - int badRating, goodRating, bookmark; - if(song.getRating() == 1) { - rateBadButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_bad_selected)); - } else { - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - badRating = R.drawable.ic_action_rating_bad_dark; - } else { - badRating = DrawableTint.getDrawableRes(context, R.attr.rating_bad); - } - rateBadButton.setImageResource(badRating); - } - - if(song.getRating() == 5) { - rateGoodButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_good_selected)); - } else { - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - goodRating = R.drawable.ic_action_rating_good_dark; - } else { - goodRating = DrawableTint.getDrawableRes(context, R.attr.rating_good); - } - rateGoodButton.setImageResource(goodRating); - } - - if(song.getBookmark() != null) { - bookmarkButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_menu_bookmark_selected)); - } else { - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - bookmark = R.drawable.ic_menu_bookmark_dark; - } else { - bookmark = DrawableTint.getDrawableRes(context, R.attr.bookmark); - } - bookmarkButton.setImageResource(bookmark); - } } else { songTitleTextView.setText(null); getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); - starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); setSubtitle(null); } } @@ -1319,6 +1202,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis 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); } } @@ -1401,6 +1285,53 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } } + @Override + public void onMetadataUpdate(Entry song, int fieldChange) { + if(song != null && song.isStarred()) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + } else { + starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); + } + } + + int badRating, goodRating, bookmark; + if(song != null && song.getRating() == 1) { + rateBadButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_bad_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + badRating = R.drawable.ic_action_rating_bad_dark; + } else { + badRating = DrawableTint.getDrawableRes(context, R.attr.rating_bad); + } + rateBadButton.setImageResource(badRating); + } + + if(song != null && song.getRating() == 5) { + rateGoodButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_good_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + goodRating = R.drawable.ic_action_rating_good_dark; + } else { + goodRating = DrawableTint.getDrawableRes(context, R.attr.rating_good); + } + rateGoodButton.setImageResource(goodRating); + } + + if(song != null && song.getBookmark() != null) { + bookmarkButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_menu_bookmark_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + bookmark = R.drawable.ic_menu_bookmark_dark; + } else { + bookmark = DrawableTint.getDrawableRes(context, R.attr.bookmark); + } + bookmarkButton.setImageResource(bookmark); + } + } + public void updateRepeatButton() { DownloadService downloadService = getDownloadService(); switch (downloadService.getRepeatMode()) { 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 2db10c2e..9e6fec45 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -57,6 +57,7 @@ import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.Pair; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.TabBackgroundTask; +import github.daneren2005.dsub.util.UpdateHelper; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.FastScroller; @@ -1037,7 +1038,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section musicService.setStarred(entries, artists, albums, false, this, context); for(Entry entry: unstar) { - new EntryInstanceUpdater(entry) { + new UpdateHelper.EntryInstanceUpdater(entry) { @Override public void update(Entry found) { found.setStarred(false); @@ -1382,10 +1383,10 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section starButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - toggleStarred(directory, new OnStarChange() { + UpdateHelper.toggleStarred(context, directory, new UpdateHelper.OnStarChange() { @Override - void starChange(boolean starred) { - if(directory.isStarred()) { + public void starChange(boolean starred) { + if (directory.isStarred()) { starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); } else { @@ -1406,9 +1407,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section ratingBarWrapper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - setRating(directory, new OnRatingChange() { + UpdateHelper.setRating(context, directory, new UpdateHelper.OnRatingChange() { @Override - void ratingChange(int rating) { + public void ratingChange(int rating) { ratingBar.setRating(directory.getRating()); } }); 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 8672f534..7baf9009 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -77,6 +77,7 @@ import github.daneren2005.dsub.util.MenuUtil; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.LoadingTask; +import github.daneren2005.dsub.util.UpdateHelper; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.AlbumView; @@ -327,7 +328,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR deleteRecursively(artist); break; case R.id.artist_menu_star: - toggleStarred(artist); + UpdateHelper.toggleStarred(context, artist); break; case R.id.album_menu_play_now: artistOverride = true; @@ -354,7 +355,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR downloadRecursively(entry.getId(), true, true, false, false, true); break; case R.id.album_menu_star: - toggleStarred(entry); + UpdateHelper.toggleStarred(context, entry); break; case R.id.album_menu_delete: deleteRecursively(entry); @@ -387,7 +388,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR addToPlaylist(songs); break; case R.id.song_menu_star: - toggleStarred(entry); + UpdateHelper.toggleStarred(context, entry); break; case R.id.song_menu_play_external: playExternalPlayer(entry); @@ -411,7 +412,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR deleteBookmark(entry, null); break; case R.id.menu_rate: - setRating(entry); + UpdateHelper.setRating(context, entry); break; default: return false; @@ -790,106 +791,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR dialog.show(); } - public void toggleStarred(Entry entry) { - toggleStarred(entry, null); - } - - public void toggleStarred(final Entry entry, final OnStarChange onStarChange) { - final boolean starred = !entry.isStarred(); - entry.setStarred(starred); - if(onStarChange != null) { - onStarChange.starChange(starred); - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - if(entry.isDirectory() && Util.isTagBrowsing(context) && !Util.isOffline(context)) { - if(entry.isAlbum()) { - musicService.setStarred(null, null, Arrays.asList(entry), starred, null, context); - } else { - musicService.setStarred(null, Arrays.asList(entry), null, starred, null, context); - } - } else { - musicService.setStarred(Arrays.asList(entry), null, null, starred, null, context); - } - - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setStarred(starred); - } - }.execute(); - - return null; - } - - @Override - protected void done(Void result) { - // UpdateView - Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getTitle())); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to star", error); - entry.setStarred(!starred); - if(onStarChange != null) { - onStarChange.starChange(!starred); - } - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - public void toggleStarred(final Artist entry) { - final boolean starred = !entry.isStarred(); - entry.setStarred(starred); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - musicService.setStarred(null, Arrays.asList(new Entry(entry)), null, starred, null, context); - } else { - musicService.setStarred(Arrays.asList(new Entry(entry)), null, null, starred, null, context); - } - return null; - } - - @Override - protected void done(Void result) { - // UpdateView - Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getName())); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to star", error); - entry.setStarred(!starred); - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.starring_content_error, entry.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { downloadRecursively(id, "", true, save, append, autoplay, shuffle, background); } @@ -1737,7 +1638,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR MusicService musicService = MusicServiceFactory.getMusicService(context); musicService.deleteBookmark(entry, context, null); - new EntryInstanceUpdater(entry) { + new UpdateHelper.EntryInstanceUpdater(entry) { @Override public void update(Entry found) { found.setBookmark(null); @@ -1773,80 +1674,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR }); } - protected void setRating(Entry entry) { - setRating(entry, null); - } - protected void setRating(final Entry entry, final OnRatingChange onRatingChange) { - View layout = context.getLayoutInflater().inflate(R.layout.rating, null); - final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar); - ratingBar.setRating((float) entry.getRating()); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(context.getResources().getString(R.string.rating_title, entry.getTitle())) - .setView(layout) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - int rating = (int) ratingBar.getRating(); - setRating(entry, rating, onRatingChange); - } - }) - .setNegativeButton(R.string.common_cancel, null); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - - protected void setRating(Entry entry, int rating) { - setRating(entry, rating, null); - } - protected void setRating(final Entry entry, final int rating, final OnRatingChange onRatingChange) { - final int oldRating = entry.getRating(); - entry.setRating(rating); - - if(onRatingChange != null) { - onRatingChange.ratingChange(rating); - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.setRating(entry, rating, context, null); - - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setRating(rating); - } - }.execute(); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(rating > 0 ? R.string.rating_set_rating : R.string.rating_remove_rating, entry.getTitle())); - } - - @Override - protected void error(Throwable error) { - entry.setRating(oldRating); - if(onRatingChange != null) { - onRatingChange.ratingChange(oldRating); - } - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(rating > 0 ? R.string.rating_set_rating_failed : R.string.rating_remove_rating_failed, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - public SectionAdapter getCurrentAdapter() { return null; } public void stopActionMode() { SectionAdapter adapter = getCurrentAdapter(); @@ -1965,47 +1792,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } } - protected abstract class EntryInstanceUpdater { - private Entry entry; - - public EntryInstanceUpdater(Entry entry) { - this.entry = entry; - } - - public abstract void update(Entry found); - - public void execute() { - DownloadService downloadService = getDownloadService(); - if(downloadService != null && !entry.isDirectory()) { - boolean serializeChanges = false; - List downloadFiles = downloadService.getDownloads(); - for(DownloadFile file: downloadFiles) { - Entry check = file.getSong(); - if(entry.getId().equals(check.getId())) { - update(entry); - serializeChanges = true; - } - } - - if(serializeChanges) { - downloadService.serializeQueue(); - } - } - - Entry find = UpdateView.findEntry(entry); - if(find != null) { - update(find); - } - } - } - - public abstract class OnRatingChange { - abstract void ratingChange(int rating); - } - public abstract class OnStarChange { - abstract void starChange(boolean starred); - } - public abstract class RecursiveLoader extends LoadingTask { protected MusicService musicService; protected static final int MAX_SONGS = 500; 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 6dedca29..576791b2 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -48,6 +48,7 @@ import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.MediaRouteManager; import github.daneren2005.dsub.util.ShufflePlayBuffer; import github.daneren2005.dsub.util.SimpleServiceBinder; +import github.daneren2005.dsub.util.UpdateHelper; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.util.compat.RemoteControlClientBase; import github.daneren2005.dsub.util.tags.BastpUtil; @@ -106,6 +107,11 @@ public class DownloadService extends Service { private static final int SHUFFLE_MODE_ALL = 1; private static final int SHUFFLE_MODE_ARTIST = 2; + public static final int METADATA_UPDATED_ALL = 0; + public static final int METADATA_UPDATED_STAR = 1; + public static final int METADATA_UPDATED_RATING = 2; + public static final int METADATA_UPDATED_BOOKMARK = 4; + private RemoteControlClientBase mRemoteControl; private final IBinder binder = new SimpleServiceBinder(this); @@ -2465,6 +2471,55 @@ public class DownloadService extends Service { } } + public void toggleStarred() { + final DownloadFile currentPlaying = this.currentPlaying; + if(currentPlaying == null) { + return; + } + + UpdateHelper.toggleStarred(this, currentPlaying.getSong(), new UpdateHelper.OnStarChange() { + @Override + public void starChange(boolean starred) { + if(currentPlaying == DownloadService.this.currentPlaying) { + onMetadataUpdate(METADATA_UPDATED_STAR); + } + } + }); + } + public void toggleRating(int rating) { + if(currentPlaying == null) { + return; + } + + MusicDirectory.Entry entry = currentPlaying.getSong(); + if(entry.getRating() == rating) { + setRating(0); + } else { + setRating(rating); + } + } + public void setRating(int rating) { + final DownloadFile currentPlaying = this.currentPlaying; + if(currentPlaying == null) { + return; + } + MusicDirectory.Entry entry = currentPlaying.getSong(); + + // Immediately skip to the next song if down thumbed + if(rating == 1) { + next(true); + } + + UpdateHelper.setRating(this, entry, rating, new UpdateHelper.OnRatingChange() { + @Override + public void ratingChange(int rating) { + if(currentPlaying == DownloadService.this.currentPlaying) { + onMetadataUpdate(METADATA_UPDATED_RATING); + } + } + }); + } + public void addOnSongChangedListener(OnSongChangedListener listener) { addOnSongChangedListener(listener, false); } @@ -2504,6 +2559,9 @@ public class DownloadService extends Service { public void run() { if(revision == atRevision) { listener.onSongChanged(currentPlaying, currentPlayingIndex); + + MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; + listener.onMetadataUpdate(entry, METADATA_UPDATED_ALL); } } }); @@ -2560,6 +2618,20 @@ public class DownloadService extends Service { }); } } + private synchronized void onMetadataUpdate() { + onMetadataUpdate(METADATA_UPDATED_ALL); + } + private synchronized void onMetadataUpdate(final int updateType) { + for(final OnSongChangedListener listener: onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + MusicDirectory.Entry entry = currentPlaying != null ? currentPlaying.getSong() : null; + listener.onMetadataUpdate(entry, updateType); + } + }); + } + } private class BufferTask extends SilentBackgroundTask { private final DownloadFile downloadFile; @@ -2672,5 +2744,6 @@ public class DownloadService extends Service { void onSongsChanged(List songs, DownloadFile currentPlaying, int currentPlayingIndex); void onSongProgress(DownloadFile currentPlaying, int millisPlayed, Integer duration, boolean isSeekable); void onStateUpdate(DownloadFile downloadFile, PlayerState playerState); + void onMetadataUpdate(MusicDirectory.Entry entry, int fieldChange); } } diff --git a/app/src/main/java/github/daneren2005/dsub/util/UpdateHelper.java b/app/src/main/java/github/daneren2005/dsub/util/UpdateHelper.java new file mode 100644 index 00000000..c7e0a04b --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/util/UpdateHelper.java @@ -0,0 +1,263 @@ +/* + 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 . + + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.View; +import android.widget.RatingBar; + +import java.util.Arrays; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.Artist; +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import github.daneren2005.dsub.fragments.SubsonicFragment; +import github.daneren2005.dsub.service.DownloadFile; +import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.service.OfflineException; +import github.daneren2005.dsub.service.ServerTooOldException; +import github.daneren2005.dsub.view.UpdateView; + +public final class UpdateHelper { + private static final String TAG = UpdateHelper.class.getSimpleName(); + + public static void toggleStarred(Context context, Entry entry) { + toggleStarred(context, entry, null); + } + + public static void toggleStarred(final Context context, final Entry entry, final OnStarChange onStarChange) { + final boolean starred = !entry.isStarred(); + entry.setStarred(starred); + if(onStarChange != null) { + onStarChange.starChange(starred); + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + if(entry.isDirectory() && Util.isTagBrowsing(context) && !Util.isOffline(context)) { + if(entry.isAlbum()) { + musicService.setStarred(null, null, Arrays.asList(entry), starred, null, context); + } else { + musicService.setStarred(null, Arrays.asList(entry), null, starred, null, context); + } + } else { + musicService.setStarred(Arrays.asList(entry), null, null, starred, null, context); + } + + new EntryInstanceUpdater(entry) { + @Override + public void update(Entry found) { + found.setStarred(starred); + } + }.execute(); + + return null; + } + + @Override + protected void done(Void result) { + // UpdateView + Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getTitle())); + } + + @Override + protected void error(Throwable error) { + Log.w(TAG, "Failed to star", error); + entry.setStarred(!starred); + if(onStarChange != null) { + onStarChange.starChange(!starred); + } + + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error); + } + + Util.toast(context, msg, false); + } + }.execute(); + } + + public static void toggleStarred(final Context context, final Artist entry) { + final boolean starred = !entry.isStarred(); + entry.setStarred(starred); + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { + musicService.setStarred(null, Arrays.asList(new Entry(entry)), null, starred, null, context); + } else { + musicService.setStarred(Arrays.asList(new Entry(entry)), null, null, starred, null, context); + } + return null; + } + + @Override + protected void done(Void result) { + // UpdateView + Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getName())); + } + + @Override + protected void error(Throwable error) { + Log.w(TAG, "Failed to star", error); + entry.setStarred(!starred); + + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.starring_content_error, entry.getName()) + " " + getErrorMessage(error); + } + + Util.toast(context, msg, false); + } + }.execute(); + } + + public static void setRating(Activity context, Entry entry) { + setRating(context, entry, null); + } + public static void setRating(final Activity context, final Entry entry, final OnRatingChange onRatingChange) { + View layout = context.getLayoutInflater().inflate(R.layout.rating, null); + final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar); + ratingBar.setRating((float) entry.getRating()); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(context.getResources().getString(R.string.rating_title, entry.getTitle())) + .setView(layout) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + int rating = (int) ratingBar.getRating(); + setRating(context, entry, rating, onRatingChange); + } + }) + .setNegativeButton(R.string.common_cancel, null); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + public static void setRating(Context context, Entry entry, int rating) { + setRating(context, entry, rating, null); + } + public static void setRating(final Context context, final Entry entry, final int rating, final OnRatingChange onRatingChange) { + final int oldRating = entry.getRating(); + entry.setRating(rating); + + if(onRatingChange != null) { + onRatingChange.ratingChange(rating); + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.setRating(entry, rating, context, null); + + new EntryInstanceUpdater(entry) { + @Override + public void update(Entry found) { + found.setRating(rating); + } + }.execute(); + return null; + } + + @Override + protected void done(Void result) { + Util.toast(context, context.getResources().getString(rating > 0 ? R.string.rating_set_rating : R.string.rating_remove_rating, entry.getTitle())); + } + + @Override + protected void error(Throwable error) { + entry.setRating(oldRating); + if(onRatingChange != null) { + onRatingChange.ratingChange(oldRating); + } + + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(rating > 0 ? R.string.rating_set_rating_failed : R.string.rating_remove_rating_failed, entry.getTitle()) + " " + getErrorMessage(error); + } + + Util.toast(context, msg, false); + } + }.execute(); + } + + public static abstract class EntryInstanceUpdater { + private Entry entry; + + public EntryInstanceUpdater(Entry entry) { + this.entry = entry; + } + + public abstract void update(Entry found); + + public void execute() { + DownloadService downloadService = DownloadService.getInstance(); + if(downloadService != null && !entry.isDirectory()) { + boolean serializeChanges = false; + List downloadFiles = downloadService.getDownloads(); + for(DownloadFile file: downloadFiles) { + Entry check = file.getSong(); + if(entry.getId().equals(check.getId())) { + update(entry); + serializeChanges = true; + } + } + + if(serializeChanges) { + downloadService.serializeQueue(); + } + } + + Entry find = UpdateView.findEntry(entry); + if(find != null) { + update(find); + } + } + } + + public static abstract class OnStarChange { + public abstract void starChange(boolean starred); + } + public static abstract class OnRatingChange { + public abstract void ratingChange(int rating); + } +} 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 8ebbc9de..e2cbb307 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 @@ -31,26 +31,31 @@ import android.media.RemoteControlClient; import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.os.Build; +import android.os.Bundle; import android.support.v7.media.MediaRouter; import android.util.Log; +import github.daneren2005.dsub.R; import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.activity.SubsonicFragmentActivity; import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.UpdateHelper; @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class RemoteControlClientLP extends RemoteControlClientBase { private static final String TAG = RemoteControlClientLP.class.getSimpleName(); + private static final String CUSTOM_ACTION_THUMBS_UP = "github.daneren2005.dsub.THUMBS_UP"; + private static final String CUSTOM_ACTION_THUMBS_DOWN = "github.daneren2005.dsub.THUMBS_DOWN"; + private static final String CUSTOM_ACTION_STAR = "github.daneren2005.dsub.STAR"; protected MediaSession mediaSession; protected DownloadService downloadService; protected ImageLoader imageLoader; - private PlaybackState previousState; - @Override public void register(Context context, ComponentName mediaButtonReceiverComponent) { downloadService = (DownloadService) context; @@ -90,12 +95,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { @Override public void setPlaybackState(int state) { - PlaybackState.Builder builder; - if(previousState == null) { - builder = new PlaybackState.Builder(); - } else { - builder = new PlaybackState.Builder(previousState); - } + PlaybackState.Builder builder = new PlaybackState.Builder(); int newState = PlaybackState.STATE_NONE; switch(state) { @@ -120,9 +120,13 @@ public class RemoteControlClientLP extends RemoteControlClientBase { builder.setState(newState, position, 1.0f); builder.setActions(getPlaybackActions()); + DownloadFile downloadFile = downloadService.getCurrentPlaying(); + if(downloadFile != null) { + addCustomActions(downloadFile.getSong(), builder); + } + PlaybackState playbackState = builder.build(); mediaSession.setPlaybackState(playbackState); - previousState = playbackState; } @Override @@ -188,8 +192,22 @@ public class RemoteControlClientLP extends RemoteControlClientBase { PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_SEEK_TO | PlaybackState.ACTION_SKIP_TO_NEXT | - PlaybackState.ACTION_SKIP_TO_PREVIOUS | - PlaybackState.ACTION_SET_RATING; + PlaybackState.ACTION_SKIP_TO_PREVIOUS; + } + protected void addCustomActions(MusicDirectory.Entry currentSong, PlaybackState.Builder builder) { + PlaybackState.CustomAction thumbsUp = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_THUMBS_UP, + downloadService.getString(R.string.download_thumbs_up), + R.drawable.ic_action_rating_good_selected).build(); + + PlaybackState.CustomAction thumbsDown = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_THUMBS_DOWN, + downloadService.getString(R.string.download_thumbs_down), + R.drawable.ic_action_rating_bad_selected).build(); + + PlaybackState.CustomAction star = new PlaybackState.CustomAction.Builder(CUSTOM_ACTION_STAR, + downloadService.getString(R.string.common_star), + R.drawable.ic_toggle_star).build(); + + builder.addCustomAction(star).addCustomAction(thumbsDown).addCustomAction(thumbsUp); } private class EventCallback extends MediaSession.Callback { @@ -223,19 +241,13 @@ public class RemoteControlClientLP extends RemoteControlClientBase { } @Override - public void onSetRating(Rating rating) { - if(rating.getRatingStyle() != Rating.RATING_THUMB_UP_DOWN) { - return; - } - - if(rating.isRated()) { - if(rating.isThumbUp()) { - - } else { - - } - } else { - + public void onCustomAction(String action, Bundle extras) { + if(CUSTOM_ACTION_THUMBS_UP.equals(action)) { + downloadService.toggleRating(5); + } else if(CUSTOM_ACTION_THUMBS_DOWN.equals(action)) { + downloadService.toggleRating(1); + } else if(CUSTOM_ACTION_STAR.equals(action)) { + downloadService.toggleStarred(); } } } -- cgit v1.2.3