diff options
Diffstat (limited to 'app/src/main')
21 files changed, 246 insertions, 66 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/domain/SearchCritera.java b/app/src/main/java/github/daneren2005/dsub/domain/SearchCritera.java index 20d46aa0..ed2400ef 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/SearchCritera.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/SearchCritera.java @@ -18,6 +18,8 @@ */ package github.daneren2005.dsub.domain; +import java.util.regex.Pattern; + /** * The criteria for a music search. * @@ -25,31 +27,67 @@ package github.daneren2005.dsub.domain; */ public class SearchCritera { - private final String query; - private final int artistCount; - private final int albumCount; - private final int songCount; - - public SearchCritera(String query, int artistCount, int albumCount, int songCount) { - this.query = query; - this.artistCount = artistCount; - this.albumCount = albumCount; - this.songCount = songCount; - } - - public String getQuery() { - return query; - } - - public int getArtistCount() { - return artistCount; - } - - public int getAlbumCount() { - return albumCount; - } - - public int getSongCount() { - return songCount; - } -}
\ No newline at end of file + private final String query; + private final int artistCount; + private final int albumCount; + private final int songCount; + private Pattern pattern; + + public SearchCritera(String query, int artistCount, int albumCount, int songCount) { + this.query = query; + this.artistCount = artistCount; + this.albumCount = albumCount; + this.songCount = songCount; + } + + public String getQuery() { + return query; + } + + public int getArtistCount() { + return artistCount; + } + + public int getAlbumCount() { + return albumCount; + } + + public int getSongCount() { + return songCount; + } + + /** + * Returns and caches a pattern instance that can be used to check if a + * string matches the query. + */ + public Pattern getPattern() { + + // If the pattern wasn't already cached, create a new regular expression + // from the search string : + // * Surround the search string with ".*" (match anything) + // * Replace spaces and wildcard '*' characters with ".*" + // * All other characters are properly quoted + if (this.pattern == null) { + String regex = ".*"; + String currentPart = ""; + for (int i = 0; i < query.length(); i++) { + char c = query.charAt(i); + if (c == '*' || c == ' ') { + regex += Pattern.quote(currentPart); + regex += ".*"; + currentPart = ""; + } else { + currentPart += c; + } + } + if (currentPart.length() > 0) { + regex += Pattern.quote(currentPart); + } + + regex += ".*"; + this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + } + + return this.pattern; + } +} 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 5de9c595..8e459996 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -906,10 +906,14 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private int getMinutes(int progress) { if(progress < 30) { return progress + 1; - } else if(progress < 61) { + } else if(progress < 49) { return (progress - 30) * 5 + getMinutes(29); + } else if(progress < 57) { + return (progress - 48) * 30 + getMinutes(48); + } else if(progress < 81) { + return (progress - 56) * 60 + getMinutes(56); } else { - return (progress - 61) * 15 + getMinutes(60); + return (progress - 80) * 150 + getMinutes(80); } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java index cb0e48b9..f231fa33 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java @@ -27,6 +27,7 @@ import android.widget.CompoundButton; import android.widget.DatePicker; import android.widget.EditText; +import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -104,10 +105,34 @@ public class SelectShareFragment extends SelectRecyclerFragment<Share> { } private void displayShareInfo(final Share share) { - String message = context.getResources().getString(R.string.share_info, - share.getUsername(), (share.getDescription() != null) ? share.getDescription() : "", share.getUrl(), - Util.formatDate(share.getCreated()), Util.formatDate(share.getLastVisited()), Util.formatDate(share.getExpires()), share.getVisitCount()); - Util.info(context, share.getName(), message); + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); + + headers.add(R.string.details_title); + details.add(share.getName()); + + headers.add(R.string.details_owner); + details.add(share.getUsername()); + + headers.add(R.string.details_description); + details.add(share.getDescription()); + + headers.add(R.string.details_url); + details.add(share.getUrl()); + + headers.add(R.string.details_created); + details.add(Util.formatDate(share.getCreated())); + + headers.add(R.string.details_last_played); + details.add(Util.formatDate(share.getLastVisited())); + + headers.add(R.string.details_expiration); + details.add(Util.formatDate(share.getExpires(), false)); + + headers.add(R.string.details_played_count); + details.add(Long.toString(share.getVisitCount())); + + Util.showDetailsDialog(context, R.string.details_title_playlist, headers, details); } private void updateShareInfo(final Share share) { 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 249b8a93..7b294849 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SettingsFragment.java @@ -138,6 +138,8 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared xml = R.xml.settings_playback; } else if("servers".equals(name)) { xml = R.xml.settings_servers; + } else if ("cast".equals(name)) { + xml = R.xml.settings_cast; } if(xml != 0) { diff --git a/app/src/main/java/github/daneren2005/dsub/provider/DSubSearchProvider.java b/app/src/main/java/github/daneren2005/dsub/provider/DSubSearchProvider.java index f91c364e..ba8c80c1 100644 --- a/app/src/main/java/github/daneren2005/dsub/provider/DSubSearchProvider.java +++ b/app/src/main/java/github/daneren2005/dsub/provider/DSubSearchProvider.java @@ -58,6 +58,10 @@ public class DSubSearchProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + if(selectionArgs[0].isEmpty()) { + return null; + } + String query = selectionArgs[0] + "*"; SearchResult searchResult = search(query); return createCursor(selectionArgs[0], searchResult); 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 d14c7fd3..3048a0db 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java @@ -307,7 +307,15 @@ public class OfflineMusicService implements MusicService { } } }); - + + // Respect counts in search criteria + int artistCount = Math.min(artists.size(), criteria.getArtistCount()); + int albumCount = Math.min(albums.size(), criteria.getAlbumCount()); + int songCount = Math.min(songs.size(), criteria.getSongCount()); + artists = artists.subList(0, artistCount); + albums = albums.subList(0, albumCount); + songs = songs.subList(0, songCount); + return new SearchResult(artists, albums, songs); } @@ -359,20 +367,13 @@ public class OfflineMusicService implements MusicService { } } private int matchCriteria(SearchCritera criteria, String name) { - String query = criteria.getQuery().toLowerCase(); - String[] queryParts = query.split(" "); - String[] nameParts = name.toLowerCase().split(" "); - - int closeness = 0; - for(String queryPart : queryParts) { - for(String namePart : nameParts) { - if(namePart.equals(queryPart)) { - closeness++; - } - } + if (criteria.getPattern().matcher(name).matches()) { + return Util.getStringDistance( + criteria.getQuery().toLowerCase(), + name.toLowerCase()); + } else { + return 0; } - - return closeness; } @Override 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 abc743f7..75023ec0 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -96,6 +96,7 @@ import github.daneren2005.dsub.service.parser.SearchResult2Parser; import github.daneren2005.dsub.service.parser.SearchResultParser; import github.daneren2005.dsub.service.parser.ShareParser; import github.daneren2005.dsub.service.parser.StarredListParser; +import github.daneren2005.dsub.service.parser.TopSongsParser; import github.daneren2005.dsub.service.parser.UserParser; import github.daneren2005.dsub.service.parser.VideosParser; import github.daneren2005.dsub.service.ssl.SSLSocketFactory; @@ -1295,7 +1296,7 @@ public class RESTMusicService implements MusicService { String method = ServerInfo.isMadsonic(context, getInstance(context)) ? "getTopTrackSongs" : "getTopSongs"; Reader reader = getReader(context, progressListener, method, null, parameterNames, parameterValues); try { - return new RandomSongsParser(context, getInstance(context)).parse(reader, progressListener); + return new TopSongsParser(context, getInstance(context)).parse(reader, progressListener); } finally { Util.close(reader); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java b/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java index 99502f5e..6c70496d 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java @@ -25,6 +25,8 @@ import java.util.Iterator; import java.util.concurrent.LinkedBlockingQueue; import github.daneren2005.dsub.domain.RemoteStatus; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.Util; import github.daneren2005.serverproxy.WebProxy; public abstract class RemoteController { @@ -43,7 +45,11 @@ public abstract class RemoteController { // Really is abstract, just don't want to require RemoteController's support it public void changeNextTrack(DownloadFile song) {} public boolean isNextSupported() { - return this.nextSupported; + if(Util.getPreferences(downloadService).getBoolean(Constants.PREFERENCES_KEY_CAST_GAPLESS_PLAYBACK, true)) { + return this.nextSupported; + } else { + return false; + } } public abstract void setVolume(int volume); public abstract void updateVolume(boolean up); diff --git a/app/src/main/java/github/daneren2005/dsub/service/parser/TopSongsParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/TopSongsParser.java new file mode 100644 index 00000000..c3719782 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/TopSongsParser.java @@ -0,0 +1,58 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2016 (C) Scott Jackson +*/ +package github.daneren2005.dsub.service.parser; + +import android.content.Context; + +import org.xmlpull.v1.XmlPullParser; + +import java.io.Reader; + +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.util.ProgressListener; + +public class TopSongsParser extends MusicDirectoryEntryParser { + + public TopSongsParser(Context context, int instance) { + super(context, instance); + } + + public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { + init(reader); + + MusicDirectory dir = new MusicDirectory(); + int eventType; + int trackNumber = 1; + do { + eventType = nextParseEvent(); + if (eventType == XmlPullParser.START_TAG) { + String name = getElementName(); + if ("song".equals(name)) { + MusicDirectory.Entry entry = parseEntry(""); + entry.setTrack(trackNumber); + dir.addChild(entry); + + trackNumber++; + } else if ("error".equals(name)) { + handleError(); + } + } + } while (eventType != XmlPullParser.END_DOCUMENT); + + validate(); + + return dir; + } +}
\ 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 00682947..88b87481 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -170,6 +170,7 @@ public final class Constants { public static final String PREFERENCES_KEY_SHUFFLE_BY_ALBUM = "shuffleByAlbum"; public static final String PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER = "neverResumePlayQueue"; public static final String PREFERENCES_KEY_BATCH_MODE = "batchMode"; + public static final String PREFERENCES_KEY_CAST_GAPLESS_PLAYBACK = "castingGaplessPlayback"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; 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 98bbe1df..be9536ed 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -22,6 +22,8 @@ import android.app.Activity; import android.graphics.Color; import android.support.annotation.StringRes; import android.support.v7.app.AlertDialog; +import android.content.ClipboardManager; +import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -46,9 +48,11 @@ import android.text.method.LinkMovementMethod; import android.text.util.Linkify; import android.util.Log; import android.util.SparseArray; +import android.view.View; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; +import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; @@ -1247,6 +1251,27 @@ public final class Util { listView.setDivider(null); listView.setScrollbarFadingEnabled(false); + // Let the user long-click on a row to copy its value to the clipboard + final Context contextRef = context; + listView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView<?> parent, View view, int pos, long id) { + + TextView nameView = (TextView) view.findViewById(R.id.detail_name); + TextView detailsView = (TextView) view.findViewById(R.id.detail_value); + CharSequence name = nameView.getText(); + CharSequence value = detailsView.getText(); + + ClipboardManager clipboard = (ClipboardManager) contextRef.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText(name, value); + clipboard.setPrimaryClip(clip); + + toast(contextRef, "Copied " + name + " to clipboard"); + + return true; + } + }); + new AlertDialog.Builder(context) // .setIcon(android.R.drawable.ic_dialog_info) .setTitle(title) diff --git a/app/src/main/res/drawable/drawer_header_clean.psd b/app/src/main/res/drawable/drawer_header_clean.psd Binary files differnew file mode 100644 index 00000000..a708d49c --- /dev/null +++ b/app/src/main/res/drawable/drawer_header_clean.psd diff --git a/app/src/main/res/drawable/drawer_header_dark.png b/app/src/main/res/drawable/drawer_header_dark.png Binary files differindex a6d2c1fb..a1c8d61f 100644 --- a/app/src/main/res/drawable/drawer_header_dark.png +++ b/app/src/main/res/drawable/drawer_header_dark.png diff --git a/app/src/main/res/drawable/drawer_header_holo.png b/app/src/main/res/drawable/drawer_header_holo.png Binary files differindex 3caa320b..d84d096d 100644 --- a/app/src/main/res/drawable/drawer_header_holo.png +++ b/app/src/main/res/drawable/drawer_header_holo.png diff --git a/app/src/main/res/drawable/drawer_header_light.png b/app/src/main/res/drawable/drawer_header_light.png Binary files differindex 8f041092..1bcf4ec3 100644 --- a/app/src/main/res/drawable/drawer_header_light.png +++ b/app/src/main/res/drawable/drawer_header_light.png diff --git a/app/src/main/res/layout/start_timer.xml b/app/src/main/res/layout/start_timer.xml index 59bd60e3..61a72233 100644 --- a/app/src/main/res/layout/start_timer.xml +++ b/app/src/main/res/layout/start_timer.xml @@ -18,5 +18,5 @@ android:id="@+id/timer_length_bar" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:max="97"/> + android:max="92"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 010d69e6..73ae6bed 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -9,7 +9,7 @@ <dimen name="Card.Radius">4dp</dimen> <dimen name="Card.TextLeftPadding">8dp</dimen> <dimen name="Card.MarginsForShadow">2dp</dimen> - <dimen name="FastScroller.LeftAlignedMargin">4dp</dimen> + <dimen name="FastScroller.LeftAlignedMargin">6dp</dimen> <dimen name="FastScroller.NormalBarMargin">4dp</dimen> <dimen name="FastScroller.RightMargin">4dp</dimen> </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54520cce..6eac3c83 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -488,10 +488,9 @@ <string name="shuffle.genre">Genre:</string> <string name="shuffle.pick_genre">Pick a genre</string> - <string name="share.info">Owner: %1$s - \nDescription: %2$s - \nURL: %3$s - \nCreation: %4$s + <string name="share.info"> + + \nLast Visited: %5$s \nExpiration: %6$s \nVisit Count: %7$s @@ -653,6 +652,8 @@ <string name="details.updated">Updated</string> <string name="details.starred">Starred</string> <string name="details.last_played">Last Played</string> + <string name="details.expiration">Expiration</string> + <string name="details.played_count">Played Count</string> <plurals name="select_album_n_songs"> <item quantity="zero">No songs</item> diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index ac247c8f..a067130a 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -31,4 +31,9 @@ android:title="@string/settings.playback_title" android:key="playback"> </PreferenceScreen> + + <PreferenceScreen + android:title="@string/settings.casting" + android:key="cast"> + </PreferenceScreen> </PreferenceScreen> diff --git a/app/src/main/res/xml/settings_cast.xml b/app/src/main/res/xml/settings_cast.xml new file mode 100644 index 00000000..058255c2 --- /dev/null +++ b/app/src/main/res/xml/settings_cast.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" + android:title="@string/settings.casting"> + <PreferenceCategory + android:title="@string/settings.casting"> + + <CheckBoxPreference + android:title="@string/settings.casting_proxy" + android:summary="@string/settings.casting_proxy_summary" + android:key="castProxy" + android:defaultValue="false"/> + + <CheckBoxPreference + android:title="@string/settings.gapless_playback" + android:summary="@string/settings.gapless_playback_summary" + android:key="castingGaplessPlayback" + android:defaultValue="true"/> + </PreferenceCategory> +</PreferenceScreen>
\ No newline at end of file diff --git a/app/src/main/res/xml/settings_playback.xml b/app/src/main/res/xml/settings_playback.xml index 3c505b6e..a4ea443e 100644 --- a/app/src/main/res/xml/settings_playback.xml +++ b/app/src/main/res/xml/settings_playback.xml @@ -59,16 +59,6 @@ </PreferenceCategory> <PreferenceCategory - android:title="@string/settings.casting"> - - <CheckBoxPreference - android:title="@string/settings.casting_proxy" - android:summary="@string/settings.casting_proxy_summary" - android:key="castProxy" - android:defaultValue="false"/> - </PreferenceCategory> - - <PreferenceCategory android:title="@string/settings.replay_gain"> <CheckBoxPreference |