aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android/src/github/daneren2005
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2013-05-16 20:09:41 -0700
committerScott Jackson <daneren2005@gmail.com>2013-05-16 20:09:41 -0700
commit7182604e3f3cd9770264e9947696506c766434ee (patch)
treead26e217d8e3b258f5770d40278787f975a97ae7 /subsonic-android/src/github/daneren2005
parent4614bb2d9151fef00d43ce9661dd4d48c4973f7c (diff)
parent876a297aeb31445957001f6e4d4fc159d8dccc4e (diff)
downloaddsub-7182604e3f3cd9770264e9947696506c766434ee.tar.gz
dsub-7182604e3f3cd9770264e9947696506c766434ee.tar.bz2
dsub-7182604e3f3cd9770264e9947696506c766434ee.zip
Merge branch 'Fragments' of https://github.com/daneren2005/Subsonic
Diffstat (limited to 'subsonic-android/src/github/daneren2005')
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java1229
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/LyricsActivity.java72
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java536
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java421
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SelectAlbumActivity.java798
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SelectArtistActivity.java264
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SelectPlaylistActivity.java301
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java616
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java630
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java1135
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java81
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java314
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java336
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java204
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java696
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java291
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java747
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java14
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java5
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/Constants.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java1
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java (renamed from subsonic-android/src/github/daneren2005/dsub/util/TabActivityBackgroundTask.java)134
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/Util.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java76
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java539
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java40
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java28
31 files changed, 5535 insertions, 4011 deletions
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
index 3de6178f..3448867a 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
@@ -18,1180 +18,153 @@
*/
package github.daneren2005.dsub.activity;
+import github.daneren2005.dsub.R;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import github.daneren2005.dsub.fragments.DownloadFragment;
+import android.app.Dialog;
+import android.view.LayoutInflater;
+import android.widget.EditText;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
import android.app.AlertDialog;
-import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Color;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Parcelable;
import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Display;
-import android.view.GestureDetector;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.LayoutInflater;
-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;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.ViewFlipper;
-import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.MenuInflater;
-import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.PlayerState;
-import github.daneren2005.dsub.domain.RepeatMode;
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.util.Constants;
-import github.daneren2005.dsub.util.HorizontalSlider;
import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.view.SongView;
import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.VisualizerView;
-
-import static github.daneren2005.dsub.domain.PlayerState.*;
-import github.daneren2005.dsub.util.*;
-import github.daneren2005.dsub.view.AutoRepeatButton;
-import java.util.ArrayList;
-import java.util.concurrent.ScheduledFuture;
-import com.mobeta.android.dslv.*;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
+import java.util.LinkedList;
+import java.util.List;
-public class DownloadActivity extends SubsonicTabActivity implements OnGestureListener {
+public class DownloadActivity extends SubsonicActivity {
private static final String TAG = DownloadActivity.class.getSimpleName();
+ private EditText playlistNameView;
- private static final int DIALOG_SAVE_PLAYLIST = 100;
- private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10;
- private static final int COLOR_BUTTON_ENABLED = Color.rgb(51, 181, 229);
- private static final int COLOR_BUTTON_DISABLED = Color.rgb(206, 213, 211);
- private static final int INCREMENT_TIME = 5000;
-
- private ViewFlipper playlistFlipper;
- private TextView emptyTextView;
- private TextView songTitleTextView;
- private ImageView albumArtImageView;
- private DragSortListView playlistView;
- private TextView positionTextView;
- private TextView durationTextView;
- private TextView statusTextView;
- private HorizontalSlider progressBar;
- private AutoRepeatButton previousButton;
- private AutoRepeatButton nextButton;
- private View pauseButton;
- private View stopButton;
- private View startButton;
- private ImageButton repeatButton;
- private Button equalizerButton;
- private Button visualizerButton;
- private Button jukeboxButton;
- private View toggleListButton;
- private ImageButton starButton;
- private ScheduledExecutorService executorService;
- private DownloadFile currentPlaying;
- private long currentRevision;
- private EditText playlistNameView;
- private GestureDetector gestureScanner;
- private int swipeDistance;
- private int swipeVelocity;
- private VisualizerView visualizerView;
- private boolean nowPlaying = true;
- private ScheduledFuture<?> hideControlsFuture;
- private SongListAdapter songListAdapter;
- private SilentBackgroundTask<Void> onProgressChangedTask;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTitle(nowPlaying ? "Now Playing" : "Downloading");
- setContentView(R.layout.download);
-
- WindowManager w = getWindowManager();
- Display d = w.getDefaultDisplay();
- swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
- swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
- gestureScanner = new GestureDetector(this);
-
- playlistFlipper = (ViewFlipper) findViewById(R.id.download_playlist_flipper);
- emptyTextView = (TextView) findViewById(R.id.download_empty);
- songTitleTextView = (TextView) findViewById(R.id.download_song_title);
- albumArtImageView = (ImageView) findViewById(R.id.download_album_art_image);
- positionTextView = (TextView) findViewById(R.id.download_position);
- durationTextView = (TextView) findViewById(R.id.download_duration);
- statusTextView = (TextView) findViewById(R.id.download_status);
- progressBar = (HorizontalSlider) findViewById(R.id.download_progress_bar);
- playlistView = (DragSortListView) findViewById(R.id.download_list);
- previousButton = (AutoRepeatButton)findViewById(R.id.download_previous);
- nextButton = (AutoRepeatButton)findViewById(R.id.download_next);
- pauseButton = findViewById(R.id.download_pause);
- stopButton = findViewById(R.id.download_stop);
- startButton = findViewById(R.id.download_start);
- repeatButton = (ImageButton) findViewById(R.id.download_repeat);
- equalizerButton = (Button) findViewById(R.id.download_equalizer);
- visualizerButton = (Button) findViewById(R.id.download_visualizer);
- jukeboxButton = (Button) findViewById(R.id.download_jukebox);
- 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();
- toggleStarred(currentSong);
- starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
- }
- }
- });
-
- View.OnTouchListener touchListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent me) {
- return gestureScanner.onTouchEvent(me);
- }
- };
- pauseButton.setOnTouchListener(touchListener);
- stopButton.setOnTouchListener(touchListener);
- startButton.setOnTouchListener(touchListener);
- equalizerButton.setOnTouchListener(touchListener);
- visualizerButton.setOnTouchListener(touchListener);
- jukeboxButton.setOnTouchListener(touchListener);
- emptyTextView.setOnTouchListener(touchListener);
- albumArtImageView.setOnTouchListener(touchListener);
-
- previousButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().previous();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- setControlsVisible(true);
- }
- });
- previousButton.setOnRepeatListener(new Runnable() {
- public void run() {
- changeProgress(-INCREMENT_TIME);
- }
- });
-
- nextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Boolean>(DownloadActivity.this) {
- @Override
- protected Boolean doInBackground() throws Throwable {
- if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
- getDownloadService().next();
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- protected void done(Boolean result) {
- if(result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }
- }.execute();
- setControlsVisible(true);
- }
- });
- nextButton.setOnRepeatListener(new Runnable() {
- public void run() {
- changeProgress(INCREMENT_TIME);
- }
- });
-
- pauseButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().pause();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- stopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().reset();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- startButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- start();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- });
-
- repeatButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- RepeatMode repeatMode = getDownloadService().getRepeatMode().next();
- getDownloadService().setRepeatMode(repeatMode);
- onDownloadListChanged();
- switch (repeatMode) {
- case OFF:
- Util.toast(DownloadActivity.this, R.string.download_repeat_off);
- break;
- case ALL:
- Util.toast(DownloadActivity.this, R.string.download_repeat_all);
- break;
- case SINGLE:
- Util.toast(DownloadActivity.this, R.string.download_repeat_single);
- break;
- default:
- break;
- }
- setControlsVisible(true);
- }
- });
-
- equalizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- DownloadService downloadService = getDownloadService();
- if(downloadService != null && downloadService.getEqualizerController() != null
- && downloadService.getEqualizerController().getEqualizer() != null) {
- startActivity(new Intent(DownloadActivity.this, EqualizerActivity.class));
- setControlsVisible(true);
- } else {
- Util.toast(DownloadActivity.this, "Failed to start equalizer. Try restarting.");
- }
- }
- });
-
- visualizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean active = !visualizerView.isActive();
- visualizerView.setActive(active);
- boolean isActive = visualizerView.isActive();
- getDownloadService().setShowVisualization(isActive);
- updateButtons();
- if(active == isActive) {
- Util.toast(DownloadActivity.this, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
- } else {
- Util.toast(DownloadActivity.this, "Failed to start visualizer. Try restarting.");
- }
- setControlsVisible(true);
- }
- });
-
- jukeboxButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean jukeboxEnabled = !getDownloadService().isJukeboxEnabled();
- getDownloadService().setJukeboxEnabled(jukeboxEnabled);
- updateButtons();
- Util.toast(DownloadActivity.this, jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
- setControlsVisible(true);
- }
- });
-
- toggleListButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- toggleFullscreenAlbumArt();
- setControlsVisible(true);
- }
- });
-
- progressBar.setOnSliderChangeListener(new HorizontalSlider.OnSliderChangeListener() {
- @Override
- public void onSliderChanged(View view, final int position, boolean inProgress) {
- Util.toast(DownloadActivity.this, Util.formatDuration(position / 1000), true);
- if (!inProgress) {
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().seekTo(position);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onProgressChanged();
- }
- }.execute();
- }
- setControlsVisible(true);
- }
- });
- playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
- if(nowPlaying) {
- warnIfNetworkOrStorageUnavailable();
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().play(position);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onCurrentChanged();
- onProgressChanged();
- }
- }.execute();
- }
- }
- });
- playlistView.setDropListener(new DragSortListView.DropListener() {
- @Override
- public void drop(int from, int to) {
- getDownloadService().swap(nowPlaying, from, to);
- onDownloadListChanged();
- }
- });
- playlistView.setRemoveListener(new DragSortListView.RemoveListener() {
- @Override
- public void remove(int which) {
- getDownloadService().remove(which);
- onDownloadListChanged();
- }
- });
-
- registerForContextMenu(playlistView);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService != null && getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) {
- getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE);
- warnIfNetworkOrStorageUnavailable();
- downloadService.setShufflePlayEnabled(true);
- }
-
- boolean visualizerAvailable = downloadService != null && downloadService.getVisualizerAvailable();
- boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable();
-
- if (!equalizerAvailable) {
- equalizerButton.setVisibility(View.GONE);
- }
- if (!visualizerAvailable) {
- visualizerButton.setVisibility(View.GONE);
- } else {
- visualizerView = new VisualizerView(this);
- visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
- }
-
- // TODO: Extract to utility method and cache.
- Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Storopia.ttf");
- equalizerButton.setTypeface(typeface);
- visualizerButton.setTypeface(typeface);
- jukeboxButton.setTypeface(typeface);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- update();
- }
- });
- }
- };
-
- executorService = Executors.newSingleThreadScheduledExecutor();
- executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
-
- setControlsVisible(true);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService == null || downloadService.getCurrentPlaying() == null) {
- playlistFlipper.setDisplayedChild(1);
- }
-
- onDownloadListChanged();
- onCurrentChanged();
- onProgressChanged();
- scrollToCurrent();
- if (downloadService != null && downloadService.getKeepScreenOn()) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- if (visualizerView != null && downloadService != null && downloadService.getShowVisualization()) {
- visualizerView.setActive(true);
- }
-
- updateButtons();
- }
-
- private void scheduleHideControls() {
- if (hideControlsFuture != null) {
- hideControlsFuture.cancel(false);
- }
-
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- setControlsVisible(false);
- }
- });
- }
- };
- hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS);
- }
-
- private void setControlsVisible(boolean visible) {
- try {
- long duration = 1700L;
- FadeOutAnimation.createAndStart(findViewById(R.id.download_overlay_buttons), !visible, duration);
-
- if (visible) {
- scheduleHideControls();
- }
- } catch(Exception e) {
-
+ /**
+ * Called when the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.download_activity);
+
+ if (findViewById(R.id.download_container) != null && savedInstanceState == null) {
+ currentFragment = new DownloadFragment();
+ currentFragment.setPrimaryFragment(true);
+ getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit();
}
- }
- private void updateButtons() {
- SharedPreferences prefs = Util.getPreferences(DownloadActivity.this);
- boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
- if(equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
- getDownloadService().getEqualizerController().isEnabled()) {
- equalizerButton.setTextColor(COLOR_BUTTON_ENABLED);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(item.getItemId() == android.R.id.home) {
+ Intent i = new Intent();
+ i.setClass(this, MainActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(i);
+ return true;
} else {
- equalizerButton.setTextColor(COLOR_BUTTON_DISABLED);
+ return super.onOptionsItemSelected(item);
}
-
- if (visualizerView != null) {
- visualizerButton.setTextColor(visualizerView.isActive() ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
-
- boolean jukeboxEnabled = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
- jukeboxButton.setTextColor(jukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
-
- // Scroll to current playing/downloading.
- private void scrollToCurrent() {
- if (getDownloadService() == null || songListAdapter == null) {
- return;
- }
-
- for (int i = 0; i < songListAdapter.getCount(); i++) {
- if (currentPlaying == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- DownloadFile currentDownloading = getDownloadService().getCurrentDownloading();
- for (int i = 0; i < songListAdapter.getCount(); i++) {
- if (currentDownloading == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- executorService.shutdown();
- if (visualizerView != null && visualizerView.isActive()) {
- visualizerView.setActive(false);
- }
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- if (id == DIALOG_SAVE_PLAYLIST) {
- AlertDialog.Builder builder;
-
- LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
- final View layout = inflater.inflate(R.layout.save_playlist, (ViewGroup) findViewById(R.id.save_playlist_root));
- playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name);
-
- builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.download_playlist_title);
- builder.setMessage(R.string.download_playlist_name);
- builder.setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- savePlaylistInBackground(String.valueOf(playlistNameView.getText()));
- }
- });
- builder.setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- builder.setView(layout);
- builder.setCancelable(true);
-
- return builder.create();
- } else {
- return super.onCreateDialog(id);
- }
- }
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog) {
- if (id == DIALOG_SAVE_PLAYLIST) {
- String playlistName = (getDownloadService() != null) ? getDownloadService().getSuggestedPlaylistName() : null;
- if (playlistName != null) {
- playlistNameView.setText(playlistName);
- } else {
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
- playlistNameView.setText(dateFormat.format(new Date()));
- }
- }
- }
+ }
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getSupportMenuInflater();
- if(Util.isOffline(this)) {
- inflater.inflate(R.menu.nowplaying_offline, menu);
+ public boolean onTouchEvent(MotionEvent me) {
+ if(currentFragment != null) {
+ return ((DownloadFragment)currentFragment).getGestureDetector().onTouchEvent(me);
} else {
- if(nowPlaying)
- inflater.inflate(R.menu.nowplaying, menu);
- else
- inflater.inflate(R.menu.nowplaying_downloading, menu);
-
- if(getDownloadService() != null && getDownloadService().getSleepTimer()) {
- menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer);
- }
- }
- if(getDownloadService() != null && getDownloadService().getKeepScreenOn()) {
- menu.findItem(R.id.menu_screen_on_off).setTitle(R.string.download_menu_screen_off);
+ return false;
}
- return true;
}
- @Override
- public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- if (view == playlistView) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
-
- android.view.MenuInflater inflater = getMenuInflater();
- if(Util.isOffline(this)) {
- inflater.inflate(R.menu.nowplaying_context_offline, menu);
- } else {
- inflater.inflate(R.menu.nowplaying_context, menu);
- menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star);
- }
-
- if (downloadFile.getSong().getParent() == null) {
- menu.findItem(R.id.menu_show_album).setVisible(false);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(android.view.MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
- return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- return menuItemSelected(menuItem.getItemId(), null) || super.onOptionsItemSelected(menuItem);
- }
-
- private boolean menuItemSelected(int menuItemId, final DownloadFile song) {
- switch (menuItemId) {
- case R.id.menu_show_album:
- Intent intent = new Intent(this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getSong().getParent());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getSong().getAlbum());
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_lyrics:
- intent = new Intent(this, LyricsActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_remove:
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().remove(song);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onDownloadListChanged();
- }
- }.execute();
- return true;
- case R.id.menu_delete:
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(1);
- songs.add(song.getSong());
- getDownloadService().delete(songs);
- return true;
- case R.id.menu_remove_all:
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().setShufflePlayEnabled(false);
- if(nowPlaying) {
- getDownloadService().clear();
- }
- else {
- getDownloadService().clearBackground();
- }
- return null;
- }
-
- @Override
- protected void done(Void result) {
- onDownloadListChanged();
- }
- }.execute();
- return true;
- case R.id.menu_screen_on_off:
- if (getDownloadService().getKeepScreenOn()) {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(false);
- } else {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(true);
- }
- invalidateOptionsMenu();
- return true;
- case R.id.menu_shuffle:
- new SilentBackgroundTask<Void>(DownloadActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().shuffle();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(DownloadActivity.this, R.string.download_menu_shuffle_notification);
- }
- }.execute();
- return true;
- case R.id.menu_save_playlist:
- showDialog(DIALOG_SAVE_PLAYLIST);
- return true;
- case R.id.menu_star:
- toggleStarred(song.getSong());
- return true;
- case R.id.menu_toggle_now_playing:
- toggleNowPlaying();
- invalidateOptionsMenu();
- return true;
- case R.id.menu_toggle_timer:
- if(getDownloadService().getSleepTimer()) {
- getDownloadService().stopSleepTimer();
- invalidateOptionsMenu();
- } else {
- startTimer();
+ @Override
+ public Dialog onCreateDialog(int id) {
+ if (id == DownloadFragment.DIALOG_SAVE_PLAYLIST) {
+ AlertDialog.Builder builder;
+
+ LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+ final View layout = inflater.inflate(R.layout.save_playlist, null);
+ playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name);
+
+ builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.download_playlist_title);
+ builder.setMessage(R.string.download_playlist_name);
+ builder.setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ savePlaylistInBackground(String.valueOf(playlistNameView.getText()));
}
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_add_playlist:
- songs = new ArrayList<MusicDirectory.Entry>(1);
- songs.add(song.getSong());
- addToPlaylist(songs);
- return true;
- case R.id.menu_info:
- displaySongInfo(song.getSong());
- return true;
- default:
- return false;
- }
- }
-
- private void update() {
- if (getDownloadService() == null) {
- return;
- }
-
- if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) {
- onDownloadListChanged();
- }
-
- if (currentPlaying != getDownloadService().getCurrentPlaying()) {
- onCurrentChanged();
- }
-
- onProgressChanged();
- }
-
- private void savePlaylistInBackground(final String playlistName) {
- Util.toast(DownloadActivity.this, getResources().getString(R.string.download_playlist_saving, playlistName));
- getDownloadService().setSuggestedPlaylistName(playlistName);
- new SilentBackgroundTask<Void>(this) {
- @Override
- protected Void doInBackground() throws Throwable {
- List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
- for (DownloadFile downloadFile : getDownloadService().getSongs()) {
- entries.add(downloadFile.getSong());
- }
- MusicService musicService = MusicServiceFactory.getMusicService(DownloadActivity.this);
- musicService.createPlaylist(null, playlistName, entries, DownloadActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(DownloadActivity.this, R.string.download_playlist_done);
- }
-
- @Override
- protected void error(Throwable error) {
- String msg = getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
- Util.toast(DownloadActivity.this, msg);
- }
- }.execute();
- }
-
- protected void startTimer() {
- View dialogView = getLayoutInflater().inflate(R.layout.start_timer, null);
- final EditText lengthBox = (EditText)dialogView.findViewById(R.id.timer_length);
-
- final SharedPreferences prefs = Util.getPreferences(DownloadActivity.this);
- lengthBox.setText(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, ""));
-
- AlertDialog.Builder builder = new AlertDialog.Builder(DownloadActivity.this);
- builder.setTitle(R.string.menu_set_timer)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ });
+ builder.setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
- String length = lengthBox.getText().toString();
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, length);
- editor.commit();
-
- getDownloadService().setSleepTimerDuration(Integer.parseInt(length));
- getDownloadService().startSleepTimer();
- invalidateOptionsMenu();
+ dialog.cancel();
}
- })
- .setNegativeButton(R.string.common_cancel, null);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- private void toggleFullscreenAlbumArt() {
- scrollToCurrent();
- if (playlistFlipper.getDisplayedChild() == 1) {
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_out));
- playlistFlipper.setDisplayedChild(0);
- } else {
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out));
- playlistFlipper.setDisplayedChild(1);
- }
- }
+ });
+ builder.setView(layout);
+ builder.setCancelable(true);
- private void start() {
- DownloadService service = getDownloadService();
- PlayerState state = service.getPlayerState();
- if (state == PAUSED || state == COMPLETED || state == STOPPED) {
- service.start();
- } else if (state == STOPPED || state == IDLE) {
- warnIfNetworkOrStorageUnavailable();
- int current = service.getCurrentPlayingIndex();
- // TODO: Use play() method.
- if (current == -1) {
- service.play(0);
- } else {
- service.play(current);
- }
- }
- }
- private void onDownloadListChanged() {
- onDownloadListChanged(false);
- }
- private void onDownloadListChanged(boolean refresh) {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return;
- }
-
- List<DownloadFile> list;
- if(nowPlaying) {
- list = downloadService.getSongs();
- }
- else {
- list = downloadService.getBackgroundDownloads();
- }
-
- if(downloadService.isShufflePlayEnabled()) {
- emptyTextView.setText(R.string.download_shuffle_loading);
- }
- else {
- emptyTextView.setText(R.string.download_empty);
- }
-
- if(songListAdapter == null || refresh) {
- playlistView.setAdapter(songListAdapter = new SongListAdapter(list));
+ return builder.create();
} else {
- songListAdapter.notifyDataSetChanged();
+ return super.onCreateDialog(id);
}
- emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
- currentRevision = downloadService.getDownloadListUpdateRevision();
-
- switch (downloadService.getRepeatMode()) {
- case OFF:
- if("light".equals(theme) | "light_fullscreen".equals(theme)) {
- repeatButton.setImageResource(R.drawable.media_repeat_off_light);
- } else {
- repeatButton.setImageResource(R.drawable.media_repeat_off);
- }
- break;
- case ALL:
- repeatButton.setImageResource(R.drawable.media_repeat_all);
- break;
- case SINGLE:
- repeatButton.setImageResource(R.drawable.media_repeat_single);
- break;
- default:
- break;
- }
- }
-
- private void onCurrentChanged() {
- if (getDownloadService() == null) {
- return;
- }
-
- currentPlaying = getDownloadService().getCurrentPlaying();
- if (currentPlaying != null) {
- MusicDirectory.Entry song = currentPlaying.getSong();
- songTitleTextView.setText(song.getTitle());
- 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);
- getImageLoader().loadImage(albumArtImageView, null, true, false);
- starButton.setImageResource(android.R.drawable.btn_star_big_off);
- }
- }
-
- private void onProgressChanged() {
- // Make sure to only be trying to run one of these at a time
- if (getDownloadService() == null || onProgressChangedTask != null) {
- return;
- }
-
- onProgressChangedTask = new SilentBackgroundTask<Void>(this) {
- DownloadService downloadService;
- boolean isJukeboxEnabled;
- int millisPlayed;
- Integer duration;
- PlayerState playerState;
-
- @Override
- protected Void doInBackground() throws Throwable {
- downloadService = getDownloadService();
- isJukeboxEnabled = downloadService.isJukeboxEnabled();
- millisPlayed = Math.max(0, downloadService.getPlayerPosition());
- duration = downloadService.getPlayerDuration();
- playerState = getDownloadService().getPlayerState();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- if (currentPlaying != null) {
- int millisTotal = duration == null ? 0 : duration;
-
- positionTextView.setText(Util.formatDuration(millisPlayed / 1000));
- durationTextView.setText(Util.formatDuration(millisTotal / 1000));
- progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug.
- progressBar.setProgress(millisPlayed);
- progressBar.setSlidingEnabled(currentPlaying.isWorkDone() || isJukeboxEnabled);
- } else {
- positionTextView.setText("0:00");
- durationTextView.setText("-:--");
- progressBar.setProgress(0);
- progressBar.setSlidingEnabled(false);
- }
-
- switch (playerState) {
- case DOWNLOADING:
- long bytes = currentPlaying.getPartialFile().length();
- statusTextView.setText(getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, DownloadActivity.this)));
- break;
- case PREPARING:
- statusTextView.setText(R.string.download_playerstate_buffering);
- break;
- case STARTED:
- statusTextView.setText((currentPlaying != null) ? (currentPlaying.getSong().getArtist() + " - " + currentPlaying.getSong().getAlbum()) : null);
- break;
- default:
- statusTextView.setText((currentPlaying != null) ? (currentPlaying.getSong().getArtist() + " - " + currentPlaying.getSong().getAlbum()) : null);
- break;
- }
-
- switch (playerState) {
- case STARTED:
- pauseButton.setVisibility(View.VISIBLE);
- stopButton.setVisibility(View.INVISIBLE);
- startButton.setVisibility(View.INVISIBLE);
- break;
- case DOWNLOADING:
- case PREPARING:
- pauseButton.setVisibility(View.INVISIBLE);
- stopButton.setVisibility(View.VISIBLE);
- startButton.setVisibility(View.INVISIBLE);
- break;
- default:
- pauseButton.setVisibility(View.INVISIBLE);
- stopButton.setVisibility(View.INVISIBLE);
- startButton.setVisibility(View.VISIBLE);
- break;
- }
-
- jukeboxButton.setTextColor(isJukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- onProgressChangedTask = null;
- }
- };
- onProgressChangedTask.execute();
- }
-
- private void changeProgress(final int ms) {
- final DownloadService downloadService = getDownloadService();
- if(downloadService == null) {
- return;
- }
-
- new SilentBackgroundTask<Void>(this) {
- boolean isJukeboxEnabled;
- int msPlayed;
- Integer duration;
- PlayerState playerState;
- int seekTo;
-
- @Override
- protected Void doInBackground() throws Throwable {
- msPlayed = Math.max(0, downloadService.getPlayerPosition());
- duration = downloadService.getPlayerDuration();
- playerState = getDownloadService().getPlayerState();
- int msTotal = duration == null ? 0 : duration;
- if(msPlayed + ms > msTotal) {
- seekTo = msTotal;
- } else {
- seekTo = msPlayed + ms;
- }
- downloadService.seekTo(seekTo);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- progressBar.setProgress(seekTo);
- }
- }.execute();
}
- private class SongListAdapter extends ArrayAdapter<DownloadFile> {
- public SongListAdapter(List<DownloadFile> entries) {
- super(DownloadActivity.this, android.R.layout.simple_list_item_1, entries);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- SongView view;
- if (convertView != null && convertView instanceof SongView) {
- view = (SongView) convertView;
- } else {
- view = new SongView(DownloadActivity.this);
- }
- DownloadFile downloadFile = getItem(position);
- view.setSong(downloadFile.getSong(), false);
- return view;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent me) {
- return gestureScanner.onTouchEvent(me);
- }
-
@Override
- public boolean onDown(MotionEvent me) {
- setControlsVisible(true);
- return false;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return false;
- }
-
- // Right to Left swipe
- if (e1.getX() - e2.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) {
- downloadService.next();
- onCurrentChanged();
- onProgressChanged();
+ public void onPrepareDialog(int id, Dialog dialog) {
+ if (id == DownloadFragment.DIALOG_SAVE_PLAYLIST) {
+ String playlistName = (getDownloadService() != null) ? getDownloadService().getSuggestedPlaylistName() : null;
+ if (playlistName != null) {
+ playlistNameView.setText(playlistName);
+ } else {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ playlistNameView.setText(dateFormat.format(new Date()));
}
- return true;
- }
-
- // Left to Right swipe
- else if (e2.getX() - e1.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.previous();
- onCurrentChanged();
- onProgressChanged();
- return true;
}
-
- // Top to Bottom swipe
- else if (e2.getY() - e1.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() + 30000);
- onProgressChanged();
- return true;
- }
-
- // Bottom to Top swipe
- else if (e1.getY() - e2.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() - 8000);
- onProgressChanged();
- return true;
- }
-
- return false;
}
- private void toggleNowPlaying() {
- nowPlaying = !nowPlaying;
- setTitle(nowPlaying ? "Now Playing" : "Downloading");
- onDownloadListChanged(true);
- }
-
@Override
- public void onLongPress(MotionEvent e) {
+ public void onBackPressed() {
+ if(onBackPressedSupport()) {
+ super.onBackPressed();
+ }
}
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- return false;
- }
+ private void savePlaylistInBackground(final String playlistName) {
+ Util.toast(this, getResources().getString(R.string.download_playlist_saving, playlistName));
+ getDownloadService().setSuggestedPlaylistName(playlistName);
+ new SilentBackgroundTask<Void>(DownloadActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
+ for (DownloadFile downloadFile : getDownloadService().getSongs()) {
+ entries.add(downloadFile.getSong());
+ }
+ MusicService musicService = MusicServiceFactory.getMusicService(DownloadActivity.this);
+ musicService.createPlaylist(null, playlistName, entries, DownloadActivity.this, null);
+ return null;
+ }
- @Override
- public void onShowPress(MotionEvent e) {
- }
+ @Override
+ protected void done(Void result) {
+ Util.toast(DownloadActivity.this, R.string.download_playlist_done);
+ }
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
+ @Override
+ protected void error(Throwable error) {
+ String msg = getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
+ Util.toast(DownloadActivity.this, msg);
+ }
+ }.execute();
}
}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/LyricsActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/LyricsActivity.java
deleted file mode 100644
index 56e59b8c..00000000
--- a/subsonic-android/src/github/daneren2005/dsub/activity/LyricsActivity.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-
-package github.daneren2005.dsub.activity;
-
-import android.os.Bundle;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Lyrics;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.TabActivityBackgroundTask;
-
-/**
- * Displays song lyrics.
- *
- * @author Sindre Mehus
- */
-public final class LyricsActivity extends SubsonicTabActivity {
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setContentView(R.layout.lyrics);
- load();
- }
-
- private void load() {
- BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(this) {
- @Override
- protected Lyrics doInBackground() throws Throwable {
- String artist = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ARTIST);
- String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_TITLE);
- MusicService musicService = MusicServiceFactory.getMusicService(LyricsActivity.this);
- return musicService.getLyrics(artist, title, LyricsActivity.this, this);
- }
-
- @Override
- protected void done(Lyrics result) {
- TextView artistView = (TextView) findViewById(R.id.lyrics_artist);
- TextView titleView = (TextView) findViewById(R.id.lyrics_title);
- TextView textView = (TextView) findViewById(R.id.lyrics_text);
- if (result != null && result.getArtist() != null) {
- artistView.setText(result.getArtist());
- titleView.setText(result.getTitle());
- textView.setText(result.getText());
- } else {
- artistView.setText(R.string.lyrics_nomatch);
- }
- }
- };
- task.execute();
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
index 36a8d17d..8ca0fdac 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
@@ -1,356 +1,236 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-
package github.daneren2005.dsub.activity;
-import java.util.Arrays;
-
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.MergeAdapter;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.util.FileUtil;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.MenuInflater;
-import android.content.Context;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.StatFs;
-import android.preference.PreferenceManager;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
+import android.os.Handler;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.view.Menu;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.KeyEvent;
import android.view.View;
-import android.widget.AdapterView;
import android.widget.ImageButton;
-import android.widget.ListView;
import android.widget.TextView;
-import android.widget.PopupWindow;
-import github.daneren2005.dsub.util.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class MainActivity extends SubsonicTabActivity {
-
- private static final int MENU_GROUP_SERVER = 10;
- private static final int MENU_ITEM_SERVER_1 = 101;
- private static final int MENU_ITEM_SERVER_2 = 102;
- private static final int MENU_ITEM_SERVER_3 = 103;
-
- private static boolean infoDialogDisplayed;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
- exit();
- }
- setContentView(R.layout.main);
-
- loadSettings();
-
- View buttons = LayoutInflater.from(this).inflate(R.layout.main_buttons, null);
-
- final View serverButton = buttons.findViewById(R.id.main_select_server);
- final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2);
- final TextView offlineButton = (TextView) buttons.findViewById(R.id.main_offline);
- offlineButton.setText(Util.isOffline(this) ? R.string.main_online : R.string.main_offline);
-
- final View albumsTitle = buttons.findViewById(R.id.main_albums);
- final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest);
- final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random);
- final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest);
- final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent);
- final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent);
- final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred);
-
- final View dummyView = findViewById(R.id.main_dummy);
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.PlayerState;
+import github.daneren2005.dsub.fragments.MainFragment;
+import github.daneren2005.dsub.fragments.SelectArtistFragment;
+import github.daneren2005.dsub.fragments.SelectPlaylistFragment;
+import github.daneren2005.dsub.service.DownloadFile;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.ChangeLog;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class MainActivity extends SubsonicActivity {
+ private static final String TAG = MainActivity.class.getSimpleName();
+ private static boolean infoDialogDisplayed;
+ private ScheduledExecutorService executorService;
+ private View coverArtView;
+ private TextView trackView;
+ private TextView artistView;
+ private ImageButton startButton;
+ private long lastBackPressTime = 0;
- int instance = Util.getActiveServer(this);
- String name = Util.getServerName(this, instance);
- serverTextView.setText(name);
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
+ stopService(new Intent(this, DownloadServiceImpl.class));
+ finish();
+ } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) {
+ getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD);
+ Intent intent = new Intent();
+ intent.setClass(this, DownloadActivity.class);
+ startActivity(intent);
+ }
+ setContentView(R.layout.main);
+
+ View bottomBar = findViewById(R.id.bottom_bar);
+ bottomBar.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent();
+ intent.setClass(v.getContext(), DownloadActivity.class);
+ startActivity(intent);
+ }
+ });
+ coverArtView = bottomBar.findViewById(R.id.album_art);
+ trackView = (TextView) bottomBar.findViewById(R.id.track_name);
+ artistView = (TextView) bottomBar.findViewById(R.id.artist_name);
+
+ ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous);
+ previousButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(MainActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if(getDownloadService() == null) {
+ return null;
+ }
+
+ getDownloadService().previous();
+ return null;
+ }
- ListView list = (ListView) findViewById(R.id.main_list);
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+
+ startButton = (ImageButton) findViewById(R.id.download_start);
+ startButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(MainActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ PlayerState state = getDownloadService().getPlayerState();
+ if(state == PlayerState.STARTED) {
+ getDownloadService().pause();
+ } else {
+ getDownloadService().start();
+ }
+
+ return null;
+ }
- MergeAdapter adapter = new MergeAdapter();
- if (!Util.isOffline(this)) {
- adapter.addViews(Arrays.asList(serverButton), true);
- }
- adapter.addView(offlineButton, true);
- if (!Util.isOffline(this)) {
- adapter.addView(albumsTitle, false);
- adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsStarredButton, albumsRecentButton, albumsFrequentButton), true);
- }
- list.setAdapter(adapter);
- registerForContextMenu(dummyView);
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+
+ ImageButton nextButton = (ImageButton) findViewById(R.id.download_next);
+ nextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(MainActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if(getDownloadService() == null) {
+ return null;
+ }
+
+ if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
+ getDownloadService().next();
+ }
+ return null;
+ }
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view == serverButton) {
- dummyView.showContextMenu();
- } else if (view == offlineButton) {
- toggleOffline();
- } else if (view == albumsNewestButton) {
- showAlbumList("newest");
- } else if (view == albumsRandomButton) {
- showAlbumList("random");
- } else if (view == albumsHighestButton) {
- showAlbumList("highest");
- } else if (view == albumsRecentButton) {
- showAlbumList("recent");
- } else if (view == albumsFrequentButton) {
- showAlbumList("frequent");
- } else if (view == albumsStarredButton) {
- showAlbumList("starred");
- }
- }
- });
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+
+ viewPager = (ViewPager) findViewById(R.id.pager);
+ pagerAdapter = new TabPagerAdapter(this, viewPager);
+ viewPager.setAdapter(pagerAdapter);
+ viewPager.setOnPageChangeListener(pagerAdapter);
- // Title: Subsonic
- setTitle(R.string.common_appname);
- showInfoDialog();
+ addTab("Home", MainFragment.class, null);
+ addTab("Library", SelectArtistFragment.class, null);
+ addTab("Playlists", SelectPlaylistFragment.class, null);
- checkUpdates();
- }
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+ getSupportActionBar().setHomeButtonEnabled(false);
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ }
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getSupportMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.menu_shuffle:
- onShuffleRequested();
- return true;
- case R.id.menu_search:
- onSearchRequested();
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- case R.id.menu_log:
- getLogs();
- return true;
- case R.id.menu_about:
- showAboutDialog();
- return true;
- }
-
- return false;
- }
-
- private void loadSettings() {
- PreferenceManager.setDefaultValues(this, R.xml.settings, false);
- SharedPreferences prefs = Util.getPreferences(this);
- if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
- editor.commit();
- }
+ protected void onPostCreate(Bundle bundle) {
+ super.onPostCreate(bundle);
- if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false);
- editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
- editor.commit();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- android.view.MenuItem menuItem1 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_1, MENU_ITEM_SERVER_1, Util.getServerName(this, 1));
- android.view.MenuItem menuItem2 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_2, MENU_ITEM_SERVER_2, Util.getServerName(this, 2));
- android.view.MenuItem menuItem3 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_3, MENU_ITEM_SERVER_3, Util.getServerName(this, 3));
- menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
- menu.setHeaderTitle(R.string.main_select_server);
-
- switch (Util.getActiveServer(this)) {
- case 1:
- menuItem1.setChecked(true);
- break;
- case 2:
- menuItem2.setChecked(true);
- break;
- case 3:
- menuItem3.setChecked(true);
- break;
- }
- }
-
- @Override
- public boolean onContextItemSelected(android.view.MenuItem menuItem) {
- switch (menuItem.getItemId()) {
- case MENU_ITEM_SERVER_1:
- setActiveServer(1);
- break;
- case MENU_ITEM_SERVER_2:
- setActiveServer(2);
- break;
- case MENU_ITEM_SERVER_3:
- setActiveServer(3);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
-
- // Restart activity
- restart();
- return true;
- }
-
- private void setActiveServer(int instance) {
- if (Util.getActiveServer(this) != instance) {
- DownloadService service = getDownloadService();
- if (service != null) {
- service.clearIncomplete();
- }
- Util.setActiveServer(this, instance);
- }
- }
+ showInfoDialog();
+
+ ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this));
+ if(changeLog.isFirstRun()) {
+ changeLog.getLogDialog().show();
+ }
+ }
- private void exit() {
- stopService(new Intent(this, DownloadServiceImpl.class));
- finish();
- }
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final Handler handler = new Handler();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ });
+ }
+ };
- private void showInfoDialog() {
- if (!infoDialogDisplayed) {
- infoDialogDisplayed = true;
- if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
- Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
- }
- }
- }
-
- private void showAboutDialog() {
- try {
- File rootFolder = FileUtil.getMusicDirectory(MainActivity.this);
- StatFs stat = new StatFs(rootFolder.getPath());
- long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
- long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
-
- String msg = getResources().getString(R.string.main_about_text,
- getPackageManager().getPackageInfo(getPackageName(), 0).versionName,
- Util.formatBytes(FileUtil.getUsedSize(MainActivity.this, rootFolder)),
- Util.formatBytes(Util.getCacheSizeMB(MainActivity.this) * 1024L * 1024L),
- Util.formatBytes(bytesAvailableFs),
- Util.formatBytes(bytesTotalFs));
- Util.info(this, R.string.main_about_title, msg);
- } catch(Exception e) {
- Util.toast(MainActivity.this, "Failed to open dialog");
- }
- // Util.toast(MainActivity.this, "Size: " + Util.formatBytes(FileUtil.getUsedSize(MainActivity.this, FileUtil.getMusicDirectory(MainActivity.this))));
+ executorService = Executors.newSingleThreadScheduledExecutor();
+ executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
}
- private void showAlbumList(String type) {
- Intent intent = new Intent(this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
- Util.startActivityWithoutTransition(this, intent);
+ @Override
+ public void onPause() {
+ super.onPause();
+ executorService.shutdown();
}
-
- private void toggleOffline() {
- Util.setOffline(this, !Util.isOffline(this));
- restart();
+
+ @Override
+ public void onBackPressed() {
+ if(onBackPressedSupport()) {
+ if(lastBackPressTime < (System.currentTimeMillis() - 4000)) {
+ lastBackPressTime = System.currentTimeMillis();
+ Util.toast(this, R.string.main_back_confirm);
+ } else {
+ finish();
+ }
+ }
}
-
- private void getLogs() {
- try {
- final String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
- new ModalBackgroundTask<File>(this, false) {
- @Override
- protected File doInBackground() throws Throwable {
- updateProgress("Gathering Logs");
- File logcat = new File(FileUtil.getSubsonicDirectory(), "logcat.txt");
- Process logcatProc = null;
- try {
- List<String> progs = new ArrayList<String>();
- progs.add("logcat");
- progs.add("-v");
- progs.add("time");
- progs.add("-d");
- progs.add("-f");
- progs.add(logcat.getPath());
- progs.add("*:I");
+ private void update() {
+ if (getDownloadService() == null) {
+ return;
+ }
- logcatProc = Runtime.getRuntime().exec(progs.toArray(new String[0]));
- logcatProc.waitFor();
- } catch(Exception e) {
- Util.toast(MainActivity.this, "Failed to gather logs");
- } finally {
- if(logcatProc != null) {
- logcatProc.destroy();
- }
- }
+ DownloadFile current = getDownloadService().getCurrentPlaying();
+ if(current == null) {
+ trackView.setText("Title");
+ artistView.setText("Artist");
+ getImageLoader().loadImage(coverArtView, null, false, false);
+ return;
+ }
- return logcat;
- }
+ MusicDirectory.Entry song = current.getSong();
+ trackView.setText(song.getTitle());
+ artistView.setText(song.getArtist());
+ getImageLoader().loadImage(coverArtView, song, false, false);
+ startButton.setImageResource((getDownloadService().getPlayerState() == PlayerState.STARTED) ? R.drawable.media_pause : R.drawable.media_start);
+ }
- @Override
- protected void done(File logcat) {
- Intent email = new Intent(android.content.Intent.ACTION_SEND);
- email.setType("text/plain");
- email.putExtra(Intent.EXTRA_EMAIL, new String[] {"dsub.android@gmail.com"});
- email.putExtra(Intent.EXTRA_SUBJECT, "DSub " + version + " Error Logs");
- email.putExtra(Intent.EXTRA_TEXT, "Describe the problem here");
- Uri attachment = Uri.fromFile(logcat);
- email.putExtra(Intent.EXTRA_STREAM, attachment);
- startActivity(email);
- }
- }.execute();
- } catch(Exception e) {}
+ private void showInfoDialog() {
+ if (!infoDialogDisplayed) {
+ infoDialogDisplayed = true;
+ if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
+ Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
+ }
+ }
}
}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java
index 0bcaa28a..aeddcf4f 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java
@@ -19,376 +19,73 @@
package github.daneren2005.dsub.activity;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Arrays;
-
+import github.daneren2005.dsub.R;
import android.content.Intent;
import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.MenuItem;
-import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.net.Uri;
-import com.actionbarsherlock.view.Menu;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.SearchCritera;
-import github.daneren2005.dsub.domain.SearchResult;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.DownloadService;
-import github.daneren2005.dsub.view.ArtistAdapter;
-import github.daneren2005.dsub.util.BackgroundTask;
+import android.util.Log;
+import github.daneren2005.dsub.fragments.SearchFragment;
import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.view.EntryAdapter;
-import github.daneren2005.dsub.util.MergeAdapter;
-import github.daneren2005.dsub.util.TabActivityBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-
-/**
- * Performs searches and displays the matching artists, albums and songs.
- *
- * @author Sindre Mehus
- */
-public class SearchActivity extends SubsonicTabActivity {
-
- private static final int DEFAULT_ARTISTS = 3;
- private static final int DEFAULT_ALBUMS = 5;
- private static final int DEFAULT_SONGS = 10;
-
- private static final int MAX_ARTISTS = 10;
- private static final int MAX_ALBUMS = 20;
- private static final int MAX_SONGS = 25;
- private ListView list;
-
- private View artistsHeading;
- private View albumsHeading;
- private View songsHeading;
- private TextView searchButton;
- private View moreArtistsButton;
- private View moreAlbumsButton;
- private View moreSongsButton;
- private SearchResult searchResult;
- private MergeAdapter mergeAdapter;
- private ArtistAdapter artistAdapter;
- private ListAdapter moreArtistsAdapter;
- private EntryAdapter albumAdapter;
- private ListAdapter moreAlbumsAdapter;
- private ListAdapter moreSongsAdapter;
- private EntryAdapter songAdapter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.search);
-
- setTitle(R.string.search_title);
-
- View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null);
-
- artistsHeading = buttons.findViewById(R.id.search_artists);
- albumsHeading = buttons.findViewById(R.id.search_albums);
- songsHeading = buttons.findViewById(R.id.search_songs);
+import com.actionbarsherlock.view.MenuItem;
- searchButton = (TextView) buttons.findViewById(R.id.search_search);
- moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
- moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
- moreSongsButton = buttons.findViewById(R.id.search_more_songs);
-
- list = (ListView) findViewById(R.id.search_list);
-
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view == searchButton) {
- onSearchRequested();
- } else if (view == moreArtistsButton) {
- expandArtists();
- } else if (view == moreAlbumsButton) {
- expandAlbums();
- } else if (view == moreSongsButton) {
- expandSongs();
- } else {
- Object item = parent.getItemAtPosition(position);
- if (item instanceof Artist) {
- onArtistSelected((Artist) item);
- } else if (item instanceof MusicDirectory.Entry) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
- if (entry.isDirectory()) {
- onAlbumSelected(entry, false);
- } else if (entry.isVideo()) {
- onVideoSelected(entry);
- } else {
- onSongSelected(entry, false, true, true, false);
- }
-
- }
- }
- }
- });
- registerForContextMenu(list);
- onNewIntent(getIntent());
- }
+public class SearchActivity extends SubsonicActivity {
+ private static final String TAG = SearchActivity.class.getSimpleName();
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
- inflater.inflate(R.menu.search, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.menu_search:
- onSearchRequested();
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- }
-
- return false;
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
- boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
- boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
-
- if (query != null) {
- mergeAdapter = new MergeAdapter();
- list.setAdapter(mergeAdapter);
- search(query, autoplay);
- } else {
- populateList();
- if (requestsearch)
- onSearchRequested();
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- Object selectedItem = list.getItemAtPosition(info.position);
-
- boolean isArtist = selectedItem instanceof Artist;
- boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory();
- boolean isSong = selectedItem instanceof MusicDirectory.Entry && (!((MusicDirectory.Entry) selectedItem).isDirectory())
- && (!((MusicDirectory.Entry) selectedItem).isVideo());
-
- if (isArtist || isAlbum) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_album_context, menu);
- } else if (isSong) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_song_context, menu);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Object selectedItem = list.getItemAtPosition(info.position);
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.download_activity);
- Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
- MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null;
- String id = artist != null ? artist.getId() : entry.getId();
+ if (findViewById(R.id.download_container) != null && savedInstanceState == null) {
+ currentFragment = new SearchFragment();
+ currentFragment.setPrimaryFragment(true);
+ getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit();
+ }
- switch (menuItem.getItemId()) {
- case R.id.album_menu_play_now:
- downloadRecursively(id, false, false, true, false, false);
- break;
- case R.id.album_menu_play_shuffled:
- downloadRecursively(id, false, false, true, true, false);
- break;
- case R.id.album_menu_play_last:
- downloadRecursively(id, false, true, false, false, false);
- break;
- case R.id.album_menu_download:
- downloadRecursively(id, false, true, false, false, true);
- break;
- case R.id.album_menu_pin:
- downloadRecursively(id, true, true, false, false, true);
- break;
- case R.id.song_menu_play_now:
- onSongSelected(entry, false, false, true, false);
- break;
- case R.id.song_menu_play_next:
- onSongSelected(entry, false, true, false, true);
- break;
- case R.id.song_menu_play_last:
- onSongSelected(entry, false, true, false, false);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ }
- return true;
- }
-
- private void search(final String query, final boolean autoplay) {
- BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(this) {
- @Override
- protected SearchResult doInBackground() throws Throwable {
- SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS);
- MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this);
- return service.search(criteria, SearchActivity.this, this);
- }
-
- @Override
- protected void done(SearchResult result) {
- searchResult = result;
- populateList();
- if (autoplay) {
- autoplay();
- }
-
- }
- };
- task.execute();
- }
-
- private void populateList() {
- mergeAdapter = new MergeAdapter();
- mergeAdapter.addView(searchButton, true);
-
- if (searchResult != null) {
- List<Artist> artists = searchResult.getArtists();
- if (!artists.isEmpty()) {
- mergeAdapter.addView(artistsHeading);
- List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
- artistAdapter = new ArtistAdapter(this, displayedArtists);
- mergeAdapter.addAdapter(artistAdapter);
- if (artists.size() > DEFAULT_ARTISTS) {
- moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true);
- }
- }
-
- List<MusicDirectory.Entry> albums = searchResult.getAlbums();
- if (!albums.isEmpty()) {
- mergeAdapter.addView(albumsHeading);
- List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
- albumAdapter = new EntryAdapter(this, getImageLoader(), displayedAlbums, false);
- mergeAdapter.addAdapter(albumAdapter);
- if (albums.size() > DEFAULT_ALBUMS) {
- moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true);
- }
- }
-
- List<MusicDirectory.Entry> songs = searchResult.getSongs();
- if (!songs.isEmpty()) {
- mergeAdapter.addView(songsHeading);
- List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
- songAdapter = new EntryAdapter(this, getImageLoader(), displayedSongs, false);
- mergeAdapter.addAdapter(songAdapter);
- if (songs.size() > DEFAULT_SONGS) {
- moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true);
- }
- }
-
- boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
- searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
- }
-
- list.setAdapter(mergeAdapter);
- }
-
- private void expandArtists() {
- artistAdapter.clear();
- for (Artist artist : searchResult.getArtists()) {
- artistAdapter.add(artist);
- }
- artistAdapter.notifyDataSetChanged();
- mergeAdapter.removeAdapter(moreArtistsAdapter);
- mergeAdapter.notifyDataSetChanged();
- }
-
- private void expandAlbums() {
- albumAdapter.clear();
- for (MusicDirectory.Entry album : searchResult.getAlbums()) {
- albumAdapter.add(album);
- }
- albumAdapter.notifyDataSetChanged();
- mergeAdapter.removeAdapter(moreAlbumsAdapter);
- mergeAdapter.notifyDataSetChanged();
- }
-
- private void expandSongs() {
- songAdapter.clear();
- for (MusicDirectory.Entry song : searchResult.getSongs()) {
- songAdapter.add(song);
- }
- songAdapter.notifyDataSetChanged();
- mergeAdapter.removeAdapter(moreSongsAdapter);
- mergeAdapter.notifyDataSetChanged();
- }
-
- private void onArtistSelected(Artist artist) {
- Intent intent = new Intent(this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
- Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay);
- Util.startActivityWithoutTransition(SearchActivity.this, intent);
- }
-
- private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) {
- DownloadService downloadService = getDownloadService();
- if (downloadService != null) {
- if (!append) {
- downloadService.clear();
- }
- downloadService.download(Arrays.asList(song), save, false, playNext, false);
- if (autoplay) {
- downloadService.play(downloadService.size() - 1);
- }
-
- Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
- }
- }
-
- private void onVideoSelected(MusicDirectory.Entry entry) {
- int maxBitrate = Util.getMaxVideoBitrate(this);
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(maxBitrate, this, entry.getId())));
- startActivity(intent);
- }
-
- private void autoplay() {
- if (!searchResult.getSongs().isEmpty()) {
- onSongSelected(searchResult.getSongs().get(0), false, false, true, false);
- } else if (!searchResult.getAlbums().isEmpty()) {
- onAlbumSelected(searchResult.getAlbums().get(0), true);
- }
- }
+ if(currentFragment != null && currentFragment instanceof SearchFragment) {
+ String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
+ boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
+ boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
+
+ if (query != null) {
+ ((SearchFragment)currentFragment).search(query, autoplay);
+ } else {
+ ((SearchFragment)currentFragment).populateList();
+ if (requestsearch) {
+ onSearchRequested();
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(item.getItemId() == android.R.id.home) {
+ Intent i = new Intent();
+ i.setClass(this, MainActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(i);
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ public void onSupportNewIntent(Intent intent) {
+ onNewIntent(intent);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if(onBackPressedSupport()) {
+ super.onBackPressed();
+ }
+ }
} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SelectAlbumActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SelectAlbumActivity.java
deleted file mode 100644
index 5016135c..00000000
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SelectAlbumActivity.java
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.activity;
-
-import github.daneren2005.dsub.view.EntryAdapter;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.*;
-import com.actionbarsherlock.view.Menu;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.service.*;
-import github.daneren2005.dsub.util.*;
-import com.mobeta.android.dslv.*;
-import java.io.File;
-
-import java.util.*;
-
-public class SelectAlbumActivity extends SubsonicTabActivity {
-
- private static final String TAG = SelectAlbumActivity.class.getSimpleName();
-
- private DragSortListView entryList;
- private View footer;
- private View emptyView;
- private boolean hideButtons = false;
- private Button moreButton;
- private Boolean licenseValid;
- private boolean showHeader = true;
- private EntryAdapter entryAdapter;
- private List<MusicDirectory.Entry> entries;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_album);
-
- entryList = (DragSortListView) findViewById(R.id.select_album_entries);
-
- footer = LayoutInflater.from(this).inflate(R.layout.select_album_footer, entryList, false);
- entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- entryList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (position >= 0) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position);
- if (entry.isDirectory()) {
- Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent);
- } else if (entry.isVideo()) {
- if(entryExists(entry)) {
- playExternalPlayer(entry);
- } else {
- streamExternalPlayer(entry);
- }
- }
- }
- }
- });
- entryList.setDropListener(new DragSortListView.DropListener() {
- @Override
- public void drop(int from, int to) {
- int max = entries.size();
- if(to >= max) {
- to = max - 1;
- }
- else if(to < 0) {
- to = 0;
- }
- entries.add(to, entries.remove(from));
- entryAdapter.notifyDataSetChanged();
- }
- });
-
- moreButton = (Button) footer.findViewById(R.id.select_album_more);
- emptyView = findViewById(R.id.select_album_empty);
-
- registerForContextMenu(entryList);
-
- String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID);
- String name = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME);
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- String albumListType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- int albumListSize = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
- int albumListOffset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
-
- if (playlistId != null) {
- getPlaylist(playlistId, playlistName);
- } else if (albumListType != null) {
- getAlbumList(albumListType, albumListSize, albumListOffset);
- } else {
- getMusicDirectory(id, name);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
- if(licenseValid == null) {
- inflater.inflate(R.menu.empty, menu);
- }
- else if(hideButtons) {
- String albumListType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- if(albumListType != null) {
- inflater.inflate(R.menu.select_album_list, menu);
- } else {
- inflater.inflate(R.menu.select_album, menu);
- }
- hideButtons = false;
- } else {
- if(Util.isOffline(this)) {
- inflater.inflate(R.menu.select_song_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_song, menu);
-
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- if(playlistId == null) {
- menu.removeItem(R.id.menu_remove_playlist);
- }
- }
- }
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.menu_play_now:
- playNow(false, false);
- return true;
- case R.id.menu_play_last:
- playNow(false, true);
- return true;
- case R.id.menu_shuffle:
- playNow(true, false);
- return true;
- case R.id.menu_select:
- selectAllOrNone();
- return true;
- case R.id.menu_refresh:
- refresh();
- return true;
- case R.id.menu_download:
- downloadBackground(false);
- selectAll(false, false);
- return true;
- case R.id.menu_cache:
- downloadBackground(true);
- selectAll(false, false);
- return true;
- case R.id.menu_delete:
- delete();
- selectAll(false, false);
- return true;
- case R.id.menu_add_playlist:
- addToPlaylist(getSelectedSongs());
- return true;
- case R.id.menu_remove_playlist:
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- removeFromPlaylist(playlistId, playlistName, getSelectedIndexes());
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- }
-
- return false;
- }
-
- private void playNow(final boolean shuffle, final boolean append) {
- if(getSelectedSongs().size() > 0) {
- download(append, false, !append, false, shuffle);
- selectAll(false, false);
- }
- else {
- playAll(shuffle, append);
- }
- }
- private void playAll(final boolean shuffle, final boolean append) {
- boolean hasSubFolders = false;
- for (int i = 0; i < entryList.getCount(); i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
- if (entry != null && entry.isDirectory()) {
- hasSubFolders = true;
- break;
- }
- }
-
- String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID);
- if (hasSubFolders && id != null) {
- downloadRecursively(id, false, append, !append, shuffle, false);
- } else {
- selectAll(true, false);
- download(append, false, !append, false, shuffle);
- selectAll(false, false);
- }
- }
-
- private void refresh() {
- finish();
- Intent intent = getIntent();
- intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- AdapterView.AdapterContextMenuInfo info =
- (AdapterView.AdapterContextMenuInfo) menuInfo;
-
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
-
- if (entry.isDirectory()) {
- MenuInflater inflater = getMenuInflater();
- if(Util.isOffline(this))
- inflater.inflate(R.menu.select_album_context_offline, menu);
- else
- inflater.inflate(R.menu.select_album_context, menu);
- } else if(!entry.isVideo()) {
- MenuInflater inflater = getMenuInflater();
- if(Util.isOffline(this)) {
- inflater.inflate(R.menu.select_song_context_offline, menu);
- }
- else {
- inflater.inflate(R.menu.select_song_context, menu);
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- if(playlistId == null) {
- menu.removeItem(R.id.song_menu_remove_playlist);
- }
- }
- } else {
- MenuInflater inflater = getMenuInflater();
- if(Util.isOffline(this))
- inflater.inflate(R.menu.select_video_context_offline, menu);
- else
- inflater.inflate(R.menu.select_video_context, menu);
- }
-
- if (!Util.isOffline(this) && !entry.isVideo()) {
- menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
- songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(info.position));
- switch (menuItem.getItemId()) {
- case R.id.album_menu_play_now:
- downloadRecursively(entry.getId(), false, false, true, false, false);
- break;
- case R.id.album_menu_play_shuffled:
- downloadRecursively(entry.getId(), false, false, true, true, false);
- break;
- case R.id.album_menu_play_last:
- downloadRecursively(entry.getId(), false, true, false, false, false);
- break;
- case R.id.album_menu_download:
- downloadRecursively(entry.getId(), false, true, false, false, true);
- break;
- case R.id.album_menu_pin:
- downloadRecursively(entry.getId(), true, true, false, false, true);
- break;
- case R.id.album_menu_star:
- toggleStarred(entry);
- break;
- case R.id.album_menu_delete:
- deleteRecursively(entry);
- break;
- case R.id.song_menu_play_now:
- getDownloadService().clear();
- getDownloadService().download(songs, false, true, true, false);
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, DownloadActivity.class);
- break;
- case R.id.song_menu_play_next:
- getDownloadService().download(songs, false, false, true, false);
- break;
- case R.id.song_menu_play_last:
- getDownloadService().download(songs, false, false, false, false);
- break;
- case R.id.song_menu_download:
- getDownloadService().downloadBackground(songs, false);
- break;
- case R.id.song_menu_pin:
- getDownloadService().downloadBackground(songs, true);
- break;
- case R.id.song_menu_delete:
- getDownloadService().delete(songs);
- break;
- case R.id.song_menu_add_playlist:
- addToPlaylist(songs);
- break;
- case R.id.song_menu_star:
- toggleStarred(entry);
- break;
- case R.id.song_menu_webview:
- playWebView(entry);
- break;
- case R.id.song_menu_play_external:
- playExternalPlayer(entry);
- break;
- case R.id.song_menu_info:
- displaySongInfo(entry);
- break;
- case R.id.song_menu_stream_external:
- streamExternalPlayer(entry);
- break;
- case R.id.song_menu_remove_playlist:
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(info.position - 1));
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- return true;
- }
-
- private void getMusicDirectory(final String id, final String name) {
- setTitle(name);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- return service.getMusicDirectory(id, name, refresh, SelectAlbumActivity.this, this);
- }
- }.execute();
- }
-
- private void getPlaylist(final String playlistId, final String playlistName) {
- setTitle(playlistName);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- return service.getPlaylist(playlistId, playlistName, SelectAlbumActivity.this, this);
- }
- }.execute();
- }
-
- private void getAlbumList(final String albumListType, final int size, final int offset) {
- showHeader = false;
-
- if ("newest".equals(albumListType)) {
- setTitle(R.string.main_albums_newest);
- } else if ("random".equals(albumListType)) {
- setTitle(R.string.main_albums_random);
- } else if ("highest".equals(albumListType)) {
- setTitle(R.string.main_albums_highest);
- } else if ("recent".equals(albumListType)) {
- setTitle(R.string.main_albums_recent);
- } else if ("frequent".equals(albumListType)) {
- setTitle(R.string.main_albums_frequent);
- } else if ("starred".equals(albumListType)) {
- setTitle(R.string.main_albums_starred);
- }
-
- if (!"starred".equals(albumListType)) {
- entryList.setDragEnabled(false);
- }
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- MusicDirectory result;
- if ("starred".equals(albumListType)) {
- result = service.getStarredList(SelectAlbumActivity.this, this);
- } else {
- result = service.getAlbumList(albumListType, size, offset, SelectAlbumActivity.this, this);
- }
- return result;
- }
-
- @Override
- protected void done(Pair<MusicDirectory, Boolean> result) {
- if (!result.getFirst().getChildren().isEmpty()) {
- if (!("starred".equals(albumListType))) {
- moreButton.setVisibility(View.VISIBLE);
- entryList.addFooterView(footer);
- }
-
- moreButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class);
- String type = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- int size = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
- int offset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) + size;
-
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset);
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent);
- }
- });
- }
- super.done(result);
- }
- }.execute();
- }
-
- private void selectAllOrNone() {
- boolean someUnselected = false;
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof MusicDirectory.Entry) {
- someUnselected = true;
- break;
- }
- }
- selectAll(someUnselected, true);
- }
-
- private void selectAll(boolean selected, boolean toast) {
- int count = entryList.getCount();
- int selectedCount = 0;
- for (int i = 0; i < count; i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
- if (entry != null && !entry.isDirectory() && !entry.isVideo()) {
- entryList.setItemChecked(i, selected);
- selectedCount++;
- }
- }
-
- // Display toast: N tracks selected / N tracks unselected
- if (toast) {
- int toastResId = selected ? R.string.select_album_n_selected
- : R.string.select_album_n_unselected;
- Util.toast(this, getString(toastResId, selectedCount));
- }
- }
-
- private List<MusicDirectory.Entry> getSelectedSongs() {
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (entryList.isItemChecked(i)) {
- songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(i));
- }
- }
- return songs;
- }
-
- private List<Integer> getSelectedIndexes() {
- List<Integer> indexes = new ArrayList<Integer>();
-
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (entryList.isItemChecked(i)) {
- indexes.add(i - 1);
- }
- }
-
- return indexes;
- }
-
- private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle) {
- if (getDownloadService() == null) {
- return;
- }
-
- final List<MusicDirectory.Entry> songs = getSelectedSongs();
- Runnable onValid = new Runnable() {
- @Override
- public void run() {
- if (!append) {
- getDownloadService().clear();
- }
-
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().download(songs, save, autoplay, playNext, shuffle);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- if (playlistName != null) {
- getDownloadService().setSuggestedPlaylistName(playlistName);
- }
- if (autoplay) {
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, DownloadActivity.class);
- } else if (save) {
- Util.toast(SelectAlbumActivity.this,
- getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
- } else if (append) {
- Util.toast(SelectAlbumActivity.this,
- getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
- }
- }
- };
-
- checkLicenseAndTrialPeriod(onValid);
- }
- private void downloadBackground(final boolean save) {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
- if(songs.isEmpty()) {
- selectAll(true, false);
- songs = getSelectedSongs();
- }
- downloadBackground(save, songs);
- }
- private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
- if (getDownloadService() == null) {
- return;
- }
-
- Runnable onValid = new Runnable() {
- @Override
- public void run() {
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().downloadBackground(songs, save);
-
- Util.toast(SelectAlbumActivity.this,
- getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
- }
- };
-
- checkLicenseAndTrialPeriod(onValid);
- }
-
- private void delete() {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
- if(songs.isEmpty()) {
- selectAll(true, false);
- songs = getSelectedSongs();
- }
- if (getDownloadService() != null) {
- getDownloadService().delete(songs);
- }
- }
-
- private boolean entryExists(MusicDirectory.Entry entry) {
- DownloadFile check = new DownloadFile(this, entry, false);
- return check.isCompleteFileAvailable();
- }
-
- private void playWebView(MusicDirectory.Entry entry) {
- int maxBitrate = Util.getMaxVideoBitrate(this);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(maxBitrate, this, entry.getId())));
-
- startActivity(intent);
- }
- private void playExternalPlayer(MusicDirectory.Entry entry) {
- if(!entryExists(entry)) {
- Util.toast(this, R.string.download_need_download);
- } else {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.parse(entry.getPath()), "video/*");
-
- List<ResolveInfo> intents = getPackageManager()
- .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if(intents != null && intents.size() > 0) {
- startActivity(intent);
- }else {
- Util.toast(this, R.string.download_no_streaming_player);
- }
- }
- }
- private void streamExternalPlayer(MusicDirectory.Entry entry) {
- int maxBitrate = Util.getMaxVideoBitrate(this);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoStreamUrl(maxBitrate, this, entry.getId())), "video/*");
-
- List<ResolveInfo> intents = getPackageManager()
- .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if(intents != null && intents.size() > 0) {
- startActivity(intent);
- } else {
- Util.toast(this, R.string.download_no_streaming_player);
- }
- }
-
- public void deleteRecursively(MusicDirectory.Entry album) {
- File dir = FileUtil.getAlbumDirectory(this, album);
- Util.recursiveDelete(dir);
- if(Util.isOffline(this)) {
- refresh();
- }
- }
-
- private void checkLicenseAndTrialPeriod(Runnable onValid) {
- if (licenseValid) {
- onValid.run();
- return;
- }
-
- int trialDaysLeft = Util.getRemainingTrialDays(this);
- Log.i(TAG, trialDaysLeft + " trial days left.");
-
- if (trialDaysLeft == 0) {
- showDonationDialog(trialDaysLeft, null);
- } else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2) {
- showDonationDialog(trialDaysLeft, onValid);
- } else {
- Util.toast(this, getResources().getString(R.string.select_album_not_licensed, trialDaysLeft));
- onValid.run();
- }
- }
-
- private void showDonationDialog(int trialDaysLeft, final Runnable onValid) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setIcon(android.R.drawable.ic_dialog_info);
-
- if (trialDaysLeft == 0) {
- builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left);
- } else {
- builder.setTitle(getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left,
- trialDaysLeft, trialDaysLeft));
- }
-
- builder.setMessage(R.string.select_album_donate_dialog_message);
-
- builder.setPositiveButton(R.string.select_album_donate_dialog_now,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL)));
- }
- });
-
- builder.setNegativeButton(R.string.select_album_donate_dialog_later,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- if (onValid != null) {
- onValid.run();
- }
- }
- });
-
- builder.create().show();
- }
-
- private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>> {
-
- public LoadTask() {
- super(SelectAlbumActivity.this);
- }
-
- protected abstract MusicDirectory load(MusicService service) throws Exception;
-
- @Override
- protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectAlbumActivity.this);
- MusicDirectory dir = load(musicService);
- boolean valid = musicService.isLicenseValid(SelectAlbumActivity.this, this);
- return new Pair<MusicDirectory, Boolean>(dir, valid);
- }
-
- @Override
- protected void done(Pair<MusicDirectory, Boolean> result) {
- entries = result.getFirst().getChildren();
-
- int songCount = 0;
- for (MusicDirectory.Entry entry : entries) {
- if (!entry.isDirectory()) {
- songCount++;
- }
- }
-
- if (songCount > 0) {
- if(showHeader) {
- entryList.addHeaderView(createHeader(entries), null, false);
- }
- } else {
- hideButtons = true;
- }
-
- emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
- entryList.setAdapter(entryAdapter = new EntryAdapter(SelectAlbumActivity.this, getImageLoader(), entries, true));
- licenseValid = result.getSecond();
- invalidateOptionsMenu();
-
- boolean playAll = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
- if (playAll && songCount > 0) {
- playAll(getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), false);
- }
- }
- }
-
- private View createHeader(List<MusicDirectory.Entry> entries) {
- View header = LayoutInflater.from(this).inflate(R.layout.select_album_header, entryList, false);
-
- View coverArtView = header.findViewById(R.id.select_album_art);
- getImageLoader().loadImage(coverArtView, entries.get(0), true, true);
-
- TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
- titleView.setText(getTitle());
-
- int songCount = 0;
-
- Set<String> artists = new HashSet<String>();
- for (MusicDirectory.Entry entry : entries) {
- if (!entry.isDirectory()) {
- songCount++;
- if (entry.getArtist() != null) {
- artists.add(entry.getArtist());
- }
- }
- }
-
- TextView artistView = (TextView) header.findViewById(R.id.select_album_artist);
- if (artists.size() == 1) {
- artistView.setText(artists.iterator().next());
- artistView.setVisibility(View.VISIBLE);
- } else {
- artistView.setVisibility(View.GONE);
- }
-
- TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
- String s = getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
- songCountView.setText(s.toUpperCase());
-
- return header;
- }
-
- public void removeFromPlaylist(final String id, final String name, final List<Integer> indexes) {
- new LoadingTask<Void>(this, true) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectAlbumActivity.this);
- musicService.removeFromPlaylist(id, indexes, SelectAlbumActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- for(int i = indexes.size() - 1; i >= 0; i--) {
- entryList.setItemChecked(indexes.get(i) + 1, false);
- entryAdapter.removeAt(indexes.get(i));
- }
- entryAdapter.notifyDataSetChanged();
- Util.toast(SelectAlbumActivity.this, getResources().getString(R.string.removed_playlist, indexes.size(), name));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = getResources().getString(R.string.updated_playlist_error, name) + " " + getErrorMessage(error);
- }
-
- Util.toast(SelectAlbumActivity.this, msg, false);
- }
- }.execute();
- }
-}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SelectArtistActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SelectArtistActivity.java
deleted file mode 100644
index b439df15..00000000
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SelectArtistActivity.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-
-package github.daneren2005.dsub.activity;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.TextView;
-import com.actionbarsherlock.view.Menu;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.Indexes;
-import github.daneren2005.dsub.domain.MusicFolder;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.view.ArtistAdapter;
-import github.daneren2005.dsub.util.BackgroundTask;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.TabActivityBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import java.io.File;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
-
- private static final int MENU_GROUP_MUSIC_FOLDER = 10;
-
- private ListView artistList;
- private View folderButton;
- private TextView folderName;
- private List<MusicFolder> musicFolders;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_artist);
-
- artistList = (ListView) findViewById(R.id.select_artist_list);
- artistList.setOnItemClickListener(this);
-
- folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false);
- folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
-
- if (!Util.isOffline(this)) {
- artistList.addHeaderView(folderButton);
- }
-
- registerForContextMenu(artistList);
- setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
-
- musicFolders = null;
- load();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
- inflater.inflate(R.menu.select_artist, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.menu_refresh:
- refresh();
- return true;
- case R.id.menu_shuffle:
- onShuffleRequested();
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- case R.id.menu_search:
- onSearchRequested();
- return true;
- }
-
- return false;
- }
-
- private void refresh() {
- finish();
- Intent intent = getIntent();
- intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void selectFolder() {
- folderButton.showContextMenu();
- }
-
- public void deleteRecursively(Artist artist) {
- File dir = FileUtil.getArtistDirectory(this, artist);
- Util.recursiveDelete(dir);
- if(Util.isOffline(this)) {
- refresh();
- }
- }
-
- private void load() {
- BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this) {
- @Override
- protected Indexes doInBackground() throws Throwable {
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
- if (!Util.isOffline(SelectArtistActivity.this)) {
- musicFolders = musicService.getMusicFolders(refresh, SelectArtistActivity.this, this);
- }
- String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
- return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
- }
-
- @Override
- protected void done(Indexes result) {
- List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
- artists.addAll(result.getShortcuts());
- artists.addAll(result.getArtists());
- artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
-
- // Display selected music folder
- if (musicFolders != null) {
- String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
- if (musicFolderId == null) {
- folderName.setText(R.string.select_artist_all_folders);
- } else {
- for (MusicFolder musicFolder : musicFolders) {
- if (musicFolder.getId().equals(musicFolderId)) {
- folderName.setText(musicFolder.getName());
- break;
- }
- }
- }
- }
- }
- };
- task.execute();
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view == folderButton) {
- selectFolder();
- } else {
- Artist artist = (Artist) parent.getItemAtPosition(position);
- Intent intent = new Intent(this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
- Util.startActivityWithoutTransition(this, intent);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
-
- if (artistList.getItemAtPosition(info.position) instanceof Artist) {
- MenuInflater inflater = getMenuInflater();
- if(Util.isOffline(this))
- inflater.inflate(R.menu.select_artist_context_offline, menu);
- else
- inflater.inflate(R.menu.select_artist_context, menu);
- } else if (info.position == 0) {
- String musicFolderId = Util.getSelectedMusicFolderId(this);
- MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders);
- if (musicFolderId == null) {
- menuItem.setChecked(true);
- }
- if (musicFolders != null) {
- for (int i = 0; i < musicFolders.size(); i++) {
- MusicFolder musicFolder = musicFolders.get(i);
- menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName());
- if (musicFolder.getId().equals(musicFolderId)) {
- menuItem.setChecked(true);
- }
- }
- }
- menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
-
- Artist artist = (Artist) artistList.getItemAtPosition(info.position);
-
- if (artist != null) {
- switch (menuItem.getItemId()) {
- case R.id.artist_menu_play_now:
- downloadRecursively(artist.getId(), false, false, true, false, false);
- break;
- case R.id.artist_menu_play_shuffled:
- downloadRecursively(artist.getId(), false, false, true, true, false);
- break;
- case R.id.artist_menu_play_last:
- downloadRecursively(artist.getId(), false, true, false, false, false);
- break;
- case R.id.artist_menu_download:
- downloadRecursively(artist.getId(), false, true, false, false, true);
- break;
- case R.id.artist_menu_pin:
- downloadRecursively(artist.getId(), true, true, false, false, true);
- break;
- case R.id.artist_menu_delete:
- deleteRecursively(artist);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- } else if (info.position == 0) {
- MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId());
- String musicFolderId = selectedFolder == null ? null : selectedFolder.getId();
- String musicFolderName = selectedFolder == null ? getString(R.string.select_artist_all_folders)
- : selectedFolder.getName();
- Util.setSelectedMusicFolderId(this, musicFolderId);
- folderName.setText(musicFolderName);
- refresh();
- }
-
- return true;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SelectPlaylistActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SelectPlaylistActivity.java
deleted file mode 100644
index 855f4502..00000000
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SelectPlaylistActivity.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-
-package github.daneren2005.dsub.activity;
-
-import github.daneren2005.dsub.view.PlaylistAdapter;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.*;
-import android.widget.AdapterView;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ListView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.Playlist;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.OfflineException;
-import github.daneren2005.dsub.service.ServerTooOldException;
-import github.daneren2005.dsub.util.*;
-
-import java.util.List;
-
-public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
- private ListView list;
- private View emptyTextView;
- private PlaylistAdapter playlistAdapter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_playlist);
-
- list = (ListView) findViewById(R.id.select_playlist_list);
- emptyTextView = findViewById(R.id.select_playlist_empty);
- list.setOnItemClickListener(this);
- registerForContextMenu(list);
-
- // Title: Playlists
- setTitle(R.string.playlist_label);
-
- load();
- }
-
- @Override
- public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
- com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
- inflater.inflate(R.menu.select_playlist, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.menu_refresh:
- refresh();
- return true;
- case R.id.menu_exit:
- intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- case R.id.menu_search:
- onSearchRequested();
- return true;
- }
-
- return false;
- }
-
- private void refresh() {
- finish();
- Intent intent = new Intent(this, SelectPlaylistActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void load() {
- final SelectPlaylistActivity me = this;
- BackgroundTask<List<Playlist>> task = new TabActivityBackgroundTask<List<Playlist>>(this) {
- @Override
- protected List<Playlist> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- List<Playlist> playlists = musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this);
- if(!Util.isOffline(me))
- new CacheCleaner(me, getDownloadService()).cleanPlaylists(playlists);
- return playlists;
- }
-
- @Override
- protected void done(List<Playlist> result) {
- list.setAdapter(playlistAdapter = new PlaylistAdapter(SelectPlaylistActivity.this, result));
- emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
- }
- };
- task.execute();
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- MenuInflater inflater = getMenuInflater();
- if (Util.isOffline(this))
- inflater.inflate(R.menu.select_playlist_context_offline, menu);
- else
- inflater.inflate(R.menu.select_playlist_context, menu);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Playlist playlist = (Playlist) list.getItemAtPosition(info.position);
-
- Intent intent;
- switch (menuItem.getItemId()) {
- case R.id.playlist_menu_download:
- downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true);
- break;
- case R.id.playlist_menu_pin:
- downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true);
- break;
- case R.id.playlist_menu_play_now:
- intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
- break;
- case R.id.playlist_menu_play_shuffled:
- intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
- break;
- case R.id.playlist_menu_delete:
- deletePlaylist(playlist);
- break;
- case R.id.playlist_info:
- displayPlaylistInfo(playlist);
- break;
- case R.id.playlist_update_info:
- updatePlaylistInfo(playlist);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- return true;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
- Playlist playlist = (Playlist) parent.getItemAtPosition(position);
-
- Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
- }
-
- private void deletePlaylist(final Playlist playlist) {
- new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.common_confirm)
- .setMessage(getResources().getString(R.string.delete_playlist, playlist.getName()))
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(SelectPlaylistActivity.this, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
- musicService.deletePlaylist(playlist.getId(), SelectPlaylistActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- playlistAdapter.remove(playlist);
- playlistAdapter.notifyDataSetChanged();
- Util.toast(SelectPlaylistActivity.this, getResources().getString(R.string.menu_deleted_playlist, playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(SelectPlaylistActivity.this, msg, false);
- }
- }.execute();
- }
-
- })
- .setNegativeButton(R.string.common_cancel, null)
- .show();
- }
-
- private void displayPlaylistInfo(final Playlist playlist) {
- String message = "Owner: " + playlist.getOwner() + "\nComments: " +
- ((playlist.getComment() == null) ? "" : playlist.getComment()) +
- "\nSong Count: " + playlist.getSongCount() +
- ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) +
- "\nCreation Date: " + playlist.getCreated().replace('T', ' ');
- new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(playlist.getName())
- .setMessage(message)
- .show();
- }
-
- private void updatePlaylistInfo(final Playlist playlist) {
- View dialogView = getLayoutInflater().inflate(R.layout.update_playlist, null);
- final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name);
- final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment);
- final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public);
-
- nameBox.setText(playlist.getName());
- commentBox.setText(playlist.getComment());
- Boolean pub = playlist.getPublic();
- if(pub == null) {
- publicBox.setEnabled(false);
- } else {
- publicBox.setChecked(pub);
- }
-
- new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.playlist_update_info)
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new LoadingTask<Void>(SelectPlaylistActivity.this, false) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
- musicService.updatePlaylist(playlist.getId(), nameBox.getText().toString(), commentBox.getText().toString(), publicBox.isChecked(), SelectPlaylistActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- refresh();
- Util.toast(SelectPlaylistActivity.this, getResources().getString(R.string.playlist_updated_info, playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(SelectPlaylistActivity.this, msg, false);
- }
- }.execute();
- }
-
- })
- .setNegativeButton(R.string.common_cancel, null)
- .show();
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java
new file mode 100644
index 00000000..f8d0019b
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java
@@ -0,0 +1,616 @@
+package github.daneren2005.dsub.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.media.AudioManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.ActionBar.Tab;
+import com.actionbarsherlock.app.ActionBar.TabListener;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.app.SherlockFragment;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.fragments.SubsonicFragment;
+import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.updates.Updater;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.ImageLoader;
+import github.daneren2005.dsub.util.Util;
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SubsonicActivity extends SherlockFragmentActivity implements OnItemSelectedListener {
+ private static final String TAG = SubsonicActivity.class.getSimpleName();
+ private static ImageLoader IMAGE_LOADER;
+ protected static String theme;
+ private boolean destroyed = false;
+ protected TabPagerAdapter pagerAdapter;
+ protected ViewPager viewPager;
+ protected List<SubsonicFragment> backStack = new ArrayList<SubsonicFragment>();
+ protected SubsonicFragment currentFragment;
+ Spinner actionBarSpinner;
+ ArrayAdapter<CharSequence> spinnerAdapter;
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ setUncaughtExceptionHandler();
+ applyTheme();
+ super.onCreate(bundle);
+ startService(new Intent(this, DownloadServiceImpl.class));
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
+
+ View actionbar = getLayoutInflater().inflate(R.layout.actionbar_spinner, null);
+ actionBarSpinner = (Spinner)actionbar.findViewById(R.id.spinner);
+ spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
+ spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ actionBarSpinner.setOnItemSelectedListener(this);
+ actionBarSpinner.setAdapter(spinnerAdapter);
+
+ getSupportActionBar().setCustomView(actionbar);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Util.registerMediaButtonEventReceiver(this);
+
+ // Make sure to update theme
+ if (theme != null && !theme.equals(Util.getTheme(this))) {
+ restart();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ destroyed = true;
+ getImageLoader().clear();
+ }
+
+ @Override
+ public void finish() {
+ super.finish();
+ Util.disablePendingTransition(this);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
+ if(viewPager == null) {
+ String[] ids = new String[backStack.size() + 1];
+ ids[0] = currentFragment.getTag();
+ int i = 1;
+ for(SubsonicFragment frag: backStack) {
+ ids[i] = frag.getTag();
+ i++;
+ }
+ savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK, ids);
+ savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1);
+ } else {
+ pagerAdapter.onSaveInstanceState(savedInstanceState);
+ }
+ }
+ @Override
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ if(viewPager == null) {
+ super.onRestoreInstanceState(savedInstanceState);
+ int size = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE);
+ String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK);
+ FragmentManager fm = getSupportFragmentManager();
+ currentFragment = (SubsonicFragment)fm.findFragmentByTag(ids[0]);
+ currentFragment.setPrimaryFragment(true);
+ invalidateOptionsMenu();
+ for(int i = 1; i < size; i++) {
+ SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[i]);
+ backStack.add(frag);
+ }
+ recreateSpinner();
+ } else {
+ pagerAdapter.onRestoreInstanceState(savedInstanceState);
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ com.actionbarsherlock.view.MenuInflater menuInflater = getSupportMenuInflater();
+ if(pagerAdapter != null) {
+ pagerAdapter.onCreateOptionsMenu(menu, menuInflater);
+ } else if(currentFragment != null) {
+ currentFragment.onCreateOptionsMenu(menu, menuInflater);
+ }
+ return true;
+ }
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(pagerAdapter != null) {
+ return pagerAdapter.onOptionsItemSelected(item);
+ } else if(currentFragment != null) {
+ return currentFragment.onOptionsItemSelected(item);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
+ boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
+ boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
+ boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
+
+ if (isVolumeAdjust && isJukebox) {
+ getDownloadService().adjustJukeboxVolume(isVolumeUp);
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ super.setTitle(title);
+ if(pagerAdapter != null) {
+ pagerAdapter.recreateSpinner();
+ } else {
+ recreateSpinner();
+ }
+ }
+ public void setSubtitle(CharSequence title) {
+ getSupportActionBar().setSubtitle(title);
+ }
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ int top = spinnerAdapter.getCount() - 1;
+ if(position < top) {
+ for(int i = top; i > position; i--) {
+ if(pagerAdapter != null) {
+ pagerAdapter.removeCurrent();
+ } else {
+ removeCurrent();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+
+ public boolean onBackPressedSupport() {
+ if(pagerAdapter != null) {
+ return pagerAdapter.onBackPressed();
+ } else {
+ if(backStack.size() > 0) {
+ removeCurrent();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ public void replaceFragment(SubsonicFragment fragment, int id, int tag) {
+ if(pagerAdapter != null) {
+ pagerAdapter.replaceCurrent(fragment, id, tag);
+ } else {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ backStack.add(currentFragment);
+
+ currentFragment = fragment;
+ currentFragment.setPrimaryFragment(true);
+ invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(id, fragment, tag + "");
+ trans.commit();
+ recreateSpinner();
+ }
+ }
+ private void removeCurrent() {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ Fragment oldFrag = (Fragment)currentFragment;
+
+ currentFragment = (SubsonicFragment) backStack.remove(backStack.size() - 1);
+ currentFragment.setPrimaryFragment(true);
+ invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(oldFrag);
+ trans.commit();
+ recreateSpinner();
+ }
+
+ private void recreateSpinner() {
+ if(backStack.size() > 0) {
+ spinnerAdapter.clear();
+ for(int i = 0; i < backStack.size(); i++) {
+ spinnerAdapter.add(backStack.get(i).getTitle());
+ }
+ spinnerAdapter.add(currentFragment.getTitle());
+ spinnerAdapter.notifyDataSetChanged();
+ actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1);
+ getSupportActionBar().setDisplayShowCustomEnabled(true);
+ } else {
+ getSupportActionBar().setDisplayShowCustomEnabled(false);
+ }
+ }
+
+ protected void addTab(int titleRes, Class fragmentClass, Bundle args) {
+ pagerAdapter.addTab(getString(titleRes), fragmentClass, args);
+ }
+ protected void addTab(CharSequence title, Class fragmentClass, Bundle args) {
+ pagerAdapter.addTab(title, fragmentClass, args);
+ }
+
+ protected void restart() {
+ Intent intent = new Intent(this, this.getClass());
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtras(getIntent());
+ Util.startActivityWithoutTransition(this, intent);
+ }
+
+ private void applyTheme() {
+ theme = Util.getTheme(this);
+ if ("dark".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Dark);
+ } else if ("light".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Light);
+ } else if ("dark_fullscreen".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Dark_Fullscreen);
+ } else if ("light_fullscreen".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Light_Fullscreen);
+ } else if("holo".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Holo);
+ } else if("holo_fullscreen".equals(theme)) {
+ setTheme(R.style.Theme_DSub_Holo_Fullscreen);
+ }else {
+ setTheme(R.style.Theme_DSub_Holo);
+ }
+ }
+
+ public boolean isDestroyed() {
+ return destroyed;
+ }
+
+ public synchronized ImageLoader getImageLoader() {
+ if (IMAGE_LOADER == null) {
+ IMAGE_LOADER = new ImageLoader(this);
+ }
+ return IMAGE_LOADER;
+ }
+ public synchronized static ImageLoader getStaticImageLoader(Context context) {
+ if (IMAGE_LOADER == null) {
+ IMAGE_LOADER = new ImageLoader(context);
+ }
+ return IMAGE_LOADER;
+ }
+
+ public DownloadService getDownloadService() {
+ // If service is not available, request it to start and wait for it.
+ for (int i = 0; i < 5; i++) {
+ DownloadService downloadService = DownloadServiceImpl.getInstance();
+ if (downloadService != null) {
+ return downloadService;
+ }
+ Log.w(TAG, "DownloadService not running. Attempting to start it.");
+ startService(new Intent(this, DownloadServiceImpl.class));
+ Util.sleepQuietly(50L);
+ }
+ return DownloadServiceImpl.getInstance();
+ }
+
+ public ViewPager getViewPager() {
+ return viewPager;
+ }
+ public TabPagerAdapter getPagerAdapter() {
+ return pagerAdapter;
+ }
+
+ public void checkUpdates() {
+ try {
+ String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
+ int ver = Integer.parseInt(version.replace(".", ""));
+ Updater updater = new Updater(ver);
+ updater.checkUpdates(SubsonicActivity.this);
+ }
+ catch(Exception e) {
+
+ }
+ }
+
+ public static String getThemeName() {
+ return theme;
+ }
+
+ private void setUncaughtExceptionHandler() {
+ Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
+ if (!(handler instanceof SubsonicActivity.SubsonicUncaughtExceptionHandler)) {
+ Thread.setDefaultUncaughtExceptionHandler(new SubsonicActivity.SubsonicUncaughtExceptionHandler(this));
+ }
+ }
+
+ /**
+ * Logs the stack trace of uncaught exceptions to a file on the SD card.
+ */
+ private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+ private final Thread.UncaughtExceptionHandler defaultHandler;
+ private final Context context;
+
+ private SubsonicUncaughtExceptionHandler(Context context) {
+ this.context = context;
+ defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+ }
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable throwable) {
+ File file = null;
+ PrintWriter printWriter = null;
+ try {
+
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo("github.daneren2005.dsub", 0);
+ file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt");
+ printWriter = new PrintWriter(file);
+ printWriter.println("Android API level: " + Build.VERSION.SDK);
+ printWriter.println("Subsonic version name: " + packageInfo.versionName);
+ printWriter.println("Subsonic version code: " + packageInfo.versionCode);
+ printWriter.println();
+ throwable.printStackTrace(printWriter);
+ Log.i(TAG, "Stack trace written to " + file);
+ } catch (Throwable x) {
+ Log.e(TAG, "Failed to write stack trace to " + file, x);
+ } finally {
+ Util.close(printWriter);
+ if (defaultHandler != null) {
+ defaultHandler.uncaughtException(thread, throwable);
+ }
+
+ }
+ }
+ }
+
+ public class TabPagerAdapter extends FragmentPagerAdapter implements TabListener, ViewPager.OnPageChangeListener {
+ private SherlockFragmentActivity activity;
+ private ViewPager pager;
+ private ActionBar actionBar;
+ private SubsonicFragment currentFragment;
+ private List<TabInfo> tabs = new ArrayList<TabInfo>();
+ private List<List<SubsonicFragment>> frags = new ArrayList<List<SubsonicFragment>>();
+ private int currentPosition;
+
+ public TabPagerAdapter(SherlockFragmentActivity activity, ViewPager pager) {
+ super(activity.getSupportFragmentManager());
+ this.activity = activity;
+ this.actionBar = activity.getSupportActionBar();
+ this.pager = pager;
+ this.currentPosition = 0;
+ }
+
+ @Override
+ public Fragment getItem(int i) {
+ final TabInfo tabInfo = tabs.get(i);
+ SubsonicFragment frag = (SubsonicFragment) Fragment.instantiate(activity, tabInfo.fragmentClass.getName(), tabInfo.args);
+ List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
+ fragStack.add(frag);
+ frags.add(i, fragStack);
+ if(currentFragment == null) {
+ currentFragment = frag;
+ currentFragment.setPrimaryFragment(true);
+ }
+ return frag;
+ }
+
+ @Override
+ public int getCount() {
+ return tabs.size();
+ }
+
+ public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ if(currentFragment != null) {
+ currentFragment.onCreateOptionsMenu(menu, menuInflater);
+ }
+ }
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(currentFragment != null) {
+ return currentFragment.onOptionsItemSelected(item);
+ } else {
+ return false;
+ }
+ }
+
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ TabInfo tabInfo = (TabInfo) tab.getTag();
+ for (int i = 0; i < tabs.size(); i++) {
+ if ( tabs.get(i) == tabInfo ) {
+ pager.setCurrentItem(i);
+ break;
+ }
+ }
+ }
+
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
+
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {}
+
+ public void onPageScrollStateChanged(int arg0) {}
+
+ public void onPageScrolled(int arg0, float arg1, int arg2) {}
+
+ public void onPageSelected(int position) {
+ currentPosition = position;
+ actionBar.setSelectedNavigationItem(position);
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ List<SubsonicFragment> fragStack = frags.get(position);
+ currentFragment = fragStack.get(fragStack.size() - 1);
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(true);
+ }
+ activity.invalidateOptionsMenu();
+ recreateSpinner();
+ }
+
+ public void addTab(CharSequence title, Class fragmentClass, Bundle args) {
+ final TabInfo tabInfo = new TabInfo(fragmentClass, args);
+
+ Tab tab = actionBar.newTab();
+ tab.setText(title);
+ tab.setTabListener(this);
+ tab.setTag(tabInfo);
+
+ tabs.add(tabInfo);
+
+ actionBar.addTab(tab);
+ notifyDataSetChanged();
+ }
+
+ public void replaceCurrent(SubsonicFragment fragment, int id, int tag) {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ List<SubsonicFragment> fragStack = frags.get(currentPosition);
+ fragStack.add(fragment);
+
+ currentFragment = fragment;
+ currentFragment.setPrimaryFragment(true);
+ activity.invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(id, fragment, tag + "");
+ trans.commit();
+ recreateSpinner();
+ }
+
+ public void removeCurrent() {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ List<SubsonicFragment> fragStack = frags.get(currentPosition);
+ Fragment oldFrag = (Fragment)fragStack.remove(fragStack.size() - 1);
+
+ currentFragment = fragStack.get(fragStack.size() - 1);
+ currentFragment.setPrimaryFragment(true);
+ activity.invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(oldFrag);
+ trans.commit();
+ }
+
+ public boolean onBackPressed() {
+ List<SubsonicFragment> fragStack = frags.get(currentPosition);
+ if(fragStack.size() > 1) {
+ removeCurrent();
+ recreateSpinner();
+ return false;
+ } else {
+ if(currentPosition == 0) {
+ return true;
+ } else {
+ viewPager.setCurrentItem(0);
+ return false;
+ }
+ }
+ }
+
+ private void recreateSpinner() {
+ if(frags.isEmpty()) {
+ return;
+ }
+
+ List<SubsonicFragment> fragStack = frags.get(currentPosition);
+ if(fragStack.size() > 1) {
+ spinnerAdapter.clear();
+ for(int i = 0; i < fragStack.size(); i++) {
+ SubsonicFragment frag = fragStack.get(i);
+ spinnerAdapter.add(frag.getTitle());
+ }
+ spinnerAdapter.notifyDataSetChanged();
+ actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1);
+ actionBar.setDisplayShowCustomEnabled(true);
+ } else {
+ actionBar.setDisplayShowCustomEnabled(false);
+ }
+ }
+
+ public void invalidate() {
+ for (int i = 0; i < frags.size(); i++) {
+ List fragStack = (List)frags.get(i);
+ SubsonicFragment frag = (SubsonicFragment)fragStack.get(fragStack.size() - 1);
+ frag.invalidate();
+ }
+ }
+
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ for(int i = 0; i < frags.size(); i++) {
+ List<SubsonicFragment> fragStack = frags.get(i);
+ String[] ids = new String[fragStack.size()];
+
+ for(int j = 0; j < fragStack.size(); j++) {
+ ids[j] = fragStack.get(j).getTag();
+ }
+ savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK + i, ids);
+ savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE + i, fragStack.size());
+ }
+ savedInstanceState.putInt(Constants.MAIN_BACK_STACK_TABS, frags.size());
+ savedInstanceState.putInt(Constants.MAIN_BACK_STACK_POSITION, currentPosition);
+ }
+
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ int tabCount = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_TABS);
+ FragmentManager fm = activity.getSupportFragmentManager();
+ for(int i = 0; i < tabCount; i++) {
+ int stackSize = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE + i);
+ String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK + i);
+ List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
+
+ for(int j = 0; j < stackSize; j++) {
+ SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[j]);
+ fragStack.add(frag);
+ }
+
+ frags.add(i, fragStack);
+ }
+ currentPosition = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_POSITION);
+ List<SubsonicFragment> fragStack = frags.get(currentPosition);
+ currentFragment = fragStack.get(fragStack.size() - 1);
+ currentFragment.setPrimaryFragment(true);
+ activity.invalidateOptionsMenu();
+ }
+
+ private class TabInfo {
+ public final Class fragmentClass;
+ public final Bundle args;
+ public TabInfo(Class fragmentClass, Bundle args) {
+ this.fragmentClass = fragmentClass;
+ this.args = args;
+ }
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java
deleted file mode 100644
index a27ad1a5..00000000
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- 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 2009 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.activity;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.media.AudioManager;
-import android.media.MediaMetadataRetriever;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import com.actionbarsherlock.app.SherlockActivity;
-import github.daneren2005.dsub.domain.Artist;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.Playlist;
-import github.daneren2005.dsub.service.*;
-import github.daneren2005.dsub.updates.Updater;
-import github.daneren2005.dsub.util.*;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * @author Sindre Mehus
- */
-public class SubsonicTabActivity extends SherlockActivity {
-
- private static final String TAG = SubsonicTabActivity.class.getSimpleName();
- private static ImageLoader IMAGE_LOADER;
- protected static String theme;
-
- private boolean destroyed;
- private View homeButton;
- private View musicButton;
- private View playlistButton;
- private View nowPlayingButton;
-
- private static final int SHUFFLE_EVERYTHING = 0;
- private static final int SHUFFLE_YEAR = 1;
- private static final int SHUFFLE_YEAR_RANGE = 2;
- private static final int SHUFFLE_GENRE = 3;
-
- @Override
- protected void onCreate(Bundle bundle) {
- setUncaughtExceptionHandler();
- applyTheme();
- super.onCreate(bundle);
- startService(new Intent(this, DownloadServiceImpl.class));
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
- }
-
- @Override
- protected void onPostCreate(Bundle bundle) {
- super.onPostCreate(bundle);
-
- homeButton = findViewById(R.id.button_bar_home);
- homeButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- musicButton = findViewById(R.id.button_bar_music);
- musicButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- playlistButton = findViewById(R.id.button_bar_playlists);
- playlistButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- nowPlayingButton = findViewById(R.id.button_bar_now_playing);
- nowPlayingButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
- }
- });
-
- if (this instanceof MainActivity) {
- homeButton.setEnabled(false);
- } else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) {
- musicButton.setEnabled(false);
- } else if (this instanceof SelectPlaylistActivity) {
- playlistButton.setEnabled(false);
- } else if (this instanceof DownloadActivity || this instanceof LyricsActivity) {
- nowPlayingButton.setEnabled(false);
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Util.registerMediaButtonEventReceiver(this);
-
- // Make sure to update theme
- if (theme != null && !theme.equals(Util.getTheme(this))) {
- restart();
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- destroyed = true;
- getImageLoader().clear();
- }
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
- boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
- boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
- boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
-
- if (isVolumeAdjust && isJukebox) {
- getDownloadService().adjustJukeboxVolume(isVolumeUp);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- protected void restart() {
- Intent intent = new Intent(this, this.getClass());
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtras(getIntent());
- Util.startActivityWithoutTransition(this, intent);
- }
-
- @Override
- public void finish() {
- super.finish();
- Util.disablePendingTransition(this);
- }
-
- private void applyTheme() {
- theme = Util.getTheme(this);
- if ("dark".equals(theme)) {
- setTheme(R.style.Theme_DSub_Dark);
- } else if ("light".equals(theme)) {
- setTheme(R.style.Theme_DSub_Light);
- } else if ("dark_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Dark_Fullscreen);
- } else if ("light_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Light_Fullscreen);
- } else if("holo".equals(theme)) {
- setTheme(R.style.Theme_DSub_Holo);
- } else if("holo_fullscreen".equals(theme)) {
- setTheme(R.style.Theme_DSub_Holo_Fullscreen);
- }else {
- setTheme(R.style.Theme_DSub_Holo);
- }
- }
-
- public boolean isDestroyed() {
- return destroyed;
- }
-
- public void toggleStarred(final MusicDirectory.Entry entry) {
- final boolean starred = !entry.isStarred();
- entry.setStarred(starred);
-
- 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) {
- // UpdateView
- Util.toast(SubsonicTabActivity.this, getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getTitle()));
- }
-
- @Override
- protected void error(Throwable error) {
- 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 toggleStarred(final Artist entry) {
- final boolean starred = !entry.isStarred();
- entry.setStarred(starred);
-
- 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) {
- // UpdateView
- Util.toast(SubsonicTabActivity.this, getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- 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.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(SubsonicTabActivity.this, msg, false);
- }
- }.execute();
- }
-
- public void setProgressVisible(boolean visible) {
- View view = findViewById(R.id.tab_progress);
- if (view != null) {
- view.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
- }
-
- public void updateProgress(String message) {
- TextView view = (TextView) findViewById(R.id.tab_progress_message);
- if (view != null) {
- view.setText(message);
- }
- }
-
- public DownloadService getDownloadService() {
- // If service is not available, request it to start and wait for it.
- for (int i = 0; i < 5; i++) {
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- if (downloadService != null) {
- return downloadService;
- }
- Log.w(TAG, "DownloadService not running. Attempting to start it.");
- startService(new Intent(this, DownloadServiceImpl.class));
- Util.sleepQuietly(50L);
- }
- return DownloadServiceImpl.getInstance();
- }
-
- protected void warnIfNetworkOrStorageUnavailable() {
- if (!Util.isExternalStoragePresent()) {
- Util.toast(this, R.string.select_album_no_sdcard);
- } else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) {
- Util.toast(this, R.string.select_album_no_network);
- }
- }
-
- protected synchronized ImageLoader getImageLoader() {
- if (IMAGE_LOADER == null) {
- IMAGE_LOADER = new ImageLoader(this);
- }
- return IMAGE_LOADER;
- }
- public synchronized static ImageLoader getStaticImageLoader(Context context) {
- if (IMAGE_LOADER == null) {
- IMAGE_LOADER = new ImageLoader(context);
- }
- return IMAGE_LOADER;
- }
-
- 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);
- }
- protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
- downloadRecursively(id, name, false, save, append, autoplay, shuffle, background);
- }
- protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
- ModalBackgroundTask<List<MusicDirectory.Entry>> task = new ModalBackgroundTask<List<MusicDirectory.Entry>>(this, false) {
- private static final int MAX_SONGS = 500;
-
- @Override
- protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- MusicDirectory root;
- if(isDirectory)
- root = musicService.getMusicDirectory(id, name, false, SubsonicTabActivity.this, this);
- else
- root = musicService.getPlaylist(id, name, SubsonicTabActivity.this, this);
- List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
- getSongsRecursively(root, songs);
- return songs;
- }
-
- private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
- if (songs.size() > MAX_SONGS) {
- return;
- }
-
- for (MusicDirectory.Entry song : parent.getChildren(false, true)) {
- if (!song.isVideo()) {
- songs.add(song);
- }
- }
- for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- getSongsRecursively(musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, SubsonicTabActivity.this, this), songs);
- }
- }
-
- @Override
- protected void done(List<MusicDirectory.Entry> songs) {
- DownloadService downloadService = getDownloadService();
- if (!songs.isEmpty() && downloadService != null) {
- if (!append) {
- downloadService.clear();
- }
- warnIfNetworkOrStorageUnavailable();
- if(!background) {
- downloadService.download(songs, save, autoplay, false, shuffle);
- if(!append) {
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
- }
- }
- else {
- downloadService.downloadBackground(songs, save);
- }
- }
- }
- };
-
- task.execute();
- }
-
- protected void addToPlaylist(final List<MusicDirectory.Entry> songs) {
- if(songs.isEmpty()) {
- Util.toast(this, "No songs selected");
- return;
- }
-
- new LoadingTask<List<Playlist>>(this, true) {
- @Override
- protected List<Playlist> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- return musicService.getPlaylists(false, SubsonicTabActivity.this, this);
- }
-
- @Override
- protected void done(final List<Playlist> playlists) {
- List<String> names = new ArrayList<String>();
- for(Playlist playlist: playlists) {
- names.add(playlist.getName());
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(SubsonicTabActivity.this);
- builder.setTitle("Add to Playlist")
- .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- addToPlaylist(playlists.get(which), songs);
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
- }
-
- Util.toast(SubsonicTabActivity.this, msg, false);
- }
- }.execute();
- }
-
- private void addToPlaylist(final Playlist playlist, final List<MusicDirectory.Entry> songs) {
- new SilentBackgroundTask<Void>(this) {
- @Override
- protected Void doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- musicService.addToPlaylist(playlist.getId(), songs, SubsonicTabActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(SubsonicTabActivity.this, getResources().getString(R.string.updated_playlist, songs.size(), playlist.getName()));
- }
-
- @Override
- protected void error(Throwable error) {
- String msg;
- if (error instanceof OfflineException || error instanceof ServerTooOldException) {
- msg = getErrorMessage(error);
- } else {
- msg = getResources().getString(R.string.updated_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
- }
-
- Util.toast(SubsonicTabActivity.this, msg, false);
- }
- }.execute();
- }
-
- protected void onShuffleRequested() {
- if(Util.isOffline(this)) {
- Intent intent = new Intent(SubsonicTabActivity.this, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- return;
- }
-
- View dialogView = getLayoutInflater().inflate(R.layout.shuffle_dialog, null);
- final EditText startYearBox = (EditText)dialogView.findViewById(R.id.start_year);
- final EditText endYearBox = (EditText)dialogView.findViewById(R.id.end_year);
- final EditText genreBox = (EditText)dialogView.findViewById(R.id.genre);
-
- final SharedPreferences prefs = Util.getPreferences(SubsonicTabActivity.this);
- final String oldStartYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "");
- final String oldEndYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "");
- final String oldGenre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "");
-
- startYearBox.setText(oldStartYear);
- endYearBox.setText(oldEndYear);
- genreBox.setText(oldGenre);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(SubsonicTabActivity.this);
- builder.setTitle("Shuffle By")
- .setView(dialogView)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- Intent intent = new Intent(SubsonicTabActivity.this, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- String genre = genreBox.getText().toString();
- String startYear = startYearBox.getText().toString();
- String endYear = endYearBox.getText().toString();
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear);
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear);
- editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre);
- editor.commit();
-
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- })
- .setNegativeButton(R.string.common_cancel, null);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- public void displaySongInfo(final MusicDirectory.Entry song) {
- Integer bitrate = null;
- String format = null;
- long size = 0;
- try {
- DownloadFile downloadFile = new DownloadFile(SubsonicTabActivity.this, song, false);
- File file = downloadFile.getCompleteFile();
- if(file.exists()) {
- MediaMetadataRetriever metadata = new MediaMetadataRetriever();
- metadata.setDataSource(file.getAbsolutePath());
- String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
- bitrate = Integer.parseInt((tmp != null) ? tmp : "0") / 1000;
- format = FileUtil.getExtension(file.getName());
- size = file.length();
-
- if(Util.isOffline(SubsonicTabActivity.this)) {
- song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
- String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
- song.setYear(Integer.parseInt((year != null) ? year : "0"));
- }
- }
- } catch(Exception e) {
- Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver");
- }
-
- String msg = "";
- if(!song.isVideo()) {
- msg += "Artist: " + song.getArtist() + "\nAlbum: " + song.getAlbum();
- }
- if(song.getTrack() != null && song.getTrack() != 0) {
- msg += "\nTrack: " + song.getTrack();
- }
- if(song.getGenre() != null && !"".equals(song.getGenre())) {
- msg += "\nGenre: " + song.getGenre();
- }
- if(song.getYear() != null && song.getYear() != 0) {
- msg += "\nYear: " + song.getYear();
- }
- if(!Util.isOffline(SubsonicTabActivity.this)) {
- msg += "\nServer Format: " + song.getSuffix();
- if(song.getBitRate() != null && song.getBitRate() != 0) {
- msg += "\nServer Bitrate: " + song.getBitRate() + " kpbs";
- }
- }
- if(format != null && !"".equals(format)) {
- msg += "\nCached Format: " + format;
- }
- if(bitrate != null && bitrate != 0) {
- msg += "\nCached Bitrate: " + bitrate + " kpbs";
- }
- if(size != 0) {
- msg += "\nSize: " + Util.formatBytes(size);
- }
- if(song.getDuration() != null && song.getDuration() != 0) {
- msg += "\nLength: " + Util.formatDuration(song.getDuration());
- }
-
- new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(song.getTitle())
- .setMessage(msg)
- .show();
- }
-
- public void checkUpdates() {
- try {
- String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
- int ver = Integer.parseInt(version.replace(".", ""));
- Updater updater = new Updater(ver);
- updater.checkUpdates(SubsonicTabActivity.this);
- }
- catch(Exception e) {
-
- }
- }
-
- private void setUncaughtExceptionHandler() {
- Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
- if (!(handler instanceof SubsonicUncaughtExceptionHandler)) {
- Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this));
- }
- }
-
- /**
- * Logs the stack trace of uncaught exceptions to a file on the SD card.
- */
- private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
-
- private final Thread.UncaughtExceptionHandler defaultHandler;
- private final Context context;
-
- private SubsonicUncaughtExceptionHandler(Context context) {
- this.context = context;
- defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- }
-
- @Override
- public void uncaughtException(Thread thread, Throwable throwable) {
- File file = null;
- PrintWriter printWriter = null;
- try {
-
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo("github.daneren2005.dsub", 0);
- file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt");
- printWriter = new PrintWriter(file);
- printWriter.println("Android API level: " + Build.VERSION.SDK);
- printWriter.println("Subsonic version name: " + packageInfo.versionName);
- printWriter.println("Subsonic version code: " + packageInfo.versionCode);
- printWriter.println();
- throwable.printStackTrace(printWriter);
- Log.i(TAG, "Stack trace written to " + file);
- } catch (Throwable x) {
- Log.e(TAG, "Failed to write stack trace to " + file, x);
- } finally {
- Util.close(printWriter);
- if (defaultHandler != null) {
- defaultHandler.uncaughtException(thread, throwable);
- }
-
- }
- }
- }
-}
-
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
new file mode 100644
index 00000000..c745e6d2
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
@@ -0,0 +1,1135 @@
+package github.daneren2005.dsub.fragments;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Display;
+import android.view.GestureDetector;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.LayoutInflater;
+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;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.ViewFlipper;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.MenuInflater;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.PlayerState;
+import github.daneren2005.dsub.domain.RepeatMode;
+import github.daneren2005.dsub.service.DownloadFile;
+import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.HorizontalSlider;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.view.SongView;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.VisualizerView;
+
+import static github.daneren2005.dsub.domain.PlayerState.*;
+import github.daneren2005.dsub.util.*;
+import github.daneren2005.dsub.view.AutoRepeatButton;
+import java.util.ArrayList;
+import java.util.concurrent.ScheduledFuture;
+import com.mobeta.android.dslv.*;
+import github.daneren2005.dsub.activity.EqualizerActivity;
+import github.daneren2005.dsub.activity.SubsonicActivity;
+
+public class DownloadFragment extends SubsonicFragment implements OnGestureListener {
+ private static final String TAG = DownloadFragment.class.getSimpleName();
+
+ public static final int DIALOG_SAVE_PLAYLIST = 100;
+ private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10;
+ private static final int COLOR_BUTTON_ENABLED = Color.rgb(51, 181, 229);
+ private static final int COLOR_BUTTON_DISABLED = Color.rgb(206, 213, 211);
+ private static final int INCREMENT_TIME = 5000;
+
+ private ViewFlipper playlistFlipper;
+ private TextView emptyTextView;
+ private TextView songTitleTextView;
+ private ImageView albumArtImageView;
+ private DragSortListView playlistView;
+ private TextView positionTextView;
+ private TextView durationTextView;
+ private TextView statusTextView;
+ private HorizontalSlider progressBar;
+ private AutoRepeatButton previousButton;
+ private AutoRepeatButton nextButton;
+ private View pauseButton;
+ private View stopButton;
+ private View startButton;
+ private ImageButton repeatButton;
+ private Button equalizerButton;
+ private Button visualizerButton;
+ private Button jukeboxButton;
+ private View toggleListButton;
+ private ImageButton starButton;
+ private View mainLayout;
+ private ScheduledExecutorService executorService;
+ private DownloadFile currentPlaying;
+ private long currentRevision;
+ private GestureDetector gestureScanner;
+ private int swipeDistance;
+ private int swipeVelocity;
+ private VisualizerView visualizerView;
+ private boolean nowPlaying = true;
+ private ScheduledFuture<?> hideControlsFuture;
+ private SongListAdapter songListAdapter;
+ private SilentBackgroundTask<Void> onProgressChangedTask;
+
+ /**
+ * Called when the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.download, container, false);
+ setTitle(nowPlaying ? "Now Playing" : "Downloading");
+
+ mainLayout = rootView.findViewById(R.id.download_layout);
+ if(!primaryFragment) {
+ mainLayout.setVisibility(View.GONE);
+ }
+
+ WindowManager w = context.getWindowManager();
+ Display d = w.getDefaultDisplay();
+ swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
+ swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
+ gestureScanner = new GestureDetector(this);
+
+ playlistFlipper = (ViewFlipper)rootView.findViewById(R.id.download_playlist_flipper);
+ emptyTextView = (TextView)rootView.findViewById(R.id.download_empty);
+ songTitleTextView = (TextView)rootView.findViewById(R.id.download_song_title);
+ albumArtImageView = (ImageView)rootView.findViewById(R.id.download_album_art_image);
+ positionTextView = (TextView)rootView.findViewById(R.id.download_position);
+ durationTextView = (TextView)rootView.findViewById(R.id.download_duration);
+ statusTextView = (TextView)rootView.findViewById(R.id.download_status);
+ progressBar = (HorizontalSlider)rootView.findViewById(R.id.download_progress_bar);
+ playlistView = (DragSortListView)rootView.findViewById(R.id.download_list);
+ previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous);
+ nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next);
+ pauseButton =rootView.findViewById(R.id.download_pause);
+ stopButton =rootView.findViewById(R.id.download_stop);
+ startButton =rootView.findViewById(R.id.download_start);
+ repeatButton = (ImageButton)rootView.findViewById(R.id.download_repeat);
+ equalizerButton = (Button)rootView.findViewById(R.id.download_equalizer);
+ visualizerButton = (Button)rootView.findViewById(R.id.download_visualizer);
+ jukeboxButton = (Button)rootView.findViewById(R.id.download_jukebox);
+ LinearLayout visualizerViewLayout = (LinearLayout)rootView.findViewById(R.id.download_visualizer_view_layout);
+ toggleListButton =rootView.findViewById(R.id.download_toggle_list);
+
+ starButton = (ImageButton)rootView.findViewById(R.id.download_star);
+ starButton.setVisibility(Util.isOffline(context) ? 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();
+ toggleStarred(currentSong);
+ starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ }
+ }
+ });
+
+ View.OnTouchListener touchListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent me) {
+ return gestureScanner.onTouchEvent(me);
+ }
+ };
+ pauseButton.setOnTouchListener(touchListener);
+ stopButton.setOnTouchListener(touchListener);
+ startButton.setOnTouchListener(touchListener);
+ equalizerButton.setOnTouchListener(touchListener);
+ visualizerButton.setOnTouchListener(touchListener);
+ jukeboxButton.setOnTouchListener(touchListener);
+ emptyTextView.setOnTouchListener(touchListener);
+ albumArtImageView.setOnTouchListener(touchListener);
+
+ previousButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ warnIfNetworkOrStorageUnavailable();
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().previous();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }.execute();
+ setControlsVisible(true);
+ }
+ });
+ previousButton.setOnRepeatListener(new Runnable() {
+ public void run() {
+ changeProgress(-INCREMENT_TIME);
+ }
+ });
+
+ nextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ warnIfNetworkOrStorageUnavailable();
+ new SilentBackgroundTask<Boolean>(context) {
+ @Override
+ protected Boolean doInBackground() throws Throwable {
+ if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
+ getDownloadService().next();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected void done(Boolean result) {
+ if(result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }
+ }.execute();
+ setControlsVisible(true);
+ }
+ });
+ nextButton.setOnRepeatListener(new Runnable() {
+ public void run() {
+ changeProgress(INCREMENT_TIME);
+ }
+ });
+
+ pauseButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().pause();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }.execute();
+ }
+ });
+
+ stopButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().reset();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }.execute();
+ }
+ });
+
+ startButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ warnIfNetworkOrStorageUnavailable();
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ start();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }.execute();
+ }
+ });
+
+ repeatButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ RepeatMode repeatMode = getDownloadService().getRepeatMode().next();
+ getDownloadService().setRepeatMode(repeatMode);
+ onDownloadListChanged();
+ switch (repeatMode) {
+ case OFF:
+ Util.toast(context, R.string.download_repeat_off);
+ break;
+ case ALL:
+ Util.toast(context, R.string.download_repeat_all);
+ break;
+ case SINGLE:
+ Util.toast(context, R.string.download_repeat_single);
+ break;
+ default:
+ break;
+ }
+ setControlsVisible(true);
+ }
+ });
+
+ equalizerButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService != null && downloadService.getEqualizerController() != null
+ && downloadService.getEqualizerController().getEqualizer() != null) {
+ context.startActivity(new Intent(context, EqualizerActivity.class));
+ setControlsVisible(true);
+ } else {
+ Util.toast(context, "Failed to start equalizer. Try restarting.");
+ }
+ }
+ });
+
+ visualizerButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ boolean active = !visualizerView.isActive();
+ visualizerView.setActive(active);
+ boolean isActive = visualizerView.isActive();
+ getDownloadService().setShowVisualization(isActive);
+ updateButtons();
+ if(active == isActive) {
+ Util.toast(context, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
+ } else {
+ Util.toast(context, "Failed to start visualizer. Try restarting.");
+ }
+ setControlsVisible(true);
+ }
+ });
+
+ jukeboxButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ boolean jukeboxEnabled = !getDownloadService().isJukeboxEnabled();
+ getDownloadService().setJukeboxEnabled(jukeboxEnabled);
+ updateButtons();
+ Util.toast(context, jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
+ setControlsVisible(true);
+ }
+ });
+
+ toggleListButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ toggleFullscreenAlbumArt();
+ setControlsVisible(true);
+ }
+ });
+
+ progressBar.setOnSliderChangeListener(new HorizontalSlider.OnSliderChangeListener() {
+ @Override
+ public void onSliderChanged(View view, final int position, boolean inProgress) {
+ Util.toast(context, Util.formatDuration(position / 1000), true);
+ if (!inProgress) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().seekTo(position);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onProgressChanged();
+ }
+ }.execute();
+ }
+ setControlsVisible(true);
+ }
+ });
+ playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
+ if(nowPlaying) {
+ warnIfNetworkOrStorageUnavailable();
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().play(position);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ }.execute();
+ }
+ }
+ });
+ playlistView.setDropListener(new DragSortListView.DropListener() {
+ @Override
+ public void drop(int from, int to) {
+ getDownloadService().swap(nowPlaying, from, to);
+ onDownloadListChanged();
+ }
+ });
+ playlistView.setRemoveListener(new DragSortListView.RemoveListener() {
+ @Override
+ public void remove(int which) {
+ getDownloadService().remove(which);
+ onDownloadListChanged();
+ }
+ });
+
+ registerForContextMenu(playlistView);
+
+ DownloadService downloadService = getDownloadService();
+ if (downloadService != null && context.getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) {
+ context.getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE);
+ warnIfNetworkOrStorageUnavailable();
+ downloadService.setShufflePlayEnabled(true);
+ }
+
+ boolean visualizerAvailable = downloadService != null && downloadService.getVisualizerAvailable();
+ boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable();
+
+ if (!equalizerAvailable) {
+ equalizerButton.setVisibility(View.GONE);
+ }
+ if (!visualizerAvailable) {
+ visualizerButton.setVisibility(View.GONE);
+ } else {
+ visualizerView = new VisualizerView(context);
+ visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
+ }
+
+ // TODO: Extract to utility method and cache.
+ Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Storopia.ttf");
+ equalizerButton.setTypeface(typeface);
+ visualizerButton.setTypeface(typeface);
+ jukeboxButton.setTypeface(typeface);
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ if(Util.isOffline(context)) {
+ menuInflater.inflate(R.menu.nowplaying_offline, menu);
+ } else {
+ if(nowPlaying) {
+ menuInflater.inflate(R.menu.nowplaying, menu);
+ }
+ else {
+ menuInflater.inflate(R.menu.nowplaying_downloading, menu);
+ }
+
+ if(getDownloadService() != null && getDownloadService().getSleepTimer()) {
+ menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer);
+ }
+ }
+ if(getDownloadService() != null && getDownloadService().getKeepScreenOn()) {
+ menu.findItem(R.id.menu_screen_on_off).setTitle(R.string.download_menu_screen_off);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ if(menuItemSelected(menuItem.getItemId(), null)) {
+ return true;
+ }
+
+ return super.onOptionsItemSelected(menuItem);
+ }
+
+ @Override
+ public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+ if (view == playlistView) {
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
+
+ android.view.MenuInflater inflater = context.getMenuInflater();
+ if(Util.isOffline(context)) {
+ inflater.inflate(R.menu.nowplaying_context_offline, menu);
+ } else {
+ inflater.inflate(R.menu.nowplaying_context, menu);
+ menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star);
+ }
+
+ if (downloadFile.getSong().getParent() == null) {
+ menu.findItem(R.id.menu_show_album).setVisible(false);
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
+ return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem);
+ }
+
+ private boolean menuItemSelected(int menuItemId, final DownloadFile song) {
+ switch (menuItemId) {
+ case R.id.menu_show_album:
+ /*Intent intent = new Intent(context, SelectAlbumActivity.class);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getSong().getParent());
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getSong().getAlbum());
+ Util.startActivityWithoutTransition(context, intent);*/
+ return true;
+ case R.id.menu_lyrics:
+ SubsonicFragment fragment = new LyricsFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
+ args.putString(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.download_layout_container);
+ return true;
+ case R.id.menu_remove:
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().remove(song);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onDownloadListChanged();
+ }
+ }.execute();
+ return true;
+ case R.id.menu_delete:
+ List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(1);
+ songs.add(song.getSong());
+ getDownloadService().delete(songs);
+ return true;
+ case R.id.menu_remove_all:
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().setShufflePlayEnabled(false);
+ if(nowPlaying) {
+ getDownloadService().clear();
+ }
+ else {
+ getDownloadService().clearBackground();
+ }
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ onDownloadListChanged();
+ }
+ }.execute();
+ return true;
+ case R.id.menu_screen_on_off:
+ if (getDownloadService().getKeepScreenOn()) {
+ context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ getDownloadService().setKeepScreenOn(false);
+ } else {
+ context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ getDownloadService().setKeepScreenOn(true);
+ }
+ context.invalidateOptionsMenu();
+ return true;
+ case R.id.menu_shuffle:
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().shuffle();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ Util.toast(context, R.string.download_menu_shuffle_notification);
+ }
+ }.execute();
+ return true;
+ case R.id.menu_save_playlist:
+ context.showDialog(DIALOG_SAVE_PLAYLIST);
+ return true;
+ case R.id.menu_star:
+ toggleStarred(song.getSong());
+ return true;
+ case R.id.menu_toggle_now_playing:
+ toggleNowPlaying();
+ context.invalidateOptionsMenu();
+ return true;
+ case R.id.menu_toggle_timer:
+ if(getDownloadService().getSleepTimer()) {
+ getDownloadService().stopSleepTimer();
+ context.invalidateOptionsMenu();
+ } else {
+ startTimer();
+ }
+ return true;
+ case R.id.menu_add_playlist:
+ songs = new ArrayList<MusicDirectory.Entry>(1);
+ songs.add(song.getSong());
+ addToPlaylist(songs);
+ return true;
+ case R.id.menu_info:
+ displaySongInfo(song.getSong());
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final Handler handler = new Handler();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ });
+ }
+ };
+
+ executorService = Executors.newSingleThreadScheduledExecutor();
+ executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
+
+ setControlsVisible(true);
+
+ DownloadService downloadService = getDownloadService();
+ if (downloadService == null || downloadService.getCurrentPlaying() == null) {
+ playlistFlipper.setDisplayedChild(1);
+ }
+
+ onDownloadListChanged();
+ onCurrentChanged();
+ onProgressChanged();
+ scrollToCurrent();
+ if (downloadService != null && downloadService.getKeepScreenOn()) {
+ context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ } else {
+ context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ if (visualizerView != null && downloadService != null && downloadService.getShowVisualization()) {
+ visualizerView.setActive(true);
+ }
+
+ updateButtons();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ executorService.shutdown();
+ if (visualizerView != null && visualizerView.isActive()) {
+ visualizerView.setActive(false);
+ }
+ }
+
+ @Override
+ public void setPrimaryFragment(boolean primary) {
+ super.setPrimaryFragment(primary);
+ if(rootView != null) {
+ if(primary) {
+ mainLayout.setVisibility(View.VISIBLE);
+ } else {
+ mainLayout.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void scheduleHideControls() {
+ if (hideControlsFuture != null) {
+ hideControlsFuture.cancel(false);
+ }
+
+ final Handler handler = new Handler();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ setControlsVisible(false);
+ }
+ });
+ }
+ };
+ hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS);
+ }
+
+ private void setControlsVisible(boolean visible) {
+ try {
+ long duration = 1700L;
+ FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration);
+
+ if (visible) {
+ scheduleHideControls();
+ }
+ } catch(Exception e) {
+
+ }
+ }
+
+ private void updateButtons() {
+ SharedPreferences prefs = Util.getPreferences(context);
+ boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
+ if(equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
+ getDownloadService().getEqualizerController().isEnabled()) {
+ equalizerButton.setTextColor(COLOR_BUTTON_ENABLED);
+ } else {
+ equalizerButton.setTextColor(COLOR_BUTTON_DISABLED);
+ }
+
+ if (visualizerView != null) {
+ visualizerButton.setTextColor(visualizerView.isActive() ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
+ }
+
+ boolean jukeboxEnabled = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
+ jukeboxButton.setTextColor(jukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
+ }
+
+ // Scroll to current playing/downloading.
+ private void scrollToCurrent() {
+ if (getDownloadService() == null || songListAdapter == null) {
+ return;
+ }
+
+ for (int i = 0; i < songListAdapter.getCount(); i++) {
+ if (currentPlaying == playlistView.getItemAtPosition(i)) {
+ playlistView.setSelectionFromTop(i, 40);
+ return;
+ }
+ }
+ DownloadFile currentDownloading = getDownloadService().getCurrentDownloading();
+ for (int i = 0; i < songListAdapter.getCount(); i++) {
+ if (currentDownloading == playlistView.getItemAtPosition(i)) {
+ playlistView.setSelectionFromTop(i, 40);
+ return;
+ }
+ }
+ }
+
+ private void update() {
+ if (getDownloadService() == null) {
+ return;
+ }
+
+ if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) {
+ onDownloadListChanged();
+ }
+
+ if (currentPlaying != getDownloadService().getCurrentPlaying()) {
+ onCurrentChanged();
+ }
+
+ onProgressChanged();
+ }
+
+ protected void startTimer() {
+ View dialogView = context.getLayoutInflater().inflate(R.layout.start_timer, null);
+ final EditText lengthBox = (EditText)dialogView.findViewById(R.id.timer_length);
+
+ final SharedPreferences prefs = Util.getPreferences(context);
+ lengthBox.setText(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, ""));
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.menu_set_timer)
+ .setView(dialogView)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ String length = lengthBox.getText().toString();
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, length);
+ editor.commit();
+
+ getDownloadService().setSleepTimerDuration(Integer.parseInt(length));
+ getDownloadService().startSleepTimer();
+ context.invalidateOptionsMenu();
+ }
+ })
+ .setNegativeButton(R.string.common_cancel, null);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private void toggleFullscreenAlbumArt() {
+ scrollToCurrent();
+ if (playlistFlipper.getDisplayedChild() == 1) {
+ playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in));
+ playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_out));
+ playlistFlipper.setDisplayedChild(0);
+ } else {
+ playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_in));
+ playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_out));
+ playlistFlipper.setDisplayedChild(1);
+ }
+ }
+
+ private void start() {
+ DownloadService service = getDownloadService();
+ PlayerState state = service.getPlayerState();
+ if (state == PAUSED || state == COMPLETED || state == STOPPED) {
+ service.start();
+ } else if (state == STOPPED || state == IDLE) {
+ warnIfNetworkOrStorageUnavailable();
+ int current = service.getCurrentPlayingIndex();
+ // TODO: Use play() method.
+ if (current == -1) {
+ service.play(0);
+ } else {
+ service.play(current);
+ }
+ }
+ }
+ private void onDownloadListChanged() {
+ onDownloadListChanged(false);
+ }
+ private void onDownloadListChanged(boolean refresh) {
+ DownloadService downloadService = getDownloadService();
+ if (downloadService == null) {
+ return;
+ }
+
+ List<DownloadFile> list;
+ if(nowPlaying) {
+ list = downloadService.getSongs();
+ }
+ else {
+ list = downloadService.getBackgroundDownloads();
+ }
+
+ if(downloadService.isShufflePlayEnabled()) {
+ emptyTextView.setText(R.string.download_shuffle_loading);
+ }
+ else {
+ emptyTextView.setText(R.string.download_empty);
+ }
+
+ if(songListAdapter == null || refresh) {
+ playlistView.setAdapter(songListAdapter = new SongListAdapter(list));
+ } else {
+ songListAdapter.notifyDataSetChanged();
+ }
+ emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
+ currentRevision = downloadService.getDownloadListUpdateRevision();
+
+ switch (downloadService.getRepeatMode()) {
+ case OFF:
+ if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) {
+ repeatButton.setImageResource(R.drawable.media_repeat_off_light);
+ } else {
+ repeatButton.setImageResource(R.drawable.media_repeat_off);
+ }
+ break;
+ case ALL:
+ repeatButton.setImageResource(R.drawable.media_repeat_all);
+ break;
+ case SINGLE:
+ repeatButton.setImageResource(R.drawable.media_repeat_single);
+ break;
+ default:
+ break;
+ }
+
+ setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
+ }
+
+ private void onCurrentChanged() {
+ DownloadService downloadService = getDownloadService();
+ if (downloadService == null) {
+ return;
+ }
+
+ currentPlaying = downloadService.getCurrentPlaying();
+ if (currentPlaying != null) {
+ MusicDirectory.Entry song = currentPlaying.getSong();
+ songTitleTextView.setText(song.getTitle());
+ getImageLoader().loadImage(albumArtImageView, song, true, true);
+ starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
+ } else {
+ songTitleTextView.setText(null);
+ getImageLoader().loadImage(albumArtImageView, null, true, false);
+ starButton.setImageResource(android.R.drawable.btn_star_big_off);
+ setSubtitle(null);
+ }
+ }
+
+ private void onProgressChanged() {
+ // Make sure to only be trying to run one of these at a time
+ if (getDownloadService() == null || onProgressChangedTask != null) {
+ return;
+ }
+
+ onProgressChangedTask = new SilentBackgroundTask<Void>(context) {
+ DownloadService downloadService;
+ boolean isJukeboxEnabled;
+ int millisPlayed;
+ Integer duration;
+ PlayerState playerState;
+
+ @Override
+ protected Void doInBackground() throws Throwable {
+ downloadService = getDownloadService();
+ isJukeboxEnabled = downloadService.isJukeboxEnabled();
+ millisPlayed = Math.max(0, downloadService.getPlayerPosition());
+ duration = downloadService.getPlayerDuration();
+ playerState = getDownloadService().getPlayerState();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ if (currentPlaying != null) {
+ int millisTotal = duration == null ? 0 : duration;
+
+ positionTextView.setText(Util.formatDuration(millisPlayed / 1000));
+ durationTextView.setText(Util.formatDuration(millisTotal / 1000));
+ progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug.
+ progressBar.setProgress(millisPlayed);
+ progressBar.setSlidingEnabled(currentPlaying.isWorkDone() || isJukeboxEnabled);
+ } else {
+ positionTextView.setText("0:00");
+ durationTextView.setText("-:--");
+ progressBar.setProgress(0);
+ progressBar.setSlidingEnabled(false);
+ }
+
+ switch (playerState) {
+ case DOWNLOADING:
+ long bytes = currentPlaying.getPartialFile().length();
+ statusTextView.setText(context.getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, context)));
+ break;
+ case PREPARING:
+ statusTextView.setText(R.string.download_playerstate_buffering);
+ break;
+ default:
+ if(currentPlaying != null) {
+ String artist = "";
+ if(currentPlaying.getSong().getArtist() != null) {
+ artist = currentPlaying.getSong().getArtist() + " - ";
+ }
+ statusTextView.setText(artist + currentPlaying.getSong().getAlbum());
+ } else {
+ statusTextView.setText(null);
+ }
+ break;
+ }
+
+ switch (playerState) {
+ case STARTED:
+ pauseButton.setVisibility(View.VISIBLE);
+ stopButton.setVisibility(View.INVISIBLE);
+ startButton.setVisibility(View.INVISIBLE);
+ break;
+ case DOWNLOADING:
+ case PREPARING:
+ pauseButton.setVisibility(View.INVISIBLE);
+ stopButton.setVisibility(View.VISIBLE);
+ startButton.setVisibility(View.INVISIBLE);
+ break;
+ default:
+ pauseButton.setVisibility(View.INVISIBLE);
+ stopButton.setVisibility(View.INVISIBLE);
+ startButton.setVisibility(View.VISIBLE);
+ break;
+ }
+
+ jukeboxButton.setTextColor(isJukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
+ onProgressChangedTask = null;
+ }
+ };
+ onProgressChangedTask.execute();
+ }
+
+ private void changeProgress(final int ms) {
+ final DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ new SilentBackgroundTask<Void>(context) {
+ boolean isJukeboxEnabled;
+ int msPlayed;
+ Integer duration;
+ PlayerState playerState;
+ int seekTo;
+
+ @Override
+ protected Void doInBackground() throws Throwable {
+ msPlayed = Math.max(0, downloadService.getPlayerPosition());
+ duration = downloadService.getPlayerDuration();
+ playerState = getDownloadService().getPlayerState();
+ int msTotal = duration == null ? 0 : duration;
+ if(msPlayed + ms > msTotal) {
+ seekTo = msTotal;
+ } else {
+ seekTo = msPlayed + ms;
+ }
+ downloadService.seekTo(seekTo);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ progressBar.setProgress(seekTo);
+ }
+ }.execute();
+ }
+
+ private class SongListAdapter extends ArrayAdapter<DownloadFile> {
+ public SongListAdapter(List<DownloadFile> entries) {
+ super(context, android.R.layout.simple_list_item_1, entries);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ SongView view;
+ if (convertView != null && convertView instanceof SongView) {
+ view = (SongView) convertView;
+ } else {
+ view = new SongView(context);
+ }
+ DownloadFile downloadFile = getItem(position);
+ view.setSong(downloadFile.getSong(), false);
+ return view;
+ }
+ }
+
+ @Override
+ public boolean onDown(MotionEvent me) {
+ setControlsVisible(true);
+ return false;
+ }
+
+ public GestureDetector getGestureDetector() {
+ return gestureScanner;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ DownloadService downloadService = getDownloadService();
+ if (downloadService == null) {
+ return false;
+ }
+ Log.d(TAG, "onFling");
+
+ // Right to Left swipe
+ if (e1.getX() - e2.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
+ warnIfNetworkOrStorageUnavailable();
+ if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) {
+ downloadService.next();
+ onCurrentChanged();
+ onProgressChanged();
+ }
+ return true;
+ }
+
+ // Left to Right swipe
+ else if (e2.getX() - e1.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
+ warnIfNetworkOrStorageUnavailable();
+ downloadService.previous();
+ onCurrentChanged();
+ onProgressChanged();
+ return true;
+ }
+
+ // Top to Bottom swipe
+ else if (e2.getY() - e1.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
+ warnIfNetworkOrStorageUnavailable();
+ downloadService.seekTo(downloadService.getPlayerPosition() + 30000);
+ onProgressChanged();
+ return true;
+ }
+
+ // Bottom to Top swipe
+ else if (e1.getY() - e2.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
+ warnIfNetworkOrStorageUnavailable();
+ downloadService.seekTo(downloadService.getPlayerPosition() - 8000);
+ onProgressChanged();
+ return true;
+ }
+
+ return false;
+ }
+
+ private void toggleNowPlaying() {
+ nowPlaying = !nowPlaying;
+ setTitle(nowPlaying ? "Now Playing" : "Downloading");
+ onDownloadListChanged(true);
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ return false;
+ }
+
+ @Override
+ public void onShowPress(MotionEvent e) {
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return false;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java
new file mode 100644
index 00000000..0b247986
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/LyricsFragment.java
@@ -0,0 +1,81 @@
+/*
+ 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 2009 (C) Sindre Mehus
+ */
+
+package github.daneren2005.dsub.fragments;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Lyrics;
+import github.daneren2005.dsub.service.MusicService;
+import github.daneren2005.dsub.service.MusicServiceFactory;
+import github.daneren2005.dsub.util.BackgroundTask;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+
+/**
+ * Displays song lyrics.
+ *
+ * @author Sindre Mehus
+ */
+public final class LyricsFragment extends SubsonicFragment {
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ setTitle(R.string.download_menu_lyrics);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.lyrics, container, false);
+ load();
+
+ return rootView;
+ }
+
+ private void load() {
+ BackgroundTask<Lyrics> task = new TabBackgroundTask<Lyrics>(this) {
+ @Override
+ protected Lyrics doInBackground() throws Throwable {
+ String artist = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST);
+ String title = getArguments().getString(Constants.INTENT_EXTRA_NAME_TITLE);
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ return musicService.getLyrics(artist, title, context, this);
+ }
+
+ @Override
+ protected void done(Lyrics result) {
+ TextView artistView = (TextView) rootView.findViewById(R.id.lyrics_artist);
+ TextView titleView = (TextView) rootView.findViewById(R.id.lyrics_title);
+ TextView textView = (TextView) rootView.findViewById(R.id.lyrics_text);
+ if (result != null && result.getArtist() != null) {
+ artistView.setText(result.getArtist());
+ titleView.setText(result.getTitle());
+ textView.setText(result.getText());
+ } else {
+ artistView.setText(R.string.lyrics_nomatch);
+ }
+ }
+ };
+ task.execute();
+ }
+} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
new file mode 100644
index 00000000..ec938ca9
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -0,0 +1,314 @@
+package github.daneren2005.dsub.fragments;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.StatFs;
+import android.preference.PreferenceManager;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.FileUtil;
+import github.daneren2005.dsub.util.MergeAdapter;
+import github.daneren2005.dsub.util.Util;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.MenuInflater;
+import github.daneren2005.dsub.util.ModalBackgroundTask;
+import github.daneren2005.dsub.view.ChangeLog;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MainFragment extends SubsonicFragment {
+ private LayoutInflater inflater;
+
+ private static final int MENU_GROUP_SERVER = 10;
+ private static final int MENU_ITEM_SERVER_1 = 101;
+ private static final int MENU_ITEM_SERVER_2 = 102;
+ private static final int MENU_ITEM_SERVER_3 = 103;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ this.inflater = inflater;
+ rootView = inflater.inflate(R.layout.home, container, false);
+
+ loadSettings();
+ createLayout();
+
+ return rootView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.main, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ switch (item.getItemId()) {
+ case R.id.menu_log:
+ getLogs();
+ return true;
+ case R.id.menu_about:
+ showAboutDialog();
+ return true;
+ case R.id.menu_changelog:
+ ChangeLog changeLog = new ChangeLog(context, Util.getPreferences(context));
+ changeLog.getFullLogDialog().show();
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ android.view.MenuItem menuItem1 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_1, MENU_ITEM_SERVER_1, Util.getServerName(context, 1));
+ android.view.MenuItem menuItem2 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_2, MENU_ITEM_SERVER_2, Util.getServerName(context, 2));
+ android.view.MenuItem menuItem3 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_3, MENU_ITEM_SERVER_3, Util.getServerName(context, 3));
+ menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
+ menu.setHeaderTitle(R.string.main_select_server);
+
+ switch (Util.getActiveServer(context)) {
+ case 1:
+ menuItem1.setChecked(true);
+ break;
+ case 2:
+ menuItem2.setChecked(true);
+ break;
+ case 3:
+ menuItem3.setChecked(true);
+ break;
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ switch (menuItem.getItemId()) {
+ case MENU_ITEM_SERVER_1:
+ setActiveServer(1);
+ break;
+ case MENU_ITEM_SERVER_2:
+ setActiveServer(2);
+ break;
+ case MENU_ITEM_SERVER_3:
+ setActiveServer(3);
+ break;
+ default:
+ return super.onContextItemSelected(menuItem);
+ }
+
+ context.getPagerAdapter().invalidate();
+ return true;
+ }
+
+ @Override
+ protected void refresh(boolean refresh) {
+ createLayout();
+ }
+
+ private void createLayout() {
+ View buttons = inflater.inflate(R.layout.main_buttons, null);
+
+ final View serverButton = buttons.findViewById(R.id.main_select_server);
+ final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2);
+ final TextView offlineButton = (TextView) buttons.findViewById(R.id.main_offline);
+ offlineButton.setText(Util.isOffline(context) ? R.string.main_online : R.string.main_offline);
+
+ final View albumsTitle = buttons.findViewById(R.id.main_albums);
+ final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest);
+ final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random);
+ final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest);
+ final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent);
+ final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent);
+ final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred);
+
+ final View dummyView = rootView.findViewById(R.id.main_dummy);
+
+ int instance = Util.getActiveServer(context);
+ String name = Util.getServerName(context, instance);
+ serverTextView.setText(name);
+
+ ListView list = (ListView) rootView.findViewById(R.id.main_list);
+
+ MergeAdapter adapter = new MergeAdapter();
+ if (!Util.isOffline(context)) {
+ adapter.addViews(Arrays.asList(serverButton), true);
+ }
+ adapter.addView(offlineButton, true);
+ if (!Util.isOffline(context)) {
+ adapter.addView(albumsTitle, false);
+ adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsStarredButton, albumsRecentButton, albumsFrequentButton), true);
+ }
+ list.setAdapter(adapter);
+ registerForContextMenu(dummyView);
+
+ list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if (view == serverButton) {
+ dummyView.showContextMenu();
+ } else if (view == offlineButton) {
+ toggleOffline();
+ } else if (view == albumsNewestButton) {
+ showAlbumList("newest");
+ } else if (view == albumsRandomButton) {
+ showAlbumList("random");
+ } else if (view == albumsHighestButton) {
+ showAlbumList("highest");
+ } else if (view == albumsRecentButton) {
+ showAlbumList("recent");
+ } else if (view == albumsFrequentButton) {
+ showAlbumList("frequent");
+ } else if (view == albumsStarredButton) {
+ showAlbumList("starred");
+ }
+ }
+ });
+ }
+
+ private void loadSettings() {
+ PreferenceManager.setDefaultValues(context, R.xml.settings, false);
+ SharedPreferences prefs = Util.getPreferences(context);
+ if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
+ editor.commit();
+ }
+
+ if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false);
+ editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
+ editor.commit();
+ }
+ }
+
+ private void setActiveServer(int instance) {
+ if (Util.getActiveServer(context) != instance) {
+ DownloadService service = getDownloadService();
+ if (service != null) {
+ service.clearIncomplete();
+ }
+ Util.setActiveServer(context, instance);
+ }
+ }
+
+ private void toggleOffline() {
+ Util.setOffline(context, !Util.isOffline(context));
+ context.getPagerAdapter().invalidate();
+ }
+
+ private void showAlbumList(String type) {
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
+ args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
+ args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.home_layout);
+ }
+
+ private void showAboutDialog() {
+ try {
+ File rootFolder = FileUtil.getMusicDirectory(context);
+ StatFs stat = new StatFs(rootFolder.getPath());
+ long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
+ long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
+
+ String msg = getResources().getString(R.string.main_about_text,
+ context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName,
+ Util.formatBytes(FileUtil.getUsedSize(context, rootFolder)),
+ Util.formatBytes(Util.getCacheSizeMB(context) * 1024L * 1024L),
+ Util.formatBytes(bytesAvailableFs),
+ Util.formatBytes(bytesTotalFs));
+ Util.info(context, R.string.main_about_title, msg);
+ } catch(Exception e) {
+ Util.toast(context, "Failed to open dialog");
+ }
+ }
+
+ private void getLogs() {
+ try {
+ final String version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
+ new ModalBackgroundTask<File>(context, false) {
+ @Override
+ protected File doInBackground() throws Throwable {
+ updateProgress("Gathering Logs");
+ File logcat = new File(FileUtil.getSubsonicDirectory(), "logcat.txt");
+ Process logcatProc = null;
+
+ try {
+ List<String> progs = new ArrayList<String>();
+ progs.add("logcat");
+ progs.add("-v");
+ progs.add("time");
+ progs.add("-d");
+ progs.add("-f");
+ progs.add(logcat.getPath());
+ progs.add("*:I");
+
+ logcatProc = Runtime.getRuntime().exec(progs.toArray(new String[0]));
+ logcatProc.waitFor();
+ } catch(Exception e) {
+ Util.toast(context, "Failed to gather logs");
+ } finally {
+ if(logcatProc != null) {
+ logcatProc.destroy();
+ }
+ }
+
+ return logcat;
+ }
+
+ @Override
+ protected void done(File logcat) {
+ Intent email = new Intent(android.content.Intent.ACTION_SEND);
+ email.setType("text/plain");
+ email.putExtra(Intent.EXTRA_EMAIL, new String[] {"dsub.android@gmail.com"});
+ email.putExtra(Intent.EXTRA_SUBJECT, "DSub " + version + " Error Logs");
+ email.putExtra(Intent.EXTRA_TEXT, "Describe the problem here");
+ Uri attachment = Uri.fromFile(logcat);
+ email.putExtra(Intent.EXTRA_STREAM, attachment);
+ startActivity(email);
+ }
+ }.execute();
+ } catch(Exception e) {}
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java
new file mode 100644
index 00000000..446285d1
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java
@@ -0,0 +1,336 @@
+package github.daneren2005.dsub.fragments;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.MenuItem;
+import android.widget.AdapterView;
+import android.widget.ImageButton;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.net.Uri;
+import android.support.v4.app.FragmentTransaction;
+import android.view.ViewGroup;
+import com.actionbarsherlock.view.Menu;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.SearchActivity;
+import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.SearchCritera;
+import github.daneren2005.dsub.domain.SearchResult;
+import github.daneren2005.dsub.service.MusicService;
+import github.daneren2005.dsub.service.MusicServiceFactory;
+import github.daneren2005.dsub.service.DownloadService;
+import github.daneren2005.dsub.view.ArtistAdapter;
+import github.daneren2005.dsub.util.BackgroundTask;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.view.EntryAdapter;
+import github.daneren2005.dsub.util.MergeAdapter;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+
+public class SearchFragment extends SubsonicFragment {
+ private static final int DEFAULT_ARTISTS = 3;
+ private static final int DEFAULT_ALBUMS = 5;
+ private static final int DEFAULT_SONGS = 10;
+
+ private static final int MAX_ARTISTS = 10;
+ private static final int MAX_ALBUMS = 20;
+ private static final int MAX_SONGS = 25;
+ private ListView list;
+
+ private View artistsHeading;
+ private View albumsHeading;
+ private View songsHeading;
+ private TextView searchButton;
+ private View moreArtistsButton;
+ private View moreAlbumsButton;
+ private View moreSongsButton;
+ private SearchResult searchResult;
+ private MergeAdapter mergeAdapter;
+ private ArtistAdapter artistAdapter;
+ private ListAdapter moreArtistsAdapter;
+ private EntryAdapter albumAdapter;
+ private ListAdapter moreAlbumsAdapter;
+ private ListAdapter moreSongsAdapter;
+ private EntryAdapter songAdapter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.search, container, false);
+ setTitle(R.string.search_title);
+
+ View buttons = inflater.inflate(R.layout.search_buttons, null);
+
+ artistsHeading = buttons.findViewById(R.id.search_artists);
+ albumsHeading = buttons.findViewById(R.id.search_albums);
+ songsHeading = buttons.findViewById(R.id.search_songs);
+
+ searchButton = (TextView) buttons.findViewById(R.id.search_search);
+ moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
+ moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
+ moreSongsButton = buttons.findViewById(R.id.search_more_songs);
+
+ list = (ListView) rootView.findViewById(R.id.search_list);
+
+ list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if (view == searchButton) {
+ context.onSearchRequested();
+ } else if (view == moreArtistsButton) {
+ expandArtists();
+ } else if (view == moreAlbumsButton) {
+ expandAlbums();
+ } else if (view == moreSongsButton) {
+ expandSongs();
+ } else {
+ Object item = parent.getItemAtPosition(position);
+ if (item instanceof Artist) {
+ onArtistSelected((Artist) item);
+ } else if (item instanceof MusicDirectory.Entry) {
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
+ if (entry.isDirectory()) {
+ onAlbumSelected(entry, false);
+ } else if (entry.isVideo()) {
+ onVideoSelected(entry);
+ } else {
+ onSongSelected(entry, false, true, true, false);
+ }
+
+ }
+ }
+ }
+ });
+ registerForContextMenu(list);
+ ((SearchActivity)context).onSupportNewIntent(context.getIntent());
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.search, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ Object selectedItem = list.getItemAtPosition(info.position);
+ onCreateContextMenu(menu, view, menuInfo, selectedItem);
+ if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) {
+ menu.removeItem(R.id.song_menu_remove_playlist);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ Object selectedItem = list.getItemAtPosition(info.position);
+
+ if(onContextItemSelected(menuItem, selectedItem)) {
+ return true;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void setPrimaryFragment(boolean primary) {
+ super.setPrimaryFragment(primary);
+ if(rootView != null && primary) {
+ ((SearchActivity)context).onSupportNewIntent(context.getIntent());
+ }
+ }
+
+ public void search(final String query, final boolean autoplay) {
+ mergeAdapter = new MergeAdapter();
+ list.setAdapter(mergeAdapter);
+
+ BackgroundTask<SearchResult> task = new TabBackgroundTask<SearchResult>(this) {
+ @Override
+ protected SearchResult doInBackground() throws Throwable {
+ SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS);
+ MusicService service = MusicServiceFactory.getMusicService(context);
+ return service.search(criteria, context, this);
+ }
+
+ @Override
+ protected void done(SearchResult result) {
+ searchResult = result;
+ populateList();
+ if (autoplay) {
+ autoplay();
+ }
+
+ }
+ };
+ task.execute();
+ }
+
+ public void populateList() {
+ mergeAdapter = new MergeAdapter();
+ mergeAdapter.addView(searchButton, true);
+
+ if (searchResult != null) {
+ List<Artist> artists = searchResult.getArtists();
+ if (!artists.isEmpty()) {
+ mergeAdapter.addView(artistsHeading);
+ List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
+ artistAdapter = new ArtistAdapter(context, displayedArtists);
+ mergeAdapter.addAdapter(artistAdapter);
+ if (artists.size() > DEFAULT_ARTISTS) {
+ moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true);
+ }
+ }
+
+ List<MusicDirectory.Entry> albums = searchResult.getAlbums();
+ if (!albums.isEmpty()) {
+ mergeAdapter.addView(albumsHeading);
+ List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
+ albumAdapter = new EntryAdapter(context, getImageLoader(), displayedAlbums, false);
+ mergeAdapter.addAdapter(albumAdapter);
+ if (albums.size() > DEFAULT_ALBUMS) {
+ moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true);
+ }
+ }
+
+ List<MusicDirectory.Entry> songs = searchResult.getSongs();
+ if (!songs.isEmpty()) {
+ mergeAdapter.addView(songsHeading);
+ List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
+ songAdapter = new EntryAdapter(context, getImageLoader(), displayedSongs, false);
+ mergeAdapter.addAdapter(songAdapter);
+ if (songs.size() > DEFAULT_SONGS) {
+ moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true);
+ }
+ }
+
+ boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
+ searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
+ }
+
+ list.setAdapter(mergeAdapter);
+ }
+
+ private void expandArtists() {
+ artistAdapter.clear();
+ for (Artist artist : searchResult.getArtists()) {
+ artistAdapter.add(artist);
+ }
+ artistAdapter.notifyDataSetChanged();
+ mergeAdapter.removeAdapter(moreArtistsAdapter);
+ mergeAdapter.notifyDataSetChanged();
+ }
+
+ private void expandAlbums() {
+ albumAdapter.clear();
+ for (MusicDirectory.Entry album : searchResult.getAlbums()) {
+ albumAdapter.add(album);
+ }
+ albumAdapter.notifyDataSetChanged();
+ mergeAdapter.removeAdapter(moreAlbumsAdapter);
+ mergeAdapter.notifyDataSetChanged();
+ }
+
+ private void expandSongs() {
+ songAdapter.clear();
+ for (MusicDirectory.Entry song : searchResult.getSongs()) {
+ songAdapter.add(song);
+ }
+ songAdapter.notifyDataSetChanged();
+ mergeAdapter.removeAdapter(moreSongsAdapter);
+ mergeAdapter.notifyDataSetChanged();
+ }
+
+ private void onArtistSelected(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());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.search_layout);
+ }
+
+ private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
+ int id = R.id.search_layout;
+ Bundle args;
+ if(album.getParent() != null) {
+ SubsonicFragment parentFragment = new SelectDirectoryFragment();
+ args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getParent());
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getArtist());
+ parentFragment.setArguments(args);
+
+ replaceFragment(parentFragment, R.id.search_layout);
+ id = R.id.select_album_layout;
+ }
+
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, id);
+ }
+
+ private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) {
+ DownloadService downloadService = getDownloadService();
+ if (downloadService != null) {
+ if (!append) {
+ downloadService.clear();
+ }
+ downloadService.download(Arrays.asList(song), save, false, playNext, false);
+ if (autoplay) {
+ downloadService.play(downloadService.size() - 1);
+ }
+
+ Util.toast(context, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
+ }
+ }
+
+ private void onVideoSelected(MusicDirectory.Entry entry) {
+ int maxBitrate = Util.getMaxVideoBitrate(context);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, entry.getId())));
+ startActivity(intent);
+ }
+
+ private void autoplay() {
+ if (!searchResult.getSongs().isEmpty()) {
+ onSongSelected(searchResult.getSongs().get(0), false, false, true, false);
+ } else if (!searchResult.getAlbums().isEmpty()) {
+ onAlbumSelected(searchResult.getAlbums().get(0), true);
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
new file mode 100644
index 00000000..8485f342
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
@@ -0,0 +1,204 @@
+package github.daneren2005.dsub.fragments;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import com.actionbarsherlock.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Indexes;
+import github.daneren2005.dsub.domain.MusicFolder;
+import github.daneren2005.dsub.service.MusicService;
+import github.daneren2005.dsub.service.MusicServiceFactory;
+import github.daneren2005.dsub.util.BackgroundTask;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.FileUtil;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.ArtistAdapter;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SelectArtistFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = SelectArtistFragment.class.getSimpleName();
+ private static final int MENU_GROUP_MUSIC_FOLDER = 10;
+
+ private ListView artistList;
+ private View folderButtonParent;
+ private View folderButton;
+ private TextView folderName;
+ private List<MusicFolder> musicFolders = null;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.select_artist, container, false);
+
+ artistList = (ListView) rootView.findViewById(R.id.select_artist_list);
+ artistList.setOnItemClickListener(this);
+
+ folderButtonParent = inflater.inflate(R.layout.select_artist_header, artistList, false);
+ folderName = (TextView) folderButtonParent.findViewById(R.id.select_artist_folder_2);
+ artistList.addHeaderView(folderButtonParent);
+ folderButton = folderButtonParent.findViewById(R.id.select_artist_folder);
+
+ registerForContextMenu(artistList);
+ invalidated = true;
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.select_artist, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ Object entry = artistList.getItemAtPosition(info.position);
+
+ if (entry instanceof Artist) {
+ onCreateContextMenu(menu, view, menuInfo, entry);
+ } else if (info.position == 0) {
+ String musicFolderId = Util.getSelectedMusicFolderId(context);
+ MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders);
+ if (musicFolderId == null) {
+ menuItem.setChecked(true);
+ }
+ if (musicFolders != null) {
+ for (int i = 0; i < musicFolders.size(); i++) {
+ MusicFolder musicFolder = musicFolders.get(i);
+ menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName());
+ if (musicFolder.getId().equals(musicFolderId)) {
+ menuItem.setChecked(true);
+ }
+ }
+ }
+ menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ Artist artist = (Artist) artistList.getItemAtPosition(info.position);
+
+ if (artist != null) {
+ return onContextItemSelected(menuItem, artist);
+ } else if (info.position == 0) {
+ MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId());
+ String musicFolderId = selectedFolder == null ? null : selectedFolder.getId();
+ String musicFolderName = selectedFolder == null ? context.getString(R.string.select_artist_all_folders)
+ : selectedFolder.getName();
+ Util.setSelectedMusicFolderId(context, musicFolderId);
+ folderName.setText(musicFolderName);
+ refresh();
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if (view == folderButtonParent) {
+ selectFolder();
+ } else {
+ Artist artist = (Artist) parent.getItemAtPosition(position);
+ 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());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_artist_layout);
+ }
+ }
+
+ @Override
+ protected void refresh(boolean refresh) {
+ load(refresh);
+ }
+
+ private void load(final boolean refresh) {
+ setTitle(R.string.search_artists);
+
+ if (Util.isOffline(context)) {
+ folderButton.setVisibility(View.GONE);
+ } else {
+ folderButton.setVisibility(View.VISIBLE);
+ }
+ artistList.setVisibility(View.INVISIBLE);
+
+ BackgroundTask<Indexes> task = new TabBackgroundTask<Indexes>(this) {
+ @Override
+ protected Indexes doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ if (!Util.isOffline(context)) {
+ musicFolders = musicService.getMusicFolders(refresh, context, this);
+ }
+ String musicFolderId = Util.getSelectedMusicFolderId(context);
+ return musicService.getIndexes(musicFolderId, refresh, context, this);
+ }
+
+ @Override
+ protected void done(Indexes result) {
+ List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
+ artists.addAll(result.getShortcuts());
+ artists.addAll(result.getArtists());
+ artistList.setAdapter(new ArtistAdapter(context, artists));
+
+ // Display selected music folder
+ if (musicFolders != null) {
+ String musicFolderId = Util.getSelectedMusicFolderId(context);
+ if (musicFolderId == null) {
+ folderName.setText(R.string.select_artist_all_folders);
+ } else {
+ for (MusicFolder musicFolder : musicFolders) {
+ if (musicFolder.getId().equals(musicFolderId)) {
+ folderName.setText(musicFolder.getName());
+ break;
+ }
+ }
+ }
+ }
+ artistList.setVisibility(View.VISIBLE);
+ }
+ };
+ task.execute();
+ }
+
+ private void selectFolder() {
+ folderButton.showContextMenu();
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
new file mode 100644
index 00000000..084269ee
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
@@ -0,0 +1,696 @@
+package github.daneren2005.dsub.fragments;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.view.EntryAdapter;
+import java.util.List;
+import com.mobeta.android.dslv.*;
+import github.daneren2005.dsub.activity.DownloadActivity;
+import github.daneren2005.dsub.activity.SearchActivity;
+import github.daneren2005.dsub.service.DownloadFile;
+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.FileUtil;
+import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.Pair;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.AlbumListAdapter;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class SelectDirectoryFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = SelectDirectoryFragment.class.getSimpleName();
+
+ private DragSortListView entryList;
+ private View footer;
+ private View emptyView;
+ private boolean hideButtons = false;
+ private Button moreButton;
+ private Boolean licenseValid;
+ private boolean showHeader = true;
+ private EntryAdapter entryAdapter;
+ private List<MusicDirectory.Entry> entries;
+
+ String id;
+ String name;
+ String playlistId;
+ String playlistName;
+ String albumListType;
+ int albumListSize;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.select_album, container, false);
+ if(!primaryFragment) {
+ ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE);
+ }
+
+ entryList = (DragSortListView) rootView.findViewById(R.id.select_album_entries);
+ footer = LayoutInflater.from(context).inflate(R.layout.select_album_footer, entryList, false);
+ entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ entryList.setOnItemClickListener(this);
+ entryList.setDropListener(new DragSortListView.DropListener() {
+ @Override
+ public void drop(int from, int to) {
+ int max = entries.size();
+ if(to >= max) {
+ to = max - 1;
+ }
+ else if(to < 0) {
+ to = 0;
+ }
+ entries.add(to, entries.remove(from));
+ entryAdapter.notifyDataSetChanged();
+ }
+ });
+
+ moreButton = (Button) footer.findViewById(R.id.select_album_more);
+ emptyView = rootView.findViewById(R.id.select_album_empty);
+
+ registerForContextMenu(entryList);
+
+ Bundle args = getArguments();
+ if(args != null) {
+ id = args.getString(Constants.INTENT_EXTRA_NAME_ID);
+ name = args.getString(Constants.INTENT_EXTRA_NAME_NAME);
+ playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
+ playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
+ albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
+ albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
+ }
+ if(primaryFragment) {
+ load(false);
+ } else {
+ invalidated = true;
+ }
+ if(name != null) {
+ setTitle(name);
+ }
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ if(licenseValid == null) {
+ menuInflater.inflate(R.menu.empty, menu);
+ }
+ else if(hideButtons) {
+ if(albumListType != null) {
+ menuInflater.inflate(R.menu.select_album_list, menu);
+ } else {
+ menuInflater.inflate(R.menu.select_album, menu);
+ }
+ } else {
+ if(Util.isOffline(context)) {
+ menuInflater.inflate(R.menu.select_song_offline, menu);
+ }
+ else {
+ menuInflater.inflate(R.menu.select_song, menu);
+
+ if(playlistId == null) {
+ menu.removeItem(R.id.menu_remove_playlist);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_play_now:
+ playNow(false, false);
+ return true;
+ case R.id.menu_play_last:
+ playNow(false, true);
+ return true;
+ case R.id.menu_shuffle:
+ playNow(true, false);
+ return true;
+ case R.id.menu_select:
+ selectAllOrNone();
+ return true;
+ case R.id.menu_download:
+ downloadBackground(false);
+ selectAll(false, false);
+ return true;
+ case R.id.menu_cache:
+ downloadBackground(true);
+ selectAll(false, false);
+ return true;
+ case R.id.menu_delete:
+ delete();
+ selectAll(false, false);
+ return true;
+ case R.id.menu_add_playlist:
+ addToPlaylist(getSelectedSongs());
+ return true;
+ case R.id.menu_remove_playlist:
+ removeFromPlaylist(playlistId, playlistName, getSelectedIndexes());
+ return true;
+ }
+
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
+ onCreateContextMenu(menu, view, menuInfo, entry);
+ if(!entry.isVideo() && !Util.isOffline(context) && playlistId == null) {
+ menu.removeItem(R.id.song_menu_remove_playlist);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ Object selectedItem = entries.get(showHeader ? (info.position - 1) : info.position);
+
+ if(onContextItemSelected(menuItem, selectedItem)) {
+ return true;
+ }
+
+ switch (menuItem.getItemId()) {
+ case R.id.song_menu_remove_playlist:
+ removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(info.position - 1));
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if (position >= 0) {
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position);
+ if (entry.isDirectory()) {
+ if(albumListType != null && entry.getParent() != null) {
+ SubsonicFragment parentFragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getParent());
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist());
+ parentFragment.setArguments(args);
+
+ replaceFragment(parentFragment, R.id.select_album_layout);
+ }
+
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_album_layout);
+ } else if (entry.isVideo()) {
+ if(entryExists(entry)) {
+ playExternalPlayer(entry);
+ } else {
+ streamExternalPlayer(entry);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setPrimaryFragment(boolean primary) {
+ super.setPrimaryFragment(primary);
+ if(rootView != null) {
+ if(primary) {
+ ((ViewGroup)rootView).getChildAt(0).setVisibility(View.VISIBLE);
+ } else {
+ ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE);
+ }
+ }
+ }
+
+ @Override
+ protected void refresh(boolean refresh) {
+ load(refresh);
+ }
+
+ private void load(boolean refresh) {
+ entryList.setVisibility(View.INVISIBLE);
+ emptyView.setVisibility(View.INVISIBLE);
+ if (playlistId != null) {
+ getPlaylist(playlistId, playlistName);
+ } else if (albumListType != null) {
+ getAlbumList(albumListType, albumListSize);
+ } else {
+ getMusicDirectory(id, name, refresh);
+ }
+ }
+
+ private void getMusicDirectory(final String id, final String name, final boolean refresh) {
+ setTitle(name);
+
+ new LoadTask() {
+ @Override
+ protected MusicDirectory load(MusicService service) throws Exception {
+ return service.getMusicDirectory(id, name, refresh, context, this);
+ }
+ }.execute();
+ }
+
+ private void getPlaylist(final String playlistId, final String playlistName) {
+ setTitle(playlistName);
+
+ new LoadTask() {
+ @Override
+ protected MusicDirectory load(MusicService service) throws Exception {
+ return service.getPlaylist(playlistId, playlistName, context, this);
+ }
+ }.execute();
+ }
+
+ private void getAlbumList(final String albumListType, final int size) {
+ showHeader = false;
+
+ if ("newest".equals(albumListType)) {
+ setTitle(R.string.main_albums_newest);
+ } else if ("random".equals(albumListType)) {
+ setTitle(R.string.main_albums_random);
+ } else if ("highest".equals(albumListType)) {
+ setTitle(R.string.main_albums_highest);
+ } else if ("recent".equals(albumListType)) {
+ setTitle(R.string.main_albums_recent);
+ } else if ("frequent".equals(albumListType)) {
+ setTitle(R.string.main_albums_frequent);
+ } else if ("starred".equals(albumListType)) {
+ setTitle(R.string.main_albums_starred);
+ }
+
+ new LoadTask() {
+ @Override
+ protected MusicDirectory load(MusicService service) throws Exception {
+ MusicDirectory result;
+ if ("starred".equals(albumListType)) {
+ result = service.getStarredList(context, this);
+ } else {
+ result = service.getAlbumList(albumListType, size, 0, context, this);
+ }
+ return result;
+ }
+ }.execute();
+ }
+
+ private abstract class LoadTask extends TabBackgroundTask<Pair<MusicDirectory, Boolean>> {
+
+ public LoadTask() {
+ super(SelectDirectoryFragment.this);
+ }
+
+ protected abstract MusicDirectory load(MusicService service) throws Exception;
+
+ @Override
+ protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ MusicDirectory dir = load(musicService);
+ boolean valid = musicService.isLicenseValid(context, this);
+ return new Pair<MusicDirectory, Boolean>(dir, valid);
+ }
+
+ @Override
+ protected void done(Pair<MusicDirectory, Boolean> result) {
+ entries = result.getFirst().getChildren();
+
+ int songCount = 0;
+ for (MusicDirectory.Entry entry : entries) {
+ if (!entry.isDirectory()) {
+ songCount++;
+ }
+ }
+
+ if (songCount > 0) {
+ if(showHeader) {
+ View header = createHeader(entries);
+ if(header != null) {
+ entryList.addHeaderView(header, null, false);
+ }
+ }
+ } else {
+ showHeader = false;
+ hideButtons = true;
+ }
+
+ emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
+ entryAdapter = new EntryAdapter(context, getImageLoader(), entries, true);
+ if(albumListType == null || "starred".equals(albumListType)) {
+ entryList.setAdapter(entryAdapter);
+ } else {
+ entryList.setAdapter(new AlbumListAdapter(context, entryAdapter, albumListType, albumListSize));
+ }
+ entryList.setVisibility(View.VISIBLE);
+ licenseValid = result.getSecond();
+ context.invalidateOptionsMenu();
+
+ Bundle args = getArguments();
+ boolean playAll = args.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
+ if (playAll && songCount > 0) {
+ playAll(args.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), false);
+ }
+ }
+ }
+
+ private void playNow(final boolean shuffle, final boolean append) {
+ if(getSelectedSongs().size() > 0) {
+ download(append, false, !append, false, shuffle);
+ selectAll(false, false);
+ }
+ else {
+ playAll(shuffle, append);
+ }
+ }
+ private void playAll(final boolean shuffle, final boolean append) {
+ boolean hasSubFolders = false;
+ for (int i = 0; i < entryList.getCount(); i++) {
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
+ if (entry != null && entry.isDirectory()) {
+ hasSubFolders = true;
+ break;
+ }
+ }
+
+ if (hasSubFolders && id != null) {
+ downloadRecursively(id, false, append, !append, shuffle, false);
+ } else {
+ selectAll(true, false);
+ download(append, false, !append, false, shuffle);
+ selectAll(false, false);
+ }
+ }
+
+ private void selectAllOrNone() {
+ boolean someUnselected = false;
+ int count = entryList.getCount();
+ for (int i = 0; i < count; i++) {
+ if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof MusicDirectory.Entry) {
+ someUnselected = true;
+ break;
+ }
+ }
+ selectAll(someUnselected, true);
+ }
+
+ private void selectAll(boolean selected, boolean toast) {
+ int count = entryList.getCount();
+ int selectedCount = 0;
+ for (int i = 0; i < count; i++) {
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
+ if (entry != null && !entry.isDirectory() && !entry.isVideo()) {
+ entryList.setItemChecked(i, selected);
+ selectedCount++;
+ }
+ }
+
+ // Display toast: N tracks selected / N tracks unselected
+ if (toast) {
+ int toastResId = selected ? R.string.select_album_n_selected
+ : R.string.select_album_n_unselected;
+ Util.toast(context, context.getString(toastResId, selectedCount));
+ }
+ }
+
+ private List<MusicDirectory.Entry> getSelectedSongs() {
+ List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
+ int count = entryList.getCount();
+ for (int i = 0; i < count; i++) {
+ if (entryList.isItemChecked(i)) {
+ songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(i));
+ }
+ }
+ return songs;
+ }
+
+ private List<Integer> getSelectedIndexes() {
+ List<Integer> indexes = new ArrayList<Integer>();
+
+ int count = entryList.getCount();
+ for (int i = 0; i < count; i++) {
+ if (entryList.isItemChecked(i)) {
+ indexes.add(i - 1);
+ }
+ }
+
+ return indexes;
+ }
+
+ private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle) {
+ if (getDownloadService() == null) {
+ return;
+ }
+
+ final List<MusicDirectory.Entry> songs = getSelectedSongs();
+ Runnable onValid = new Runnable() {
+ @Override
+ public void run() {
+ if (!append) {
+ getDownloadService().clear();
+ }
+
+ warnIfNetworkOrStorageUnavailable();
+ getDownloadService().download(songs, save, autoplay, playNext, shuffle);
+ if (playlistName != null) {
+ getDownloadService().setSuggestedPlaylistName(playlistName);
+ }
+ if (autoplay) {
+ Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ if(context instanceof SearchActivity) {
+ context.finish();
+ }
+ } else if (save) {
+ Util.toast(context,
+ context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
+ } else if (append) {
+ Util.toast(context,
+ context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
+ }
+ }
+ };
+
+ checkLicenseAndTrialPeriod(onValid);
+ }
+ private void downloadBackground(final boolean save) {
+ List<MusicDirectory.Entry> songs = getSelectedSongs();
+ if(songs.isEmpty()) {
+ selectAll(true, false);
+ songs = getSelectedSongs();
+ }
+ downloadBackground(save, songs);
+ }
+ private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
+ if (getDownloadService() == null) {
+ return;
+ }
+
+ Runnable onValid = new Runnable() {
+ @Override
+ public void run() {
+ warnIfNetworkOrStorageUnavailable();
+ getDownloadService().downloadBackground(songs, save);
+
+ Util.toast(context,
+ context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
+ }
+ };
+
+ checkLicenseAndTrialPeriod(onValid);
+ }
+
+ private void delete() {
+ List<MusicDirectory.Entry> songs = getSelectedSongs();
+ if(songs.isEmpty()) {
+ selectAll(true, false);
+ songs = getSelectedSongs();
+ }
+ if (getDownloadService() != null) {
+ getDownloadService().delete(songs);
+ }
+ }
+
+ public void removeFromPlaylist(final String id, final String name, final List<Integer> indexes) {
+ new LoadingTask<Void>(context, true) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.removeFromPlaylist(id, indexes, context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ for(int i = indexes.size() - 1; i >= 0; i--) {
+ entryList.setItemChecked(indexes.get(i) + 1, false);
+ entryAdapter.removeAt(indexes.get(i));
+ }
+ entryAdapter.notifyDataSetChanged();
+ Util.toast(context, context.getResources().getString(R.string.removed_playlist, indexes.size(), name));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.updated_playlist_error, name) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ private void checkLicenseAndTrialPeriod(Runnable onValid) {
+ if (licenseValid) {
+ onValid.run();
+ return;
+ }
+
+ int trialDaysLeft = Util.getRemainingTrialDays(context);
+ Log.i(TAG, trialDaysLeft + " trial days left.");
+
+ if (trialDaysLeft == 0) {
+ showDonationDialog(trialDaysLeft, null);
+ } else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2) {
+ showDonationDialog(trialDaysLeft, onValid);
+ } else {
+ Util.toast(context, context.getResources().getString(R.string.select_album_not_licensed, trialDaysLeft));
+ onValid.run();
+ }
+ }
+
+ private void showDonationDialog(int trialDaysLeft, final Runnable onValid) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setIcon(android.R.drawable.ic_dialog_info);
+
+ if (trialDaysLeft == 0) {
+ builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left);
+ } else {
+ builder.setTitle(context.getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left,
+ trialDaysLeft, trialDaysLeft));
+ }
+
+ builder.setMessage(R.string.select_album_donate_dialog_message);
+
+ builder.setPositiveButton(R.string.select_album_donate_dialog_now,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL)));
+ }
+ });
+
+ builder.setNegativeButton(R.string.select_album_donate_dialog_later,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ dialogInterface.dismiss();
+ if (onValid != null) {
+ onValid.run();
+ }
+ }
+ });
+
+ builder.create().show();
+ }
+
+ private View createHeader(List<MusicDirectory.Entry> entries) {
+ View header = entryList.findViewById(R.id.select_album_header);
+ boolean add = false;
+ if(header == null) {
+ header = LayoutInflater.from(context).inflate(R.layout.select_album_header, entryList, false);
+ add = true;
+ }
+
+ View coverArtView = header.findViewById(R.id.select_album_art);
+ getImageLoader().loadImage(coverArtView, entries.get(random.nextInt(entries.size())), true, true);
+
+ TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
+ if(playlistName != null) {
+ titleView.setText(playlistName);
+ } else if(name != null) {
+ titleView.setText(name);
+ }
+
+ int songCount = 0;
+
+ Set<String> artists = new HashSet<String>();
+ Integer totalDuration = 0;
+ for (MusicDirectory.Entry entry : entries) {
+ if (!entry.isDirectory()) {
+ songCount++;
+ if (entry.getArtist() != null) {
+ artists.add(entry.getArtist());
+ }
+ Integer duration = entry.getDuration();
+ if(duration != null) {
+ totalDuration += duration;
+ }
+ }
+ }
+
+ TextView artistView = (TextView) header.findViewById(R.id.select_album_artist);
+ if (artists.size() == 1) {
+ artistView.setText(artists.iterator().next());
+ artistView.setVisibility(View.VISIBLE);
+ } else {
+ artistView.setVisibility(View.GONE);
+ }
+
+ TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
+ String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
+ songCountView.setText(s.toUpperCase());
+
+ TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length);
+ songLengthView.setText(Util.formatDuration(totalDuration));
+
+ if(add) {
+ return header;
+ } else {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
new file mode 100644
index 00000000..1369eef0
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
@@ -0,0 +1,291 @@
+package github.daneren2005.dsub.fragments;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ListView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Playlist;
+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.BackgroundTask;
+import github.daneren2005.dsub.util.CacheCleaner;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.PlaylistAdapter;
+import java.util.List;
+
+public class SelectPlaylistFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = SelectPlaylistFragment.class.getSimpleName();
+
+ private ListView list;
+ private View emptyTextView;
+ private PlaylistAdapter playlistAdapter;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.select_playlist, container, false);
+
+ list = (ListView) rootView.findViewById(R.id.select_playlist_list);
+ emptyTextView = rootView.findViewById(R.id.select_playlist_empty);
+ list.setOnItemClickListener(this);
+ registerForContextMenu(list);
+ invalidated = true;
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.select_playlist, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ MenuInflater inflater = context.getMenuInflater();
+ if (Util.isOffline(context)) {
+ inflater.inflate(R.menu.select_playlist_context_offline, menu);
+ }
+ else {
+ inflater.inflate(R.menu.select_playlist_context, menu);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ Playlist playlist = (Playlist) list.getItemAtPosition(info.position);
+
+ SubsonicFragment fragment;
+ Bundle args;
+ FragmentTransaction trans;
+ switch (menuItem.getItemId()) {
+ case R.id.playlist_menu_download:
+ downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true);
+ break;
+ case R.id.playlist_menu_pin:
+ downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true);
+ break;
+ case R.id.playlist_menu_play_now:
+ fragment = new SelectDirectoryFragment();
+ args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_playlist_layout);
+ break;
+ case R.id.playlist_menu_play_shuffled:
+ fragment = new SelectDirectoryFragment();
+ args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_playlist_layout);
+ break;
+ case R.id.playlist_menu_delete:
+ deletePlaylist(playlist);
+ break;
+ case R.id.playlist_info:
+ displayPlaylistInfo(playlist);
+ break;
+ case R.id.playlist_update_info:
+ updatePlaylistInfo(playlist);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Playlist playlist = (Playlist) parent.getItemAtPosition(position);
+
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_playlist_layout);
+ }
+
+ @Override
+ protected void refresh(boolean refresh) {
+ load(refresh);
+ }
+
+ private void load(final boolean refresh) {
+ setTitle(R.string.playlist_label);
+
+ BackgroundTask<List<Playlist>> task = new TabBackgroundTask<List<Playlist>>(this) {
+ @Override
+ protected List<Playlist> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ List<Playlist> playlists = musicService.getPlaylists(refresh, context, this);
+ if(!Util.isOffline(context) && refresh) {
+ new CacheCleaner(context, getDownloadService()).cleanPlaylists(playlists);
+ }
+ return playlists;
+ }
+
+ @Override
+ protected void done(List<Playlist> result) {
+ list.setAdapter(playlistAdapter = new PlaylistAdapter(context, result));
+ emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
+ }
+ };
+ task.execute();
+ }
+
+ private void deletePlaylist(final Playlist playlist) {
+ new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.common_confirm)
+ .setMessage(context.getResources().getString(R.string.delete_playlist, playlist.getName()))
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ new LoadingTask<Void>(context, false) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.deletePlaylist(playlist.getId(), context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ playlistAdapter.remove(playlist);
+ playlistAdapter.notifyDataSetChanged();
+ Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName()));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ })
+ .setNegativeButton(R.string.common_cancel, null)
+ .show();
+ }
+
+ private void displayPlaylistInfo(final Playlist playlist) {
+ String message = "Owner: " + playlist.getOwner() + "\nComments: " +
+ ((playlist.getComment() == null) ? "" : playlist.getComment()) +
+ "\nSong Count: " + playlist.getSongCount() +
+ ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) +
+ "\nCreation Date: " + playlist.getCreated().replace('T', ' ');
+ new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(playlist.getName())
+ .setMessage(message)
+ .show();
+ }
+
+ private void updatePlaylistInfo(final Playlist playlist) {
+ View dialogView = context.getLayoutInflater().inflate(R.layout.update_playlist, null);
+ final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name);
+ final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment);
+ final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public);
+
+ nameBox.setText(playlist.getName());
+ commentBox.setText(playlist.getComment());
+ Boolean pub = playlist.getPublic();
+ if(pub == null) {
+ publicBox.setEnabled(false);
+ } else {
+ publicBox.setChecked(pub);
+ }
+
+ new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.playlist_update_info)
+ .setView(dialogView)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ new LoadingTask<Void>(context, false) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.updatePlaylist(playlist.getId(), nameBox.getText().toString(), commentBox.getText().toString(), publicBox.isChecked(), context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ refresh();
+ Util.toast(context, context.getResources().getString(R.string.playlist_updated_info, playlist.getName()));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ })
+ .setNegativeButton(R.string.common_cancel, null)
+ .show();
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
new file mode 100644
index 00000000..35a272eb
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -0,0 +1,747 @@
+/*
+ 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 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.fragments;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.TextView;
+import com.actionbarsherlock.app.SherlockFragment;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.DownloadActivity;
+import github.daneren2005.dsub.activity.HelpActivity;
+import github.daneren2005.dsub.activity.MainActivity;
+import github.daneren2005.dsub.activity.SearchActivity;
+import github.daneren2005.dsub.activity.SettingsActivity;
+import github.daneren2005.dsub.activity.SubsonicActivity;
+import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.Playlist;
+import github.daneren2005.dsub.service.DownloadFile;
+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.FileUtil;
+import github.daneren2005.dsub.util.ImageLoader;
+import github.daneren2005.dsub.util.ModalBackgroundTask;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.Util;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+public class SubsonicFragment extends SherlockFragment {
+ private static final String TAG = SubsonicFragment.class.getSimpleName();
+ private static int TAG_INC = 10;
+ private int tag;
+
+ protected SubsonicActivity context;
+ protected CharSequence title = "DSub";
+ protected CharSequence subtitle = null;
+ protected View rootView;
+ protected boolean primaryFragment = false;
+ protected boolean invalidated = false;
+ protected static Random random = new Random();
+
+ public SubsonicFragment() {
+ super();
+ tag = TAG_INC++;
+ }
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ context = (SubsonicActivity)activity;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_refresh:
+ refresh(true);
+ return true;
+ case R.id.menu_shuffle:
+ onShuffleRequested();
+ return true;
+ case R.id.menu_search:
+ context.onSearchRequested();
+ return true;
+ case R.id.menu_exit:
+ exit();
+ return true;
+ case R.id.menu_settings:
+ startActivity(new Intent(context, SettingsActivity.class));
+ return true;
+ case R.id.menu_help:
+ startActivity(new Intent(context, HelpActivity.class));
+ return true;
+ }
+
+ return false;
+ }
+
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo, Object selected) {
+ MenuInflater inflater = context.getMenuInflater();
+
+ if(selected instanceof MusicDirectory.Entry) {
+ MusicDirectory.Entry entry = (MusicDirectory.Entry) selected;
+ if (entry.isDirectory()) {
+ if(Util.isOffline(context)) {
+ inflater.inflate(R.menu.select_album_context_offline, menu);
+ }
+ else {
+ inflater.inflate(R.menu.select_album_context, menu);
+ }
+ } else if(!entry.isVideo()) {
+ if(Util.isOffline(context)) {
+ inflater.inflate(R.menu.select_song_context_offline, menu);
+ }
+ else {
+ inflater.inflate(R.menu.select_song_context, menu);
+ }
+ } else {
+ if(Util.isOffline(context)) {
+ inflater.inflate(R.menu.select_video_context_offline, menu);
+ }
+ else {
+ inflater.inflate(R.menu.select_video_context, menu);
+ }
+ }
+
+ if (!Util.isOffline(context) && !entry.isVideo()) {
+ menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star);
+ }
+ } else if(selected instanceof Artist) {
+ if(Util.isOffline(context)) {
+ inflater.inflate(R.menu.select_artist_context_offline, menu);
+ }
+ else {
+ inflater.inflate(R.menu.select_artist_context, menu);
+ }
+ }
+ }
+
+ public boolean onContextItemSelected(MenuItem menuItem, Object selectedItem) {
+ Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
+ MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null;
+ List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
+ songs.add(entry);
+
+ switch (menuItem.getItemId()) {
+ case R.id.artist_menu_play_now:
+ downloadRecursively(artist.getId(), false, false, true, false, false);
+ break;
+ case R.id.artist_menu_play_shuffled:
+ downloadRecursively(artist.getId(), false, false, true, true, false);
+ break;
+ case R.id.artist_menu_play_last:
+ downloadRecursively(artist.getId(), false, true, false, false, false);
+ break;
+ case R.id.artist_menu_download:
+ downloadRecursively(artist.getId(), false, true, false, false, true);
+ break;
+ case R.id.artist_menu_pin:
+ downloadRecursively(artist.getId(), true, true, false, false, true);
+ break;
+ case R.id.artist_menu_delete:
+ deleteRecursively(artist);
+ break;
+ case R.id.album_menu_play_now:
+ downloadRecursively(entry.getId(), false, false, true, false, false);
+ break;
+ case R.id.album_menu_play_shuffled:
+ downloadRecursively(entry.getId(), false, false, true, true, false);
+ break;
+ case R.id.album_menu_play_last:
+ downloadRecursively(entry.getId(), false, true, false, false, false);
+ break;
+ case R.id.album_menu_download:
+ downloadRecursively(entry.getId(), false, true, false, false, true);
+ break;
+ case R.id.album_menu_pin:
+ downloadRecursively(entry.getId(), true, true, false, false, true);
+ break;
+ case R.id.album_menu_star:
+ toggleStarred(entry);
+ break;
+ case R.id.album_menu_delete:
+ deleteRecursively(entry);
+ break;
+ case R.id.song_menu_play_now:
+ getDownloadService().clear();
+ getDownloadService().download(songs, false, true, true, false);
+ Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ if(context instanceof SearchActivity) {
+ context.finish();
+ }
+ break;
+ case R.id.song_menu_play_next:
+ getDownloadService().download(songs, false, false, true, false);
+ break;
+ case R.id.song_menu_play_last:
+ getDownloadService().download(songs, false, false, false, false);
+ break;
+ case R.id.song_menu_download:
+ getDownloadService().downloadBackground(songs, false);
+ break;
+ case R.id.song_menu_pin:
+ getDownloadService().downloadBackground(songs, true);
+ break;
+ case R.id.song_menu_delete:
+ getDownloadService().delete(songs);
+ break;
+ case R.id.song_menu_add_playlist:
+ addToPlaylist(songs);
+ break;
+ case R.id.song_menu_star:
+ toggleStarred(entry);
+ break;
+ case R.id.song_menu_webview:
+ playWebView(entry);
+ break;
+ case R.id.song_menu_play_external:
+ playExternalPlayer(entry);
+ break;
+ case R.id.song_menu_info:
+ displaySongInfo(entry);
+ break;
+ case R.id.song_menu_stream_external:
+ streamExternalPlayer(entry);
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ public void replaceFragment(SubsonicFragment fragment, int id) {
+ context.replaceFragment(fragment, id, fragment.getSupportTag());
+ }
+
+ public int getSupportTag() {
+ return tag;
+ }
+
+ public void setPrimaryFragment(boolean primary) {
+ primaryFragment = primary;
+ if(primary) {
+ if(context != null) {
+ context.setTitle(title);
+ context.setSubtitle(subtitle);
+ }
+ if(invalidated) {
+ invalidated = false;
+ refresh(false);
+ }
+ }
+ }
+
+ public void invalidate() {
+ if(primaryFragment) {
+ refresh(false);
+ } else {
+ invalidated = true;
+ }
+ }
+
+ public DownloadService getDownloadService() {
+ return context != null ? context.getDownloadService() : null;
+ }
+
+ protected void refresh() {
+ refresh(true);
+ }
+ protected void refresh(boolean refresh) {
+
+ }
+
+ protected void exit() {
+ if(context.getClass() != MainActivity.class) {
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
+ Util.startActivityWithoutTransition(context, intent);
+ } else {
+ context.stopService(new Intent(context, DownloadServiceImpl.class));
+ context.finish();
+ }
+ }
+
+ public void setProgressVisible(boolean visible) {
+ View view = rootView.findViewById(R.id.tab_progress);
+ if (view != null) {
+ view.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void updateProgress(String message) {
+ TextView view = (TextView) rootView.findViewById(R.id.tab_progress_message);
+ if (view != null) {
+ view.setText(message);
+ }
+ }
+
+ protected synchronized ImageLoader getImageLoader() {
+ return context.getImageLoader();
+ }
+ public synchronized static ImageLoader getStaticImageLoader(Context context) {
+ return SubsonicActivity.getStaticImageLoader(context);
+ }
+
+ public void setTitle(CharSequence title) {
+ this.title = title;
+ context.setTitle(title);
+ }
+ public void setTitle(int title) {
+ this.title = context.getResources().getString(title);
+ context.setTitle(this.title);
+ }
+ public void setSubtitle(CharSequence title) {
+ this.subtitle = title;
+ context.setSubtitle(title);
+ }
+ public CharSequence getTitle() {
+ return this.title;
+ }
+
+ protected void warnIfNetworkOrStorageUnavailable() {
+ if (!Util.isExternalStoragePresent()) {
+ Util.toast(context, R.string.select_album_no_sdcard);
+ } else if (!Util.isOffline(context) && !Util.isNetworkConnected(context)) {
+ Util.toast(context, R.string.select_album_no_network);
+ }
+ }
+
+ protected void onShuffleRequested() {
+ if(Util.isOffline(context)) {
+ Intent intent = new Intent(context, DownloadActivity.class);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
+ Util.startActivityWithoutTransition(context, intent);
+ return;
+ }
+
+ View dialogView = context.getLayoutInflater().inflate(R.layout.shuffle_dialog, null);
+ final EditText startYearBox = (EditText)dialogView.findViewById(R.id.start_year);
+ final EditText endYearBox = (EditText)dialogView.findViewById(R.id.end_year);
+ final EditText genreBox = (EditText)dialogView.findViewById(R.id.genre);
+
+ final SharedPreferences prefs = Util.getPreferences(context);
+ final String oldStartYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "");
+ final String oldEndYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "");
+ final String oldGenre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "");
+
+ startYearBox.setText(oldStartYear);
+ endYearBox.setText(oldEndYear);
+ genreBox.setText(oldGenre);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle("Shuffle By")
+ .setView(dialogView)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ Intent intent = new Intent(context, DownloadActivity.class);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
+ String genre = genreBox.getText().toString();
+ String startYear = startYearBox.getText().toString();
+ String endYear = endYearBox.getText().toString();
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear);
+ editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear);
+ editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre);
+ editor.commit();
+
+ Util.startActivityWithoutTransition(context, intent);
+ }
+ })
+ .setNegativeButton(R.string.common_cancel, null);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ public void toggleStarred(final MusicDirectory.Entry entry) {
+ final boolean starred = !entry.isStarred();
+ entry.setStarred(starred);
+
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.setStarred(entry.getId(), starred, context, null);
+ 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) {
+ 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.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<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.setStarred(entry.getId(), starred, context, null);
+ 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) {
+ 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);
+ }
+ protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
+ downloadRecursively(id, name, false, save, append, autoplay, shuffle, background);
+ }
+ protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) {
+ ModalBackgroundTask<List<MusicDirectory.Entry>> task = new ModalBackgroundTask<List<MusicDirectory.Entry>>(context, false) {
+ private static final int MAX_SONGS = 500;
+
+ @Override
+ protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ MusicDirectory root;
+ if(isDirectory)
+ root = musicService.getMusicDirectory(id, name, false, context, this);
+ else
+ root = musicService.getPlaylist(id, name, context, this);
+ List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
+ getSongsRecursively(root, songs);
+ return songs;
+ }
+
+ private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
+ if (songs.size() > MAX_SONGS) {
+ return;
+ }
+
+ for (MusicDirectory.Entry song : parent.getChildren(false, true)) {
+ if (!song.isVideo()) {
+ songs.add(song);
+ }
+ }
+ for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ getSongsRecursively(musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, context, this), songs);
+ }
+ }
+
+ @Override
+ protected void done(List<MusicDirectory.Entry> songs) {
+ DownloadService downloadService = getDownloadService();
+ if (!songs.isEmpty() && downloadService != null) {
+ if (!append) {
+ downloadService.clear();
+ }
+ warnIfNetworkOrStorageUnavailable();
+ if(!background) {
+ downloadService.download(songs, save, autoplay, false, shuffle);
+ if(!append) {
+ Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ if(context instanceof SearchActivity) {
+ context.finish();
+ }
+ }
+ }
+ else {
+ downloadService.downloadBackground(songs, save);
+ }
+ }
+ }
+ };
+
+ task.execute();
+ }
+
+ protected void addToPlaylist(final List<MusicDirectory.Entry> songs) {
+ if(songs.isEmpty()) {
+ Util.toast(context, "No songs selected");
+ return;
+ }
+
+ new LoadingTask<List<Playlist>>(context, true) {
+ @Override
+ protected List<Playlist> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ return musicService.getPlaylists(false, context, this);
+ }
+
+ @Override
+ protected void done(final List<Playlist> playlists) {
+ List<String> names = new ArrayList<String>();
+ for(Playlist playlist: playlists) {
+ names.add(playlist.getName());
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle("Add to Playlist")
+ .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ addToPlaylist(playlists.get(which), songs);
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ private void addToPlaylist(final Playlist playlist, final List<MusicDirectory.Entry> songs) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.addToPlaylist(playlist.getId(), songs, context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ Util.toast(context, context.getResources().getString(R.string.updated_playlist, songs.size(), playlist.getName()));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.updated_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ public void displaySongInfo(final MusicDirectory.Entry song) {
+ Integer bitrate = null;
+ String format = null;
+ long size = 0;
+ try {
+ DownloadFile downloadFile = new DownloadFile(context, song, false);
+ File file = downloadFile.getCompleteFile();
+ if(file.exists()) {
+ MediaMetadataRetriever metadata = new MediaMetadataRetriever();
+ metadata.setDataSource(file.getAbsolutePath());
+ String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
+ bitrate = Integer.parseInt((tmp != null) ? tmp : "0") / 1000;
+ format = FileUtil.getExtension(file.getName());
+ size = file.length();
+
+ if(Util.isOffline(context)) {
+ song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
+ String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
+ song.setYear(Integer.parseInt((year != null) ? year : "0"));
+ }
+ }
+ } catch(Exception e) {
+ Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver");
+ }
+
+ String msg = "";
+ if(!song.isVideo()) {
+ msg += "Artist: " + song.getArtist() + "\nAlbum: " + song.getAlbum();
+ }
+ if(song.getTrack() != null && song.getTrack() != 0) {
+ msg += "\nTrack: " + song.getTrack();
+ }
+ if(song.getGenre() != null && !"".equals(song.getGenre())) {
+ msg += "\nGenre: " + song.getGenre();
+ }
+ if(song.getYear() != null && song.getYear() != 0) {
+ msg += "\nYear: " + song.getYear();
+ }
+ if(!Util.isOffline(context)) {
+ msg += "\nServer Format: " + song.getSuffix();
+ if(song.getBitRate() != null && song.getBitRate() != 0) {
+ msg += "\nServer Bitrate: " + song.getBitRate() + " kpbs";
+ }
+ }
+ if(format != null && !"".equals(format)) {
+ msg += "\nCached Format: " + format;
+ }
+ if(bitrate != null && bitrate != 0) {
+ msg += "\nCached Bitrate: " + bitrate + " kpbs";
+ }
+ if(size != 0) {
+ msg += "\nSize: " + Util.formatBytes(size);
+ }
+ if(song.getDuration() != null && song.getDuration() != 0) {
+ msg += "\nLength: " + Util.formatDuration(song.getDuration());
+ }
+
+ new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(song.getTitle())
+ .setMessage(msg)
+ .show();
+ }
+
+ protected void playWebView(MusicDirectory.Entry entry) {
+ int maxBitrate = Util.getMaxVideoBitrate(context);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, entry.getId())));
+
+ startActivity(intent);
+ }
+ protected void playExternalPlayer(MusicDirectory.Entry entry) {
+ if(!entryExists(entry)) {
+ Util.toast(context, R.string.download_need_download);
+ } else {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(Uri.parse(entry.getPath()), "video/*");
+
+ List<ResolveInfo> intents = context.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if(intents != null && intents.size() > 0) {
+ startActivity(intent);
+ }else {
+ Util.toast(context, R.string.download_no_streaming_player);
+ }
+ }
+ }
+ protected void streamExternalPlayer(MusicDirectory.Entry entry) {
+ int maxBitrate = Util.getMaxVideoBitrate(context);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoStreamUrl(maxBitrate, context, entry.getId())), "video/*");
+
+ List<ResolveInfo> intents = context.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if(intents != null && intents.size() > 0) {
+ startActivity(intent);
+ } else {
+ Util.toast(context, R.string.download_no_streaming_player);
+ }
+ }
+
+ protected boolean entryExists(MusicDirectory.Entry entry) {
+ DownloadFile check = new DownloadFile(context, entry, false);
+ return check.isCompleteFileAvailable();
+ }
+
+ public void deleteRecursively(Artist artist) {
+ File dir = FileUtil.getArtistDirectory(context, artist);
+ Util.recursiveDelete(dir);
+ if(Util.isOffline(context)) {
+ refresh();
+ }
+ }
+
+ public void deleteRecursively(MusicDirectory.Entry album) {
+ File dir = FileUtil.getAlbumDirectory(context, album);
+ Util.recursiveDelete(dir);
+ if(Util.isOffline(context)) {
+ refresh();
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
index 069345fa..c61e215a 100644
--- a/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
+++ b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
@@ -43,6 +43,7 @@ import github.daneren2005.dsub.activity.MainActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.FileUtil;
/**
@@ -210,26 +211,29 @@ public class DSubWidgetProvider extends AppWidgetProvider {
* otherwise we launch {@link MainActivity}.
*/
private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
-
- Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
+ Intent intent = new Intent(context, MainActivity.class);
+ if(playerActive) {
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ }
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent);
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
// Emulate media button clicks.
- intent = new Intent("1");
+ intent = new Intent("DSub.PLAY_PAUSE");
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
- intent = new Intent("2"); // Use a unique action name to ensure a different PendingIntent to be created.
+ intent = new Intent("DSub.NEXT"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
- intent = new Intent("3"); // Use a unique action name to ensure a different PendingIntent to be created.
+ intent = new Intent("DSub.PREVIOUS"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
index bae4310d..fabeba6f 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
@@ -62,12 +62,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.util.Log;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
-import github.daneren2005.dsub.util.FileUtil;
import java.net.URLEncoder;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
/**
* @author Sindre Mehus
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
index a35573a6..302ececf 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
@@ -50,6 +50,7 @@ public final class Constants {
public static final String INTENT_EXTRA_NAME_REFRESH = "subsonic.refresh";
public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch";
public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ;
+ public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download";
// Notification IDs.
public static final int NOTIFICATION_ID_PLAYING = 100;
@@ -92,6 +93,11 @@ public final class Constants {
public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings";
public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification";
public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback";
+
+ public static final String MAIN_BACK_STACK = "backStackIds";
+ public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize";
+ public static final String MAIN_BACK_STACK_TABS = "backStackTabs";
+ public static final String MAIN_BACK_STACK_POSITION = "backStackPosition";
// Name of the preferences file.
public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences";
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java b/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java
index 0875742f..0b48a338 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java
@@ -2,7 +2,7 @@ package github.daneren2005.dsub.util;
import android.app.ProgressDialog;
import android.content.DialogInterface;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
+import github.daneren2005.dsub.activity.SubsonicActivity;
/**
* @author Sindre Mehus
@@ -10,11 +10,11 @@ import github.daneren2005.dsub.activity.SubsonicTabActivity;
*/
public abstract class LoadingTask<T> extends BackgroundTask<T> {
- private final SubsonicTabActivity tabActivity;
+ private final SubsonicActivity tabActivity;
private final boolean cancellable;
private boolean cancelled = false;
- public LoadingTask(SubsonicTabActivity activity, final boolean cancellable) {
+ public LoadingTask(SubsonicActivity activity, final boolean cancellable) {
super(activity);
tabActivity = activity;
this.cancellable = cancellable;
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java b/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java
index 6b5d0996..3bc022ac 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java
@@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.service.MusicService;
import github.daneren2005.dsub.service.MusicServiceFactory;
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/TabActivityBackgroundTask.java b/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java
index f5cf94b9..c345b982 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/TabActivityBackgroundTask.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java
@@ -1,67 +1,67 @@
-package github.daneren2005.dsub.util;
-
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T> {
-
- private final SubsonicTabActivity tabActivity;
-
- public TabActivityBackgroundTask(SubsonicTabActivity activity) {
- super(activity);
- tabActivity = activity;
- }
-
- @Override
- public void execute() {
- tabActivity.setProgressVisible(true);
-
- new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
- if (isCancelled()) {
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.setProgressVisible(false);
- done(result);
- }
- });
- } catch (final Throwable t) {
- if (isCancelled()) {
- return;
- }
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.setProgressVisible(false);
- error(t);
- }
- });
- }
- }
- }.start();
- }
-
- private boolean isCancelled() {
- return tabActivity.isDestroyed();
- }
-
- @Override
- public void updateProgress(final String message) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.updateProgress(message);
- }
- });
- }
-}
+package github.daneren2005.dsub.util;
+
+import github.daneren2005.dsub.fragments.SubsonicFragment;
+
+/**
+ * @author Sindre Mehus
+ * @version $Id$
+ */
+public abstract class TabBackgroundTask<T> extends BackgroundTask<T> {
+
+ private final SubsonicFragment tabFragment;
+
+ public TabBackgroundTask(SubsonicFragment fragment) {
+ super(fragment.getActivity());
+ tabFragment = fragment;
+ }
+
+ @Override
+ public void execute() {
+ tabFragment.setProgressVisible(true);
+
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ final T result = doInBackground();
+ if (isCancelled()) {
+ return;
+ }
+
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ tabFragment.setProgressVisible(false);
+ done(result);
+ }
+ });
+ } catch (final Throwable t) {
+ if (isCancelled()) {
+ return;
+ }
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ tabFragment.setProgressVisible(false);
+ error(t);
+ }
+ });
+ }
+ }
+ }.start();
+ }
+
+ private boolean isCancelled() {
+ return !tabFragment.isAdded();
+ }
+
+ @Override
+ public void updateProgress(final String message) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ tabFragment.updateProgress(message);
+ }
+ });
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
index 25226bcd..43aad67b 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
@@ -52,7 +52,7 @@ import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.DownloadActivity;
+import github.daneren2005.dsub.activity.MainActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RepeatMode;
@@ -659,7 +659,9 @@ public final class Util {
setupViews(smallContentView, context, song, playing);
notification.contentView = smallContentView;
- Intent notificationIntent = new Intent(context, DownloadActivity.class);
+ Intent notificationIntent = new Intent(context, MainActivity.class);
+ notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
+ notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
handler.post(new Runnable() {
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
index 52361fd4..a8fed63d 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
@@ -10,7 +10,7 @@ import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.RemoteControlClient;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
+import github.daneren2005.dsub.activity.SubsonicActivity;
@TargetApi(14)
public class RemoteControlClientICS extends RemoteControlClientHelper {
@@ -40,7 +40,7 @@ public class RemoteControlClientICS extends RemoteControlClientHelper {
RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
RemoteControlClient.FLAG_KEY_MEDIA_STOP);
- imageLoader = SubsonicTabActivity.getStaticImageLoader(context);
+ imageLoader = SubsonicActivity.getStaticImageLoader(context);
}
public void unregister(final Context context) {
@@ -56,7 +56,7 @@ public class RemoteControlClientICS extends RemoteControlClientHelper {
public void updateMetadata(final Context context, final MusicDirectory.Entry currentSong) {
if(imageLoader == null) {
- imageLoader = SubsonicTabActivity.getStaticImageLoader(context);
+ imageLoader = SubsonicActivity.getStaticImageLoader(context);
}
// Update the remote controls
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java
new file mode 100644
index 00000000..6c8d315a
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/view/AlbumListAdapter.java
@@ -0,0 +1,76 @@
+/*
+ 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 2010 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.view;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import com.commonsware.cwac.endless.EndlessAdapter;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.service.MusicService;
+import github.daneren2005.dsub.service.MusicServiceFactory;
+import java.util.List;
+
+public class AlbumListAdapter extends EndlessAdapter {
+ Context context;
+ ArrayAdapter<MusicDirectory.Entry> adapter;
+ String type;
+ int size;
+ int offset;
+ List<MusicDirectory.Entry> entries;
+
+ public AlbumListAdapter(Context context, ArrayAdapter<MusicDirectory.Entry> adapter, String type, int size) {
+ super(adapter);
+ this.context = context;
+ this.adapter = adapter;
+ this.type = type;
+ this.size = size;
+ this.offset = size;
+ }
+
+ @Override
+ protected boolean cacheInBackground() throws Exception {
+ MusicService service = MusicServiceFactory.getMusicService(context);
+ MusicDirectory result = service.getAlbumList(type, size, offset, context, null);
+ entries = result.getChildren();
+ if(entries.size() > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected void appendCachedData() {
+ for(MusicDirectory.Entry entry: entries) {
+ adapter.add(entry);
+ }
+ offset += entries.size();
+ }
+
+ @Override
+ protected View getPendingView(ViewGroup parent) {
+ View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null);
+ progress.setVisibility(View.VISIBLE);
+ return progress;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
index 0edb03c5..7e9bf218 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
@@ -18,13 +18,13 @@
*/
package github.daneren2005.dsub.view;
+import android.content.Context;
import github.daneren2005.dsub.R;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.SectionIndexer;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
import github.daneren2005.dsub.domain.Artist;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -35,13 +35,13 @@ import java.util.Set;
*/
public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexer {
- private final SubsonicTabActivity activity;
+ private final Context activity;
// Both arrays are indexed by section ID.
private final Object[] sections;
private final Integer[] positions;
- public ArtistAdapter(SubsonicTabActivity activity, List<Artist> artists) {
+ public ArtistAdapter(Context activity, List<Artist> artists) {
super(activity, R.layout.artist_list_item, artists);
this.activity = activity;
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java b/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java
new file mode 100644
index 00000000..630fb021
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/view/ChangeLog.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2012 Christian Ketterer (cketti)
+ *
+ * Portions Copyright (C) 2012 Martin van Zuilekom (http://martin.cubeactive.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Based on android-change-log:
+ *
+ * Copyright (C) 2011, Karsten Priegnitz
+ *
+ * Permission to use, copy, modify, and distribute this piece of software
+ * for any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in the
+ * source code of all copies.
+ *
+ * It would be appreciated if you mention the author in your change log,
+ * contributors list or the like.
+ *
+ * http://code.google.com/p/android-change-log/
+ */
+package github.daneren2005.dsub.view;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.webkit.WebView;
+import github.daneren2005.dsub.R;
+
+
+/**
+ * Display a dialog showing a full or partial (What's New) change log.
+ */
+public class ChangeLog {
+ /**
+ * Tag that is used when sending error/debug messages to the log.
+ */
+ protected static final String LOG_TAG = "ckChangeLog";
+
+ /**
+ * This is the key used when storing the version code in SharedPreferences.
+ */
+ protected static final String VERSION_KEY = "ckChangeLog_last_version_code";
+
+ /**
+ * Constant that used when no version code is available.
+ */
+ protected static final int NO_VERSION = -1;
+
+ /**
+ * Default CSS styles used to format the change log.
+ */
+ private static final String DEFAULT_CSS =
+ "h1 { margin-left: 0px; font-size: 1.2em;}" +
+ "li { margin-left: 0px;}" +
+ "ul { padding-left: 2em;}";
+
+
+ /**
+ * Context that is used to access the resources and to create the ChangeLog dialogs.
+ */
+ protected final Context mContext;
+
+ /**
+ * Contains the CSS rules used to format the change log.
+ */
+ protected final String mCss;
+
+ /**
+ * Last version code read from {@code SharedPreferences} or {@link #NO_VERSION}.
+ */
+ private int mLastVersionCode;
+
+ /**
+ * Version code of the current installation.
+ */
+ private int mCurrentVersionCode;
+
+ /**
+ * Version name of the current installation.
+ */
+ private String mCurrentVersionName;
+
+
+ /**
+ * Contains constants for the root element of {@code changelog.xml}.
+ */
+ protected interface ChangeLogTag {
+ static final String NAME = "changelog";
+ }
+
+ /**
+ * Contains constants for the release element of {@code changelog.xml}.
+ */
+ protected interface ReleaseTag {
+ static final String NAME = "release";
+ static final String ATTRIBUTE_VERSION = "version";
+ static final String ATTRIBUTE_VERSION_CODE = "versioncode";
+ }
+
+ /**
+ * Contains constants for the change element of {@code changelog.xml}.
+ */
+ protected interface ChangeTag {
+ static final String NAME = "change";
+ }
+
+ /**
+ * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
+ *
+ * @param context
+ * Context that is used to access the resources and to create the ChangeLog dialogs.
+ */
+ public ChangeLog(Context context) {
+ this(context, PreferenceManager.getDefaultSharedPreferences(context), DEFAULT_CSS);
+ }
+
+ /**
+ * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
+ *
+ * @param context
+ * Context that is used to access the resources and to create the ChangeLog dialogs.
+ * @param css
+ * CSS styles that will be used to format the change log.
+ */
+ public ChangeLog(Context context, String css) {
+ this(context, PreferenceManager.getDefaultSharedPreferences(context), css);
+ }
+
+ public ChangeLog(Context context, SharedPreferences preferences) {
+ this(context, preferences, DEFAULT_CSS);
+ }
+
+ /**
+ * Create a {@code ChangeLog} instance using the supplied {@code SharedPreferences} instance.
+ *
+ * @param context
+ * Context that is used to access the resources and to create the ChangeLog dialogs.
+ * @param preferences
+ * {@code SharedPreferences} instance that is used to persist the last version code.
+ * @param css
+ * CSS styles used to format the change log (excluding {@code <style>} and
+ * {@code </style>}).
+ *
+ */
+ public ChangeLog(Context context, SharedPreferences preferences, String css) {
+ mContext = context;
+ mCss = css;
+
+ // Get last version code
+ mLastVersionCode = preferences.getInt(VERSION_KEY, NO_VERSION);
+
+ // Get current version code and version name
+ try {
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
+ context.getPackageName(), 0);
+
+ mCurrentVersionCode = packageInfo.versionCode;
+ mCurrentVersionName = packageInfo.versionName;
+ } catch (NameNotFoundException e) {
+ mCurrentVersionCode = NO_VERSION;
+ Log.e(LOG_TAG, "Could not get version information from manifest!", e);
+ }
+ }
+
+ /**
+ * Get version code of last installation.
+ *
+ * @return The version code of the last installation of this app (as described in the former
+ * manifest). This will be the same as returned by {@link #getCurrentVersionCode()} the
+ * second time this version of the app is launched (more precisely: the second time
+ * {@code ChangeLog} is instantiated).
+ *
+ * @see AndroidManifest.xml#android:versionCode
+ */
+ public int getLastVersionCode() {
+ return mLastVersionCode;
+ }
+
+ /**
+ * Get version code of current installation.
+ *
+ * @return The version code of this app as described in the manifest.
+ *
+ * @see AndroidManifest.xml#android:versionCode
+ */
+ public int getCurrentVersionCode() {
+ return mCurrentVersionCode;
+ }
+
+ /**
+ * Get version name of current installation.
+ *
+ * @return The version name of this app as described in the manifest.
+ *
+ * @see AndroidManifest.xml#android:versionName
+ */
+ public String getCurrentVersionName() {
+ return mCurrentVersionName;
+ }
+
+ /**
+ * Check if this is the first execution of this app version.
+ *
+ * @return {@code true} if this version of your app is started the first time.
+ */
+ public boolean isFirstRun() {
+ return mLastVersionCode < mCurrentVersionCode;
+ }
+
+ /**
+ * Check if this is a new installation.
+ *
+ * @return {@code true} if your app including {@code ChangeLog} is started the first time ever.
+ * Also {@code true} if your app was uninstalled and installed again.
+ */
+ public boolean isFirstRunEver() {
+ return mLastVersionCode == NO_VERSION;
+ }
+
+ /**
+ * Get the "What's New" dialog.
+ *
+ * @return An AlertDialog displaying the changes since the previous installed version of your
+ * app (What's New). But when this is the first run of your app including
+ * {@code ChangeLog} then the full log dialog is show.
+ */
+ public AlertDialog getLogDialog() {
+ return getDialog(isFirstRunEver());
+ }
+
+ /**
+ * Get a dialog with the full change log.
+ *
+ * @return An AlertDialog with a full change log displayed.
+ */
+ public AlertDialog getFullLogDialog() {
+ return getDialog(true);
+ }
+
+ /**
+ * Create a dialog containing (parts of the) change log.
+ *
+ * @param full
+ * If this is {@code true} the full change log is displayed. Otherwise only changes for
+ * versions newer than the last version are displayed.
+ *
+ * @return A dialog containing the (partial) change log.
+ */
+ protected AlertDialog getDialog(boolean full) {
+ WebView wv = new WebView(mContext);
+ //wv.setBackgroundColor(0); // transparent
+ wv.loadDataWithBaseURL(null, getLog(full), "text/html", "UTF-8", null);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(
+ mContext.getResources().getString(
+ full ? R.string.changelog_full_title : R.string.changelog_title))
+ .setView(wv)
+ .setCancelable(false)
+ // OK button
+ .setPositiveButton(
+ mContext.getResources().getString(R.string.changelog_ok_button),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // The user clicked "OK" so save the current version code as
+ // "last version code".
+ updateVersionInPreferences();
+ }
+ });
+
+ if (!full) {
+ // Show "Moreā€¦" button if we're only displaying a partial change log.
+ builder.setNegativeButton(R.string.changelog_show_full,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ getFullLogDialog().show();
+ }
+ });
+ }
+
+ return builder.create();
+ }
+
+ /**
+ * Write current version code to the preferences.
+ */
+ protected void updateVersionInPreferences() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(VERSION_KEY, mCurrentVersionCode);
+
+ // TODO: Update preferences from a background thread
+ editor.commit();
+ }
+
+ /**
+ * Get changes since last version as HTML string.
+ *
+ * @return HTML string containing the changes since the previous installed version of your app
+ * (What's New).
+ */
+ public String getLog() {
+ return getLog(false);
+ }
+
+ /**
+ * Get full change log as HTML string.
+ *
+ * @return HTML string containing the full change log.
+ */
+ public String getFullLog() {
+ return getLog(true);
+ }
+
+ /**
+ * Get (partial) change log as HTML string.
+ *
+ * @param full
+ * If this is {@code true} the full change log is returned. Otherwise only changes for
+ * versions newer than the last version are returned.
+ *
+ * @return The (partial) change log.
+ */
+ private String getLog(boolean full) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("<html><head><style type=\"text/css\">");
+ sb.append(mCss);
+ sb.append("</style></head><body>");
+
+ Resources resources = mContext.getResources();
+
+ // Read master change log from raw/changelog.xml
+ SparseArray<ReleaseItem> defaultChangelog;
+ try {
+ XmlPullParser xml = XmlPullParserFactory.newInstance().newPullParser();
+ InputStreamReader reader = new InputStreamReader(resources.openRawResource(R.raw.changelog));
+ xml.setInput(reader);
+ try {
+ defaultChangelog = readChangeLog(xml, full);
+ } finally {
+ try { reader.close(); } catch (Exception e) { /* do nothing */ }
+ }
+ } catch (XmlPullParserException e) {
+ Log.e(LOG_TAG, "Error reading raw/changelog.xml", e);
+ return null;
+ }
+
+ // Read localized change log from xml[-lang]/changelog.xml
+ XmlResourceParser resXml = mContext.getResources().getXml(R.xml.changelog);
+ SparseArray<ReleaseItem> changelog;
+ try {
+ changelog = readChangeLog(resXml, full);
+ } finally {
+ resXml.close();
+ }
+
+ String versionFormat = resources.getString(R.string.changelog_version_format);
+
+ // Get all version codes from the master change log...
+ List<Integer> versions = new ArrayList<Integer>(defaultChangelog.size());
+ for (int i = 0, len = defaultChangelog.size(); i < len; i++) {
+ int key = defaultChangelog.keyAt(i);
+ versions.add(key);
+ }
+
+ // ... and sort them (newest version first).
+ Collections.sort(versions, Collections.reverseOrder());
+
+ for (Integer version : versions) {
+ int key = version.intValue();
+
+ // Use release information from localized change log and fall back to the master file
+ // if necessary.
+ ReleaseItem release = changelog.get(key, defaultChangelog.get(key));
+
+ sb.append("<h1>");
+ sb.append(String.format(versionFormat, release.versionName));
+ sb.append("</h1><ul>");
+ for (String change : release.changes) {
+ sb.append("<li>");
+ sb.append(change);
+ sb.append("</li>");
+ }
+ sb.append("</ul>");
+ }
+
+ sb.append("</body></html>");
+
+ return sb.toString();
+ }
+
+ /**
+ * Read the change log from an XML file.
+ *
+ * @param xml
+ * The {@code XmlPullParser} instance used to read the change log.
+ * @param full
+ * If {@code true} the full change log is read. Otherwise only the changes since the
+ * last (saved) version are read.
+ *
+ * @return A {@code SparseArray} mapping the version codes to release information.
+ */
+ protected SparseArray<ReleaseItem> readChangeLog(XmlPullParser xml, boolean full) {
+ SparseArray<ReleaseItem> result = new SparseArray<ReleaseItem>();
+
+ try {
+ int eventType = xml.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ReleaseTag.NAME)) {
+ if (parseReleaseTag(xml, full, result)) {
+ // Stop reading more elements if this entry is not newer than the last
+ // version.
+ break;
+ }
+ }
+ eventType = xml.next();
+ }
+ } catch (XmlPullParserException e) {
+ Log.e(LOG_TAG, e.getMessage(), e);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.getMessage(), e);
+ }
+
+ return result;
+ }
+
+ /**
+ * Parse the {@code release} tag of a change log XML file.
+ *
+ * @param xml
+ * The {@code XmlPullParser} instance used to read the change log.
+ * @param full
+ * If {@code true} the contents of the {@code release} tag are always added to
+ * {@code changelog}. Otherwise only if the item's {@code versioncode} attribute is
+ * higher than the last version code.
+ * @param changelog
+ * The {@code SparseArray} to add a new {@link ReleaseItem} instance to.
+ *
+ * @return {@code true} if the {@code release} element is describing changes of a version older
+ * or equal to the last version. In that case {@code changelog} won't be modified and
+ * {@link #readChangeLog(XmlPullParser, boolean)} will stop reading more elements from
+ * the change log file.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private boolean parseReleaseTag(XmlPullParser xml, boolean full,
+ SparseArray<ReleaseItem> changelog) throws XmlPullParserException, IOException {
+
+ String version = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION);
+
+ int versionCode;
+ try {
+ String versionCodeStr = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION_CODE);
+ versionCode = Integer.parseInt(versionCodeStr);
+ } catch (NumberFormatException e) {
+ versionCode = NO_VERSION;
+ }
+
+ if (!full && versionCode <= mLastVersionCode) {
+ return true;
+ }
+
+ int eventType = xml.getEventType();
+ List<String> changes = new ArrayList<String>();
+ while (eventType != XmlPullParser.END_TAG || xml.getName().equals(ChangeTag.NAME)) {
+ if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ChangeTag.NAME)) {
+ eventType = xml.next();
+
+ changes.add(xml.getText());
+ }
+ eventType = xml.next();
+ }
+
+ ReleaseItem release = new ReleaseItem(versionCode, version, changes);
+ changelog.put(versionCode, release);
+
+ return false;
+ }
+
+ /**
+ * Container used to store information about a release/version.
+ */
+ protected static class ReleaseItem {
+ /**
+ * Version code of the release.
+ */
+ public final int versionCode;
+
+ /**
+ * Version name of the release.
+ */
+ public final String versionName;
+
+ /**
+ * List of changes introduced with that release.
+ */
+ public final List<String> changes;
+
+ ReleaseItem(int versionCode, String versionName, List<String> changes) {
+ this.versionCode = versionCode;
+ this.versionName = versionName;
+ this.changes = changes;
+ }
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java
index 476d3478..0d67c4c4 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/EntryAdapter.java
@@ -18,14 +18,12 @@
*/
package github.daneren2005.dsub.view;
-import github.daneren2005.dsub.view.AlbumView;
-import github.daneren2005.dsub.view.SongView;
+import android.content.Context;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.util.ImageLoader;
@@ -34,12 +32,12 @@ import github.daneren2005.dsub.util.ImageLoader;
*/
public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> {
- private final SubsonicTabActivity activity;
+ private final Context activity;
private final ImageLoader imageLoader;
private final boolean checkable;
private List<MusicDirectory.Entry> entries;
- public EntryAdapter(SubsonicTabActivity activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) {
+ public EntryAdapter(Context activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) {
super(activity, android.R.layout.simple_list_item_1, entries);
this.entries = entries;
this.activity = activity;
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java
index c9377721..71727c04 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistAdapter.java
@@ -18,12 +18,12 @@
*/
package github.daneren2005.dsub.view;
+import android.content.Context;
import github.daneren2005.dsub.R;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
-import github.daneren2005.dsub.activity.SubsonicTabActivity;
import github.daneren2005.dsub.domain.Playlist;
import java.util.Collections;
import java.util.Comparator;
@@ -33,16 +33,16 @@ import java.util.Comparator;
*/
public class PlaylistAdapter extends ArrayAdapter<Playlist> {
- private final SubsonicTabActivity activity;
+ private final Context activity;
- public PlaylistAdapter(SubsonicTabActivity activity, List<Playlist> Playlists) {
- super(activity, R.layout.playlist_list_item, Playlists);
- this.activity = activity;
- }
+ public PlaylistAdapter(Context activity, List<Playlist> Playlists) {
+ super(activity, R.layout.playlist_list_item, Playlists);
+ this.activity = activity;
+ }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Playlist entry = getItem(position);
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Playlist entry = getItem(position);
PlaylistView view;
if (convertView != null && convertView instanceof PlaylistView) {
view = (PlaylistView) convertView;
@@ -51,18 +51,18 @@ public class PlaylistAdapter extends ArrayAdapter<Playlist> {
}
view.setPlaylist(entry);
return view;
- }
-
+ }
+
public static class PlaylistComparator implements Comparator<Playlist> {
- @Override
- public int compare(Playlist playlist1, Playlist playlist2) {
- return playlist1.getName().compareToIgnoreCase(playlist2.getName());
- }
+ @Override
+ public int compare(Playlist playlist1, Playlist playlist2) {
+ return playlist1.getName().compareToIgnoreCase(playlist2.getName());
+ }
- public static List<Playlist> sort(List<Playlist> playlists) {
- Collections.sort(playlists, new PlaylistComparator());
- return playlists;
- }
+ public static List<Playlist> sort(List<Playlist> playlists) {
+ Collections.sort(playlists, new PlaylistComparator());
+ return playlists;
+ }
- }
+ }
}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java
index b09c91d4..effd5a98 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/PlaylistView.java
@@ -36,32 +36,32 @@ import java.io.File;
*/
public class PlaylistView extends UpdateView {
private static final String TAG = PlaylistView.class.getSimpleName();
-
+
private Playlist playlist;
- private TextView titleView;
+ private TextView titleView;
private ImageView moreButton;
- public PlaylistView(Context context) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
+ public PlaylistView(Context context) {
+ super(context);
+ LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
- titleView = (TextView) findViewById(R.id.playlist_name);
+ titleView = (TextView) findViewById(R.id.playlist_name);
moreButton = (ImageView) findViewById(R.id.playlist_more);
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.showContextMenu();
}
});
- }
+ }
+
+ public void setPlaylist(Playlist playlist) {
+ this.playlist = playlist;
- public void setPlaylist(Playlist playlist) {
- this.playlist = playlist;
-
- titleView.setText(playlist.getName());
+ titleView.setText(playlist.getName());
update();
- }
-
+ }
+
@Override
protected void update() {
File file = FileUtil.getPlaylistFile(playlist.getName());
@@ -70,5 +70,5 @@ public class PlaylistView extends UpdateView {
} else {
moreButton.setImageResource(R.drawable.list_item_more);
}
- }
+ }
}