aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--subsonic-android/res/layout/create_podcast.xml27
-rw-r--r--subsonic-android/res/menu/select_podcasts.xml5
-rw-r--r--subsonic-android/res/menu/select_podcasts_context.xml9
-rw-r--r--subsonic-android/res/values/strings.xml8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java167
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java5
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java17
8 files changed, 222 insertions, 24 deletions
diff --git a/subsonic-android/res/layout/create_podcast.xml b/subsonic-android/res/layout/create_podcast.xml
new file mode 100644
index 00000000..5a2ec970
--- /dev/null
+++ b/subsonic-android/res/layout/create_podcast.xml
@@ -0,0 +1,27 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/create_podcast_url_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:textSize="20dp"
+ android:text="@string/select_podcasts.add_url"/>
+ <EditText
+ android:id="@+id/create_podcast_url"
+ android:inputType="textUri"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="4dp"
+ android:text="http://"/>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/menu/select_podcasts.xml b/subsonic-android/res/menu/select_podcasts.xml
index eea03827..e77b43db 100644
--- a/subsonic-android/res/menu/select_podcasts.xml
+++ b/subsonic-android/res/menu/select_podcasts.xml
@@ -7,6 +7,11 @@
android:showAsAction="always|withText"/>
<item
+ android:id="@+id/menu_add_podcast"
+ android:icon="@drawable/action_exit"
+ android:title="@string/menu.add_podcast"/>
+
+ <item
android:id="@+id/menu_check"
android:icon="@drawable/action_refresh"
android:title="@string/menu.check_podcasts"/>
diff --git a/subsonic-android/res/menu/select_podcasts_context.xml b/subsonic-android/res/menu/select_podcasts_context.xml
new file mode 100644
index 00000000..af4edb55
--- /dev/null
+++ b/subsonic-android/res/menu/select_podcasts_context.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/podcast_channel_info"
+ android:title="@string/common.info"/>
+ <item
+ android:id="@+id/podcast_channel_delete"
+ android:title="@string/common.delete"/>
+</menu> \ No newline at end of file
diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml
index f67dd9fe..e02383b0 100644
--- a/subsonic-android/res/values/strings.xml
+++ b/subsonic-android/res/values/strings.xml
@@ -71,7 +71,8 @@
<string name="menu.deleted_playlist_error">Failed to delete playlist %s</string>
<string name="menu.log">Send Log</string>
<string name="menu.set_timer">Set Timer</string>
- <string name="menu.check_podcasts">Request Server Refresh</string>
+ <string name="menu.check_podcasts">Check For New Episodes</string>
+ <string name="menu.add_podcast">Add Channel</string>
<string name="playlist.label">Playlists</string>
<string name="playlist.update_info">Update Information</string>
@@ -139,6 +140,11 @@
<string name="select_podcasts.server_delete">Delete from server</string>
<string name="select_podcasts.downloading">Now downloading %s on the server</string>
<string name="select_podcasts.refreshing">The server is checking for new podcasts now</string>
+ <string name="select_podcasts.deleted">Deleted podcast %s</string>
+ <string name="select_podcasts.deleted_error">Failed to delete podcast %s</string>
+ <string name="select_podcasts.add_url">URL:</string>
+ <string name="select_podcasts.created_error">Failed to add podcast</string>
+ <string name="select_podcasts.invalid_podcast_channel">Invalid podcast channel: %s</string>
<string name="select_playlist.empty">No saved playlists on server</string>
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java
index 6cb3944f..a39e8d04 100644
--- a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java
+++ b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java
@@ -30,6 +30,7 @@ public class PodcastChannel implements Serializable {
private String url;
private String description;
private String status;
+ private String errorMessage;
public PodcastChannel() {
@@ -69,4 +70,11 @@ public class PodcastChannel implements Serializable {
public void setStatus(String status) {
this.status = status;
}
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
index ac12e17d..764ee49d 100644
--- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
@@ -18,22 +18,32 @@
*/
package github.daneren2005.dsub.fragments;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.os.Bundle;
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
import android.util.Log;
+import android.view.ContextMenu;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.TextView;
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.PodcastChannel;
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.Constants;
+import github.daneren2005.dsub.util.LoadingTask;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.TabBackgroundTask;
import github.daneren2005.dsub.util.Util;
@@ -48,6 +58,7 @@ import java.util.List;
public class SelectPodcastsFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
private static final String TAG = SelectPodcastsFragment.class.getSimpleName();
private ListView podcastListView;
+ private PodcastChannelAdapter podcastAdapter;
private View emptyView;
@Override
@@ -78,7 +89,7 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
if(super.onOptionsItemSelected(item)) {
return true;
}
@@ -87,12 +98,45 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
case R.id.menu_check:
refreshPodcasts();
break;
+ case R.id.menu_add_podcast:
+ addNewPodcast();
+ break;
}
return false;
}
@Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+ if(!Util.isOffline(context)) {
+ android.view.MenuInflater inflater = context.getMenuInflater();
+ inflater.inflate(R.menu.select_podcasts_context, menu);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ PodcastChannel channel = (PodcastChannel) podcastListView.getItemAtPosition(info.position);
+
+ switch (menuItem.getItemId()) {
+ case R.id.podcast_channel_info:
+ displayPodcastInfo(channel);
+ break;
+ case R.id.podcast_channel_delete:
+ deletePodcast(channel);
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
protected void refresh(final boolean refresh) {
setTitle(R.string.button_bar_podcasts);
podcastListView.setVisibility(View.INVISIBLE);
@@ -118,7 +162,7 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
if (result != null) {
- podcastListView.setAdapter(new PodcastChannelAdapter(context, result));
+ podcastListView.setAdapter(podcastAdapter = new PodcastChannelAdapter(context, result));
podcastListView.setVisibility(View.VISIBLE);
}
}
@@ -130,14 +174,18 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position);
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, channel.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME, channel.getName());
- args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription());
- fragment.setArguments(args);
-
- replaceFragment(fragment, R.id.select_podcasts_layout);
+ if("error".equals(channel.getStatus())) {
+ Util.toast(context, context.getResources().getString(R.string.select_podcasts_invalid_podcast_channel, channel.getErrorMessage() == null ? "error" : channel.getErrorMessage()));
+ } else {
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, channel.getId());
+ args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME, channel.getName());
+ args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription());
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.select_podcasts_layout);
+ }
}
public void refreshPodcasts() {
@@ -160,4 +208,101 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
}
}.execute();
}
+
+ private void addNewPodcast() {
+ View dialogView = context.getLayoutInflater().inflate(R.layout.create_podcast, null);
+ final TextView urlBox = (TextView) dialogView.findViewById(R.id.create_podcast_url);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.menu_add_podcast)
+ .setView(dialogView)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ addNewPodcast(urlBox.getText().toString());
+ }
+ })
+ .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ })
+ .setCancelable(true);
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ private void addNewPodcast(final String url) {
+ new LoadingTask<Void>(context, false) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.createPodcastChannel(url, context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ refresh();
+ }
+
+ @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.select_podcasts_created_error) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+
+ private void displayPodcastInfo(final PodcastChannel channel) {
+ String message = ((channel.getName()) == null ? "" : "Title: " + channel.getName()) +
+ "\nURL: " + channel.getUrl() +
+ "\nStatus: " + channel.getStatus() +
+ ((channel.getErrorMessage()) == null ? "" : "\nError Message: " + channel.getErrorMessage()) +
+ ((channel.getDescription()) == null ? "" : "\nDescription: " + channel.getDescription());
+
+ Util.info(context, channel.getName(), message);
+ }
+
+ private void deletePodcast(final PodcastChannel channel) {
+ Util.confirmDialog(context, R.string.common_delete, channel.getName(), 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.deletePodcastChannel(channel.getId(), context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ podcastAdapter.remove(channel);
+ podcastAdapter.notifyDataSetChanged();
+ Util.toast(context, context.getResources().getString(R.string.select_podcasts_deleted, channel.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.select_podcasts_deleted_error, channel.getName()) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+ });
+ }
}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java
index 4fc49290..b091aefa 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java
@@ -53,10 +53,7 @@ public class PodcastChannelParser extends AbstractParser {
channel.setName(get("title"));
channel.setDescription(get("description"));
channel.setStatus(get("status"));
-
- if("error".equals(channel.getStatus())) {
- channel.setStatus(get("errorMessage"));
- }
+ channel.setErrorMessage(get("errorMessage"));
channels.add(channel);
} else if ("error".equals(name)) {
handleError();
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java
index 62e67a9a..926ba1ba 100644
--- a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java
+++ b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java
@@ -31,23 +31,24 @@ public class PodcastChannelView extends UpdateView {
private static final String TAG = PodcastChannelView.class.getSimpleName();
private TextView titleView;
- private ImageButton starButton;
- private ImageView moreButton;
public PodcastChannelView(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
- moreButton = (ImageView) findViewById(R.id.artist_more);
- moreButton.setClickable(false);
+ ImageButton starButton = (ImageButton) findViewById(R.id.artist_star);
+ starButton.setVisibility(View.GONE);
+ starButton.setFocusable(false);
+ ImageView moreButton = (ImageView) findViewById(R.id.artist_more);
+ moreButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ v.showContextMenu();
+ }
+ });
}
public void setPodcastChannel(PodcastChannel podcastChannel) {
titleView.setText(podcastChannel.getName());
-
- starButton.setVisibility(View.GONE);
- starButton.setFocusable(false);
}
}