diff options
Diffstat (limited to 'subsonic-android')
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);
}
- }
+ }
}
|