diff options
15 files changed, 170 insertions, 5 deletions
diff --git a/subsonic-android/res/layout-land/download.xml b/subsonic-android/res/layout-land/download.xml index 01a9b68d..b0303e52 100644 --- a/subsonic-android/res/layout-land/download.xml +++ b/subsonic-android/res/layout-land/download.xml @@ -14,15 +14,15 @@ android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
- android:background="@color/mediaControlBackground"
- >
+ android:background="@color/mediaControlBackground">
<LinearLayout
+ android:id="@+id/download_play_controls_layout"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true">
+ android:layout_centerHorizontal="true">
<ImageButton
android:id="@+id/download_previous"
@@ -87,7 +87,6 @@ android:id="@+id/download_song_title"
android:layout_width="150dip"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
android:layout_above="@+id/download_status"
android:layout_centerHorizontal="true"
android:layout_marginLeft="12dip"
@@ -99,6 +98,7 @@ android:textColor="@color/mediaControlForeground"/>
<LinearLayout
+ android:id="@+id/download_other_controls_layout"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -111,6 +111,7 @@ android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_below="@+id/download_play_controls_layout"
android:padding="9dip"/>
<ImageButton
android:id="@+id/download_repeat"
@@ -120,6 +121,13 @@ android:layout_height="wrap_content"
android:padding="9dip"/>
<ImageButton
+ android:id="@+id/download_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@null"
+ android:src="@android:drawable/star_big_off"/>
+ <ImageButton
android:id="@+id/download_toggle_list"
android:src="@drawable/media_toggle_list"
android:background="@android:color/transparent"
diff --git a/subsonic-android/res/layout-port/download.xml b/subsonic-android/res/layout-port/download.xml index e2a198a2..e6a2358a 100644 --- a/subsonic-android/res/layout-port/download.xml +++ b/subsonic-android/res/layout-port/download.xml @@ -72,6 +72,15 @@ android:paddingTop="12dip"
android:paddingRight="12dip"
android:paddingBottom="12dip"/>
+
+ <ImageButton
+ android:id="@+id/download_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/download_repeat"
+ android:layout_below="@+id/download_jukebox"
+ android:background="@null"
+ android:src="@android:drawable/star_big_off"/>
<ImageView
android:id="@+id/download_album_art_image"
diff --git a/subsonic-android/res/layout/album_list_item.xml b/subsonic-android/res/layout/album_list_item.xml index 15d999c3..aa2ac803 100644 --- a/subsonic-android/res/layout/album_list_item.xml +++ b/subsonic-android/res/layout/album_list_item.xml @@ -36,6 +36,15 @@ android:singleLine="true"/>
</LinearLayout>
+
+ <ImageButton
+ android:id="@+id/album_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|center_vertical"
+ android:background="@null"
+ android:focusable="false"
+ android:src="@android:drawable/star_big_off" />
<ImageView
android:src="@drawable/list_item_artist"
diff --git a/subsonic-android/res/layout/song_list_item.xml b/subsonic-android/res/layout/song_list_item.xml index 2163ef72..87f56a22 100644 --- a/subsonic-android/res/layout/song_list_item.xml +++ b/subsonic-android/res/layout/song_list_item.xml @@ -73,4 +73,14 @@ </LinearLayout>
</LinearLayout>
+
+ <ImageButton
+ android:id="@+id/song_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|center_vertical"
+ android:background="@null"
+ android:focusable="false"
+ android:src="@android:drawable/btn_star_big_off" />
+
</LinearLayout>
diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml index 7f9f6728..eef510e4 100644 --- a/subsonic-android/res/values/strings.xml +++ b/subsonic-android/res/values/strings.xml @@ -110,6 +110,8 @@ <string name="download.jukebox_server_too_old">Remote control is not supported. Please upgrade your Subsonic server.</string>
<string name="download.jukebox_offline">Remote control is not available in offline mode.</string>
<string name="download.jukebox_not_authorized">Remote control is not allowed. Please enable jukebox mode in <b>Users > Settings</b> on your Subsonic server.</string>
+
+ <string name="starring_content_error">Failed to update \"%s\", please try later.</string>
<string name="song_details.all">%1$s %2$s</string>
<string name="song_details.kbps">%d kbps</string>
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java index a657b7eb..04d710d5 100644 --- a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java +++ b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java @@ -45,6 +45,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.AnimationUtils; @@ -106,6 +107,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi private Button visualizerButton; private Button jukeboxButton; private View toggleListButton; + private ImageButton starButton; private ScheduledExecutorService executorService; private DownloadFile currentPlaying; private long currentRevision; @@ -154,6 +156,19 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi LinearLayout visualizerViewLayout = (LinearLayout) findViewById(R.id.download_visualizer_view_layout); toggleListButton = findViewById(R.id.download_toggle_list); + + starButton = (ImageButton) findViewById(R.id.download_star); + starButton.setVisibility(Util.isOffline(this) ? View.GONE : View.VISIBLE); + starButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + DownloadFile currentDownload = getDownloadService().getCurrentPlaying(); + if (currentDownload != null) { + MusicDirectory.Entry currentSong = currentDownload.getSong(); + toggleStarredInBackground(currentSong, starButton); + } + } + }); View.OnTouchListener touchListener = new View.OnTouchListener() { @Override @@ -711,11 +726,13 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi albumTextView.setText(song.getAlbum()); artistTextView.setText(song.getArtist()); getImageLoader().loadImage(albumArtImageView, song, true, true); + starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); } else { songTitleTextView.setText(null); albumTextView.setText(null); artistTextView.setText(null); getImageLoader().loadImage(albumArtImageView, null, true, false); + starButton.setImageResource(android.R.drawable.btn_star_big_off); } } diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java index 6afe842b..e3548302 100644 --- a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java +++ b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java @@ -39,6 +39,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; +import android.widget.ImageButton; import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; @@ -46,9 +47,12 @@ import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.DownloadServiceImpl; 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.util.Constants; import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.util.ModalBackgroundTask; +import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; /** @@ -227,6 +231,44 @@ public class SubsonicTabActivity extends Activity { private void updateButtonVisibility() { int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE; } + + public void toggleStarredInBackground(final MusicDirectory.Entry entry, final ImageButton button) { + + final boolean starred = !entry.isStarred(); + + button.setImageResource(starred ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + entry.setStarred(starred); + + // Util.toast(SubsonicTabActivity.this, getResources().getString(R.string.starring_content, entry.getTitle())); + new SilentBackgroundTask<Void>(this) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this); + musicService.setStarred(entry.getId(), starred, SubsonicTabActivity.this, null); + return null; + } + + @Override + protected void done(Void result) { + // Util.toast(SubsonicTabActivity.this, getResources().getString(R.string.starring_content_done, entry.getTitle())); + } + + @Override + protected void error(Throwable error) { + button.setImageResource(!starred ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + entry.setStarred(!starred); + + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error); + } + + Util.toast(SubsonicTabActivity.this, msg, false); + } + }.execute(); + } public void setProgressVisible(boolean visible) { View view = findViewById(R.id.tab_progress); diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java b/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java index 420ce813..da0d8cbc 100644 --- a/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java +++ b/subsonic-android/src/github/daneren2005/dsub/domain/MusicDirectory.java @@ -80,6 +80,7 @@ public class MusicDirectory { private Integer bitRate; private String path; private boolean video; + private boolean starred; public String getId() { return id; @@ -232,6 +233,14 @@ public class MusicDirectory { public void setVideo(boolean video) { this.video = video; } + + public boolean isStarred() { + return starred; + } + + public void setStarred(boolean starred) { + this.starred = starred; + } @Override public boolean equals(Object o) { diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java index 094c959f..dbd421f2 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -222,6 +222,11 @@ public class CachedMusicService implements MusicService { public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { return musicService.setJukeboxGain(gain, context, progressListener); } + + @Override + public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { + musicService.setStarred(id, starred, context, progressListener); + } private void checkSettingsChanged(Context context) { String newUrl = Util.getRestUrl(context, null); diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java index e8fca8f0..a5045b18 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java @@ -88,4 +88,6 @@ public interface MusicService { JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception; JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception; + + void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception; }
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java index 9c49d550..29992029 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -308,6 +308,11 @@ public class OfflineMusicService extends RESTMusicService { public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } + + @Override + public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Starring not available in offline mode"); + } @Override public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception { diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java index 748eacee..c24b2c06 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -602,6 +602,17 @@ public class RESTMusicService implements MusicService { Util.close(reader); } } + + @Override + public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception { + checkServerVersion(context, "1.8", "Starring is not supported."); + Reader reader = getReader(context, progressListener, starred ? "star" : "unstar", null, "id", id); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception { return getReader(context, progressListener, method, requestParams, Collections.<String>emptyList(), Collections.emptyList()); diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java index 3a1826e5..d724f63c 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java @@ -38,6 +38,7 @@ public class MusicDirectoryEntryParser extends AbstractParser { entry.setDirectory(getBoolean("isDir")); entry.setCoverArt(get("coverArt")); entry.setArtist(get("artist")); + entry.setStarred(get("starred") != null); if (!entry.isDirectory()) { entry.setAlbum(get("album")); diff --git a/subsonic-android/src/github/daneren2005/dsub/util/AlbumView.java b/subsonic-android/src/github/daneren2005/dsub/util/AlbumView.java index 98bd500f..8c799aad 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/AlbumView.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/AlbumView.java @@ -21,9 +21,11 @@ package github.daneren2005.dsub.util; import android.content.Context; import android.view.LayoutInflater; import android.view.View; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.activity.SubsonicTabActivity; import github.daneren2005.dsub.domain.MusicDirectory; /** @@ -32,10 +34,13 @@ import github.daneren2005.dsub.domain.MusicDirectory; * @author Sindre Mehus */ public class AlbumView extends LinearLayout { + + private MusicDirectory.Entry album; private TextView titleView; private TextView artistView; private View coverArtView; + private ImageButton starButton; public AlbumView(Context context) { super(context); @@ -44,12 +49,26 @@ public class AlbumView extends LinearLayout { titleView = (TextView) findViewById(R.id.album_title); artistView = (TextView) findViewById(R.id.album_artist); coverArtView = findViewById(R.id.album_coverart); + starButton = (ImageButton) findViewById(R.id.album_star); + starButton.setVisibility(Util.isOffline(getContext()) ? View.GONE : View.VISIBLE); + starButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SubsonicTabActivity activity = (SubsonicTabActivity) getContext(); + activity.toggleStarredInBackground(album, starButton); + } + }); } public void setAlbum(MusicDirectory.Entry album, ImageLoader imageLoader) { + this.album = album; + titleView.setText(album.getTitle()); artistView.setText(album.getArtist()); artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE); imageLoader.loadImage(coverArtView, album, false, true); + + starButton.setImageResource(album.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + starButton.setFocusable(false); } } diff --git a/subsonic-android/src/github/daneren2005/dsub/util/SongView.java b/subsonic-android/src/github/daneren2005/dsub/util/SongView.java index 61846c27..1bc2b9c0 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/SongView.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/SongView.java @@ -25,9 +25,11 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.Checkable; import android.widget.CheckedTextView; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.activity.SubsonicTabActivity; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.DownloadServiceImpl; @@ -46,13 +48,15 @@ public class SongView extends LinearLayout implements Checkable { private static final String TAG = SongView.class.getSimpleName(); private static final WeakHashMap<SongView, ?> INSTANCES = new WeakHashMap<SongView, Object>(); private static Handler handler; + + private MusicDirectory.Entry song; private CheckedTextView checkedTextView; private TextView titleTextView; private TextView artistTextView; private TextView durationTextView; private TextView statusTextView; - private MusicDirectory.Entry song; + private ImageButton starButton; public SongView(Context context) { super(context); @@ -63,6 +67,15 @@ public class SongView extends LinearLayout implements Checkable { artistTextView = (TextView) findViewById(R.id.song_artist); durationTextView = (TextView) findViewById(R.id.song_duration); statusTextView = (TextView) findViewById(R.id.song_status); + starButton = (ImageButton) findViewById(R.id.song_star); + starButton.setVisibility(Util.isOffline(getContext()) ? View.GONE : View.VISIBLE); + starButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SubsonicTabActivity activity = (SubsonicTabActivity) getContext(); + activity.toggleStarredInBackground(song, starButton); + } + }); INSTANCES.put(this, null); int instanceCount = INSTANCES.size(); @@ -96,6 +109,9 @@ public class SongView extends LinearLayout implements Checkable { artistTextView.setText(artist); durationTextView.setText(Util.formatDuration(song.getDuration())); checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); + + starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + starButton.setFocusable(false); update(); } |