From 9e3cef176e0431d97e13425fd503258807630425 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Thu, 8 Sep 2016 08:39:03 -0700 Subject: #172 Add Internet Radio tab UI --- .../dsub/activity/SubsonicActivity.java | 12 +++ .../dsub/activity/SubsonicFragmentActivity.java | 3 + .../dsub/adapter/InternetRadioStationAdapter.java | 56 +++++++++++++ .../dsub/domain/InternetRadioStation.java | 43 ++++++++++ .../github/daneren2005/dsub/domain/ServerInfo.java | 3 + .../SelectInternetRadioStationFragment.java | 94 ++++++++++++++++++++++ .../dsub/service/CachedMusicService.java | 17 ++++ .../daneren2005/dsub/service/MusicService.java | 3 + .../dsub/service/OfflineMusicService.java | 6 ++ .../daneren2005/dsub/service/RESTMusicService.java | 13 +++ .../service/parser/InternetRadioStationParser.java | 63 +++++++++++++++ .../github/daneren2005/dsub/util/Constants.java | 1 + .../dsub/view/InternetRadioStationView.java | 39 +++++++++ app/src/main/res/menu/drawer_navigation.xml | 4 + .../res/menu/select_internet_radio_context.xml | 7 ++ app/src/main/res/values/arrays.xml | 2 + app/src/main/res/values/attrs.xml | 1 + app/src/main/res/values/strings.xml | 6 ++ app/src/main/res/values/themes.xml | 2 + app/src/main/res/xml/settings_drawer.xml | 6 ++ 20 files changed, 381 insertions(+) create mode 100644 app/src/main/java/github/daneren2005/dsub/adapter/InternetRadioStationAdapter.java create mode 100644 app/src/main/java/github/daneren2005/dsub/domain/InternetRadioStation.java create mode 100644 app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java create mode 100644 app/src/main/java/github/daneren2005/dsub/service/parser/InternetRadioStationParser.java create mode 100644 app/src/main/java/github/daneren2005/dsub/view/InternetRadioStationView.java create mode 100644 app/src/main/res/menu/select_internet_radio_context.xml (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java index 8882ad98..9b14f4f6 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -162,6 +162,9 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte case Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED: setDrawerItemVisible(R.id.drawer_bookmarks, false); break; + case Constants.PREFERENCES_KEY_INTERNET_RADIO_ENABLED: + setDrawerItemVisible(R.id.drawer_internet_radio_stations, false); + break; case Constants.PREFERENCES_KEY_SHARED_ENABLED: setDrawerItemVisible(R.id.drawer_shares, false); break; @@ -311,6 +314,9 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte case R.id.drawer_bookmarks: drawerItemSelected("Bookmark"); return true; + case R.id.drawer_internet_radio_stations: + drawerItemSelected("Internet Radio"); + return true; case R.id.drawer_shares: drawerItemSelected("Share"); return true; @@ -586,6 +592,7 @@ public class SubsonicActivity extends AppCompatActivity 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) && ServerInfo.canBookmark(this); + boolean internetRadioEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_INTERNET_RADIO_ENABLED, true) && !Util.isOffline(this) && ServerInfo.canInternetRadio(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); boolean adminEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_ADMIN_ENABLED, true) && !Util.isOffline(this); @@ -615,6 +622,9 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte if(!bookmarksEnabled) { setDrawerItemVisible(R.id.drawer_bookmarks, false); } + if(!internetRadioEnabled) { + setDrawerItemVisible(R.id.drawer_internet_radio_stations, false); + } if(!sharedEnabled) { setDrawerItemVisible(R.id.drawer_shares, false); } @@ -1191,6 +1201,8 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte return R.id.drawer_podcasts; case "Bookmark": return R.id.drawer_bookmarks; + case "Internet Radio": + return R.id.drawer_internet_radio_stations; case "Share": return R.id.drawer_shares; case "Chat": diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index ca6dd168..33b7d033 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -66,6 +66,7 @@ import github.daneren2005.dsub.fragments.SearchFragment; import github.daneren2005.dsub.fragments.SelectArtistFragment; import github.daneren2005.dsub.fragments.SelectBookmarkFragment; import github.daneren2005.dsub.fragments.SelectDirectoryFragment; +import github.daneren2005.dsub.fragments.SelectInternetRadioStationFragment; import github.daneren2005.dsub.fragments.SelectPlaylistFragment; import github.daneren2005.dsub.fragments.SelectPodcastsFragment; import github.daneren2005.dsub.fragments.SelectShareFragment; @@ -662,6 +663,8 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo return new SelectPodcastsFragment(); } else if("Bookmark".equals(fragmentType)) { return new SelectBookmarkFragment(); + } else if("Internet Radio".equals(fragmentType)) { + return new SelectInternetRadioStationFragment(); } else if("Share".equals(fragmentType)) { return new SelectShareFragment(); } else if("Admin".equals(fragmentType)) { diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/InternetRadioStationAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/InternetRadioStationAdapter.java new file mode 100644 index 00000000..9d47d70c --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/InternetRadioStationAdapter.java @@ -0,0 +1,56 @@ +/* + 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 2016 (C) Scott Jackson +*/ +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.ViewGroup; + +import java.util.List; + +import github.daneren2005.dsub.domain.InternetRadioStation; +import github.daneren2005.dsub.view.FastScroller; +import github.daneren2005.dsub.view.InternetRadioStationView; +import github.daneren2005.dsub.view.UpdateView; + +public class InternetRadioStationAdapter extends SectionAdapter implements FastScroller.BubbleTextGetter { + public static int VIEW_TYPE_INTERNET_RADIO_STATION = 1; + + public InternetRadioStationAdapter(Context context, List stations, OnItemClickedListener listener) { + super(context, stations); + this.onItemClickedListener = listener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new InternetRadioStationView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, InternetRadioStation station, int viewType) { + holder.getUpdateView().setObject(station); + holder.setItem(station); + } + + @Override + public int getItemViewType(InternetRadioStation station) { + return VIEW_TYPE_INTERNET_RADIO_STATION; + } + + @Override + public String getTextToShowInBubble(int position) { + InternetRadioStation item = getItemForPosition(position); + return item.getTitle(); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/domain/InternetRadioStation.java b/app/src/main/java/github/daneren2005/dsub/domain/InternetRadioStation.java new file mode 100644 index 00000000..47d79b99 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/domain/InternetRadioStation.java @@ -0,0 +1,43 @@ +/* + 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 2016 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.domain; + +public class InternetRadioStation extends MusicDirectory.Entry { + private String streamUrl; + private String homePageUrl; + + public InternetRadioStation() {} + + public String getStreamUrl() { + return streamUrl; + } + + public void setStreamUrl(String streamUrl) { + this.streamUrl = streamUrl; + } + + public String getHomePageUrl() { + return homePageUrl; + } + + public void setHomePageUrl(String homePageUrl) { + this.homePageUrl = homePageUrl; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java index 7f538484..d85db045 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java @@ -215,6 +215,9 @@ public class ServerInfo implements Serializable { public static boolean canBookmark(Context context) { return checkServerVersion(context, "1.9"); } + public static boolean canInternetRadio(Context context) { + return checkServerVersion(context, "1.9"); + } public static boolean canSavePlayQueue(Context context) { return ServerInfo.checkServerVersion(context, "1.12") && (!ServerInfo.isMadsonic(context) || checkServerVersion(context, "2.0")); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java new file mode 100644 index 00000000..94c0f1e2 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java @@ -0,0 +1,94 @@ +/* + 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 2016 (C) Scott Jackson +*/ +package github.daneren2005.dsub.fragments; + +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.InternetRadioStationAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; +import github.daneren2005.dsub.domain.InternetRadioStation; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.UpdateView; + +public class SelectInternetRadioStationFragment extends SelectRecyclerFragment { + @Override + public int getOptionsMenu() { + return R.menu.abstract_top_menu; + } + + @Override + public SectionAdapter getAdapter(List objs) { + return new InternetRadioStationAdapter(context, objs, this); + } + + @Override + public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + return musicService.getInternetRadioStations(refresh, context, listener); + } + + @Override + public int getTitleResource() { + return R.string.button_bar_internet_radio; + } + + @Override + public void onItemClicked(UpdateView updateView, InternetRadioStation item) { + + } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView updateView, InternetRadioStation item) { + menuInflater.inflate(R.menu.select_internet_radio_context, menu); + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView updateView, InternetRadioStation item) { + switch (menuItem.getItemId()) { + case R.id.internet_radio_info: + displayInternetRadioStationInfo(item); + break; + } + + return false; + } + + private void displayInternetRadioStationInfo(final InternetRadioStation station) { + List headers = new ArrayList<>(); + List details = new ArrayList<>(); + + headers.add(R.string.details_title); + details.add(station.getTitle()); + + headers.add(R.string.details_home_page); + details.add(station.getHomePageUrl()); + + headers.add(R.string.details_stream_url); + details.add(station.getStreamUrl()); + + Util.showDetailsDialog(context, R.string.details_title_internet_radio_station, headers, details); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java index 1a17dfb3..00fb4624 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java @@ -39,6 +39,7 @@ import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.ChatMessage; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.PlayerQueue; import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.RemoteStatus; @@ -1217,6 +1218,22 @@ public class CachedMusicService implements MusicService { return musicService.getPlayQueue(context, progressListener); } + @Override + public List getInternetRadioStations(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List result = null; + + if(!refresh) { + result = FileUtil.deserialize(context, getCacheName(context, "internetRadioStations"), ArrayList.class); + } + + if(result == null) { + result = musicService.getInternetRadioStations(refresh, context, progressListener); + FileUtil.serialize(context, new ArrayList<>(result), getCacheName(context, "internetRadioStations")); + } + + return result; + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return musicService.processOfflineSyncs(context, progressListener); diff --git a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java index 22f154c4..1e275108 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java @@ -30,6 +30,7 @@ import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.ChatMessage; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.PlayerQueue; import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.dsub.domain.Lyrics; @@ -194,6 +195,8 @@ public interface MusicService { void savePlayQueue(List songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception; PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception; + + List getInternetRadioStations(boolean refresh, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; diff --git a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java index e004101d..2c439ec4 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java @@ -41,6 +41,7 @@ import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.ChatMessage; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory.Entry; import github.daneren2005.dsub.domain.PlayerQueue; import github.daneren2005.dsub.domain.PodcastEpisode; @@ -889,6 +890,11 @@ public class OfflineMusicService implements MusicService { throw new OfflineException(ERRORMSG); } + @Override + public List getInternetRadioStations(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException(ERRORMSG); + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ throw new OfflineException(ERRORMSG); diff --git a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java index 1f9e5494..6ccf562c 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -80,6 +80,7 @@ import github.daneren2005.dsub.service.parser.ChatMessageParser; import github.daneren2005.dsub.service.parser.ErrorParser; import github.daneren2005.dsub.service.parser.GenreParser; import github.daneren2005.dsub.service.parser.IndexesParser; +import github.daneren2005.dsub.service.parser.InternetRadioStationParser; import github.daneren2005.dsub.service.parser.JukeboxStatusParser; import github.daneren2005.dsub.service.parser.LicenseParser; import github.daneren2005.dsub.service.parser.LyricsParser; @@ -1764,6 +1765,18 @@ public class RESTMusicService implements MusicService { } } + @Override + public List getInternetRadioStations(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + checkServerVersion(context, "1.9", null); + + Reader reader = getReader(context, progressListener, "getInternetRadioStations", null); + try { + return new InternetRadioStationParser(context, getInstance(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/app/src/main/java/github/daneren2005/dsub/service/parser/InternetRadioStationParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/InternetRadioStationParser.java new file mode 100644 index 00000000..77d7bc4a --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/InternetRadioStationParser.java @@ -0,0 +1,63 @@ +/* + 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 2016 (C) Scott Jackson +*/ +package github.daneren2005.dsub.service.parser; + +import android.content.Context; +import github.daneren2005.dsub.domain.InternetRadioStation; +import github.daneren2005.dsub.util.ProgressListener; +import org.xmlpull.v1.XmlPullParser; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +public class InternetRadioStationParser extends ErrorParser { + public InternetRadioStationParser(Context context, int instance) { + super(context, instance); + } + + public List parse(Reader reader, ProgressListener progressListener) throws Exception { + init(reader); + + List result = new ArrayList<>(); + int eventType; + do { + eventType = nextParseEvent(); + if (eventType == XmlPullParser.START_TAG) { + String name = getElementName(); + if ("internetRadioStation".equals(name)) { + InternetRadioStation station = new InternetRadioStation(); + + station.setId(get("id")); + station.setTitle(get("name")); + station.setStreamUrl(get("streamUrl")); + station.setHomePageUrl(get("homePageUrl")); + + result.add(station); + } else if ("error".equals(name)) { + handleError(); + } + } + } while (eventType != XmlPullParser.END_DOCUMENT); + + validate(); + return result; + } + +} \ No newline at end of file diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index b7a68962..918edcc9 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -134,6 +134,7 @@ public final class Constants { public static final String PREFERENCES_KEY_HIDE_WIDGET = "hideWidget"; public static final String PREFERENCES_KEY_PODCASTS_ENABLED = "podcastsEnabled"; public static final String PREFERENCES_KEY_BOOKMARKS_ENABLED = "bookmarksEnabled"; + public static final String PREFERENCES_KEY_INTERNET_RADIO_ENABLED = "internetRadioEnabled"; public static final String PREFERENCES_KEY_CUSTOM_SORT_ENABLED = "customSortEnabled"; public static final String PREFERENCES_KEY_MENU_PLAY_NOW = "showPlayNow"; public static final String PREFERENCES_KEY_MENU_PLAY_SHUFFLED = "showPlayShuffled"; diff --git a/app/src/main/java/github/daneren2005/dsub/view/InternetRadioStationView.java b/app/src/main/java/github/daneren2005/dsub/view/InternetRadioStationView.java new file mode 100644 index 00000000..36aaa8af --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/InternetRadioStationView.java @@ -0,0 +1,39 @@ +/* + 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 2016 (C) Scott Jackson +*/ +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.ImageView; +import android.widget.TextView; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.InternetRadioStation; + +public class InternetRadioStationView extends UpdateView { + private TextView titleView; + + public InternetRadioStationView(Context context) { + super(context); + LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + + titleView = (TextView) findViewById(R.id.item_name); + moreButton = (ImageView) findViewById(R.id.item_more); + } + + protected void setObjectImpl(InternetRadioStation station) { + titleView.setText(station.getTitle()); + } +} diff --git a/app/src/main/res/menu/drawer_navigation.xml b/app/src/main/res/menu/drawer_navigation.xml index bd309455..32de5cd5 100644 --- a/app/src/main/res/menu/drawer_navigation.xml +++ b/app/src/main/res/menu/drawer_navigation.xml @@ -21,6 +21,10 @@ android:id="@+id/drawer_bookmarks" android:icon="?attr/drawerBookmarks" android:title="@string/button_bar.bookmarks"/> + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index ee246d16..e9aadce7 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -6,6 +6,7 @@ @string/button_bar.playlists @string/button_bar.podcasts @string/button_bar.bookmarks + @string/button_bar.internet_radio @string/button_bar.shares @string/button_bar.chat @@ -16,6 +17,7 @@ Playlist Podcast Bookmark + Internet Radio Share Chat diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 7cd447f0..055726b8 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -49,6 +49,7 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c15a5d3e..9ac609c3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -36,6 +36,7 @@ Now Playing Podcasts Bookmarks + Internet Radio Shares Chat Admin @@ -410,6 +411,8 @@ Whether or not to display the podcast listing in the pull out drawer Bookmarks Enabled Whether or not to display the bookmarks listing in the pull out drawer + Internet Radio Enabled + Whether or not to display the internet radio listing in the pull out drawer Shares Enabled Whether or not to display the shares listing in the pull out drawer Sync @@ -610,6 +613,7 @@ Podcast Details Playlist Details Artist Details + Internet Radio Details Podcast Status Artist @@ -649,6 +653,8 @@ Last Played Expiration Played Count + Stream URL + Home Page DSub cannot function without the ability to write to storage diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 9e95fe9d..8cccab93 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -49,6 +49,7 @@ @drawable/ic_menu_playlist_light @drawable/ic_menu_podcast_light @drawable/ic_menu_bookmark_light + @drawable/ic_menu_radio_light @drawable/ic_menu_share_light @drawable/ic_menu_chat_light @drawable/ic_menu_admin_light @@ -120,6 +121,7 @@ @drawable/ic_menu_playlist_dark @drawable/ic_menu_podcast_dark @drawable/ic_menu_bookmark_dark + @drawable/ic_menu_radio_dark @drawable/ic_menu_share_dark @drawable/ic_menu_chat_dark @drawable/ic_menu_admin_dark diff --git a/app/src/main/res/xml/settings_drawer.xml b/app/src/main/res/xml/settings_drawer.xml index 4b92737e..21ec1586 100644 --- a/app/src/main/res/xml/settings_drawer.xml +++ b/app/src/main/res/xml/settings_drawer.xml @@ -18,6 +18,12 @@ android:key="bookmarksEnabled" android:defaultValue="true"/> + + Date: Fri, 9 Sep 2016 16:36:10 -0700 Subject: Reintroduce tokens for Subsonic 6+ with a check for error code 41 --- .../main/java/github/daneren2005/dsub/domain/ServerInfo.java | 12 ++++++++++-- .../daneren2005/dsub/service/parser/AbstractParser.java | 6 ++++++ .../main/java/github/daneren2005/dsub/util/Constants.java | 1 + app/src/main/java/github/daneren2005/dsub/util/Util.java | 12 ++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java index 7f538484..dd41bcac 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/ServerInfo.java @@ -24,6 +24,7 @@ import java.io.Serializable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.Util; @@ -231,8 +232,15 @@ public class ServerInfo implements Serializable { return canUseToken(context, Util.getActiveServer(context)); } public static boolean canUseToken(Context context, int instance) { - return false; /*isStockSubsonic(context, instance) && checkServerVersion(context, "1.13", instance) || - isMadsonic(context, instance) && checkServerVersion(context, "2.0", instance);*/ + if(isStockSubsonic(context, instance) && checkServerVersion(context, "1.14", instance)) { + if(Util.getBlockTokenUse(context, instance)) { + return false; + } else { + return true; + } + } else { + return false; + } } public static boolean hasSimilarArtists(Context context) { return !ServerInfo.isMadsonic(context) || ServerInfo.checkServerVersion(context, "2.0"); diff --git a/app/src/main/java/github/daneren2005/dsub/service/parser/AbstractParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/AbstractParser.java index d6e1a002..d4c090c1 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/parser/AbstractParser.java +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/AbstractParser.java @@ -18,6 +18,7 @@ */ package github.daneren2005.dsub.service.parser; +import java.io.IOException; import java.io.Reader; import org.xmlpull.v1.XmlPullParser; @@ -72,6 +73,11 @@ public abstract class AbstractParser { case 40: message = context.getResources().getString(R.string.parser_not_authenticated); break; + case 41: + Util.setBlockTokenUse(context, instance, true); + + // Throw IOException so RESTMusicService knows to retry + throw new IOException(); case 50: message = context.getResources().getString(R.string.parser_not_authorized); break; diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index b7a68962..7fa05a2c 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -189,6 +189,7 @@ public final class Constants { public static final String CACHE_KEY_IGNORE = "ignoreArticles"; public static final String CACHE_AUDIO_SESSION_ID = "audioSessionId"; + public static final String CACHE_BLOCK_TOKEN_USE = "blockTokenUse"; public static final String MAIN_BACK_STACK = "backStackIds"; public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index b1f1617d..5151c5d6 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -421,6 +421,18 @@ public final class Util { return builder.toString().hashCode(); } + public static String getBlockTokenUsePref(Context context, int instance) { + return Constants.CACHE_BLOCK_TOKEN_USE + Util.getRestUrl(context, null, instance, false); + } + public static boolean getBlockTokenUse(Context context, int instance) { + return getPreferences(context).getBoolean(getBlockTokenUsePref(context, instance), false); + } + public static void setBlockTokenUse(Context context, int instance, boolean block) { + SharedPreferences.Editor editor = getPreferences(context).edit(); + editor.putBoolean(getBlockTokenUsePref(context, instance), block); + editor.commit(); + } + public static String replaceInternalUrl(Context context, String url) { // Only change to internal when using https if(url.indexOf("https") != -1) { -- cgit v1.2.3 From 5f0853a56d5214ab1c9d4238c500c8433d64e28e Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 13 Sep 2016 17:39:00 -0700 Subject: Fix error if adding a user with no current users --- app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java | 2 +- app/src/main/java/github/daneren2005/dsub/util/UserUtil.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java index 187f0d55..552712f7 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java @@ -47,7 +47,7 @@ public class AdminFragment extends SelectRecyclerFragment { switch (item.getItemId()) { case R.id.menu_add_user: - UserUtil.addNewUser(context, this, objects.get(0)); + UserUtil.addNewUser(context, this, (objects.size() > 0) ? objects.get(0) : null); break; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java index 24d3906b..db1c628f 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java +++ b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java @@ -406,7 +406,7 @@ public final class UserUtil { } } - if(sampleUser.getMusicFolderSettings() != null) { + if(sampleUser != null && sampleUser.getMusicFolderSettings() != null) { for(User.Setting setting: sampleUser.getMusicFolderSettings()) { User.MusicFolderSetting musicFolderSetting = (User.MusicFolderSetting) setting; user.addMusicFolder(musicFolderSetting, true); -- cgit v1.2.3 From e774bc406535cb90896c1370dc67c8cf8ee491f0 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Wed, 14 Sep 2016 22:08:08 -0700 Subject: #172 Implement playback of internet radio stations + hide UI elements which don't make sense on streams --- .../dsub/activity/SubsonicFragmentActivity.java | 31 +++++++--- .../dsub/fragments/NowPlayingFragment.java | 62 +++++++++++++++---- .../SelectInternetRadioStationFragment.java | 22 ++++++- .../daneren2005/dsub/service/DownloadFile.java | 14 +++++ .../daneren2005/dsub/service/DownloadService.java | 72 ++++++++++++++++------ .../daneren2005/dsub/util/Notifications.java | 28 ++++++++- 6 files changed, 184 insertions(+), 45 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index 33b7d033..c7190046 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -925,7 +925,13 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo if (currentPlaying != null) { song = currentPlaying.getSong(); trackView.setText(song.getTitle()); - artistView.setText(song.getArtist()); + + if(song.getArtist() != null) { + artistView.setVisibility(View.VISIBLE); + artistView.setText(song.getArtist()); + } else { + artistView.setVisibility(View.GONE); + } } else { trackView.setText(R.string.main_title); artistView.setText(R.string.main_artist); @@ -942,18 +948,25 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo getImageLoader().loadImage(coverArtView, song, false, height, false); } - if(currentPlaying != null && currentPlaying.getSong() != null && (currentPlaying.getSong().isPodcast() || currentPlaying.getSong().isAudioBook())) { + if(getDownloadService().isCurrentPlayingSingle()) { previousButton.setVisibility(View.GONE); nextButton.setVisibility(View.GONE); - - rewindButton.setVisibility(View.VISIBLE); - fastforwardButton.setVisibility(View.VISIBLE); - } else { - previousButton.setVisibility(View.VISIBLE); - nextButton.setVisibility(View.VISIBLE); - rewindButton.setVisibility(View.GONE); fastforwardButton.setVisibility(View.GONE); + } else { + if (currentPlaying != null && currentPlaying.getSong() != null && (currentPlaying.getSong().isPodcast() || currentPlaying.getSong().isAudioBook())) { + previousButton.setVisibility(View.GONE); + nextButton.setVisibility(View.GONE); + + rewindButton.setVisibility(View.VISIBLE); + fastforwardButton.setVisibility(View.VISIBLE); + } else { + previousButton.setVisibility(View.VISIBLE); + nextButton.setVisibility(View.VISIBLE); + + rewindButton.setVisibility(View.GONE); + fastforwardButton.setVisibility(View.GONE); + } } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java index 9eddbc89..985b7bec 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -535,6 +535,15 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis mediaRouteButton.setDialogFactory(new CustomMediaRouteDialogFactory()); mediaRouteButton.setRouteSelector(downloadService.getRemoteSelector()); } + + if(downloadService.isCurrentPlayingSingle()) { + if(!Util.isOffline(context)) { + menu.removeItem(R.id.menu_save_playlist); + } + + menu.removeItem(R.id.menu_batch_mode); + menu.removeItem(R.id.menu_remove_played); + } } if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_BATCH_MODE, false)) { @@ -867,6 +876,11 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } private void setControlsVisible(boolean visible) { + DownloadService downloadService = getDownloadService(); + if(downloadService != null && downloadService.isCurrentPlayingSingle()) { + return; + } + try { long duration = 1700L; FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration); @@ -1242,18 +1256,25 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis this.currentPlaying = currentPlaying; setupSubtitle(currentPlayingIndex); - if(currentPlaying != null && !currentPlaying.isSong()) { + if(getDownloadService().isCurrentPlayingSingle()) { previousButton.setVisibility(View.GONE); nextButton.setVisibility(View.GONE); - - rewindButton.setVisibility(View.VISIBLE); - fastforwardButton.setVisibility(View.VISIBLE); - } else { - previousButton.setVisibility(View.VISIBLE); - nextButton.setVisibility(View.VISIBLE); - rewindButton.setVisibility(View.GONE); fastforwardButton.setVisibility(View.GONE); + } else { + if (currentPlaying != null && !currentPlaying.isSong()) { + previousButton.setVisibility(View.GONE); + nextButton.setVisibility(View.GONE); + + rewindButton.setVisibility(View.VISIBLE); + fastforwardButton.setVisibility(View.VISIBLE); + } else { + previousButton.setVisibility(View.VISIBLE); + nextButton.setVisibility(View.VISIBLE); + + rewindButton.setVisibility(View.GONE); + fastforwardButton.setVisibility(View.GONE); + } } updateTitle(); } @@ -1265,7 +1286,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis getImageLoader().loadImage(albumArtImageView, song, true, true); DownloadService downloadService = getDownloadService(); - if(downloadService.isShufflePlayEnabled()) { + if(downloadService.isCurrentPlayingSingle()) { + setSubtitle(null); + } else if(downloadService.isShufflePlayEnabled()) { setSubtitle(context.getResources().getString(R.string.download_playerstate_playing_shuffle)); } else if(downloadService.isArtistRadio()) { setSubtitle(context.getResources().getString(R.string.download_playerstate_playing_artist_radio)); @@ -1314,6 +1337,14 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } else { setupSubtitle(currentPlayingIndex); } + + if(downloadService.isCurrentPlayingSingle()) { + toggleListButton.setVisibility(View.GONE); + repeatButton.setVisibility(View.GONE); + } else { + toggleListButton.setVisibility(View.VISIBLE); + repeatButton.setVisibility(View.VISIBLE); + } } @Override @@ -1368,11 +1399,16 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis break; default: if(currentPlaying != null) { - String artist = ""; - if(currentPlaying.getSong().getArtist() != null) { - artist = currentPlaying.getSong().getArtist() + " - "; + Entry entry = currentPlaying.getSong(); + if(entry.getAlbum() != null) { + String artist = ""; + if (entry.getArtist() != null) { + artist = currentPlaying.getSong().getArtist() + " - "; + } + statusTextView.setText(artist + entry.getAlbum()); + } else { + statusTextView.setText(null); } - statusTextView.setText(artist + currentPlaying.getSong().getAlbum()); } else { statusTextView.setText(null); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java index 94c0f1e2..16082cbd 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java @@ -29,8 +29,10 @@ import github.daneren2005.dsub.R; import github.daneren2005.dsub.adapter.InternetRadioStationAdapter; import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.InternetRadioStation; +import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.TabBackgroundTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UpdateView; @@ -56,8 +58,24 @@ public class SelectInternetRadioStationFragment extends SelectRecyclerFragment updateView, InternetRadioStation item) { - + public void onItemClicked(UpdateView updateView, final InternetRadioStation item) { + new TabBackgroundTask(this) { + @Override + protected Void doInBackground() throws Throwable { + DownloadService downloadService = getDownloadService(); + if(downloadService == null) { + return null; + } + + downloadService.download(item); + return null; + } + + @Override + protected void done(Void result) { + context.openNowPlaying(); + } + }.execute(); } @Override diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java index e4bab798..d1c594ce 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java @@ -29,6 +29,8 @@ import android.content.Context; import android.net.wifi.WifiManager; import android.os.PowerManager; import android.util.Log; + +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.SilentBackgroundTask; @@ -377,6 +379,18 @@ public class DownloadFile implements BufferFile { } } + public boolean isStream() { + return song != null && song instanceof InternetRadioStation; + } + public String getStream() { + if(song != null && song instanceof InternetRadioStation) { + InternetRadioStation station = (InternetRadioStation) song; + return station.getStreamUrl(); + } else { + return null; + } + } + @Override public String toString() { return "DownloadFile (" + song + ")"; diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index cec98865..915906c8 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -35,6 +35,7 @@ import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.audiofx.AudioEffectsController; import github.daneren2005.dsub.audiofx.EqualizerController; import github.daneren2005.dsub.domain.Bookmark; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.PodcastEpisode; @@ -60,6 +61,7 @@ import github.daneren2005.serverproxy.BufferProxy; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Iterator; @@ -123,7 +125,7 @@ public class DownloadService extends Service { private RemoteControlClientBase mRemoteControl; - private final IBinder binder = new SimpleServiceBinder(this); + private final IBinder binder = new SimpleServiceBinder<>(this); private Looper mediaPlayerLooper; private MediaPlayer mediaPlayer; private MediaPlayer nextMediaPlayer; @@ -382,6 +384,10 @@ public class DownloadService extends Service { handler.postDelayed(r, millis); } + public synchronized void download(InternetRadioStation station) { + clear(); + download(Arrays.asList((MusicDirectory.Entry) station), false, true, false, false); + } public synchronized void download(List songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle) { download(songs, save, autoplay, playNext, shuffle, 0, 0); } @@ -394,7 +400,10 @@ public class DownloadService extends Service { if (songs.isEmpty()) { return; + } else if(isCurrentPlayingSingle()) { + clear(); } + if (playNext) { if (autoplay && getCurrentPlayingIndex() >= 0) { offset = 0; @@ -996,6 +1005,21 @@ public class DownloadService extends Service { public List getToDelete() { return toDelete; } + public boolean isCurrentPlayingSingle() { + if(currentPlaying != null && currentPlaying.getSong() instanceof InternetRadioStation) { + return true; + } else { + return false; + } + } + public boolean isCurrentPlayingStream() { + if(currentPlaying != null) { + return currentPlaying.isStream(); + } else { + return false; + } + } + public synchronized List getDownloads() { List temp = new ArrayList(); temp.addAll(downloadList); @@ -1819,7 +1843,7 @@ public class DownloadService extends Service { bufferAndPlay(position, true); } private synchronized void bufferAndPlay(int position, boolean start) { - if(!currentPlaying.isCompleteFileAvailable()) { + if(!currentPlaying.isCompleteFileAvailable() && !currentPlaying.isStream()) { if(Util.isAllowedToDownload(this)) { reset(); @@ -1835,11 +1859,6 @@ public class DownloadService extends Service { private synchronized void doPlay(final DownloadFile downloadFile, final int position, final boolean start) { try { - downloadFile.setPlaying(true); - final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); - boolean isPartial = file.equals(downloadFile.getPartialFile()); - downloadFile.updateModificationDate(); - subtractPosition = 0; mediaPlayer.setOnCompletionListener(null); mediaPlayer.setOnPreparedListener(null); @@ -1851,19 +1870,33 @@ public class DownloadService extends Service { } catch(Throwable e) { mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } - String dataSource = file.getAbsolutePath(); - if(isPartial && !Util.isOffline(this)) { - if (proxy == null) { - proxy = new BufferProxy(this); - proxy.start(); - } - proxy.setBufferFile(downloadFile); - dataSource = proxy.getPrivateAddress(dataSource); + + String dataSource; + boolean isPartial = false; + if(downloadFile.isStream()) { + dataSource = downloadFile.getStream(); Log.i(TAG, "Data Source: " + dataSource); - } else if(proxy != null) { - proxy.stop(); - proxy = null; + } else { + downloadFile.setPlaying(true); + final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); + isPartial = file.equals(downloadFile.getPartialFile()); + downloadFile.updateModificationDate(); + + dataSource = file.getAbsolutePath(); + if (isPartial && !Util.isOffline(this)) { + if (proxy == null) { + proxy = new BufferProxy(this); + proxy.start(); + } + proxy.setBufferFile(downloadFile); + dataSource = proxy.getPrivateAddress(dataSource); + Log.i(TAG, "Data Source: " + dataSource); + } else if (proxy != null) { + proxy.stop(); + proxy = null; + } } + mediaPlayer.setDataSource(dataSource); setPlayerState(PREPARING); @@ -2167,6 +2200,9 @@ public class DownloadService extends Service { if (downloadList.isEmpty() && backgroundDownloadList.isEmpty()) { return; } + if(currentPlaying != null && currentPlaying.isStream()) { + return; + } // Need to download current playing and not casting? if (currentPlaying != null && remoteState == LOCAL && currentPlaying != currentDownloading && !currentPlaying.isWorkDone()) { diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java index 2948844b..0d4a0f9c 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -67,9 +67,10 @@ public final class Notifications { notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; } boolean remote = downloadService.isRemoteEnabled(); + boolean isSingle = downloadService.isCurrentPlayingSingle(); if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded); - setupViews(expandedContentView ,context, song, true, playing, remote); + setupViews(expandedContentView ,context, song, true, playing, remote, isSingle); notification.bigContentView = expandedContentView; notification.priority = Notification.PRIORITY_HIGH; } @@ -82,7 +83,7 @@ public final class Notifications { } RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification); - setupViews(smallContentView, context, song, false, playing, remote); + setupViews(smallContentView, context, song, false, playing, remote, isSingle); notification.contentView = smallContentView; Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); @@ -122,7 +123,7 @@ public final class Notifications { DSubWidgetProvider.notifyInstances(context, downloadService, playing); } - private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote) { + private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote, boolean isSingleFile) { boolean isLongFile = song.isAudioBook() || song.isPodcast(); // Use the same text for the ticker and the expanded notification @@ -209,6 +210,27 @@ public final class Notifications { close = R.id.notification_close; rv.setViewVisibility(close, View.VISIBLE); } + + if(isSingleFile) { + if(previous > 0) { + rv.setViewVisibility(previous, View.GONE); + previous = 0; + } + if(rewind > 0) { + rv.setViewVisibility(rewind, View.GONE); + rewind = 0; + } + + if(next > 0) { + rv.setViewVisibility(next, View.GONE); + next = 0; + } + + if(fastForward > 0) { + rv.setViewVisibility(fastForward, View.GONE); + fastForward = 0; + } + } if(previous > 0) { Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS"); -- cgit v1.2.3 From a1b4150eafd6358d4b2724693fc4b4a847c4b37a Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 19 Sep 2016 17:30:38 -0700 Subject: Fixes #735: Add Play Now to song's context menu when click to add --- .../java/github/daneren2005/dsub/fragments/SubsonicFragment.java | 9 +++++++++ app/src/main/res/menu/select_song_context.xml | 6 ++++++ app/src/main/res/menu/select_song_context_offline.xml | 9 +++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java index b7478c8a..818324ed 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -309,6 +309,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(entry.getBookmark() == null) { menu.removeItem(R.id.bookmark_menu_delete); } + + + String songPressAction = Util.getSongPressAction(context); + if(!"next".equals(songPressAction) && !"last".equals(songPressAction)) { + menu.setGroupVisible(R.id.hide_play_now, false); + } } } else { if(Util.isOffline(context)) { @@ -430,6 +436,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR case R.id.album_menu_share: createShare(songs); break; + case R.id.song_menu_play_now: + playNow(songs); + break; case R.id.song_menu_play_next: getDownloadService().download(songs, false, false, true, false); break; diff --git a/app/src/main/res/menu/select_song_context.xml b/app/src/main/res/menu/select_song_context.xml index b68dcad9..46eaaa38 100644 --- a/app/src/main/res/menu/select_song_context.xml +++ b/app/src/main/res/menu/select_song_context.xml @@ -15,6 +15,12 @@ android:title="@string/menu.show_artist"/> + + + + - + + + + + Date: Mon, 19 Sep 2016 17:44:50 -0700 Subject: Fixes #734: Auto skip uncached songs when no network --- app/src/main/java/github/daneren2005/dsub/service/DownloadService.java | 2 +- app/src/main/java/github/daneren2005/dsub/util/Util.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index cec98865..1ee099cd 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -2160,7 +2160,7 @@ public class DownloadService extends Service { checkArtistRadio(); } - if (!Util.isNetworkConnected(this, true) || Util.isOffline(this)) { + if (!Util.isAllowedToDownload(this)) { return; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index 5151c5d6..b69ea55e 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -1125,7 +1125,7 @@ public final class Util { } public static boolean isAllowedToDownload(Context context) { - return !isWifiRequiredForDownload(context) || isWifiConnected(context); + return isNetworkConnected(context, true) && !isOffline(context); } public static boolean isWifiRequiredForDownload(Context context) { SharedPreferences prefs = getPreferences(context); -- cgit v1.2.3 From 5c4db8635facc00df744c3e6421cbec5bb88a370 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Wed, 21 Sep 2016 17:35:19 -0700 Subject: Don't scrobble/load image for Internet Radio Stations (closes #172) --- .../daneren2005/dsub/service/DownloadServiceLifecycleSupport.java | 4 +++- app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java | 3 ++- app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java index 726840b2..1c80b622 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java @@ -36,6 +36,8 @@ import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; import android.view.KeyEvent; + +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerQueue; import github.daneren2005.dsub.domain.PlayerState; @@ -310,7 +312,7 @@ public class DownloadServiceLifecycleSupport { FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER); // If we are on Subsonic 5.2+, save play queue - if(serializeRemote && ServerInfo.canSavePlayQueue(downloadService) && !Util.isOffline(downloadService) && state.songs.size() > 0) { + if(serializeRemote && ServerInfo.canSavePlayQueue(downloadService) && !Util.isOffline(downloadService) && state.songs.size() > 0 && !(state.songs.get(0) instanceof InternetRadioStation)) { // Cancel any currently running tasks if(currentSavePlayQueueTask != null) { currentSavePlayQueueTask.cancel(); diff --git a/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java b/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java index 168a7777..c7ad639e 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java +++ b/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java @@ -3,6 +3,7 @@ package github.daneren2005.dsub.service; import android.content.Context; import android.util.Log; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.util.SilentBackgroundTask; @@ -69,7 +70,7 @@ public class Scrobbler { return null; } // Ignore podcasts - else if(song.getSong() instanceof PodcastEpisode) { + else if(song.getSong() instanceof PodcastEpisode || song.getSong() instanceof InternetRadioStation) { return null; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java index a85141df..2321e69e 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java +++ b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java @@ -43,6 +43,7 @@ import java.lang.ref.WeakReference; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.ArtistInfo; +import github.daneren2005.dsub.domain.InternetRadioStation; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; @@ -221,8 +222,11 @@ public class ImageLoader { return loadImage(view, entry, large, size, crossfade); } public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) { - // TODO: If we know this a artist, try to load artist info instead - if(entry != null && !entry.isAlbum() && ServerInfo.checkServerVersion(context, "1.11") && !Util.isOffline(context)) { + if(entry != null && entry instanceof InternetRadioStation) { + // Continue on and load a null bitmap + } + // If we know this a artist, try to load artist info instead + else if(entry != null && !entry.isAlbum() && ServerInfo.checkServerVersion(context, "1.11") && !Util.isOffline(context)) { SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); task.execute(); return task; -- cgit v1.2.3 From ede4d2d49ada1845bab4db12c48cc6fd28f7c73a Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 23 Sep 2016 21:12:41 -0700 Subject: Fix applicationIdSuffix not working with custom attributes --- app/src/main/res/xml/settings_drawer.xml | 2 +- app/src/main/res/xml/settings_playback.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/res/xml/settings_drawer.xml b/app/src/main/res/xml/settings_drawer.xml index 21ec1586..f89fb990 100644 --- a/app/src/main/res/xml/settings_drawer.xml +++ b/app/src/main/res/xml/settings_drawer.xml @@ -1,6 +1,6 @@ Date: Fri, 23 Sep 2016 21:35:11 -0700 Subject: Fix error when removing and then immediately adding server --- .../main/java/github/daneren2005/dsub/fragments/SettingsFragment.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java index ad064d01..d5ba25f5 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java @@ -431,6 +431,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared for (ServerSettings ss : serverSettings.values()) { if(!ss.update()) { serversCategory.removePreference(ss.getScreen()); + serverCount--; } } } -- cgit v1.2.3 From 72751eafc2f9485d4720bbed9ec3b75726f92c9d Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 23 Sep 2016 21:55:27 -0700 Subject: DSub 5.3 Released to beta --- app/build.gradle | 4 ++-- app/src/main/res/xml/changelog.xml | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/build.gradle b/app/build.gradle index be7e32fc..ced2d978 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "github.daneren2005.dsub" minSdkVersion 14 targetSdkVersion 23 - versionCode 185 - versionName '5.2.2' + versionCode 186 + versionName '5.3' setProperty("archivesBaseName", "DSub $versionName") resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv" } diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml index 490c427a..89f076f7 100644 --- a/app/src/main/res/xml/changelog.xml +++ b/app/src/main/res/xml/changelog.xml @@ -1,5 +1,16 @@ + + Listen to Radio Internet Stations + Automatic Day/Night theme + Android 6.0 runtime permissions + Custom variable playback speed + Add Play Now for songs when click action is add to queue + More secure connections with tokens (Subsonic 6+) + Auto skip uncached songs when no network + Shrink install size + Fix DLNA casting on Android 7.0+ + Fix lagging in landscape view on the Now Playing screen -- cgit v1.2.3 From 01e5812356a918da1f526b8476a5775608f3750c Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 23 Sep 2016 22:11:25 -0700 Subject: Move cast id over to EnvironmentVariables --- .../github/daneren2005/dsub/service/ChromeCastController.java | 5 +++-- .../java/github/daneren2005/dsub/util/EnvironmentVariables.java | 1 + .../main/java/github/daneren2005/dsub/util/compat/CastCompat.java | 8 ++------ 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java index c2007139..2df290cf 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java @@ -41,6 +41,7 @@ import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RemoteControlState; import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.EnvironmentVariables; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.util.compat.CastCompat; @@ -465,14 +466,14 @@ public class ChromeCastController extends RemoteController { void launchApplication() { try { - Cast.CastApi.launchApplication(apiClient, CastCompat.APPLICATION_ID, false).setResultCallback(resultCallback); + Cast.CastApi.launchApplication(apiClient, EnvironmentVariables.CAST_APPLICATION_ID, false).setResultCallback(resultCallback); } catch (Exception e) { Log.e(TAG, "Failed to launch application", e); } } void reconnectApplication() { try { - Cast.CastApi.joinApplication(apiClient, CastCompat.APPLICATION_ID, sessionId).setResultCallback(resultCallback); + Cast.CastApi.joinApplication(apiClient, EnvironmentVariables.CAST_APPLICATION_ID, sessionId).setResultCallback(resultCallback); } catch (Exception e) { Log.e(TAG, "Failed to reconnect application", e); } diff --git a/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java b/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java index d8046d1b..710d5232 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java +++ b/app/src/main/java/github/daneren2005/dsub/util/EnvironmentVariables.java @@ -17,4 +17,5 @@ package github.daneren2005.dsub.util; public final class EnvironmentVariables { public static final String PASTEBIN_DEV_KEY = ""; + public static final String CAST_APPLICATION_ID = ""; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java b/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java index ab64bca9..415106db 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/CastCompat.java @@ -23,13 +23,9 @@ import com.google.android.gms.cast.CastMediaControlIntent; import github.daneren2005.dsub.service.ChromeCastController; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.RemoteController; +import github.daneren2005.dsub.util.EnvironmentVariables; -/** - * Created by owner on 2/9/14. - */ public final class CastCompat { - public static final String APPLICATION_ID = "5F85EBEB"; - static { try { Class.forName("com.google.android.gms.cast.CastDevice"); @@ -52,6 +48,6 @@ public final class CastCompat { } public static String getCastControlCategory() { - return CastMediaControlIntent.categoryForCast(APPLICATION_ID); + return CastMediaControlIntent.categoryForCast(EnvironmentVariables.CAST_APPLICATION_ID); } } -- cgit v1.2.3 From 78b673c99c3b595af1672cde967e1b592a274d70 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 27 Sep 2016 17:14:25 -0700 Subject: Update hu translation --- app/src/main/res/values-hu/strings.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index a720b214..12102043 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -36,6 +36,7 @@ Várólista Podcastok Könyvjelzők + Internet rádió Megosztások Csevegés (Chat) Admin @@ -225,6 +226,7 @@ 1.5x 2x 3x + Egyéni Új podcastok: \"%s\" Új lejátszási listák: \"%s\" @@ -305,6 +307,8 @@ Sötét Fekete Holo + Nappal/Éjszaka + Nappal/Fekete éjszaka Teljes képernyős Teljes képernyős üzemmód (értesítési sáv elrejtése). Dalsorszám megjelenítése @@ -407,6 +411,8 @@ Podcastok menüpont megjelenítése az elhúzható oldalsávon. Könyvjelzők engedélyezése Könyvjelzők menüpont megjelenítése az elhúzható oldalsávon. + Internet rádió engedélyezése + Internet rádió menüpont megjelenítése az elhúzható oldalsávon. Megosztások engedélyezése Megosztások menüpont megjelenítése az elhúzható oldalsávon. Szinkronizálás @@ -464,7 +470,7 @@ Dal értékeiből Hangerő-kiegyenlítés előerősítése Dalok hangerő-kiegyenlítés nélkül - Casting (Tartalmak átküldése) + Casting (tartalmak átküldése) Eszköz használata proxyként Streamelés az eszközön (mint egy proxyn) keresztül. Ez megoldást jelenthet néhány esetben, pl. saját aláírású tanúsítvány használatakor. Duplikált dalok átnevezése -- cgit v1.2.3 From 538cb889c45559f7af54fee33801547de719fbfc Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 27 Sep 2016 17:15:45 -0700 Subject: Fixes #737: Don't show playback speed button on < 6.0 --- .../main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java index 985b7bec..f55dbe1d 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -522,7 +522,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis menu.removeItem(R.id.menu_equalizer); } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && isRemoteEnabled) { + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || isRemoteEnabled) { playbackSpeedButton.setVisibility(View.GONE); } else { playbackSpeedButton.setVisibility(View.VISIBLE); -- cgit v1.2.3