aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-android')
-rw-r--r--subsonic-android/project.properties2
-rw-r--r--subsonic-android/res/layout-land/download.xml3
-rw-r--r--subsonic-android/res/layout-port/download.xml3
-rw-r--r--subsonic-android/res/layout/download_activity.xml4
-rw-r--r--subsonic-android/res/layout/download_slider.xml3
-rw-r--r--subsonic-android/res/layout/home.xml23
-rw-r--r--subsonic-android/res/layout/main.xml109
-rw-r--r--subsonic-android/res/layout/search.xml4
-rw-r--r--subsonic-android/res/layout/select_album.xml38
-rw-r--r--subsonic-android/res/layout/select_artist.xml32
-rw-r--r--subsonic-android/res/layout/select_playlist.xml44
-rw-r--r--subsonic-android/res/values/strings.xml1
-rw-r--r--subsonic-android/res/values/styles.xml1
-rw-r--r--subsonic-android/res/values/themes.xml6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java1229
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java528
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java418
-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.java448
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java10
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java1105
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java310
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java315
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java198
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java661
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java289
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java724
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/LoadingTask.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java67
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java5
-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
35 files changed, 4692 insertions, 3333 deletions
diff --git a/subsonic-android/project.properties b/subsonic-android/project.properties
index cd253d77..f3eba228 100644
--- a/subsonic-android/project.properties
+++ b/subsonic-android/project.properties
@@ -9,5 +9,5 @@
# Project target.
target=android-16
-android.library.reference.1=../ActionBarSherlock/library
+android.library.reference.1=../ActionBarSherlock/actionbarsherlock
android.library.reference.2=../DragSortListView/library \ No newline at end of file
diff --git a/subsonic-android/res/layout-land/download.xml b/subsonic-android/res/layout-land/download.xml
index 4992d169..f7ea3162 100644
--- a/subsonic-android/res/layout-land/download.xml
+++ b/subsonic-android/res/layout-land/download.xml
@@ -124,7 +124,4 @@
</LinearLayout>
</LinearLayout>
-
- <include layout="@layout/button_bar"/>
-
</LinearLayout>
diff --git a/subsonic-android/res/layout-port/download.xml b/subsonic-android/res/layout-port/download.xml
index 2b61dd7b..33c94e1f 100644
--- a/subsonic-android/res/layout-port/download.xml
+++ b/subsonic-android/res/layout-port/download.xml
@@ -138,8 +138,5 @@
<include layout="@layout/download_media_buttons"/>
<include layout="@layout/download_slider"/>
-
- <include layout="@layout/button_bar"/>
-
</LinearLayout>
diff --git a/subsonic-android/res/layout/download_activity.xml b/subsonic-android/res/layout/download_activity.xml
new file mode 100644
index 00000000..3a1aa5e4
--- /dev/null
+++ b/subsonic-android/res/layout/download_activity.xml
@@ -0,0 +1,4 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/download_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" /> \ No newline at end of file
diff --git a/subsonic-android/res/layout/download_slider.xml b/subsonic-android/res/layout/download_slider.xml
index 32e146e7..1794126b 100644
--- a/subsonic-android/res/layout/download_slider.xml
+++ b/subsonic-android/res/layout/download_slider.xml
@@ -3,7 +3,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
- android:background="@android:color/transparent">
+ android:background="@android:color/transparent"
+ android:paddingBottom="10dip">
<TextView
android:id="@+id/download_position"
diff --git a/subsonic-android/res/layout/home.xml b/subsonic-android/res/layout/home.xml
new file mode 100644
index 00000000..018061fa
--- /dev/null
+++ b/subsonic-android/res/layout/home.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/home_layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
+
+ <ListView
+ android:id="@+id/main_list"
+ android:layout_width="fill_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"/>
+
+ <View android:id="@+id/main_dummy"
+ android:layout_width="0px"
+ android:layout_height="0px"/>
+</LinearLayout>
+
diff --git a/subsonic-android/res/layout/main.xml b/subsonic-android/res/layout/main.xml
index 56b013fe..fe79716c 100644
--- a/subsonic-android/res/layout/main.xml
+++ b/subsonic-android/res/layout/main.xml
@@ -1,28 +1,81 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <ListView
- android:id="@+id/main_list"
- android:layout_width="fill_parent"
- android:layout_height="0px"
- android:layout_weight="1"/>
-
- <View android:id="@+id/main_dummy"
- android:layout_width="0px"
- android:layout_height="0px"/>
-
- <include
- layout="@layout/button_bar"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"/>
-
-</LinearLayout>
-
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="fill_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" >
+ </android.support.v4.view.ViewPager>
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
+
+ <LinearLayout
+ android:id="@+id/bottom_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/media_button"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/album_art"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_gravity="left|center"
+ android:scaleType="fitXY"
+ android:src="@drawable/unknown_album"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="8dip">
+
+ <TextView
+ android:id="@+id/track_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="?android:textColorPrimary"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="13sp"
+ android:text="@string/search.artists"/>
+
+ <TextView
+ android:id="@+id/artist_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="?android:textColorSecondary"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="12sp"
+ android:text="@string/search.albums"/>
+ </LinearLayout>
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_previous"
+ android:src="?attr/media_button_backward"
+ android:layout_centerVertical="true"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_start"
+ android:src="?attr/media_button_start"
+ android:layout_centerVertical="true"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_next"
+ android:src="?attr/media_button_forward"
+ android:layout_centerVertical="true"/>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/layout/search.xml b/subsonic-android/res/layout/search.xml
index 5f5c26e0..d1c5c84c 100644
--- a/subsonic-android/res/layout/search.xml
+++ b/subsonic-android/res/layout/search.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/search_layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
@@ -18,7 +19,4 @@
android:layout_weight="1.0"
android:fastScrollEnabled="true"
/>
-
- <include layout="@layout/button_bar"/>
-
</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/layout/select_album.xml b/subsonic-android/res/layout/select_album.xml
index b688a95b..0bf5367f 100644
--- a/subsonic-android/res/layout/select_album.xml
+++ b/subsonic-android/res/layout/select_album.xml
@@ -1,25 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:id="@+id/select_album_layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
- <include layout="@layout/tab_progress"/>
+ <include layout="@layout/tab_progress"/>
- <TextView
- android:id="@+id/select_album_empty"
- android:text="@string/select_album.empty"
- android:visibility="gone"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"/>
+ <TextView
+ android:id="@+id/select_album_empty"
+ android:text="@string/select_album.empty"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"/>
- <com.mobeta.android.dslv.DragSortListView
+ <com.mobeta.android.dslv.DragSortListView
style="@style/DragDropListView"
android:id="@+id/select_album_entries"
android:textFilterEnabled="true"
@@ -28,7 +29,4 @@
android:layout_weight="1.0"
android:fastScrollEnabled="true"/>
- <include layout="@layout/button_bar"/>
-
-</LinearLayout>
-
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/layout/select_artist.xml b/subsonic-android/res/layout/select_artist.xml
index bebfdec4..fef51d3c 100644
--- a/subsonic-android/res/layout/select_artist.xml
+++ b/subsonic-android/res/layout/select_artist.xml
@@ -1,24 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:id="@+id/select_artist_layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
- <include layout="@layout/tab_progress"/>
-
- <ListView android:id="@+id/select_artist_list"
- android:textFilterEnabled="true"
- android:fastScrollEnabled="true"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"/>
-
- <include layout="@layout/button_bar"/>
+ <include layout="@layout/tab_progress"/>
+ <ListView android:id="@+id/select_artist_list"
+ android:textFilterEnabled="true"
+ android:fastScrollEnabled="true"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"/>
</LinearLayout>
diff --git a/subsonic-android/res/layout/select_playlist.xml b/subsonic-android/res/layout/select_playlist.xml
index 2555687d..e18283bd 100644
--- a/subsonic-android/res/layout/select_playlist.xml
+++ b/subsonic-android/res/layout/select_playlist.xml
@@ -1,32 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:id="@+id/select_playlist_layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
- <include layout="@layout/tab_progress"/>
+ <include layout="@layout/tab_progress"/>
- <TextView
- android:id="@+id/select_playlist_empty"
- android:text="@string/select_playlist.empty"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:visibility="gone"/>
+ <TextView
+ android:id="@+id/select_playlist_empty"
+ android:text="@string/select_playlist.empty"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:visibility="gone"/>
- <ListView android:id="@+id/select_playlist_list"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:fastScrollEnabled="true"
- />
-
- <include layout="@layout/button_bar"/>
+ <ListView android:id="@+id/select_playlist_list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"
+ android:fastScrollEnabled="true"/>
</LinearLayout>
diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml
index 90e455eb..c9c7c991 100644
--- a/subsonic-android/res/values/strings.xml
+++ b/subsonic-android/res/values/strings.xml
@@ -50,6 +50,7 @@
<string name="main.albums_highest">Top rated</string>
<string name="main.albums_starred">Starred</string>
<string name="main.albums_random">Random</string>
+ <string name="main.back_confirm">Press back again to exit</string>
<string name="menu.search">Search</string>
<string name="menu.shuffle">Shuffle</string>
diff --git a/subsonic-android/res/values/styles.xml b/subsonic-android/res/values/styles.xml
index 2d53a8d9..4dcce34f 100644
--- a/subsonic-android/res/values/styles.xml
+++ b/subsonic-android/res/values/styles.xml
@@ -12,6 +12,7 @@
</style>
<style name="PlaybackControl.Small" parent="@style/PlaybackControl">
+ <item name="android:padding">4dip</item>
<item name="android:layout_width">46dip</item>
<item name="android:layout_height">46dip</item>
</style>
diff --git a/subsonic-android/res/values/themes.xml b/subsonic-android/res/values/themes.xml
index 59869254..510ff977 100644
--- a/subsonic-android/res/values/themes.xml
+++ b/subsonic-android/res/values/themes.xml
@@ -52,15 +52,21 @@
<style name="Widget.DSub.ActionBarStyle.Light" parent="Widget.Sherlock.Light.ActionBar.Solid.Inverse">
<item name="background">@drawable/menubar_button_normal</item>
<item name="android:background">@drawable/actionbar_background</item>
+ <item name="backgroundStacked">@drawable/actionbar_background</item>
+ <item name="android:backgroundStacked">@drawable/actionbar_background</item>
</style>
<style name="Widget.DSub.ActionBarStyle.Dark" parent="Widget.Sherlock.ActionBar.Solid">
<item name="background">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
+ <item name="backgroundStacked">@android:color/transparent</item>
+ <item name="android:backgroundStacked">@android:color/transparent</item>
</style>
<style name="Widget.DSub.ActionBarStyle.Holo" parent="Widget.Sherlock.ActionBar.Solid">
<item name="background">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
+ <item name="backgroundStacked">@android:color/transparent</item>
+ <item name="android:backgroundStacked">@android:color/transparent</item>
</style>
</resources>
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
index 3de6178f..f229421e 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/DownloadActivity.java
@@ -18,1180 +18,145 @@
*/
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).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();
- }
- 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;
+ return super.onCreateDialog(id);
}
-
- 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) {
- }
-
- @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/MainActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
index 36a8d17d..53fb35ba 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
@@ -1,356 +1,230 @@
-/*
- 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;
+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 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;
- /**
- * 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();
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
+ stopService(new Intent(this, DownloadServiceImpl.class));
+ finish();
}
- 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);
-
- int instance = Util.getActiveServer(this);
- String name = Util.getServerName(this, instance);
- serverTextView.setText(name);
+ 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);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
- checkUpdates();
- }
+ }
@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);
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+ getSupportActionBar().setHomeButtonEnabled(false);
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- 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();
+ }
- 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 {
+ super.onBackPressed();
+ }
+ }
}
-
- 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..c06203f7 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SearchActivity.java
@@ -19,376 +19,68 @@
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;
+import com.actionbarsherlock.view.MenuItem;
- 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);
-
- 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);
+public class SearchActivity extends SubsonicActivity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.download_activity);
- list = (ListView) findViewById(R.id.search_list);
+ if (findViewById(R.id.download_container) != null && savedInstanceState == null) {
+ currentFragment = new SearchFragment();
+ currentFragment.setPrimaryFragment(true);
+ getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment).commit();
+ }
- 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);
- }
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ }
- }
- }
- }
- });
- registerForContextMenu(list);
- onNewIntent(getIntent());
- }
-
@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:
+ 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) {
+ ((SearchFragment)currentFragment).search(query, autoplay);
+ } else {
+ ((SearchFragment)currentFragment).populateList();
+ if (requestsearch) {
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);
-
- 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();
-
- 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);
- }
-
- 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);
-
- 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);
- }
- }
+ }
+ }
+ }
+
+ @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..8b48d74e
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicActivity.java
@@ -0,0 +1,448 @@
+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.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.KeyEvent;
+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.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 {
+ 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;
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ setUncaughtExceptionHandler();
+ applyTheme();
+ super.onCreate(bundle);
+ startService(new Intent(this, DownloadServiceImpl.class));
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ }
+
+ @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 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);
+ }
+
+ public boolean onBackPressedSupport() {
+ if(pagerAdapter != null) {
+ return pagerAdapter.onBackPressed();
+ } else {
+ if(backStack.size() > 0) {
+ 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();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ public void replaceFragment(SubsonicFragment fragment, int id) {
+ if(pagerAdapter != null) {
+ pagerAdapter.replaceCurrent(fragment, id);
+ } else {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ backStack.add(currentFragment);
+
+ currentFragment = fragment;
+ currentFragment.setPrimaryFragment(true);
+ invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(id, fragment);
+ trans.commit();
+ }
+ }
+
+ 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 tabs = new ArrayList();
+ private List frags = new ArrayList();
+ 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 = (TabInfo)tabs.get(i);
+ SherlockFragment frag = (SherlockFragment) Fragment.instantiate(activity, tabInfo.fragmentClass.getName(), tabInfo.args);
+ List fragStack = new ArrayList();
+ fragStack.add(frag);
+ frags.add(i, fragStack);
+ if(currentFragment == null) {
+ currentFragment = (SubsonicFragment) 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 fragStack = (List)frags.get(position);
+ currentFragment = (SubsonicFragment) fragStack.get(fragStack.size() - 1);
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(true);
+ }
+ activity.invalidateOptionsMenu();
+ }
+
+ 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) {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ List fragStack = (List)frags.get(currentPosition);
+ fragStack.add(fragment);
+
+ currentFragment = fragment;
+ currentFragment.setPrimaryFragment(true);
+ activity.invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(id, fragment);
+ trans.commit();
+ }
+
+ public void removeCurrent() {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false);
+ }
+ List fragStack = (List)frags.get(currentPosition);
+ Fragment oldFrag = (Fragment)fragStack.remove(fragStack.size() - 1);
+
+ currentFragment = (SubsonicFragment) fragStack.get(fragStack.size() - 1);
+ currentFragment.setPrimaryFragment(true);
+ activity.invalidateOptionsMenu();
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(oldFrag);
+ trans.commit();
+ }
+
+ public boolean onBackPressed() {
+ List fragStack = (List)frags.get(currentPosition);
+ if(fragStack.size() > 1) {
+ removeCurrent();
+ return false;
+ } else {
+ if(currentPosition == 0) {
+ return true;
+ } else {
+ viewPager.setCurrentItem(0);
+ return 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();
+ }
+ }
+
+ 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
index a27ad1a5..6bb7da6f 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/SubsonicTabActivity.java
@@ -86,7 +86,7 @@ public class SubsonicTabActivity extends SherlockActivity {
protected void onPostCreate(Bundle bundle) {
super.onPostCreate(bundle);
- homeButton = findViewById(R.id.button_bar_home);
+ /*homeButton = findViewById(R.id.button_bar_home);
homeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -124,7 +124,7 @@ public class SubsonicTabActivity extends SherlockActivity {
}
});
- if (this instanceof MainActivity) {
+ /*if (this instanceof MainActivity) {
homeButton.setEnabled(false);
} else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) {
musicButton.setEnabled(false);
@@ -132,7 +132,7 @@ public class SubsonicTabActivity extends SherlockActivity {
playlistButton.setEnabled(false);
} else if (this instanceof DownloadActivity || this instanceof LyricsActivity) {
nowPlayingButton.setEnabled(false);
- }
+ }*/
}
@Override
@@ -389,7 +389,7 @@ public class SubsonicTabActivity extends SherlockActivity {
return;
}
- new LoadingTask<List<Playlist>>(this, true) {
+ /*new LoadingTask<List<Playlist>>(this, true) {
@Override
protected List<Playlist> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
@@ -425,7 +425,7 @@ public class SubsonicTabActivity extends SherlockActivity {
Util.toast(SubsonicTabActivity.this, msg, false);
}
- }.execute();
+ }.execute();*/
}
private void addToPlaylist(final Playlist playlist, final List<MusicDirectory.Entry> songs) {
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..7ec4d5c7
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
@@ -0,0 +1,1105 @@
+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.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.activity.EqualizerActivity;
+import github.daneren2005.dsub.activity.LyricsActivity;
+import github.daneren2005.dsub.activity.SubsonicActivity;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+
+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 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");
+
+ 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) {
+ 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) {
+ Intent intent;
+ 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:
+ intent = new Intent(context, LyricsActivity.class);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
+ Util.startActivityWithoutTransition(context, intent);
+ 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);
+ }
+ }
+
+ 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;
+ }
+ }
+
+ 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>(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;
+ 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>(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/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
new file mode 100644
index 00000000..427c5098
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -0,0 +1,310 @@
+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 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;
+ }
+
+ 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..725f84bd
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SearchFragment.java
@@ -0,0 +1,315 @@
+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;
+ }
+
+ 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) {
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle 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, R.id.search_layout);
+ }
+
+ 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..95452eb6
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
@@ -0,0 +1,198 @@
+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 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);
+
+ folderButton = inflater.inflate(R.layout.select_artist_header, artistList, false);
+ folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
+
+ if (!Util.isOffline(context)) {
+ artistList.addHeaderView(folderButton);
+ }
+
+ 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 == folderButton) {
+ 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) {
+ 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..63c41546
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
@@ -0,0 +1,661 @@
+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 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;
+ int albumListOffset;
+
+ @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);
+
+ 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);
+ albumListOffset = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
+ }
+ load(false);
+
+ 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()) {
+ 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
+ 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, albumListOffset);
+ } 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, 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);
+ }
+
+ 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, offset, context, this);
+ }
+ return result;
+ }
+
+ @Override
+ protected void done(Pair<MusicDirectory, Boolean> result) {
+ if (!result.getFirst().getChildren().isEmpty()) {
+ if (!("starred".equals(albumListType))) {
+ moreButton.setVisibility(View.VISIBLE);
+ if(entryList.getFooterViewsCount() == 0) {
+ entryList.addFooterView(footer);
+ }
+ }
+
+ moreButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ albumListOffset += albumListSize;
+ refresh();
+ }
+ });
+ }
+ super.done(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) {
+ entryList.addHeaderView(createHeader(entries), null, false);
+ }
+ } else {
+ showHeader = false;
+ hideButtons = true;
+ }
+
+ emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
+ entryList.setAdapter(entryAdapter = new EntryAdapter(context, getImageLoader(), entries, true));
+ 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 = LayoutInflater.from(context).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);
+ if(playlistName != null) {
+ titleView.setText(playlistName);
+ } else if(name != null) {
+ titleView.setText(name);
+ }
+
+ 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 = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
+ songCountView.setText(s.toUpperCase());
+
+ return header;
+ }
+} \ 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..68222385
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
@@ -0,0 +1,289 @@
+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) {
+ 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..1284a99a
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -0,0 +1,724 @@
+/*
+ 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;
+
+public class SubsonicFragment extends SherlockFragment {
+ private static final String TAG = SubsonicFragment.class.getSimpleName();
+ protected SubsonicActivity context;
+ protected CharSequence title = "DSub";
+ protected View rootView;
+ protected boolean primaryFragment = false;
+ protected boolean invalidated = false;
+
+ @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);
+ }
+
+ public void setPrimaryFragment(boolean primary) {
+ primaryFragment = primary;
+ if(primary) {
+ if(context != null) {
+ context.setTitle(title);
+ }
+ 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);
+ }
+
+ protected void setTitle(CharSequence title) {
+ this.title = title;
+ context.setTitle(title);
+ }
+ protected void setTitle(int title) {
+ this.title = context.getResources().getString(title);
+ context.setTitle(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/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/TabBackgroundTask.java b/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java
new file mode 100644
index 00000000..c345b982
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/util/TabBackgroundTask.java
@@ -0,0 +1,67 @@
+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/view/ArtistAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
index 0edb03c5..64e5f055 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/ArtistAdapter.java
@@ -18,6 +18,7 @@
*/
package github.daneren2005.dsub.view;
+import android.content.Context;
import github.daneren2005.dsub.R;
import java.util.List;
import android.view.View;
@@ -35,13 +36,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/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);
}
- }
+ }
}