From 3f27964f47a7aed7afddf4e4d3542ffecb23afc1 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sun, 29 Dec 2013 00:46:38 -0800 Subject: #173 Add a share management tab --- res/drawable-hdpi/ic_menu_share_dark.png | Bin 0 -> 737 bytes res/drawable-hdpi/ic_menu_share_light.png | Bin 0 -> 825 bytes res/drawable-mdpi/ic_menu_share_dark.png | Bin 0 -> 455 bytes res/drawable-mdpi/ic_menu_share_light.png | Bin 0 -> 534 bytes res/drawable-xhdpi/ic_menu_share_dark.png | Bin 0 -> 947 bytes res/drawable-xhdpi/ic_menu_share_light.png | Bin 0 -> 1101 bytes res/drawable-xxhdpi/ic_menu_share_dark.png | Bin 0 -> 1592 bytes res/drawable-xxhdpi/ic_menu_share_light.png | Bin 0 -> 1790 bytes res/layout/complex_list_item.xml | 50 +++++ res/layout/update_share.xml | 69 +++++++ res/menu/select_share_context.xml | 17 ++ res/values/arrays.xml | 4 + res/values/strings.xml | 19 ++ .../dsub/activity/SubsonicActivity.java | 15 +- .../dsub/activity/SubsonicFragmentActivity.java | 3 + .../daneren2005/dsub/domain/MusicDirectory.java | 3 + src/github/daneren2005/dsub/domain/Share.java | 22 ++- .../dsub/fragments/SelectDirectoryFragment.java | 29 ++- .../dsub/fragments/SelectShareFragment.java | 216 +++++++++++++++++++++ .../dsub/fragments/SubsonicFragment.java | 11 +- .../dsub/service/CachedMusicService.java | 15 ++ .../daneren2005/dsub/service/MusicService.java | 6 + .../daneren2005/dsub/service/RESTMusicService.java | 82 ++++++++ .../dsub/service/parser/ShareParser.java | 12 +- src/github/daneren2005/dsub/util/Constants.java | 2 + src/github/daneren2005/dsub/view/ShareAdapter.java | 55 ++++++ src/github/daneren2005/dsub/view/ShareView.java | 65 +++++++ 27 files changed, 682 insertions(+), 13 deletions(-) create mode 100644 res/drawable-hdpi/ic_menu_share_dark.png create mode 100644 res/drawable-hdpi/ic_menu_share_light.png create mode 100644 res/drawable-mdpi/ic_menu_share_dark.png create mode 100644 res/drawable-mdpi/ic_menu_share_light.png create mode 100644 res/drawable-xhdpi/ic_menu_share_dark.png create mode 100644 res/drawable-xhdpi/ic_menu_share_light.png create mode 100644 res/drawable-xxhdpi/ic_menu_share_dark.png create mode 100644 res/drawable-xxhdpi/ic_menu_share_light.png create mode 100644 res/layout/complex_list_item.xml create mode 100644 res/layout/update_share.xml create mode 100644 res/menu/select_share_context.xml create mode 100644 src/github/daneren2005/dsub/fragments/SelectShareFragment.java create mode 100644 src/github/daneren2005/dsub/view/ShareAdapter.java create mode 100644 src/github/daneren2005/dsub/view/ShareView.java diff --git a/res/drawable-hdpi/ic_menu_share_dark.png b/res/drawable-hdpi/ic_menu_share_dark.png new file mode 100644 index 00000000..218aa864 Binary files /dev/null and b/res/drawable-hdpi/ic_menu_share_dark.png differ diff --git a/res/drawable-hdpi/ic_menu_share_light.png b/res/drawable-hdpi/ic_menu_share_light.png new file mode 100644 index 00000000..cfd19d43 Binary files /dev/null and b/res/drawable-hdpi/ic_menu_share_light.png differ diff --git a/res/drawable-mdpi/ic_menu_share_dark.png b/res/drawable-mdpi/ic_menu_share_dark.png new file mode 100644 index 00000000..c37aadba Binary files /dev/null and b/res/drawable-mdpi/ic_menu_share_dark.png differ diff --git a/res/drawable-mdpi/ic_menu_share_light.png b/res/drawable-mdpi/ic_menu_share_light.png new file mode 100644 index 00000000..72eeb598 Binary files /dev/null and b/res/drawable-mdpi/ic_menu_share_light.png differ diff --git a/res/drawable-xhdpi/ic_menu_share_dark.png b/res/drawable-xhdpi/ic_menu_share_dark.png new file mode 100644 index 00000000..41073d1f Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_share_dark.png differ diff --git a/res/drawable-xhdpi/ic_menu_share_light.png b/res/drawable-xhdpi/ic_menu_share_light.png new file mode 100644 index 00000000..36f9f55f Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_share_light.png differ diff --git a/res/drawable-xxhdpi/ic_menu_share_dark.png b/res/drawable-xxhdpi/ic_menu_share_dark.png new file mode 100644 index 00000000..1fa12609 Binary files /dev/null and b/res/drawable-xxhdpi/ic_menu_share_dark.png differ diff --git a/res/drawable-xxhdpi/ic_menu_share_light.png b/res/drawable-xxhdpi/ic_menu_share_light.png new file mode 100644 index 00000000..7511340b Binary files /dev/null and b/res/drawable-xxhdpi/ic_menu_share_light.png differ diff --git a/res/layout/complex_list_item.xml b/res/layout/complex_list_item.xml new file mode 100644 index 00000000..87fa7b2f --- /dev/null +++ b/res/layout/complex_list_item.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/update_share.xml b/res/layout/update_share.xml new file mode 100644 index 00000000..92b7137b --- /dev/null +++ b/res/layout/update_share.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/menu/select_share_context.xml b/res/menu/select_share_context.xml new file mode 100644 index 00000000..3ef2826f --- /dev/null +++ b/res/menu/select_share_context.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 4b8caa96..a9702496 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -6,6 +6,7 @@ @string/button_bar.playlists @string/button_bar.podcasts @string/button_bar.bookmarks + @string/button_bar.shares @string/button_bar.chat @string/menu.settings @@ -16,6 +17,7 @@ Playlist Podcast Bookmark + Share Chat Settings @@ -26,6 +28,7 @@ @drawable/ic_menu_playlist_light @drawable/ic_menu_podcast_light @drawable/ic_menu_bookmark_light + @drawable/ic_menu_share_light @drawable/ic_menu_chat_light @drawable/ic_menu_settings_light @@ -36,6 +39,7 @@ @drawable/ic_menu_playlist_dark @drawable/ic_menu_podcast_dark @drawable/ic_menu_bookmark_dark + @drawable/ic_menu_share_dark @drawable/ic_menu_chat_dark @drawable/ic_menu_settings_dark diff --git a/res/values/strings.xml b/res/values/strings.xml index 744b6dcd..2c0d2ff3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -31,6 +31,7 @@ Now Playing Podcasts Bookmarks + Shares Chat Welcome! @@ -389,6 +390,24 @@ Genre: Pick a genre + Owner: %1$s + \nDescription: %2$s + \nURL: %3$s + \nCreation: %4$s + \nLast Visited: %5$s + \nExpiration: %6$s + \nVisit Count: %7$s + + + Expires: %s + Never Expires + Deleted share %s + Failed to delete share %s + No expiration + Expires: + Updated share information for %s + Failed to update share information for %s + A network error occurred. Retrying %1$d of %2$d. Please wait... diff --git a/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/src/github/daneren2005/dsub/activity/SubsonicActivity.java index bc239b4b..77a592bb 100644 --- a/src/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/src/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -375,6 +375,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte SharedPreferences prefs = Util.getPreferences(this); boolean podcastsEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_PODCASTS_ENABLED, true); boolean bookmarksEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true) && !Util.isOffline(this); + boolean sharedEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SHARED_ENABLED, true) && !Util.isOffline(this); boolean chatEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true) && !Util.isOffline(this); if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == chatEnabled) { @@ -412,15 +413,23 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte drawerItemsIconsList.remove(4 - alreadyRemoved); alreadyRemoved++; } - - // Selectively remove chat listing: [5] - if(!chatEnabled) { + + // Selectively remove shared listing [5] + if(!bookmarksEnabled) { drawerItemsList.remove(5 - alreadyRemoved); drawerItemsDescriptionsList.remove(5 - alreadyRemoved); drawerItemsIconsList.remove(5 - alreadyRemoved); alreadyRemoved++; } + // Selectively remove chat listing: [6] + if(!chatEnabled) { + drawerItemsList.remove(6 - alreadyRemoved); + drawerItemsDescriptionsList.remove(6 - alreadyRemoved); + drawerItemsIconsList.remove(6 - alreadyRemoved); + alreadyRemoved++; + } + // Put list back together if(alreadyRemoved > 0) { drawerItems = drawerItemsList.toArray(new String[0]); diff --git a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index b51eb29b..423e1c23 100644 --- a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -53,6 +53,7 @@ import github.daneren2005.dsub.fragments.SelectBookmarkFragment; import github.daneren2005.dsub.fragments.SelectDirectoryFragment; import github.daneren2005.dsub.fragments.SelectPlaylistFragment; import github.daneren2005.dsub.fragments.SelectPodcastsFragment; +import github.daneren2005.dsub.fragments.SelectShareFragment; import github.daneren2005.dsub.fragments.SubsonicFragment; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; @@ -381,6 +382,8 @@ public class SubsonicFragmentActivity extends SubsonicActivity { return new SelectPodcastsFragment(); } else if("Bookmark".equals(fragmentType)) { return new SelectBookmarkFragment(); + } else if("Share".equals(fragmentType)) { + return new SelectShareFragment(); } else { return new MainFragment(); } diff --git a/src/github/daneren2005/dsub/domain/MusicDirectory.java b/src/github/daneren2005/dsub/domain/MusicDirectory.java index b5707daf..8233ee48 100644 --- a/src/github/daneren2005/dsub/domain/MusicDirectory.java +++ b/src/github/daneren2005/dsub/domain/MusicDirectory.java @@ -72,6 +72,9 @@ public class MusicDirectory implements Serializable { public void addChild(Entry child) { children.add(child); } + public void addChildren(List children) { + this.children.addAll(children); + } public void replaceChildren(List children) { this.children = children; diff --git a/src/github/daneren2005/dsub/domain/Share.java b/src/github/daneren2005/dsub/domain/Share.java index d19496f9..31ab7b8d 100644 --- a/src/github/daneren2005/dsub/domain/Share.java +++ b/src/github/daneren2005/dsub/domain/Share.java @@ -41,6 +41,14 @@ public class Share implements Serializable { public Share() { entries = new ArrayList(); } + + public String getName() { + if(description != null && !"".equals(description)) { + return description; + } else { + return url.replaceFirst(".*/([^/?]+).*", "$1"); + } + } public String getId() { return id; @@ -55,7 +63,7 @@ public class Share implements Serializable { } public void setUrl(String url) { - this.url = url; + this.url = url; } public String getDescription() { @@ -129,12 +137,20 @@ public class Share implements Serializable { public void setVisitCount(Long visitCount) { this.visitCount = visitCount; } - + + public MusicDirectory getMusicDirectory() { + MusicDirectory dir = new MusicDirectory(); + dir.addChildren(entries); + dir.setId(getId()); + dir.setName(getName()); + return dir; + } + public List getEntries() { return this.entries; } public void addEntry(Entry entry) { - entries.add(entry); + entries.add(entry); } } diff --git a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index acc659b2..f16c197d 100644 --- a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -21,6 +21,7 @@ import android.widget.ListView; import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.view.EntryAdapter; @@ -131,6 +132,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter 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); + Object shareObj = args.getSerializable(Constants.INTENT_EXTRA_NAME_SHARE); + share = (shareObj != null) ? (Share) shareObj : null; 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); @@ -363,6 +366,12 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter getPlaylist(playlistId, playlistName, refresh); } else if(podcastId != null) { getPodcast(podcastId, podcastName, refresh); + } else if (share != null) { + if(showAll) { + getRecursiveMusicDirectory(share.getId(), share.getName(), refresh); + } else { + getShare(share, refresh); + } } else if (albumListType != null) { getAlbumList(albumListType, albumListSize); } else { @@ -397,7 +406,12 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { - MusicDirectory root = service.getMusicDirectory(id, name, refresh, context, this); + MusicDirectory root; + if(share == null) { + root = service.getMusicDirectory(id, name, refresh, context, this); + } else { + root = share.getMusicDirectory(); + } List songs = new ArrayList(); getSongsRecursively(root, songs); root.replaceChildren(songs); @@ -442,6 +456,17 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter }.execute(); } + private void getShare(final Share share, final boolean refresh) { + setTitle(share.getName()); + + new LoadTask() { + @Override + protected MusicDirectory load(MusicService service) throws Exception { + return share.getMusicDirectory(); + } + }.execute(); + } + private void getAlbumList(final String albumListType, final int size) { showHeader = false; @@ -564,7 +589,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } } - if (hasSubFolders && id != null) { + if (hasSubFolders && (id != null || share != null)) { downloadRecursively(id, false, append, !append, shuffle, false); } else { selectAll(true, false); diff --git a/src/github/daneren2005/dsub/fragments/SelectShareFragment.java b/src/github/daneren2005/dsub/fragments/SelectShareFragment.java new file mode 100644 index 00000000..556fc8da --- /dev/null +++ b/src/github/daneren2005/dsub/fragments/SelectShareFragment.java @@ -0,0 +1,216 @@ +package github.daneren2005.dsub.fragments; + +import android.app.AlertDialog; +import android.app.DatePickerDialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.Log; +import android.view.ContextMenu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.DatePicker; +import android.widget.EditText; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.Share; +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.LoadingTask; +import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.ShareAdapter; + +/** + * Created by Scott on 12/28/13. + */ +public class SelectShareFragment extends SelectListFragment { + private static final String TAG = SelectShareFragment.class.getSimpleName(); + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + android.view.MenuInflater inflater = context.getMenuInflater(); + inflater.inflate(R.menu.select_share_context, menu); + recreateContextMenu(menu); + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + if(menuItem.getGroupId() != getSupportTag()) { + return false; + } + + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); + Share share = (Share) listView.getItemAtPosition(info.position); + + switch (menuItem.getItemId()) { + case R.id.share_menu_info: + displayShareInfo(share); + break; + case R.id.share_menu_delete: + deleteShare(share); + break; + case R.id.share_update_info: + updateShareInfo(share); + break; + } + + return true; + } + + @Override + public int getOptionsMenu() { + return R.menu.abstract_top_menu; + } + + @Override + public ArrayAdapter getAdapter(List objs) { + return new ShareAdapter(context, objs); + } + + @Override + public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + return musicService.getShares(context, listener); + } + + @Override + public int getTitleResource() { + return R.string.button_bar_shares; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Share share = (Share) parent.getItemAtPosition(position); + + SubsonicFragment fragment = new SelectDirectoryFragment(); + Bundle args = new Bundle(); + args.putSerializable(Constants.INTENT_EXTRA_NAME_SHARE, share); + fragment.setArguments(args); + + replaceFragment(fragment, R.id.fragment_list_layout); + } + + private void displayShareInfo(final Share share) { + String message = context.getResources().getString(R.string.share_info, + share.getUsername(), (share.getDescription() != null) ? share.getDescription() : "", share.getUrl(), + share.getCreated(), share.getLastVisited(), share.getExpires(), share.getVisitCount()); + Util.info(context, share.getName(), message); + } + + private void updateShareInfo(final Share share) { + View dialogView = context.getLayoutInflater().inflate(R.layout.update_share, null); + final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_share_name); + final DatePicker expireBox = (DatePicker)dialogView.findViewById(R.id.get_share_expire); + final CheckBox noExpiresBox = (CheckBox)dialogView.findViewById(R.id.get_share_no_expire); + + nameBox.setText(share.getDescription()); + Date expires = share.getExpires(); + if(expires != null) { + expireBox.updateDate(expires.getYear() + 1900, expires.getMonth(), expires.getDate()); + } + + boolean noExpires = share.getExpires() == null; + if(noExpires) { + expireBox.setEnabled(false); + noExpiresBox.setChecked(true); + } + + noExpiresBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + expireBox.setEnabled(!isChecked); + } + }); + + 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(context, false) { + @Override + protected Void doInBackground() throws Throwable { + Long expiresIn = 0L; + if (!noExpiresBox.isChecked()) { + Date expires = new Date(expireBox.getYear() - 1900, expireBox.getMonth(), expireBox.getDayOfMonth()); + expiresIn = expires.getTime(); + } + + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.updateShare(share.getId(), nameBox.getText().toString(), expiresIn, context, null); + return null; + } + + @Override + protected void done(Void result) { + refresh(); + Util.toast(context, context.getResources().getString(R.string.share_updated_info, share.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.share_updated_info_error, share.getName()) + " " + getErrorMessage(error); + } + + Util.toast(context, msg, false); + } + }.execute(); + } + + }) + .setNegativeButton(R.string.common_cancel, null) + .show(); + } + + private void deleteShare(final Share share) { + Util.confirmDialog(context, R.string.common_delete, share.getName(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + new LoadingTask(context, false) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.deleteShare(share.getId(), context, null); + return null; + } + + @Override + protected void done(Void result) { + adapter.remove(share); + adapter.notifyDataSetChanged(); + Util.toast(context, context.getResources().getString(R.string.share_deleted, share.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.share_deleted_error, share.getName()) + " " + getErrorMessage(error); + } + + Util.toast(context, msg, false); + } + }.execute(); + } + }); + } +} diff --git a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java index c9040048..626d4259 100644 --- a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -51,6 +51,7 @@ import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastEpisode; +import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.DownloadServiceImpl; @@ -90,6 +91,7 @@ public class SubsonicFragment extends Fragment { protected boolean invalidated = false; protected static Random random = new Random(); protected GestureDetector gestureScanner; + protected Share share; public SubsonicFragment() { super(); @@ -662,10 +664,15 @@ public class SubsonicFragment extends Fragment { protected List doInBackground() throws Throwable { MusicService musicService = MusicServiceFactory.getMusicService(context); MusicDirectory root; - if(isDirectory) + if(share != null) { + root = share.getMusicDirectory(); + } + else if(isDirectory) { root = musicService.getMusicDirectory(id, name, false, context, this); - else + } + else { root = musicService.getPlaylist(true, id, name, context, this); + } List songs = new LinkedList(); getSongsRecursively(root, songs); return songs; diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 221ea03c..21c2ae68 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -327,6 +327,21 @@ public class CachedMusicService implements MusicService { return musicService.getShares(context, progressListener); } + @Override + public List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { + return musicService.createShare(ids, description, expires, context, progressListener); + } + + @Override + public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception { + musicService.deleteShare(id, context, progressListener); + } + + @Override + public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { + musicService.updateShare(id, description, expires, context, progressListener); + } + @Override public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { return musicService.getChatMessages(since, context, progressListener); diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index 1fb317ce..7e19e49e 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -116,6 +116,12 @@ public interface MusicService { void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception; List getShares(Context context, ProgressListener progressListener) throws Exception; + + List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception; + + void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception; + + void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception; List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index febabc69..6d55cbd3 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -834,6 +834,88 @@ public class RESTMusicService implements MusicService { } } + @Override + public List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { + List parameterNames = new LinkedList(); + List parameterValues = new LinkedList(); + + for (String id : ids) { + parameterNames.add("id"); + parameterValues.add(id); + } + + if (description != null) { + parameterNames.add("description"); + parameterValues.add(description); + } + + if (expires > 0) { + parameterNames.add("expires"); + parameterValues.add(expires); + } + + Reader reader = getReader(context, progressListener, "createShare", null, parameterNames, parameterValues); + try { + return new ShareParser(context).parse(reader, progressListener); + } + finally { + Util.close(reader); + } + } + + @Override + public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception { + checkServerVersion(context, "1.6", "Shares not supported."); + + HttpParams params = new BasicHttpParams(); + HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); + + List parameterNames = new ArrayList(); + List parameterValues = new ArrayList(); + + parameterNames.add("id"); + parameterValues.add(id); + + Reader reader = getReader(context, progressListener, "deleteShare", params, parameterNames, parameterValues); + + try { + new ErrorParser(context).parse(reader); + } + finally { + Util.close(reader); + } + } + + @Override + public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { + checkServerVersion(context, "1.6", "Updating share not supported."); + + HttpParams params = new BasicHttpParams(); + HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); + + List parameterNames = new ArrayList(); + List parameterValues = new ArrayList(); + + parameterNames.add("id"); + parameterValues.add(id); + + if (description != null) { + parameterNames.add("description"); + parameterValues.add(description); + } + + parameterNames.add("expires"); + parameterValues.add(expires); + + Reader reader = getReader(context, progressListener, "updateShare", params, parameterNames, parameterValues); + try { + new ErrorParser(context).parse(reader); + } + finally { + Util.close(reader); + } + } + @Override public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.2", "Chat not supported."); diff --git a/src/github/daneren2005/dsub/service/parser/ShareParser.java b/src/github/daneren2005/dsub/service/parser/ShareParser.java index c317e799..4688faf8 100644 --- a/src/github/daneren2005/dsub/service/parser/ShareParser.java +++ b/src/github/daneren2005/dsub/service/parser/ShareParser.java @@ -19,6 +19,8 @@ package github.daneren2005.dsub.service.parser; import android.content.Context; +import android.util.Log; + import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.util.ProgressListener; @@ -31,8 +33,9 @@ import java.util.List; * @author Joshua Bahnsen */ public class ShareParser extends MusicDirectoryEntryParser { + private static final String TAG = ShareParser.class.getSimpleName(); - public ShareParser(Context context) { + public ShareParser(Context context) { super(context); } @@ -54,15 +57,18 @@ public class ShareParser extends MusicDirectoryEntryParser { if ("share".equals(name)) { share = new Share(); share.setCreated(get("created")); + share.setUrl(get("url")); share.setDescription(get("description")); share.setExpires(get("expires")); share.setId(get("id")); share.setLastVisited(get("lastVisited")); - share.setUrl(get("url")); share.setUsername(get("username")); share.setVisitCount(getLong("visitCount")); + dir.add(share); } else if ("entry".equals(name)) { - share.addEntry(parseEntry(null)); + if(share != null) { + share.addEntry(parseEntry(null)); + } } else if ("error".equals(name)) { handleError(); } diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java index 4383a964..c51e1ee1 100644 --- a/src/github/daneren2005/dsub/util/Constants.java +++ b/src/github/daneren2005/dsub/util/Constants.java @@ -59,6 +59,7 @@ public final class Constants { 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"; + public static final String INTENT_EXTRA_NAME_SHARE = "subsonic.share"; public static final String INTENT_EXTRA_FRAGMENT_TYPE = "fragmentType"; public static final String INTENT_EXTRA_REFRESH_LISTINGS = "refreshListings"; @@ -134,6 +135,7 @@ public final class Constants { public static final String PREFERENCES_KEY_MENU_PLAY_NEXT = "showPlayNext"; public static final String PREFERENCES_KEY_MENU_PLAY_LAST = "showPlayLast"; public static final String PREFERENCES_KEY_MENU_STAR = "showStar"; + public static final String PREFERENCES_KEY_SHARED_ENABLED = "sharedEnabled"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; diff --git a/src/github/daneren2005/dsub/view/ShareAdapter.java b/src/github/daneren2005/dsub/view/ShareAdapter.java new file mode 100644 index 00000000..362e1c83 --- /dev/null +++ b/src/github/daneren2005/dsub/view/ShareAdapter.java @@ -0,0 +1,55 @@ +/* + 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 . + + Copyright 2010 (C) Sindre Mehus + */ +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; + +import java.util.List; + +import github.daneren2005.dsub.domain.Share; + +/** + * @author Sindre Mehus +*/ +public class ShareAdapter extends ArrayAdapter{ + private Context activity; + private List shares; + + public ShareAdapter(Context context, List shares) { + super(context, android.R.layout.simple_list_item_1, shares); + this.activity = context; + this.shares = shares; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Share share = shares.get(position); + ShareView view; + if (convertView != null && convertView instanceof ShareView) { + view = (ShareView) convertView; + } else { + view = new ShareView(activity); + } + view.setObject(share); + return view; + } +} diff --git a/src/github/daneren2005/dsub/view/ShareView.java b/src/github/daneren2005/dsub/view/ShareView.java new file mode 100644 index 00000000..d00e9d7c --- /dev/null +++ b/src/github/daneren2005/dsub/view/ShareView.java @@ -0,0 +1,65 @@ +/* + 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 . + + 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 java.text.SimpleDateFormat; +import java.util.Locale; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.Share; + +public class ShareView extends UpdateView { + private static final String TAG = ShareView.class.getSimpleName(); + + private TextView titleView; + private TextView descriptionView; + + public ShareView(Context context) { + super(context); + LayoutInflater.from(context).inflate(R.layout.complex_list_item, this, true); + + titleView = (TextView) findViewById(R.id.item_name); + descriptionView = (TextView) findViewById(R.id.item_description); + starButton = (ImageButton) findViewById(R.id.item_star); + starButton.setFocusable(false); + moreButton = (ImageView) findViewById(R.id.item_more); + moreButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + v.showContextMenu(); + } + }); + } + + public void setObjectImpl(Object obj) { + Share share = (Share) obj; + titleView.setText(share.getName()); + if(share.getExpires() != null) { + descriptionView.setText(context.getResources().getString(R.string.share_expires, new SimpleDateFormat("E MMM d yyyy", Locale.ENGLISH).format(share.getExpires()))); + } else { + descriptionView.setText(context.getResources().getString(R.string.share_expires_never)); + } + } +} -- cgit v1.2.3