diff options
18 files changed, 689 insertions, 7 deletions
diff --git a/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png b/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png Binary files differnew file mode 100644 index 00000000..f3805bfb --- /dev/null +++ b/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png diff --git a/subsonic-android/res/layout/select_podcasts.xml b/subsonic-android/res/layout/select_podcasts.xml new file mode 100644 index 00000000..3fda5799 --- /dev/null +++ b/subsonic-android/res/layout/select_podcasts.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/select_podcasts_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <include layout="@layout/tab_progress" /> + + <TextView + android:id="@+id/select_podcasts_empty" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:padding="10dip" + android:text="@string/select_podcasts.empty" + android:visibility="gone" /> + + <ListView + android:id="@+id/select_podcasts_list" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1.0" + android:textFilterEnabled="true" + android:fastScrollEnabled="true"/> + </LinearLayout> +</FrameLayout> diff --git a/subsonic-android/res/menu/select_podcasts.xml b/subsonic-android/res/menu/select_podcasts.xml new file mode 100644 index 00000000..e0f9a718 --- /dev/null +++ b/subsonic-android/res/menu/select_podcasts.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/menu_refresh" + android:icon="@drawable/action_refresh" + android:title="@string/menu.refresh" + android:showAsAction="always|withText"/> + + <item + android:id="@+id/menu_settings" + android:icon="@drawable/action_settings" + android:title="@string/menu.settings"/> + + <item + android:id="@+id/menu_exit" + android:icon="@drawable/action_exit" + android:title="@string/menu.exit"/> +</menu>
\ No newline at end of file diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml index 150933fd..d7c0d089 100644 --- a/subsonic-android/res/values/strings.xml +++ b/subsonic-android/res/values/strings.xml @@ -27,6 +27,7 @@ <string name="button_bar.search">Search</string>
<string name="button_bar.playlists">Playlists</string>
<string name="button_bar.now_playing">Playing</string>
+ <string name="button_bar.podcasts">Podcasts</string>
<string name="button_bar.chat">Chat</string>
<string name="main.welcome_title">Welcome!</string>
@@ -129,6 +130,8 @@ <string name="select_genre.empty">No genres found</string>
<string name="select_genre.blank">Blank</string>
+ <string name="select_podcasts.empty">No podcasts found</string>
+
<string name="select_playlist.empty">No saved playlists on server</string>
<string name="download.empty">Playlist is empty</string>
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java new file mode 100644 index 00000000..6cb3944f --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java @@ -0,0 +1,72 @@ +/*
+ 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.domain;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author Scott
+ */
+public class PodcastChannel implements Serializable {
+ private String id;
+ private String name;
+ private String url;
+ private String description;
+ private String status;
+
+ public PodcastChannel() {
+
+ }
+
+ public String getId() {
+ return id;
+ }
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java new file mode 100644 index 00000000..d85e8325 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java @@ -0,0 +1,62 @@ +/*
+ 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.domain;
+
+/**
+ *
+ * @author Scott
+ */
+public class PodcastEpisode extends MusicDirectory.Entry {
+ private String episodeId;
+ private String description;
+ private String date;
+ private String status;
+
+ public PodcastEpisode() {
+ setDirectory(false);
+ }
+
+ public String getEpisodeId() {
+ return episodeId;
+ }
+ public void setEpisodeId(String episodeId) {
+ this.episodeId = episodeId;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDate() {
+ return date;
+ }
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index 82b6c481..5b007e6f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -54,6 +54,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter String name;
String playlistId;
String playlistName;
+ String podcastId;
+ String podcastName;
+ String podcastDescription;
String albumListType;
String albumListExtra;
int albumListSize;
@@ -100,6 +103,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter 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);
+ podcastId = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_ID);
+ podcastName = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME);
+ podcastDescription = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION);
albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA);
albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
@@ -267,6 +273,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter emptyView.setVisibility(View.INVISIBLE);
if (playlistId != null) {
getPlaylist(playlistId, playlistName);
+ } else if(podcastId != null) {
+ getPodcast(podcastId, podcastName);
} else if (albumListType != null) {
getAlbumList(albumListType, albumListSize);
} else {
@@ -295,6 +303,17 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter }
}.execute();
}
+
+ private void getPodcast(final String podcastId, final String podcastName) {
+ setTitle(podcastName);
+
+ new LoadTask() {
+ @Override
+ protected MusicDirectory load(MusicService service) throws Exception {
+ return service.getPodcastEpisodes(podcastId, context, this);
+ }
+ }.execute();
+ }
private void getAlbumList(final String albumListType, final int size) {
showHeader = false;
@@ -648,6 +667,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
if(playlistName != null) {
titleView.setText(playlistName);
+ } else if(podcastName != null) {
+ titleView.setText(podcastName);
+ titleView.setPadding(0, 6, 4, 8);
} else if(name != null) {
titleView.setText(name);
}
@@ -673,16 +695,24 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter if (artists.size() == 1) {
artistView.setText(artists.iterator().next());
artistView.setVisibility(View.VISIBLE);
+ } else if(podcastDescription != null) {
+ artistView.setText(podcastDescription);
+ artistView.setSingleLine(false);
+ artistView.setLines(5);
} else {
artistView.setVisibility(View.GONE);
}
TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
- String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
- songCountView.setText(s.toUpperCase());
-
TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length);
- songLengthView.setText(Util.formatDuration(totalDuration));
+ if(podcastDescription == null) {
+ String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
+ songCountView.setText(s.toUpperCase());
+ songLengthView.setText(Util.formatDuration(totalDuration));
+ } else {
+ songCountView.setVisibility(View.GONE);
+ songLengthView.setVisibility(View.GONE);
+ }
if(add) {
return header;
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java new file mode 100644 index 00000000..923eac87 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java @@ -0,0 +1,140 @@ +/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2010 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.fragments;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+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.util.BackgroundTask;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.view.PodcastChannelAdapter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Scott
+ */
+public class SelectPodcastsFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = SelectPodcastsFragment.class.getSimpleName();
+ private ListView podcastListView;
+ private View emptyView;
+
+ @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_podcasts, container, false);
+
+ podcastListView = (ListView)rootView.findViewById(R.id.select_podcasts_list);
+ podcastListView.setOnItemClickListener(this);
+ emptyView = rootView.findViewById(R.id.select_podcasts_empty);
+ refresh();
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.select_podcasts, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void setPrimaryFragment(boolean primary) {
+ super.setPrimaryFragment(primary);
+ if(rootView != null) {
+ if(primary) {
+ ((ViewGroup)rootView).getChildAt(0).setVisibility(View.VISIBLE);
+ } else {
+ ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE);
+ }
+ }
+ }
+
+ @Override
+ protected void refresh(final boolean refresh) {
+ setTitle(R.string.button_bar_podcasts);
+
+ BackgroundTask<List<PodcastChannel>> task = new TabBackgroundTask<List<PodcastChannel>>(this) {
+ @Override
+ protected List<PodcastChannel> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+
+ List<PodcastChannel> channels = new ArrayList<PodcastChannel>();
+
+ try {
+ channels = musicService.getPodcastChannels(refresh, context, this);
+ } catch (Exception x) {
+ Log.e(TAG, "Failed to load podcasts", x);
+ }
+
+ return channels;
+ }
+
+ @Override
+ protected void done(List<PodcastChannel> result) {
+ emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
+
+ if (result != null) {
+ podcastListView.setAdapter(new PodcastChannelAdapter(context, result));
+ }
+
+ }
+ };
+ task.execute();
+ }
+
+ @Override
+ 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);
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java index a6d6e8f8..e06f3372 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -33,6 +33,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; @@ -59,6 +61,7 @@ public class CachedMusicService implements MusicService { private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS); private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS); private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS); + private final TimeLimitedCache<List<PodcastChannel>> cachedPodcastChannels = new TimeLimitedCache<List<PodcastChannel>>(10 * 3600, TimeUnit.SECONDS); private String restUrl; public CachedMusicService(MusicService musicService) { @@ -303,6 +306,23 @@ public class CachedMusicService implements MusicService { } @Override + public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List<PodcastChannel> result = refresh ? null : cachedPodcastChannels.get(); + + if (result == null) { + result = musicService.getPodcastChannels(refresh, context, progressListener); + cachedPodcastChannels.set(result); + } + + return result; + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + return musicService.getPodcastEpisodes(id, context, progressListener); + } + + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return musicService.processOfflineSyncs(context, progressListener); } diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java index c6efffc3..57deff8f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java @@ -32,6 +32,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; @@ -116,7 +118,11 @@ public interface MusicService { List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; + + List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception; + + MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; }
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java index ba194562..ea45b626 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -42,6 +42,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.util.Constants; @@ -595,6 +597,16 @@ public class OfflineMusicService extends RESTMusicService { return result; } + + @Override + public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting Podcasts not available in offline mode"); + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting Podcasts not available in offline mode"); + } @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java index ac564f29..ffa8e676 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -84,6 +84,8 @@ import github.daneren2005.dsub.service.parser.MusicDirectoryParser; import github.daneren2005.dsub.service.parser.MusicFoldersParser; import github.daneren2005.dsub.service.parser.PlaylistParser; import github.daneren2005.dsub.service.parser.PlaylistsParser; +import github.daneren2005.dsub.service.parser.PodcastChannelParser; +import github.daneren2005.dsub.service.parser.PodcastEntryParser; import github.daneren2005.dsub.service.parser.RandomSongsParser; import github.daneren2005.dsub.service.parser.SearchResult2Parser; import github.daneren2005.dsub.service.parser.SearchResultParser; @@ -885,6 +887,26 @@ public class RESTMusicService implements MusicService { } @Override + public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("includeEpisodes"), Arrays.<Object>asList("false")); + try { + return new PodcastChannelParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("id"), Arrays.<Object>asList(id)); + try { + return new PodcastEntryParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); } diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java new file mode 100644 index 00000000..4fc49290 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java @@ -0,0 +1,70 @@ +/*
+ 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.service.parser;
+
+import android.content.Context;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.PodcastChannel;
+import github.daneren2005.dsub.util.ProgressListener;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ *
+ * @author Scott
+ */
+public class PodcastChannelParser extends AbstractParser {
+ public PodcastChannelParser(Context context) {
+ super(context);
+ }
+
+ public List<PodcastChannel> parse(Reader reader, ProgressListener progressListener) throws Exception {
+ updateProgress(progressListener, R.string.parser_reading);
+ init(reader);
+
+ List<PodcastChannel> channels = new ArrayList<PodcastChannel>();
+ int eventType;
+ do {
+ eventType = nextParseEvent();
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+ if ("channel".equals(name)) {
+ PodcastChannel channel = new PodcastChannel();
+ channel.setId(get("id"));
+ channel.setUrl(get("url"));
+ channel.setName(get("title"));
+ channel.setDescription(get("description"));
+ channel.setStatus(get("status"));
+
+ if("error".equals(channel.getStatus())) {
+ channel.setStatus(get("errorMessage"));
+ }
+ channels.add(channel);
+ } else if ("error".equals(name)) {
+ handleError();
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ return channels;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java new file mode 100644 index 00000000..efc36a7e --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java @@ -0,0 +1,79 @@ +/*
+ 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.service.parser;
+
+import android.content.Context;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.PodcastEpisode;
+import github.daneren2005.dsub.util.ProgressListener;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ *
+ * @author Scott
+ */
+public class PodcastEntryParser extends AbstractParser {
+ public PodcastEntryParser(Context context) {
+ super(context);
+ }
+
+ public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
+ updateProgress(progressListener, R.string.parser_reading);
+ init(reader);
+
+ MusicDirectory episodes = new MusicDirectory();
+ int eventType;
+ do {
+ eventType = nextParseEvent();
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+ if ("channel".equals(name)) {
+ episodes.setId(get("id"));
+ episodes.setName(get("title"));
+ }
+ else if ("episode".equals(name)) {
+ PodcastEpisode episode = new PodcastEpisode();
+ episode.setEpisodeId(get("id"));
+ episode.setId(get("streamId"));
+ episode.setTitle(get("title"));
+ episode.setDescription(get("description"));
+ episode.setDate(get("publishDate"));
+ episode.setStatus(get("status"));
+ episode.setCoverArt(get("coverArt"));
+ episode.setSize(getLong("size"));
+ episode.setContentType(get("contentType"));
+ episode.setSuffix(get("suffix"));
+ episode.setDuration(getInteger("duration"));
+ episode.setBitRate(getInteger("bitRate"));
+ episode.setPath(get("path"));
+ episodes.addChild(episode);
+ } else if ("error".equals(name)) {
+ handleError();
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ return episodes;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java index 2d7edbab..a5168a9a 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java @@ -55,6 +55,9 @@ public final class Constants { public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ; public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download"; public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album"; + public static final String INTENT_EXTRA_NAME_PODCAST_ID = "subsonic.podcast.id"; + public static final String INTENT_EXTRA_NAME_PODCAST_NAME = "subsonic.podcast.name"; + public static final String INTENT_EXTRA_NAME_PODCAST_DESCRIPTION = "subsonic.podcast.description"; // Notification IDs. public static final int NOTIFICATION_ID_PLAYING = 100; diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java new file mode 100644 index 00000000..6b7af991 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java @@ -0,0 +1,59 @@ +/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2010 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.view;
+
+import android.widget.ArrayAdapter;
+import android.widget.SectionIndexer;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.PodcastChannel;
+
+import java.util.List;
+import java.util.Set;
+import java.util.LinkedHashSet;
+import java.util.ArrayList;
+
+/**
+ * @author Sindre Mehus
+*/
+public class PodcastChannelAdapter extends ArrayAdapter<PodcastChannel>{
+ private Context activity;
+ private List<PodcastChannel> podcasts;
+
+ public PodcastChannelAdapter(Context context, List<PodcastChannel> podcasts) {
+ super(context, android.R.layout.simple_list_item_1, podcasts);
+ this.activity = context;
+ this.podcasts = podcasts;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ PodcastChannel podcast = podcasts.get(position);
+ PodcastChannelView view;
+ if (convertView != null && convertView instanceof PodcastChannelView) {
+ view = (PodcastChannelView) convertView;
+ } else {
+ view = new PodcastChannelView(activity);
+ }
+ view.setPodcastChannel(podcast);
+ return view;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java new file mode 100644 index 00000000..62e67a9a --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java @@ -0,0 +1,53 @@ +/*
+ 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.view;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.PodcastChannel;
+
+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);
+ }
+
+ public void setPodcastChannel(PodcastChannel podcastChannel) {
+ titleView.setText(podcastChannel.getName());
+
+ starButton.setVisibility(View.GONE);
+ starButton.setFocusable(false);
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/SongView.java b/subsonic-android/src/github/daneren2005/dsub/view/SongView.java index 64a1d911..6f594048 100644 --- a/subsonic-android/src/github/daneren2005/dsub/view/SongView.java +++ b/subsonic-android/src/github/daneren2005/dsub/view/SongView.java @@ -87,7 +87,10 @@ public class SongView extends UpdateView implements Checkable { } if(!song.isVideo()) { - artist.append(song.getArtist()).append(" (") + if(song.getArtist() != null) { + artist.append(song.getArtist()); + } + artist.append(" (") .append(String.format(getContext().getString(R.string.song_details_all), bitRate == null ? "" : bitRate, fileFormat)) .append(")"); } else { @@ -101,7 +104,7 @@ public class SongView extends UpdateView implements Checkable { } titleTextView.setText(title); - artistTextView.setText(artist); + artistTextView.setText(artist); durationTextView.setText(Util.formatDuration(song.getDuration())); checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); starButton.setVisibility(!song.isStarred() ? View.GONE : View.VISIBLE); |