diff options
author | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-04-12 18:11:00 -0400 |
---|---|---|
committer | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-04-12 18:11:00 -0400 |
commit | 6a1a9afa6b31e9bc2b422d0e75866626af1bc90e (patch) | |
tree | 602b96fb1a9318ac6ffbf52d0647e24f92ca555d /app/src/main/java | |
parent | 7eee089bb8653916c45880ed31bcefbc389df362 (diff) | |
parent | 09bd600f5cbd78c02bf60b8ed399b211014820ee (diff) | |
download | AntennaPod-6a1a9afa6b31e9bc2b422d0e75866626af1bc90e.zip |
Merge pull request #735 from AntennaPod/version_1.11.1
Version 1.1
Diffstat (limited to 'app/src/main/java')
30 files changed, 1048 insertions, 179 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index 8401b41a7..287ae3568 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -138,7 +138,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { @Override public void onClick(View v) { try { - Feed f = new Feed(selectedDownloadUrl, new Date(), feed.getTitle()); + Feed f = new Feed(selectedDownloadUrl, new Date(0), feed.getTitle()); f.setPreferences(feed.getPreferences()); DefaultOnlineFeedViewActivity.this.feed = f; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index b3e95f0c0..2efee838d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -66,8 +66,8 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity public static final String SAVE_TITLE = "title"; - public static final int POS_NEW = 0, - POS_QUEUE = 1, + public static final int POS_QUEUE = 0, + POS_NEW = 1, POS_DOWNLOADS = 2, POS_HISTORY = 3, POS_ADD = 4; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 9f028000e..3b03ed2db 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -13,9 +13,21 @@ import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; + +import org.apache.commons.lang3.StringUtils; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; @@ -31,16 +43,7 @@ import de.danoeh.antennapod.core.util.FileNameGenerator; import de.danoeh.antennapod.core.util.StorageUtils; import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer; -import org.apache.commons.lang3.StringUtils; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; +import de.danoeh.antennapod.dialog.AuthenticationDialog; /** * Downloads a feed from a feed URL and parses it. Subclasses can display the @@ -181,7 +184,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { if (BuildConfig.DEBUG) Log.d(TAG, "Starting feed download"); url = URLChecker.prepareURL(url); - feed = new Feed(url, new Date()); + feed = new Feed(url, new Date(0)); if (username != null && password != null) { feed.setPreferences(new FeedPreferences(0, false, username, password)); } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java index 162a8f2e5..c1bbb7e52 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java @@ -1,7 +1,9 @@ package de.danoeh.antennapod.activity; -import android.app.AlertDialog; -import android.content.DialogInterface; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.Menu; @@ -10,23 +12,31 @@ import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; -import android.widget.Toast; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.LangUtils; import de.danoeh.antennapod.core.util.StorageUtils; -import java.io.*; - /** * Lets the user start the OPML-import process from a path */ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { + private static final String TAG = "OpmlImportFromPathActivity"; - private TextView txtvPath; - private Button butStart; - private String importPath; + + private static final int CHOOSE_OPML_FILE = 1; + + private Intent intentPickAction; + private Intent intentGetContentAction; @Override protected void onCreate(Bundle savedInstanceState) { @@ -36,47 +46,74 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { getSupportActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.opml_import); - txtvPath = (TextView) findViewById(R.id.txtvPath); - butStart = (Button) findViewById(R.id.butStartImport); + final TextView txtvHeaderExplanation1 = (TextView) findViewById(R.id.txtvHeadingExplanation1); + final TextView txtvExplanation1 = (TextView) findViewById(R.id.txtvExplanation1); + final TextView txtvHeaderExplanation2 = (TextView) findViewById(R.id.txtvHeadingExplanation2); + final TextView txtvExplanation2 = (TextView) findViewById(R.id.txtvExplanation2); + final TextView txtvHeaderExplanation3 = (TextView) findViewById(R.id.txtvHeadingExplanation3); - butStart.setOnClickListener(new OnClickListener() { + Button butChooseFilesystem = (Button) findViewById(R.id.butChooseFileFromFilesystem); + butChooseFilesystem.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - checkFolderForFiles(); + chooseFileFromFilesystem(); } }); + + Button butChooseExternal = (Button) findViewById(R.id.butChooseFileFromExternal); + butChooseExternal.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + chooseFileFromExternal(); + } + }); + + int nextOption = 1; + intentPickAction = new Intent(Intent.ACTION_PICK); + intentPickAction.setData(Uri.parse("file://")); + List<ResolveInfo> intentActivities = getPackageManager() + .queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE); + if(intentActivities.size() == 0) { + intentPickAction.setData(null); + intentActivities = getPackageManager() + .queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE); + if(intentActivities.size() == 0) { + txtvHeaderExplanation1.setVisibility(View.GONE); + txtvExplanation1.setVisibility(View.GONE); + findViewById(R.id.divider1).setVisibility(View.GONE); + butChooseFilesystem.setVisibility(View.GONE); + } + } + if(txtvExplanation1.getVisibility() == View.VISIBLE) { + txtvHeaderExplanation1.setText("Option " + nextOption); + nextOption++; + } + + intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT); + intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE); + intentGetContentAction.setType("*/*"); + intentActivities = getPackageManager() + .queryIntentActivities(intentGetContentAction, CHOOSE_OPML_FILE); + if(intentActivities.size() == 0) { + txtvHeaderExplanation2.setVisibility(View.GONE); + txtvExplanation2.setVisibility(View.GONE); + findViewById(R.id.divider2).setVisibility(View.GONE); + butChooseExternal.setVisibility(View.GONE); + } else { + txtvHeaderExplanation2.setText("Option " + nextOption); + nextOption++; + } + + txtvHeaderExplanation3.setText("Option " + nextOption); } @Override protected void onResume() { super.onResume(); StorageUtils.checkStorageAvailability(this); - setImportPath(); } - /** - * Sets the importPath variable and makes txtvPath display the import - * directory. - */ - private void setImportPath() { - File importDir = UserPreferences.getDataFolder(this, UserPreferences.IMPORT_DIR); - boolean success = true; - if (!importDir.exists()) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Import directory doesn't exist. Creating..."); - success = importDir.mkdir(); - if (!success) { - Log.e(TAG, "Could not create directory"); - } - } - if (success) { - txtvPath.setText(importDir.toString()); - importPath = importDir.toString(); - } else { - txtvPath.setText(R.string.opml_directory_error); - } - } @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -95,32 +132,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { } } - /** - * Looks at the contents of the import directory and decides what to do. If - * more than one file is in the directory, a dialog will be created to let - * the user choose which item to import - */ - private void checkFolderForFiles() { - File dir = new File(importPath); - if (dir.isDirectory()) { - File[] fileList = dir.listFiles(); - if (fileList.length == 1) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Found one file, choosing that one."); - startImport(fileList[0]); - } else if (fileList.length > 1) { - Log.w(TAG, "Import directory contains more than one file."); - askForFile(dir); - } else { - Log.e(TAG, "Import directory is empty"); - Toast toast = Toast - .makeText(this, R.string.opml_import_error_dir_empty, - Toast.LENGTH_LONG); - toast.show(); - } - } - } - private void startImport(File file) { Reader mReader = null; try { @@ -134,38 +145,36 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { } } - /** - * Asks the user to choose from a list of files in a directory and returns - * his choice. + /* + * Creates an implicit intent to launch a file manager which lets + * the user choose a specific OPML-file to import from. */ - private void askForFile(File dir) { - final File[] fileList = dir.listFiles(); - String[] fileNames = dir.list(); - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(R.string.choose_file_to_import_label); - dialog.setNeutralButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Dialog was cancelled"); - dialog.dismiss(); - } - }); - dialog.setItems(fileNames, new DialogInterface.OnClickListener() { + private void chooseFileFromFilesystem() { + try { + startActivityForResult(intentPickAction, CHOOSE_OPML_FILE); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "No activity found. Should never happen..."); + } + } - @Override - public void onClick(DialogInterface dialog, int which) { - if (BuildConfig.DEBUG) - Log.d(TAG, "File at index " + which + " was chosen"); - dialog.dismiss(); - startImport(fileList[which]); - } - }); - dialog.create().show(); + private void chooseFileFromExternal() { + try { + startActivityForResult(intentGetContentAction, CHOOSE_OPML_FILE); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "No activity found. Should never happen..."); + } } + /** + * Gets the path of the file chosen with chooseFileToImport() + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) { + String filename = data.getData().getPath(); + startImport(new File(filename)); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java index c35bb9694..8d3e73429 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java @@ -57,7 +57,7 @@ public class ActionButtonUtils { } else { // item is not being downloaded butSecondary.setVisibility(View.VISIBLE); - if (media.isPlaying()) { + if (media.isCurrentlyPlaying()) { butSecondary.setImageDrawable(drawables.getDrawable(3)); } else { butSecondary diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java index 800462023..14644dd68 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; +import android.content.Intent; import android.widget.Toast; import org.apache.commons.lang3.Validate; @@ -9,6 +10,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; @@ -46,7 +48,15 @@ public class DefaultActionButtonCallback implements ActionButtonCallback { DownloadRequester.getInstance().cancelDownload(context, media); Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show(); } else { // media is downloaded - DBTasks.playMedia(context, media, true, true, false); + if (item.hasMedia() && item.getMedia().isCurrentlyPlaying()) { + context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE)); + } + else if (item.hasMedia() && item.getMedia().isCurrentlyPaused()) { + context.sendBroadcast(new Intent(PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE)); + } + else { + DBTasks.playMedia(context, media, false, true, false); + } } } else { if (!item.isRead()) { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index 8f1a838f9..d56bfc587 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -9,6 +9,7 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.*; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index a0ba0f794..05783e3ee 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -25,7 +25,7 @@ public class NavListAdapter extends BaseAdapter { public static final int VIEW_TYPE_SECTION_DIVIDER = 1; public static final int VIEW_TYPE_SUBSCRIPTION = 2; - public static final int[] NAV_TITLES = {R.string.all_episodes_label, R.string.queue_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label}; + public static final int[] NAV_TITLES = {R.string.queue_label, R.string.new_episodes_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label}; private final Drawable[] drawables; @@ -38,7 +38,7 @@ public class NavListAdapter extends BaseAdapter { this.itemAccess = itemAccess; this.context = context; - TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.ic_new, R.attr.stat_playlist, + TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.stat_playlist, R.attr.ic_new, R.attr.av_download, R.attr.ic_history, R.attr.content_new}); drawables = new Drawable[]{ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2), ta.getDrawable(3), ta.getDrawable(4)}; @@ -132,7 +132,7 @@ public class NavListAdapter extends BaseAdapter { } else { holder.count.setVisibility(View.GONE); } - } else if (NAV_TITLES[position] == R.string.all_episodes_label) { + } else if (NAV_TITLES[position] == R.string.new_episodes_label) { int unreadItems = itemAccess.getNumberOfUnreadItems(); if (unreadItems > 0) { holder.count.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java index 1f98ec158..2d481a7ef 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; +import android.graphics.Color; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; @@ -11,9 +12,11 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.nineoldandroids.view.ViewHelper; import com.squareup.picasso.Picasso; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -139,6 +142,13 @@ public class NewEpisodesListAdapter extends BaseAdapter { .fit() .into(holder.imageView); + if (item.isRead()) { + // grey it out + ViewHelper.setAlpha(convertView, .2f); + } else { + ViewHelper.setAlpha(convertView, 1.0f); + } + return convertView; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java index d5b85575b..a256dc129 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; +import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -13,9 +14,11 @@ import android.widget.TextView; import com.squareup.picasso.Picasso; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Converter; /** * List adapter for the queue. @@ -64,12 +67,16 @@ public class QueueListAdapter extends BaseAdapter { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.queue_listitem, parent, false); + holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate); + holder.progressLeft = (TextView) convertView.findViewById(R.id.txtvProgressLeft); + holder.progressRight = (TextView) convertView + .findViewById(R.id.txtvProgressRight); holder.butSecondary = (ImageButton) convertView .findViewById(R.id.butSecondaryAction); - holder.position = (TextView) convertView.findViewById(R.id.txtvPosition); holder.progress = (ProgressBar) convertView - .findViewById(R.id.pbar_download_progress); + .findViewById(R.id.progressBar); holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); convertView.setTag(holder); } else { @@ -77,19 +84,39 @@ public class QueueListAdapter extends BaseAdapter { } holder.title.setText(item.getTitle()); + FeedMedia media = item.getMedia(); - AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.position, holder.progress); - FeedMedia media = item.getMedia(); + holder.title.setText(item.getTitle()); + String pubDate = DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL); + holder.pubDate.setText(pubDate.replace(" ", "\n")); + if (media != null) { final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media); - - if (!media.isDownloaded()) { - if (isDownloadingMedia) { - // item is being downloaded + FeedItem.State state = item.getState(); + if (isDownloadingMedia) { + holder.progressLeft.setText(Converter.byteToString(itemAccess.getItemDownloadedBytes(item))); + if(itemAccess.getItemDownloadSize(item) > 0) { + holder.progressRight.setText(Converter.byteToString(itemAccess.getItemDownloadSize(item))); + } else { + holder.progressRight.setText(Converter.byteToString(media.getSize())); + } + holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); + holder.progress.setVisibility(View.VISIBLE); + } else if (state == FeedItem.State.PLAYING + || state == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + int progress = (int) (100.0 * media.getPosition() / media.getDuration()); + holder.progress.setProgress(progress); holder.progress.setVisibility(View.VISIBLE); - holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); + holder.progressLeft.setText(Converter + .getDurationStringLong(media.getPosition())); + holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration())); } + } else { + holder.progressLeft.setText(Converter.byteToString(media.getSize())); + holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration())); + holder.progress.setVisibility(View.GONE); } } @@ -116,18 +143,20 @@ public class QueueListAdapter extends BaseAdapter { static class Holder { - TextView title; ImageView imageView; - TextView position; + TextView title; + TextView pubDate; + TextView progressLeft; + TextView progressRight; ProgressBar progress; ImageButton butSecondary; } public interface ItemAccess { - int getCount(); - FeedItem getItem(int position); - + int getCount(); + long getItemDownloadedBytes(FeedItem item); + long getItemDownloadSize(FeedItem item); int getItemDownloadProgressPercent(FeedItem item); } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java index 58af2c4d5..b85709c5e 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java @@ -39,16 +39,15 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.gpodnet_podcast_listitem, parent, false); - holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); holder.image = (ImageView) convertView.findViewById(R.id.imgvCover); - + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.subscribers = (TextView) convertView.findViewById(R.id.txtvSubscribers); + holder.url = (TextView) convertView.findViewById(R.id.txtvUrl); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } - holder.title.setText(podcast.getTitle()); - if (StringUtils.isNotBlank(podcast.getLogoUrl())) { Picasso.with(convertView.getContext()) .load(podcast.getLogoUrl()) @@ -56,11 +55,17 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> { .into(holder.image); } + holder.title.setText(podcast.getTitle()); + holder.subscribers.setText(String.valueOf(podcast.getSubscribers())); + holder.url.setText(podcast.getUrl()); + return convertView; } static class Holder { - TextView title; ImageView image; + TextView title; + TextView subscribers; + TextView url; } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java new file mode 100644 index 000000000..b4eadefb5 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java @@ -0,0 +1,54 @@ +package de.danoeh.antennapod.adapter.gpodnet; + +import android.content.Context; +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 de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag; + +/** + * Adapter for displaying a list of GPodnetPodcast-Objects. + */ +public class TagListAdapter extends ArrayAdapter<GpodnetTag> { + + public TagListAdapter(Context context, int resource, List<GpodnetTag> objects) { + super(context, resource, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + + GpodnetTag tag = getItem(position); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.gpodnet_tag_listitem, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.usage = (TextView) convertView.findViewById(R.id.txtvUsage); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(tag.getTitle()); + holder.usage.setText(String.valueOf(tag.getUsage())); + + return convertView; + } + + static class Holder { + TextView title; + TextView usage; + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java new file mode 100644 index 000000000..4fc2838b7 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java @@ -0,0 +1,187 @@ +package de.danoeh.antennapod.adapter.itunes; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; + +public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { + /** + * Related Context + */ + private final Context context; + + /** + * List holding the podcasts found in the search + */ + private final List<Podcast> data; + + /** + * Constructor. + * + * @param context Related context + * @param objects Search result + */ + public ItunesAdapter(Context context, List<Podcast> objects) { + super(context, 0, objects); + this.data = objects; + this.context = context; + } + + /** + * Updates the given ImageView with the image in the given Podcast's imageUrl + */ + class FetchImageTask extends AsyncTask<Void,Void,Bitmap>{ + /** + * Current podcast + */ + private final Podcast podcast; + + /** + * ImageView to be updated + */ + private final ImageView imageView; + + /** + * Constructor + * + * @param podcast Podcast that has the image + * @param imageView UI image to be updated + */ + FetchImageTask(Podcast podcast, ImageView imageView){ + this.podcast = podcast; + this.imageView = imageView; + } + + //Get the image from the url + @Override + protected Bitmap doInBackground(Void... params) { + HttpClient client = new DefaultHttpClient(); + HttpGet get = new HttpGet(podcast.imageUrl); + try { + HttpResponse response = client.execute(get); + return BitmapFactory.decodeStream(response.getEntity().getContent()); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + //Set the background image for the podcast + @Override + protected void onPostExecute(Bitmap img) { + super.onPostExecute(img); + if(img!=null) { + imageView.setImageBitmap(img); + } + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + //Current podcast + Podcast podcast = data.get(position); + + //ViewHolder + PodcastViewHolder viewHolder; + + //Resulting view + View view; + + //Handle view holder stuff + if(convertView == null) { + view = ((MainActivity) context).getLayoutInflater() + .inflate(R.layout.itunes_podcast_listitem, parent, false); + viewHolder = new PodcastViewHolder(view); + view.setTag(viewHolder); + } else { + view = convertView; + viewHolder = (PodcastViewHolder) view.getTag(); + } + + //Set the title + viewHolder.titleView.setText(podcast.title); + + //Update the empty imageView with the image from the feed + new FetchImageTask(podcast,viewHolder.coverView).execute(); + + //Feed the grid view + return view; + } + + /** + * View holder object for the GridView + */ + class PodcastViewHolder { + + /** + * ImageView holding the Podcast image + */ + public final ImageView coverView; + + /** + * TextView holding the Podcast title + */ + public final TextView titleView; + + + /** + * Constructor + * @param view GridView cell + */ + PodcastViewHolder(View view){ + coverView = (ImageView) view.findViewById(R.id.imgvCover); + titleView = (TextView) view.findViewById(R.id.txtvTitle); + } + } + + /** + * Represents an individual podcast on the iTunes Store. + */ + public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model + + /** + * The name of the podcast + */ + public final String title; + + /** + * URL of the podcast image + */ + public final String imageUrl; + /** + * URL of the podcast feed + */ + public final String feedUrl; + + /** + * Constructor. + * + * @param json object holding the podcast information + * @throws JSONException + */ + public Podcast(JSONObject json) throws JSONException { + title = json.getString("collectionName"); + imageUrl = json.getString("artworkUrl100"); + feedUrl = json.getString("feedUrl"); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java index cb9197b8e..00327bce0 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java @@ -4,16 +4,17 @@ import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; -import de.danoeh.antennapod.core.R; + +import java.util.Arrays; +import java.util.Date; + import de.danoeh.antennapod.activity.OpmlImportHolder; +import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.opml.OpmlElement; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; -import java.util.Arrays; -import java.util.Date; - /** Queues items for download in the background. */ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> { private Context context; @@ -46,7 +47,7 @@ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> { for (int idx = 0; idx < selection.length; idx++) { OpmlElement element = OpmlImportHolder.getReadElements().get( selection[idx]); - Feed feed = new Feed(element.getXmlUrl(), new Date(), + Feed feed = new Feed(element.getXmlUrl(), new Date(0), element.getText()); try { requester.downloadFeed(context.getApplicationContext(), feed); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java index f5ae5a777..e4ae1683b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -8,6 +8,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity; import de.danoeh.antennapod.activity.MainActivity; @@ -41,10 +42,18 @@ public class AddFeedFragment extends Fragment { Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet); Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport); Button butConfirm = (Button) root.findViewById(R.id.butConfirm); + Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); final MainActivity activity = (MainActivity) getActivity(); activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label); + butSearchITunes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + activity.loadChildFragment(new ItunesSearchFragment()); + } + }); + butBrowserGpoddernet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -53,7 +62,6 @@ public class AddFeedFragment extends Fragment { }); butOpmlImport.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { startActivity(new Intent(getActivity(), diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java index c40fce351..0f6f7d53c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java @@ -1,25 +1,35 @@ package de.danoeh.antennapod.fragment; import android.content.Context; +import android.content.res.TypedArray; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; +import android.support.v4.view.MenuItemCompat; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.ListView; +import java.util.List; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.DownloadLogAdapter; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DBReader; - -import java.util.List; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.menuhandler.MenuItemUtils; +import de.danoeh.antennapod.menuhandler.NavDrawerActivity; /** * Shows the download log */ public class DownloadLogFragment extends ListFragment { + private static final String TAG = "DownloadLogFragment"; + private List<DownloadStatus> downloadLog; private DownloadLogAdapter adapter; @@ -29,6 +39,7 @@ public class DownloadLogFragment extends ListFragment { @Override public void onStart() { super.onStart(); + setHasOptionsMenu(true); EventDistributor.getInstance().register(contentUpdate); startItemLoader(); } @@ -63,7 +74,7 @@ public class DownloadLogFragment extends ListFragment { } setListShown(true); adapter.notifyDataSetChanged(); - + getActivity().supportInvalidateOptionsMenu(); } private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() { @@ -105,6 +116,41 @@ public class DownloadLogFragment extends ListFragment { } } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + if (itemsLoaded && !MenuItemUtils.isActivityDrawerOpen((NavDrawerActivity) getActivity())) { + MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label); + MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); + TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.content_discard}); + clearHistory.setIcon(drawables.getDrawable(0)); + drawables.recycle(); + } + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + if (itemsLoaded && !MenuItemUtils.isActivityDrawerOpen((NavDrawerActivity) getActivity())) { + menu.findItem(R.id.clear_history_item).setVisible(downloadLog != null && !downloadLog.isEmpty()); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (!super.onOptionsItemSelected(item)) { + switch (item.getItemId()) { + case R.id.clear_history_item: + DBWriter.clearDownloadLog(getActivity()); + return true; + default: + return false; + } + } else { + return true; + } + } + private class ItemLoader extends AsyncTask<Void, Void, List<DownloadStatus>> { @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index ac9e744ed..e80bf5f14 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -16,6 +16,7 @@ import android.support.v4.util.Pair; import android.support.v7.widget.PopupMenu; import android.support.v7.widget.Toolbar; import android.text.TextUtils; +import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -49,6 +50,7 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.QueueAccess; import de.danoeh.antennapod.core.util.playback.Timeline; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; @@ -91,6 +93,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba private View header; private WebView webvDescription; private TextView txtvTitle; + private TextView txtvDuration; + private TextView txtvPublished; private ImageView imgvCover; private ProgressBar progbarDownload; private ProgressBar progbarLoading; @@ -166,6 +170,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false); root = (ViewGroup) layout.findViewById(R.id.content_root); txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); + txtvDuration = (TextView) header.findViewById(R.id.txtvDuration); + txtvPublished = (TextView) header.findViewById(R.id.txtvPublished); if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448 txtvTitle.setEllipsize(TextUtils.TruncateAt.END); } @@ -313,6 +319,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba private void updateAppearance() { txtvTitle.setText(item.getTitle()); + txtvPublished.setText(DateUtils.formatDateTime(getActivity(), item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL)); + Picasso.with(getActivity()).load(item.getImageUri()) .fit() .into(imgvCover); @@ -348,7 +356,10 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba } drawables.recycle(); - } else { + } else {if(media.getDuration() > 0) { + txtvDuration.setText(Converter.getDurationStringLong(media.getDuration())); + } + boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media); TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play, R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel}); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java index 5312beeeb..acb07626c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -66,7 +66,8 @@ public class ItemlistFragment extends ListFragment { private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.QUEUE_UPDATE - | EventDistributor.UNREAD_ITEMS_UPDATE; + | EventDistributor.UNREAD_ITEMS_UPDATE + | EventDistributor.PLAYER_STATUS_UPDATE; public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem"; public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id"; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java new file mode 100644 index 000000000..c14b0cc6e --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java @@ -0,0 +1,193 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.widget.SearchView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.GridView; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity; +import de.danoeh.antennapod.activity.OnlineFeedViewActivity; +import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; + +import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.*; + +//Searches iTunes store for given string and displays results in a list +public class ItunesSearchFragment extends Fragment { + final String TAG = "ItunesSearchFragment"; + /** + * Search input field + */ + private SearchView searchView; + + /** + * Adapter responsible with the search results + */ + private ItunesAdapter adapter; + + /** + * List of podcasts retreived from the search + */ + private List<Podcast> searchResults; + + /** + * Replace adapter data with provided search results from SearchTask. + * @param result List of Podcast objects containing search results + */ + void updateData(List<Podcast> result) { + this.searchResults = result; + adapter.clear(); + + //ArrayAdapter.addAll() requires minsdk > 10 + for(Podcast p: result) { + adapter.add(p); + } + + adapter.notifyDataSetInvalidated(); + } + + /** + * Constructor + */ + public ItunesSearchFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + adapter = new ItunesAdapter(getActivity(), new ArrayList<Podcast>()); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = inflater.inflate(R.layout.fragment_itunes_search, container, false); + GridView gridView = (GridView) view.findViewById(R.id.gridView); + gridView.setAdapter(adapter); + + //Show information about the podcast when the list item is clicked + gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + Intent intent = new Intent(getActivity(), + DefaultOnlineFeedViewActivity.class); + + //Tell the OnlineFeedViewActivity where to go + String url = searchResults.get(position).feedUrl; + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url); + + intent.putExtra(DefaultOnlineFeedViewActivity.ARG_TITLE, "iTunes"); + startActivity(intent); + } + }); + + //Configure search input view to be expanded by default with a visible submit button + searchView = (SearchView) view.findViewById(R.id.itunes_search_view); + searchView.setIconifiedByDefault(false); + searchView.setIconified(false); + searchView.setSubmitButtonEnabled(true); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + //This prevents onQueryTextSubmit() from being called twice when keyboard is used + //to submit the query. + searchView.clearFocus(); + new SearchTask(s).execute(); + return false; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + + return view; + } + + /** + * Search the iTunes store for podcasts using the given query + */ + class SearchTask extends AsyncTask<Void,Void,Void> { + /** + * Incomplete iTunes API search URL + */ + final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s"; + + /** + * Search terms + */ + final String query; + + /** + * Search result + */ + final List<Podcast> taskData = new ArrayList<>(); + + /** + * Constructor + * + * @param query Search string + */ + public SearchTask(String query){ + this.query = query; + } + + //Get the podcast data + @Override + protected Void doInBackground(Void... params) { + + //Spaces in the query need to be replaced with '+' character. + String formattedUrl = String.format(apiUrl, query).replace(' ', '+'); + + HttpClient client = new DefaultHttpClient(); + HttpGet get = new HttpGet(formattedUrl); + + try { + HttpResponse response = client.execute(get); + String resultString = EntityUtils.toString(response.getEntity()); + JSONObject result = new JSONObject(resultString); + JSONArray j = result.getJSONArray("results"); + + for (int i = 0; i < j.length(); i++){ + JSONObject podcastJson = j.getJSONObject(i); + Podcast podcast = new Podcast(podcastJson); + taskData.add(podcast); + } + + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + return null; + } + + //Save the data and update the list + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + updateData(taskData); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index d97ede0ef..8bc4099a9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -2,12 +2,15 @@ package de.danoeh.antennapod.fragment; import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; +import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v7.widget.SearchView; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -29,6 +32,7 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; import de.danoeh.antennapod.adapter.NewEpisodesListAdapter; import de.danoeh.antennapod.core.asynctask.DownloadObserver; +import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; @@ -41,6 +45,8 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.QueueAccess; +import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken; +import de.danoeh.antennapod.core.util.gui.UndoBarController; import de.danoeh.antennapod.menuhandler.MenuItemUtils; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; @@ -52,18 +58,22 @@ public class NewEpisodesFragment extends Fragment { private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.QUEUE_UPDATE | - EventDistributor.UNREAD_ITEMS_UPDATE; + EventDistributor.UNREAD_ITEMS_UPDATE | + EventDistributor.PLAYER_STATUS_UPDATE; private static final int RECENT_EPISODES_LIMIT = 150; private static final String PREF_NAME = "PrefNewEpisodesFragment"; private static final String PREF_EPISODE_FILTER_BOOL = "newEpisodeFilterEnabled"; - + private static final String PREF_KEY_LIST_TOP = "list_top"; + private static final String PREF_KEY_LIST_SELECTION = "list_selection"; private DragSortListView listView; private NewEpisodesListAdapter listAdapter; private TextView txtvEmpty; private ProgressBar progLoading; + private UndoBarController undoBarController; + private List<FeedItem> unreadItems; private List<FeedItem> recentItems; private QueueAccess queueAccess; @@ -109,6 +119,12 @@ public class NewEpisodesFragment extends Fragment { } @Override + public void onPause() { + super.onPause(); + saveScrollPosition(); + } + + @Override public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); @@ -127,10 +143,35 @@ public class NewEpisodesFragment extends Fragment { resetViewState(); } + private void saveScrollPosition() { + SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + View v = listView.getChildAt(0); + int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop()); + editor.putInt(PREF_KEY_LIST_SELECTION, listView.getFirstVisiblePosition()); + editor.putInt(PREF_KEY_LIST_TOP, top); + editor.commit(); + } + + private void restoreScrollPosition() { + SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + int listSelection = prefs.getInt(PREF_KEY_LIST_SELECTION, 0); + int top = prefs.getInt(PREF_KEY_LIST_TOP, 0); + if(listSelection > 0 || top > 0) { + listView.setSelectionFromTop(listSelection, top); + // restore once, then forget + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(PREF_KEY_LIST_SELECTION, 0); + editor.putInt(PREF_KEY_LIST_TOP, 0); + editor.commit(); + } + } + private void resetViewState() { listAdapter = null; activity.set(null); viewsCreated = false; + undoBarController = null; if (downloadObserver != null) { downloadObserver.onPause(); } @@ -190,8 +231,19 @@ public class NewEpisodesFragment extends Fragment { } return true; case R.id.mark_all_read_item: - DBWriter.markAllItemsRead(getActivity()); - Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show(); + ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), + R.string.mark_all_read_label, + R.string.mark_all_read_confirmation_msg) { + + @Override + public void onConfirmButtonPressed( + DialogInterface dialog) { + dialog.dismiss(); + DBWriter.markAllItemsRead(getActivity()); + Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show(); + } + }; + conDialog.createNewDialog().show(); return true; case R.id.episode_filter_item: boolean newVal = !item.isChecked(); @@ -210,7 +262,7 @@ public class NewEpisodesFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); - ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.all_episodes_label); + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.new_episodes_label); View root = inflater.inflate(R.layout.new_episodes_fragment, container, false); @@ -229,6 +281,33 @@ public class NewEpisodesFragment extends Fragment { } }); + listView.setRemoveListener(new DragSortListView.RemoveListener() { + @Override + public void remove(int which) { + Log.d(TAG, "remove("+which+")"); + stopItemLoader(); + FeedItem item = (FeedItem) listView.getAdapter().getItem(which); + DBWriter.markItemRead(getActivity(), item.getId(), true); + undoBarController.showUndoBar(false, + getString(R.string.marked_as_read_label), new FeedItemUndoToken(item, + which) + ); + } + }); + + undoBarController = new UndoBarController(root.findViewById(R.id.undobar), new UndoBarController.UndoListener() { + @Override + public void onUndo(Parcelable token) { + // Perform the undo + FeedItemUndoToken undoToken = (FeedItemUndoToken) token; + if (token != null) { + long itemId = undoToken.getFeedItemId(); + int position = undoToken.getPosition(); + DBWriter.markItemRead(getActivity(), itemId, false); + } + } + }); + final int secondColor = (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) ? R.color.swipe_refresh_secondary_color_dark : R.color.swipe_refresh_secondary_color_light; if (!itemsLoaded) { @@ -254,6 +333,7 @@ public class NewEpisodesFragment extends Fragment { downloadObserver.onResume(); } listAdapter.notifyDataSetChanged(); + restoreScrollPosition(); getActivity().supportInvalidateOptionsMenu(); updateShowOnlyEpisodesListViewState(); } @@ -332,7 +412,7 @@ public class NewEpisodesFragment extends Fragment { private void updateShowOnlyEpisodes() { SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); - showOnlyNewEpisodes = prefs.getBoolean(PREF_EPISODE_FILTER_BOOL, false); + showOnlyNewEpisodes = prefs.getBoolean(PREF_EPISODE_FILTER_BOOL, true); } private void setShowOnlyNewEpisodes(boolean newVal) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index f6d2d5d07..ab38af106 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -34,6 +34,8 @@ import de.danoeh.antennapod.menuhandler.NavDrawerActivity; public class PlaybackHistoryFragment extends ListFragment { private static final String TAG = "PlaybackHistoryFragment"; + private static final int EVENTS = EventDistributor.PLAYBACK_HISTORY_UPDATE | + EventDistributor.PLAYER_STATUS_UPDATE; private List<FeedItem> playbackHistory; private QueueAccess queue; @@ -167,7 +169,7 @@ public class PlaybackHistoryFragment extends ListFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { - if ((arg & EventDistributor.PLAYBACK_HISTORY_UPDATE) != 0) { + if ((arg & EVENTS) != 0) { startItemLoader(); getActivity().supportInvalidateOptionsMenu(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index ca8543b4c..70a231cad 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -2,10 +2,12 @@ package de.danoeh.antennapod.fragment; import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v7.widget.SearchView; import android.util.Log; @@ -30,6 +32,7 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; import de.danoeh.antennapod.adapter.QueueListAdapter; import de.danoeh.antennapod.core.asynctask.DownloadObserver; +import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; @@ -41,6 +44,8 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.QueueSorter; +import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken; +import de.danoeh.antennapod.core.util.gui.UndoBarController; import de.danoeh.antennapod.menuhandler.MenuItemUtils; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; @@ -51,13 +56,16 @@ public class QueueFragment extends Fragment { private static final String TAG = "QueueFragment"; private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | - EventDistributor.QUEUE_UPDATE; + EventDistributor.QUEUE_UPDATE | + EventDistributor.PLAYER_STATUS_UPDATE; private DragSortListView listView; private QueueListAdapter listAdapter; private TextView txtvEmpty; private ProgressBar progLoading; + private UndoBarController undoBarController; + private List<FeedItem> queue; private List<Downloader> downloaderList; @@ -65,6 +73,10 @@ public class QueueFragment extends Fragment { private boolean viewsCreated = false; private boolean isUpdatingFeeds = false; + private static final String PREFS = "QueueFragment"; + private static final String PREF_KEY_LIST_TOP = "list_top"; + private static final String PREF_KEY_LIST_SELECTION = "list_selection"; + private AtomicReference<Activity> activity = new AtomicReference<Activity>(); private DownloadObserver downloadObserver = null; @@ -103,6 +115,12 @@ public class QueueFragment extends Fragment { } @Override + public void onPause() { + super.onPause(); + saveScrollPosition(); + } + + @Override public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); @@ -115,10 +133,35 @@ public class QueueFragment extends Fragment { this.activity.set((MainActivity) activity); } + private void saveScrollPosition() { + SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + View v = listView.getChildAt(0); + int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop()); + editor.putInt(PREF_KEY_LIST_SELECTION, listView.getFirstVisiblePosition()); + editor.putInt(PREF_KEY_LIST_TOP, top); + editor.commit(); + } + + private void restoreScrollPosition() { + SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE); + int listSelection = prefs.getInt(PREF_KEY_LIST_SELECTION, 0); + int top = prefs.getInt(PREF_KEY_LIST_TOP, 0); + if(listSelection > 0 || top > 0) { + listView.setSelectionFromTop(listSelection, top); + // restore once, then forget + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(PREF_KEY_LIST_SELECTION, 0); + editor.putInt(PREF_KEY_LIST_TOP, 0); + editor.commit(); + } + } + private void resetViewState() { unregisterForContextMenu(listView); listAdapter = null; activity.set(null); + undoBarController = null; viewsCreated = false; blockDownloadObserverUpdate = false; if (downloadObserver != null) { @@ -175,6 +218,21 @@ public class QueueFragment extends Fragment { DBTasks.refreshAllFeeds(getActivity(), feeds); } return true; + case R.id.clear_queue: + // make sure the user really wants to clear the queue + ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), + R.string.clear_queue_label, + R.string.clear_queue_confirmation_msg) { + + @Override + public void onConfirmButtonPressed( + DialogInterface dialog) { + dialog.dismiss(); + DBWriter.clearQueue(getActivity()); + } + }; + conDialog.createNewDialog().show(); + return true; case R.id.queue_sort_alpha_asc: QueueSorter.sort(getActivity(), QueueSorter.Rule.ALPHA_ASC, true); return true; @@ -285,9 +343,31 @@ public class QueueFragment extends Fragment { @Override public void remove(int which) { + Log.d(TAG, "remove("+which+")"); + stopItemLoader(); + FeedItem item = (FeedItem) listView.getAdapter().getItem(which); + DBWriter.removeQueueItem(getActivity(), item.getId(), true); + undoBarController.showUndoBar(false, + getString(R.string.removed_from_queue), new FeedItemUndoToken(item, + which) + ); } }); + undoBarController = new UndoBarController(root.findViewById(R.id.undobar), new UndoBarController.UndoListener() { + @Override + public void onUndo(Parcelable token) { + // Perform the undo + FeedItemUndoToken undoToken = (FeedItemUndoToken) token; + if (token != null) { + long itemId = undoToken.getFeedItemId(); + int position = undoToken.getPosition(); + DBWriter.addQueueItemAt(getActivity(), itemId, position, false); + } + } + }); + + registerForContextMenu(listView); if (!itemsLoaded) { @@ -313,6 +393,8 @@ public class QueueFragment extends Fragment { } listAdapter.notifyDataSetChanged(); + restoreScrollPosition(); + // we need to refresh the options menu because it sometimes // needs data that may have just been loaded. getActivity().supportInvalidateOptionsMenu(); @@ -347,6 +429,33 @@ public class QueueFragment extends Fragment { } @Override + public long getItemDownloadedBytes(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + Log.d(TAG, "downloaded bytes: " + downloader.getDownloadRequest().getSoFar()); + return downloader.getDownloadRequest().getSoFar(); + } + } + } + return 0; + } + + @Override + public long getItemDownloadSize(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + Log.d(TAG, "downloaded size: " + downloader.getDownloadRequest().getSize()); + return downloader.getDownloadRequest().getSize(); + } + } + } + return 0; + } + @Override public int getItemDownloadProgressPercent(FeedItem item) { if (downloaderList != null) { for (Downloader downloader : downloaderList) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java index c8cdbcfed..e2450f03d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java @@ -24,11 +24,11 @@ public class TagFragment extends PodcastListFragment { private GpodnetTag tag; - public static TagFragment newInstance(String tagName) { - Validate.notNull(tagName); + public static TagFragment newInstance(GpodnetTag tag) { + Validate.notNull(tag); TagFragment fragment = new TagFragment(); Bundle args = new Bundle(); - args.putString("tag", tagName); + args.putParcelable("tag", tag); fragment.setArguments(args); return fragment; } @@ -38,14 +38,14 @@ public class TagFragment extends PodcastListFragment { super.onCreate(savedInstanceState); Bundle args = getArguments(); - Validate.isTrue(args != null && args.getString("tag") != null, "args invalid"); - tag = new GpodnetTag(args.getString("tag")); + Validate.isTrue(args != null && args.getParcelable("tag") != null, "args invalid"); + tag = args.getParcelable("tag"); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getName()); + ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getTitle()); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java index 24e0e4caa..cc87407b4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java @@ -10,14 +10,13 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.TextView; -import java.util.ArrayList; import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.gpodnet.TagListAdapter; import de.danoeh.antennapod.core.gpoddernet.GpodnetService; import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag; @@ -67,9 +66,9 @@ public class TagListFragment extends ListFragment { getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - String selectedTag = (String) getListAdapter().getItem(position); + GpodnetTag tag = (GpodnetTag) getListAdapter().getItem(position); MainActivity activity = (MainActivity) getActivity(); - activity.loadChildFragment(TagFragment.newInstance(selectedTag)); + activity.loadChildFragment(TagFragment.newInstance(tag)); } }); @@ -77,6 +76,12 @@ public class TagListFragment extends ListFragment { } @Override + public void onResume() { + super.onResume(); + ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(R.string.add_feed_label); + } + + @Override public void onDestroyView() { super.onDestroyView(); cancelLoadTask(); @@ -121,11 +126,7 @@ public class TagListFragment extends ListFragment { final Context context = getActivity(); if (context != null) { if (gpodnetTags != null) { - List<String> tagNames = new ArrayList<String>(); - for (GpodnetTag tag : gpodnetTags) { - tagNames.add(tag.getName()); - } - setListAdapter(new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, tagNames)); + setListAdapter(new TagListAdapter(context, android.R.layout.simple_list_item_1, gpodnetTags)); } else if (exception != null) { TextView txtvError = new TextView(getActivity()); txtvError.setText(exception.getMessage()); diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java index b62fd22b2..efb4adb01 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.menuhandler; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.util.Log; @@ -10,6 +11,7 @@ import android.view.MenuItem; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.BuildConfig; +import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; @@ -51,8 +53,8 @@ public class FeedMenuHandler { * * @throws DownloadRequestException */ - public static boolean onOptionsItemClicked(Context context, MenuItem item, - Feed selectedFeed) throws DownloadRequestException { + public static boolean onOptionsItemClicked(final Context context, final MenuItem item, + final Feed selectedFeed) throws DownloadRequestException { switch (item.getItemId()) { case R.id.refresh_item: DBTasks.refreshFeed(context, selectedFeed); @@ -61,7 +63,18 @@ public class FeedMenuHandler { DBTasks.refreshCompleteFeed(context, selectedFeed); break; case R.id.mark_all_read_item: - DBWriter.markFeedRead(context, selectedFeed.getId()); + ConfirmationDialog conDialog = new ConfirmationDialog(context, + R.string.mark_all_read_label, + R.string.mark_all_read_feed_confirmation_msg) { + + @Override + public void onConfirmButtonPressed( + DialogInterface dialog) { + dialog.dismiss(); + DBWriter.markFeedRead(context, selectedFeed.getId()); + } + }; + conDialog.createNewDialog().show(); break; case R.id.visit_website_item: Uri uri = Uri.parse(selectedFeed.getLink()); diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java index 05d6ded4d..fc942ce20 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java @@ -14,7 +14,7 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte public static MenuItem addSearchItem(Menu menu, SearchView searchView) { MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label); - MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); + MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS); MenuItemCompat.setActionView(item, searchView); return item; } diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java new file mode 100644 index 000000000..898a56004 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java @@ -0,0 +1,33 @@ +package de.danoeh.antennapod.preferences; + +import android.app.AlertDialog; +import android.content.Context; +import android.os.Build; +import android.preference.EditTextPreference; +import android.util.AttributeSet; + +import de.danoeh.antennapod.R; + +public class CustomEditTextPreference extends EditTextPreference { + + public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public CustomEditTextPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomEditTextPreference(Context context) { + super(context); + } + + @Override + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + builder.setInverseBackgroundForced(true); + getEditText().setTextColor(getContext().getResources().getColor(R.color.black)); + } + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java index ffac05321..227ea8dfb 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -9,10 +9,14 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Build; import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceScreen; +import android.text.Editable; +import android.text.TextWatcher; import android.util.Log; +import android.widget.EditText; import android.widget.Toast; import java.io.File; @@ -59,8 +63,6 @@ public class PreferenceController { public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname"; public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; - private static final String PREF_PERSISTENT_NOTIFICATION = "prefPersistNotify"; - private final PreferenceUI ui; @@ -216,6 +218,52 @@ public class PreferenceController { } } ); + ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS) + .setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + if (o instanceof String) { + try { + int value = Integer.valueOf((String) o); + if (1 <= value && value <= 50) { + setParallelDownloadsText(value); + return true; + } + } catch(NumberFormatException e) { + return false; + } + } + return false; + } + } + ); + // validate and set correct value: number of downloads between 1 and 50 (inclusive) + final EditText ev = ((EditTextPreference)ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText(); + ev.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + if(s.length() > 0) { + try { + int value = Integer.valueOf(s.toString()); + if (value <= 0) { + ev.setText("1"); + } else if (value > 50) { + ev.setText("50"); + } + } catch(NumberFormatException e) { + ev.setText("6"); + } + ev.setSelection(ev.getText().length()); + } + } + }); ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE) .setOnPreferenceChangeListener( new Preference.OnPreferenceChangeListener() { @@ -302,6 +350,7 @@ public class PreferenceController { public void onResume() { checkItemVisibility(); + setParallelDownloadsText(UserPreferences.getParallelDownloads()); setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize()); setDataFolderText(); updateGpodnetPreferenceScreen(); @@ -381,6 +430,15 @@ public class PreferenceController { .setEnabled(UserPreferences.isEnableAutodownload()); } + + private void setParallelDownloadsText(int downloads) { + final Resources res = ui.getActivity().getResources(); + + String s = Integer.toString(downloads) + + res.getString(R.string.parallel_downloads_suffix); + ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s); + } + private void setEpisodeCacheSizeText(int cacheSize) { final Resources res = ui.getActivity().getResources(); diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java index 0e7784381..f050e031d 100644 --- a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java +++ b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java @@ -13,16 +13,19 @@ import de.danoeh.antennapod.core.storage.DownloadRequester; // modified from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html // and ConnectivityActionReceiver.java +// Updated based on http://stackoverflow.com/questions/20833241/android-charge-intent-has-no-extra-data +// Since the intent doesn't have the EXTRA_STATUS like the android.com article says it does +// (though it used to) public class PowerConnectionReceiver extends BroadcastReceiver { private static final String TAG = "PowerConnectionReceiver"; @Override public void onReceive(Context context, Intent intent) { - int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || - status == BatteryManager.BATTERY_STATUS_FULL; + final String action = intent.getAction(); - if (isCharging) { + Log.d(TAG, "charging intent: " + action); + + if (Intent.ACTION_POWER_CONNECTED.equals(action)) { Log.d(TAG, "charging, starting auto-download"); // we're plugged in, this is a great time to auto-download if everything else is // right. So, even if the user allows auto-dl on battery, let's still start diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java index 359a546f6..d15108bfe 100644 --- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java +++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java @@ -5,15 +5,17 @@ import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.Toast; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Date; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; -import java.util.Date; /** * Receives intents from AntennaPod Single Purpose apps @@ -34,7 +36,7 @@ public class SPAReceiver extends BroadcastReceiver{ if (feedUrls != null) { if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls)); for (String url : feedUrls) { - Feed f = new Feed(url, new Date()); + Feed f = new Feed(url, new Date(0)); try { DownloadRequester.getInstance().downloadFeed(context, f); } catch (DownloadRequestException e) { |