aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2015-07-22 20:03:30 -0700
committerScott Jackson <daneren2005@gmail.com>2015-07-22 20:03:30 -0700
commitfbd1a68042dfc3601eaa0a9e37b3957bbdd51420 (patch)
tree3e96009d06e032ae266f5787dc6cf592b6ae504f /app/src/main/java
parent569281e423b93cf67db2141b49f04103036d4db5 (diff)
downloaddsub-fbd1a68042dfc3601eaa0a9e37b3957bbdd51420.tar.gz
dsub-fbd1a68042dfc3601eaa0a9e37b3957bbdd51420.tar.bz2
dsub-fbd1a68042dfc3601eaa0a9e37b3957bbdd51420.zip
Update details dialogs, remove play/cache/delete from more menus to keep context menus smaller
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java62
-rw-r--r--app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java29
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java57
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java12
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java60
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java30
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java178
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java46
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java2
-rw-r--r--app/src/main/java/github/daneren2005/dsub/util/FileUtil.java19
-rw-r--r--app/src/main/java/github/daneren2005/dsub/util/Util.java32
11 files changed, 311 insertions, 216 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java
new file mode 100644
index 00000000..efafe27a
--- /dev/null
+++ b/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of Subsonic.
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+ Copyright 2015 (C) Scott Jackson
+*/
+
+package github.daneren2005.dsub.adapter;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+import github.daneren2005.dsub.R;
+
+public class DetailsAdapter extends ArrayAdapter<String> {
+ private List<String> headers;
+ private List<String> details;
+
+ public DetailsAdapter(Context context, int layout, List<String> headers, List<String> details) {
+ super(context, layout, headers);
+
+ this.headers = headers;
+ this.details = details;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent){
+ View view;
+ if(convertView == null) {
+ view = LayoutInflater.from(getContext()).inflate(R.layout.details_item, null);
+ } else {
+ view = convertView;
+ }
+
+ TextView nameView = (TextView) view.findViewById(R.id.detail_name);
+ TextView detailsView = (TextView) view.findViewById(R.id.detail_value);
+
+ nameView.setText(headers.get(position));
+
+ detailsView.setText(details.get(position));
+ Linkify.addLinks(detailsView, Linkify.ALL);
+
+ return view;
+ }
+}
diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java
index 9d577409..3f6086d5 100644
--- a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java
+++ b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java
@@ -178,9 +178,7 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
if(sections.size() == 1 && !singleSectionHeader) {
T item = sections.get(0).get(position);
onBindViewHolder(holder, item, getItemViewType(position));
- if(updateView.isCheckable()) {
- setChecked(updateView, selected.contains(item));
- }
+ postBindView(updateView, item);
holder.setItem(item);
return;
}
@@ -199,9 +197,7 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
T item = section.get(position - subPosition - headerOffset);
onBindViewHolder(holder, item, getItemViewType(item));
- if(updateView.isCheckable()) {
- setChecked(updateView, selected.contains(item));
- }
+ postBindView(updateView, item);
holder.setItem(item);
return;
}
@@ -214,6 +210,27 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
}
}
+ private void postBindView(UpdateView updateView, T item) {
+ if(updateView.isCheckable()) {
+ setChecked(updateView, selected.contains(item));
+ }
+
+ View moreButton = updateView.findViewById(R.id.more_button);
+ if(moreButton == null) {
+ moreButton = updateView.findViewById(R.id.item_more);
+ }
+ if(moreButton != null) {
+ PopupMenu popup = new PopupMenu(context, moreButton);
+ Menu menu = popup.getMenu();
+ onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item);
+ if(menu.size() == 0) {
+ moreButton.setVisibility(View.GONE);
+ } else {
+ moreButton.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
@Override
public int getItemCount() {
if(sections.size() == 1 && !singleSectionHeader) {
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java
index 87da5d9c..d25315ac 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java
@@ -1,5 +1,6 @@
package github.daneren2005.dsub.fragments;
+import android.content.res.Resources;
import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
@@ -277,32 +278,54 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
}
private void showAboutDialog() {
- new LoadingTask<String>(context) {
+ new LoadingTask<Void>(context) {
+ Long[] used;
+ long bytesTotalFs;
+ long bytesAvailableFs;
+
@Override
- protected String doInBackground() throws Throwable {
+ protected Void doInBackground() throws Throwable {
File rootFolder = FileUtil.getMusicDirectory(context);
StatFs stat = new StatFs(rootFolder.getPath());
- long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
- long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
-
- Pair<Long, Long> used = FileUtil.getUsedSize(context, rootFolder);
-
- return getResources().getString(R.string.main_about_text,
- context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName,
- used.getFirst(),
- Util.formatLocalizedBytes(used.getSecond(), context),
- Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context),
- Util.formatLocalizedBytes(bytesAvailableFs, context),
- Util.formatLocalizedBytes(bytesTotalFs, context));
+ bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
+ bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
+
+ used = FileUtil.getUsedSize(context, rootFolder);
+ return null;
}
@Override
- protected void done(String msg) {
+ protected void done(Void result) {
+ List<Integer> headers = new ArrayList<>();
+ List<String> details = new ArrayList<>();
+
+ headers.add(R.string.details_author);
+ details.add("Scott Jackson");
+
+ headers.add(R.string.details_email);
+ details.add("dsub.android@gmail.com");
+
try {
- Util.info(context, R.string.main_about_title, msg);
+ headers.add(R.string.details_version);
+ details.add(context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName);
} catch(Exception e) {
- Util.toast(context, "Failed to open dialog");
+ details.add("");
}
+
+ Resources res = context.getResources();
+ headers.add(R.string.details_files_cached);
+ details.add(Long.toString(used[0]));
+
+ headers.add(R.string.details_files_permanent);
+ details.add(Long.toString(used[1]));
+
+ headers.add(R.string.details_used_space);
+ details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(used[2], context), Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context)));
+
+ headers.add(R.string.details_available_space);
+ details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(bytesAvailableFs, context), Util.formatLocalizedBytes(bytesTotalFs, context)));
+
+ Util.showDetailsDialog(context, R.string.main_about_title, headers, details);
}
}.execute();
}
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
index 2ab8316c..555e308e 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
@@ -360,18 +360,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
}
@Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Entry> updateView, Entry entry) {
- if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, false) && menuItem.getItemId() == R.id.song_menu_play_now) {
- List<Entry> songs = new ArrayList<Entry>();
- songs.add(entry);
- Iterator it = entries.listIterator(entries.indexOf(entry));
- while(it.hasNext()) {
- songs.add((Entry) it.next());
- }
-
- playNow(songs);
- return true;
- }
-
if(onContextItemSelected(menuItem, entry)) {
return true;
}
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
index 5b7e68a6..b1587e24 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
@@ -68,40 +68,13 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
@Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Playlist> updateView, Playlist playlist) {
- SubsonicFragment fragment;
- Bundle args;
- FragmentTransaction trans;
switch (menuItem.getItemId()) {
- case R.id.playlist_menu_download:
- downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true);
- break;
case R.id.playlist_menu_sync:
syncPlaylist(playlist);
break;
case R.id.playlist_menu_stop_sync:
stopSyncPlaylist(playlist);
break;
- case R.id.playlist_menu_play_now:
- fragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- fragment.setArguments(args);
-
- replaceFragment(fragment);
- break;
- case R.id.playlist_menu_play_shuffled:
- fragment = new SelectDirectoryFragment();
- args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
- args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
- args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- fragment.setArguments(args);
-
- replaceFragment(fragment);
- break;
case R.id.playlist_menu_delete:
deletePlaylist(playlist);
break;
@@ -213,12 +186,33 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
}
private void displayPlaylistInfo(final Playlist playlist) {
- String message = "Owner: " + playlist.getOwner() + "\nComments: " +
- ((playlist.getComment() == null) ? "" : playlist.getComment()) +
- "\nSong Count: " + playlist.getSongCount() +
- ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) +
- "\nCreated: " + Util.formatDate(context, playlist.getCreated());
- Util.info(context, playlist.getName(), message);
+ List<Integer> headers = new ArrayList<>();
+ List<String> details = new ArrayList<>();
+
+ if(playlist.getOwner() != null) {
+ headers.add(R.string.details_owner);
+ details.add(playlist.getOwner());
+ }
+
+ if(playlist.getComment() != null) {
+ headers.add(R.string.details_comments);
+ details.add(playlist.getComment());
+ }
+
+ headers.add(R.string.details_song_count);
+ details.add(playlist.getSongCount());
+
+ if(playlist.getPublic() != null) {
+ headers.add(R.string.details_public);
+ details.add(Boolean.toString(playlist.getPublic()));
+ }
+
+ if(playlist.getCreated() != null) {
+ headers.add(R.string.details_created);
+ details.add(Util.formatDate(context, playlist.getCreated()));
+ }
+
+ Util.showDetailsDialog(context, R.string.details_title_playlist, headers, details);
}
private void updatePlaylistInfo(final Playlist playlist) {
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
index f8afce6e..381453c0 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
@@ -214,13 +214,29 @@ public class SelectPodcastsFragment extends SelectRecyclerFragment<PodcastChanne
}
private void displayPodcastInfo(final PodcastChannel channel) {
- String message = ((channel.getName()) == null ? "" : "Title: " + channel.getName()) +
- "\nURL: " + channel.getUrl() +
- "\nStatus: " + channel.getStatus() +
- ((channel.getErrorMessage()) == null ? "" : "\nError Message: " + channel.getErrorMessage()) +
- ((channel.getDescription()) == null ? "" : "\n\nDescription: " + channel.getDescription());
-
- Util.info(context, channel.getName(), message);
+ List<Integer> headers = new ArrayList<>();
+ List<String> details = new ArrayList<>();
+
+ if(channel.getName() != null) {
+ headers.add(R.string.details_title);
+ details.add(channel.getName());
+ }
+
+ headers.add(R.string.details_url);
+ details.add(channel.getUrl());
+ headers.add(R.string.details_status);
+ details.add(channel.getStatus());
+
+ if(channel.getErrorMessage() != null) {
+ headers.add(R.string.details_error);
+ details.add(channel.getErrorMessage());
+ }
+ if(channel.getDescription() != null) {
+ headers.add(R.string.details_description);
+ details.add(channel.getDescription());
+ }
+
+ Util.showDetailsDialog(context, R.string.details_title_podcast, headers, details);
}
private void deletePodcast(final PodcastChannel channel) {
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 438649c3..6925b2da 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -241,9 +241,8 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
} else if(selected instanceof Artist) {
Artist artist = (Artist) selected;
if(Util.isOffline(context)) {
- menuInflater.inflate(R.menu.select_artist_context_offline, menu);
- }
- else {
+ // menuInflater.inflate(R.menu.select_artist_context_offline, menu);
+ } else {
menuInflater.inflate(R.menu.select_artist_context, menu);
menu.findItem(R.id.artist_menu_star).setTitle(artist.isStarred() ? R.string.common_unstar : R.string.common_star);
@@ -281,56 +280,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true)) {
menu.setGroupVisible(R.id.hide_rating, false);
}
-
- if(!Util.isOffline(context)) {
- // If we are looking at a standard song view, get downloadFile to cache what options to show
- if(updateView instanceof SongView) {
- SongView songView = (SongView) updateView;
- DownloadFile downloadFile = songView.getDownloadFile();
-
- try {
- if(downloadFile != null) {
- if(downloadFile.isWorkDone()) {
- // Remove permanent cache menu if already perma cached
- if(downloadFile.isSaved()) {
- menu.removeItem(R.id.song_menu_pin);
- }
-
- // Remove cache option no matter what if already downloaded
- menu.removeItem(R.id.song_menu_download);
- } else {
- // Remove delete option if nothing to delete
- menu.removeItem(R.id.song_menu_delete);
- }
- }
- } catch(Exception e) {
- Log.w(TAG, "Failed to lookup downloadFile info", e);
- }
- }
- // Apply similar logic to album views
- else if(updateView instanceof AlbumView || updateView instanceof ArtistView || updateView instanceof ArtistEntryView) {
- File folder = null;
- int id = 0;
- if(updateView instanceof AlbumView) {
- folder = ((AlbumView) updateView).getFile();
- id = R.id.album_menu_delete;
- } else if(updateView instanceof ArtistView) {
- folder = ((ArtistView) updateView).getFile();
- id = R.id.artist_menu_delete;
- } else if(updateView instanceof ArtistEntryView) {
- folder = ((ArtistEntryView) updateView).getFile();
- id = R.id.artist_menu_delete;
- }
-
- try {
- if(folder != null && !folder.exists()) {
- menu.removeItem(id);
- }
- } catch(Exception e) {
- Log.w(TAG, "Failed to lookup album directory info", e);
- }
- }
- }
}
protected void recreateContextMenu(Menu menu) {
@@ -355,60 +304,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
songs.add(entry);
switch (menuItem.getItemId()) {
- case R.id.artist_menu_play_now:
- downloadRecursively(artist.getId(), false, false, true, false, false);
- break;
- case R.id.artist_menu_play_shuffled:
- downloadRecursively(artist.getId(), false, false, true, true, false);
- break;
- case R.id.artist_menu_play_next:
- downloadRecursively(artist.getId(), false, true, false, false, false, true);
- break;
- case R.id.artist_menu_play_last:
- downloadRecursively(artist.getId(), false, true, false, false, false);
- break;
- case R.id.artist_menu_download:
- downloadRecursively(artist.getId(), false, true, false, false, true);
- break;
- case R.id.artist_menu_pin:
- downloadRecursively(artist.getId(), true, true, false, false, true);
- break;
- case R.id.artist_menu_delete:
- deleteRecursively(artist);
- break;
case R.id.artist_menu_star:
toggleStarred(artist);
break;
- case R.id.album_menu_play_now:
- artistOverride = true;
- downloadRecursively(entry.getId(), false, false, true, false, false);
- break;
- case R.id.album_menu_play_shuffled:
- artistOverride = true;
- downloadRecursively(entry.getId(), false, false, true, true, false);
- break;
- case R.id.album_menu_play_next:
- artistOverride = true;
- downloadRecursively(entry.getId(), false, true, false, false, false, true);
- break;
- case R.id.album_menu_play_last:
- artistOverride = true;
- downloadRecursively(entry.getId(), false, true, false, false, false);
- break;
- case R.id.album_menu_download:
- artistOverride = true;
- downloadRecursively(entry.getId(), false, true, false, false, true);
- break;
- case R.id.album_menu_pin:
- artistOverride = true;
- downloadRecursively(entry.getId(), true, true, false, false, true);
- break;
case R.id.album_menu_star:
toggleStarred(entry);
break;
- case R.id.album_menu_delete:
- deleteRecursively(entry);
- break;
case R.id.album_menu_info:
displaySongInfo(entry);
break;
@@ -418,21 +319,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;
- case R.id.song_menu_play_last:
- getDownloadService().download(songs, false, false, false, false);
- break;
case R.id.song_menu_download:
getDownloadService().downloadBackground(songs, false);
break;
- case R.id.song_menu_pin:
- getDownloadService().downloadBackground(songs, true);
- break;
case R.id.song_menu_delete:
getDownloadService().delete(songs);
break;
@@ -1262,7 +1151,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}.execute();
}
- @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
public void displaySongInfo(final Entry song) {
Integer duration = null;
Integer bitrate = null;
@@ -1302,55 +1190,83 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}
}
- String msg = "";
+ List<Integer> headers = new ArrayList<>();
+ List<String> details = new ArrayList<>();
if(song instanceof PodcastEpisode) {
- msg += "Podcast: " + song.getArtist() + "\nStatus: " + ((PodcastEpisode)song).getStatus();
+ headers.add(R.string.details_podcast);
+ details.add(song.getArtist());
+
+ headers.add(R.string.details_status);
+ details.add(((PodcastEpisode)song).getStatus());
} else if(!song.isVideo()) {
if(song.getArtist() != null && !"".equals(song.getArtist())) {
- msg += "Artist: " + song.getArtist();
+ headers.add(R.string.details_artist);
+ details.add(song.getArtist());
}
if(song.getAlbum() != null && !"".equals(song.getAlbum())) {
- msg += "\nAlbum: " + song.getAlbum();
+ headers.add(R.string.details_album);
+ details.add(song.getAlbum());
}
}
if(song.getTrack() != null && song.getTrack() != 0) {
- msg += "\nTrack: " + song.getTrack();
+ headers.add(R.string.details_track);
+ details.add(Integer.toString(song.getTrack()));
}
if(song.getGenre() != null && !"".equals(song.getGenre())) {
- msg += "\nGenre: " + song.getGenre();
+ headers.add(R.string.details_genre);
+ details.add(song.getGenre());
}
if(song.getYear() != null && song.getYear() != 0) {
- msg += "\nYear: " + song.getYear();
+ headers.add(R.string.details_year);
+ details.add(Integer.toString(song.getYear()));
}
if(!Util.isOffline(context) && song.getSuffix() != null) {
- msg += "\nServer Format: " + song.getSuffix();
+ headers.add(R.string.details_server_format);
+ details.add(song.getSuffix());
+
if(song.getBitRate() != null && song.getBitRate() != 0) {
- msg += "\nServer Bitrate: " + song.getBitRate() + " kbps";
+ headers.add(R.string.details_server_bitrate);
+ details.add(song.getBitRate() + " kbps");
}
}
if(format != null && !"".equals(format)) {
- msg += "\nCached Format: " + format;
+ headers.add(R.string.details_cached_format);
+ details.add(format);
}
if(bitrate != null && bitrate != 0) {
- msg += "\nCached Bitrate: " + bitrate + " kbps";
+ headers.add(R.string.details_cached_bitrate);
+ details.add(bitrate + " kbps");
}
if(size != 0) {
- msg += "\nSize: " + Util.formatLocalizedBytes(size, context);
+ headers.add(R.string.details_size);
+ details.add(Util.formatLocalizedBytes(size, context));
}
if(song.getDuration() != null && song.getDuration() != 0) {
- msg += "\nLength: " + Util.formatDuration(song.getDuration());
+ headers.add(R.string.details_length);
+ details.add(Util.formatDuration(song.getDuration()));
}
if(song.getBookmark() != null) {
- msg += "\nBookmark Position: " + Util.formatDuration(song.getBookmark().getPosition() / 1000);
+ headers.add(R.string.details_bookmark_position);
+ details.add(Util.formatDuration(song.getBookmark().getPosition() / 1000));
}
if(song.getRating() != 0) {
- msg += "\nRating: " + song.getRating() + " stars";
+ headers.add(R.string.details_rating);
+ details.add(song.getRating() + " stars");
}
if(song instanceof PodcastEpisode) {
- msg += "\n\nDescription: " + song.getAlbum();
+ headers.add(R.string.details_description);
+ details.add(song.getAlbum());
}
- Util.info(context, song.getTitle(), msg);
+ int title;
+ if(song.isDirectory()) {
+ title = R.string.details_title_album;
+ } else if(song instanceof PodcastEpisode) {
+ title = R.string.details_title_podcast;
+ } else {
+ title = R.string.details_title_song;
+ }
+ Util.showDetailsDialog(context, title, headers, details);
}
protected void playVideo(Entry entry) {
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 b4105d07..8ebf4c13 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -382,6 +382,42 @@ public class OfflineMusicService implements MusicService {
String id = file.getName();
String filename = server + ": " + FileUtil.getBaseName(id);
Playlist playlist = new Playlist(server, filename);
+
+ Reader reader = null;
+ BufferedReader buffer = null;
+ try {
+ int songCount = 0;
+ reader = new FileReader(file);
+ buffer = new BufferedReader(reader);
+
+ String line = buffer.readLine();
+ while( (line = buffer.readLine()) != null ){
+ // No matter what, end file can't have .complete in it
+ line = line.replace(".complete", "");
+ File entryFile = new File(line);
+
+ // Don't add file to playlist if it doesn't exist as cached or pinned!
+ File checkFile = entryFile;
+ if(!checkFile.exists()) {
+ // If normal file doens't exist, check if .complete version does
+ checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName())
+ + ".complete." + FileUtil.getExtension(entryFile.getName()));
+ }
+
+ String entryName = getName(entryFile);
+ if(checkFile.exists() && entryName != null){
+ songCount++;
+ }
+ }
+
+ playlist.setSongCount(Integer.toString(songCount));
+ } catch(Exception e) {
+ Log.w(TAG, "Failed to count songs in playlist", e);
+ } finally {
+ Util.close(buffer);
+ Util.close(reader);
+ }
+
playlists.add(playlist);
}
}
@@ -684,10 +720,16 @@ public class OfflineMusicService implements MusicService {
for(File file: dir.listFiles()) {
BufferedReader br = new BufferedReader(new FileReader(file));
while ((line = br.readLine()) != null && !"".equals(line)) {
+ String[] parts = line.split("\t");
+
PodcastChannel channel = new PodcastChannel();
- channel.setId(line);
- channel.setName(line);
+ channel.setId(parts[0]);
+ channel.setName(parts[0]);
channel.setStatus("completed");
+
+ if(parts.length > 1) {
+ channel.setUrl(parts[1]);
+ }
if(FileUtil.getPodcastDirectory(context, channel).exists() && !channels.contains(channel)) {
channels.add(channel);
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 459c8c9e..ed34e1cb 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
@@ -1204,7 +1204,7 @@ public class RESTMusicService implements MusicService {
String content = "";
for(PodcastChannel channel: channels) {
- content += channel.getName() + "\n";
+ content += channel.getName() + "\t" + channel.getUrl() + "\n";
}
File file = FileUtil.getPodcastFile(context, Util.getServerName(context, getInstance(context)));
diff --git a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java
index 990eae06..185a6b29 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java
@@ -741,23 +741,28 @@ public class FileUtil {
return index == -1 ? name : name.substring(0, index);
}
- public static Pair<Long, Long> getUsedSize(Context context, File file) {
+ public static Long[] getUsedSize(Context context, File file) {
long number = 0L;
+ long permanent = 0L;
long size = 0L;
if(file.isFile()) {
if(isMediaFile(file)) {
- return new Pair<Long, Long>(1L, file.length());
+ if(file.getAbsolutePath().indexOf(".complete") == -1) {
+ permanent++;
+ }
+ return new Long[] {1L, permanent, file.length()};
} else {
- return new Pair<Long, Long>(0L, 0L);
+ return new Long[] {0L, 0L, 0L};
}
} else {
for (File child : FileUtil.listFiles(file)) {
- Pair<Long, Long> pair = getUsedSize(context, child);
- number += pair.getFirst();
- size += pair.getSecond();
+ Long[] pair = getUsedSize(context, child);
+ number += pair[0];
+ permanent += pair[1];
+ size += pair[2];
}
- return new Pair<Long, Long>(number, size);
+ return new Long[] {number, permanent, size};
}
}
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 ce26bf1e..db0cb7c1 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Util.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java
@@ -19,6 +19,7 @@ package github.daneren2005.dsub.util;
import android.annotation.TargetApi;
import android.app.Activity;
+import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
@@ -45,11 +46,14 @@ import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.Log;
import android.view.Gravity;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.activity.SettingsActivity;
import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
+import github.daneren2005.dsub.adapter.DetailsAdapter;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RepeatMode;
@@ -73,8 +77,10 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
@@ -1137,6 +1143,32 @@ public final class Util {
((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
}
+ public static void showDetailsDialog(Context context, @StringRes int title, List<Integer> headers, List<String> details) {
+ List<String> headerStrings = new ArrayList<>();
+ for(@StringRes Integer res: headers) {
+ headerStrings.add(context.getResources().getString(res));
+ }
+ showDetailsDialog(context, context.getResources().getString(title), headerStrings, details);
+ }
+ public static void showDetailsDialog(Context context, String title, List<String> headers, List<String> details) {
+ ListView listView = new ListView(context);
+ listView.setAdapter(new DetailsAdapter(context, R.layout.details_item, headers, details));
+ listView.setDivider(null);
+ listView.setScrollbarFadingEnabled(false);
+
+ new AlertDialog.Builder(context)
+ // .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(title)
+ .setView(listView)
+ .setPositiveButton(R.string.common_close, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int i) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+
public static void sleepQuietly(long millis) {
try {
Thread.sleep(millis);