diff options
Diffstat (limited to 'src/de/danoeh/antennapod/fragment')
17 files changed, 2592 insertions, 363 deletions
diff --git a/src/de/danoeh/antennapod/fragment/AddFeedFragment.java b/src/de/danoeh/antennapod/fragment/AddFeedFragment.java new file mode 100644 index 000000000..f5ae5a777 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -0,0 +1,76 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +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; +import de.danoeh.antennapod.activity.OnlineFeedViewActivity; +import de.danoeh.antennapod.activity.OpmlImportFromPathActivity; +import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment; + +/** + * Provides actions for adding new podcast subscriptions + */ +public class AddFeedFragment extends Fragment { + private static final String TAG = "AddFeedFragment"; + + /** + * Preset value for url text field. + */ + public static final String ARG_FEED_URL = "feedurl"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View root = inflater.inflate(R.layout.addfeed, container, false); + + final EditText etxtFeedurl = (EditText) root.findViewById(R.id.etxtFeedurl); + + Bundle args = getArguments(); + if (args != null && args.getString(ARG_FEED_URL) != null) { + etxtFeedurl.setText(args.getString(ARG_FEED_URL)); + } + + Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet); + Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport); + Button butConfirm = (Button) root.findViewById(R.id.butConfirm); + + final MainActivity activity = (MainActivity) getActivity(); + activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label); + + butBrowserGpoddernet.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + activity.loadChildFragment(new GpodnetMainFragment()); + } + }); + + butOpmlImport.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + startActivity(new Intent(getActivity(), + OpmlImportFromPathActivity.class)); + } + }); + + butConfirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(getActivity(), DefaultOnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString()); + intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label)); + startActivity(intent); + } + }); + + return root; + } +} diff --git a/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java new file mode 100644 index 000000000..ed304ad37 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -0,0 +1,195 @@ +package de.danoeh.antennapod.fragment; + +import android.app.Activity; +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.ListView; +import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter; +import de.danoeh.antennapod.dialog.FeedItemDialog; +import de.danoeh.antennapod.feed.EventDistributor; +import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBWriter; +import de.danoeh.antennapod.util.QueueAccess; + +import java.util.List; + +/** + * Displays all running downloads and provides a button to delete them + */ +public class CompletedDownloadsFragment extends ListFragment { + private static final int EVENTS = + EventDistributor.DOWNLOAD_HANDLED | + EventDistributor.DOWNLOADLOG_UPDATE | + EventDistributor.QUEUE_UPDATE | + EventDistributor.UNREAD_ITEMS_UPDATE; + + private List<FeedItem> items; + private QueueAccess queue; + private DownloadedEpisodesListAdapter listAdapter; + + private boolean viewCreated = false; + private boolean itemsLoaded = false; + + private FeedItemDialog feedItemDialog; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + startItemLoader(); + } + + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + } + + @Override + public void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(contentUpdate); + stopItemLoader(); + } + + @Override + public void onDetach() { + super.onDetach(); + stopItemLoader(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + listAdapter = null; + viewCreated = false; + feedItemDialog = null; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (viewCreated && itemsLoaded) { + onFragmentLoaded(); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + viewCreated = true; + if (itemsLoaded && getActivity() != null) { + onFragmentLoaded(); + } + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + FeedItem item = listAdapter.getItem(position - l.getHeaderViewsCount()); + if (item != null) { + feedItemDialog = FeedItemDialog.newInstance(getActivity(), item, queue); + feedItemDialog.show(); + } + + } + + private void onFragmentLoaded() { + if (listAdapter == null) { + listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess); + setListAdapter(listAdapter); + } + listAdapter.notifyDataSetChanged(); + if (feedItemDialog != null) { + boolean res = feedItemDialog.updateContent(queue, items); + if (!res && feedItemDialog.isShowing()) { + feedItemDialog.dismiss(); + } + } + } + + private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() { + @Override + public int getCount() { + return (items != null) ? items.size() : 0; + } + + @Override + public FeedItem getItem(int position) { + return (items != null) ? items.get(position) : null; + } + + @Override + public void onFeedItemSecondaryAction(FeedItem item) { + DBWriter.deleteFeedMediaOfItem(getActivity(), item.getMedia().getId()); + } + }; + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EventDistributor.DOWNLOAD_QUEUED) != 0) { + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateMenuAppearance(); + } + } else if ((arg & EVENTS) != 0) { + startItemLoader(); + } + } + }; + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Void, Void, Object[]> { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (!itemsLoaded && viewCreated) { + setListShown(false); + } + } + + @Override + protected void onPostExecute(Object[] results) { + super.onPostExecute(results); + setListShown(true); + if (results != null) { + items = (List<FeedItem>) results[0]; + queue = (QueueAccess) results[1]; + itemsLoaded = true; + if (viewCreated && getActivity() != null) { + onFragmentLoaded(); + } + } + } + + @Override + protected Object[] doInBackground(Void... params) { + Context context = getActivity(); + if (context != null) { + return new Object[]{DBReader.getDownloadedItems(context), + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } + return null; + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java new file mode 100644 index 000000000..d81ba4b86 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java @@ -0,0 +1,121 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import de.danoeh.antennapod.adapter.DownloadLogAdapter; +import de.danoeh.antennapod.feed.EventDistributor; +import de.danoeh.antennapod.service.download.DownloadStatus; +import de.danoeh.antennapod.storage.DBReader; + +import java.util.List; + +/** + * Shows the download log + */ +public class DownloadLogFragment extends ListFragment { + + private List<DownloadStatus> downloadLog; + private DownloadLogAdapter adapter; + + private boolean viewsCreated = false; + private boolean itemsLoaded = false; + + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + startItemLoader(); + } + + @Override + public void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(contentUpdate); + stopItemLoader(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + viewsCreated = true; + if (itemsLoaded) { + onFragmentLoaded(); + } + } + + private void onFragmentLoaded() { + if (adapter == null) { + adapter = new DownloadLogAdapter(getActivity(), itemAccess); + setListAdapter(adapter); + } + setListShown(true); + adapter.notifyDataSetChanged(); + + } + + private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() { + + @Override + public int getCount() { + return (downloadLog != null) ? downloadLog.size() : 0; + } + + @Override + public DownloadStatus getItem(int position) { + return (downloadLog != null) ? downloadLog.get(position) : null; + } + }; + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) { + startItemLoader(); + } + } + }; + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Void, Void, List<DownloadStatus>> { + + @Override + protected void onPostExecute(List<DownloadStatus> downloadStatuses) { + super.onPostExecute(downloadStatuses); + if (downloadStatuses != null) { + downloadLog = downloadStatuses; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + } + + @Override + protected List<DownloadStatus> doInBackground(Void... params) { + Context context = getActivity(); + if (context != null) { + return DBReader.getDownloadLog(context); + } + return null; + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/DownloadsFragment.java b/src/de/danoeh/antennapod/fragment/DownloadsFragment.java new file mode 100644 index 000000000..5a71cb36b --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/DownloadsFragment.java @@ -0,0 +1,145 @@ +package de.danoeh.antennapod.fragment; + +import android.app.Activity; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; + +/** + * Shows the CompletedDownloadsFragment and the RunningDownloadsFragment + */ +public class DownloadsFragment extends Fragment { + + public static final String ARG_SELECTED_TAB = "selected_tab"; + + public static final int POS_RUNNING = 0; + public static final int POS_COMPLETED = 1; + public static final int POS_LOG = 2; + + private ViewPager pager; + private MainActivity activity; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View root = inflater.inflate(R.layout.pager_fragment, container, false); + pager = (ViewPager) root.findViewById(R.id.pager); + DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources()); + pager.setAdapter(pagerAdapter); + final ActionBar actionBar = activity.getMainActivtyActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + ActionBar.TabListener tabListener = new ActionBar.TabListener() { + @Override + public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + pager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + + } + + @Override + public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + + } + }; + actionBar.removeAllTabs(); + actionBar.addTab(actionBar.newTab() + .setText(R.string.downloads_running_label) + .setTabListener(tabListener)); + actionBar.addTab(actionBar.newTab() + .setText(R.string.downloads_completed_label) + .setTabListener(tabListener)); + actionBar.addTab(actionBar.newTab() + .setText(R.string.downloads_log_label) + .setTabListener(tabListener)); + + pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + actionBar.setSelectedNavigationItem(position); + } + }); + return root; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() != null) { + int tab = getArguments().getInt(ARG_SELECTED_TAB); + pager.setCurrentItem(tab, false); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity = (MainActivity) activity; + } + + @Override + public void onDetach() { + super.onDetach(); + activity.getMainActivtyActionBar().removeAllTabs(); + activity.getMainActivtyActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + } + + public class DownloadsPagerAdapter extends FragmentPagerAdapter { + + + + + Resources resources; + + public DownloadsPagerAdapter(FragmentManager fm, Resources resources) { + super(fm); + this.resources = resources; + } + + @Override + public Fragment getItem(int position) { + switch (position) { + case POS_RUNNING: + return new RunningDownloadsFragment(); + case POS_COMPLETED: + return new CompletedDownloadsFragment(); + case POS_LOG: + return new DownloadLogFragment(); + default: + return null; + } + } + + @Override + public int getCount() { + return 3; + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case POS_RUNNING: + return resources.getString(R.string.downloads_running_label); + case POS_COMPLETED: + return resources.getString(R.string.downloads_completed_label); + case POS_LOG: + return resources.getString(R.string.downloads_log_label); + default: + return super.getPageTitle(position); + } + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 47cd3f244..db47cd8a4 100644 --- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -29,8 +29,6 @@ public class ExternalPlayerFragment extends Fragment { private ImageView imgvCover; private ViewGroup layoutInfo; private TextView txtvTitle; - private TextView txtvPosition; - private TextView txtvStatus; private ImageButton butPlay; private PlaybackController controller; @@ -48,9 +46,7 @@ public class ExternalPlayerFragment extends Fragment { imgvCover = (ImageView) root.findViewById(R.id.imgvCover); layoutInfo = (ViewGroup) root.findViewById(R.id.layoutInfo); txtvTitle = (TextView) root.findViewById(R.id.txtvTitle); - txtvPosition = (TextView) root.findViewById(R.id.txtvPosition); butPlay = (ImageButton) root.findViewById(R.id.butPlay); - txtvStatus = (TextView) root.findViewById(R.id.txtvStatus); layoutInfo.setOnClickListener(new OnClickListener() { @@ -84,12 +80,6 @@ public class ExternalPlayerFragment extends Fragment { @Override public void onPositionObserverUpdate() { - int duration = controller.getDuration(); - int position = controller.getPosition(); - if (duration != PlaybackController.INVALID_TIME - && position != PlaybackController.INVALID_TIME) { - txtvPosition.setText(getPositionString(position, duration)); - } } @Override @@ -127,12 +117,10 @@ public class ExternalPlayerFragment extends Fragment { @Override public void postStatusMsg(int msg) { - txtvStatus.setText(msg); } @Override public void clearStatusMsg() { - txtvStatus.setText(""); } @Override @@ -223,8 +211,6 @@ public class ExternalPlayerFragment extends Fragment { (int) getActivity().getResources().getDimension( R.dimen.external_player_height)); - txtvPosition.setText(getPositionString(media.getPosition(), - media.getDuration())); fragmentLayout.setVisibility(View.VISIBLE); if (controller.isPlayingVideo()) { butPlay.setVisibility(View.GONE); diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index 48c544457..bf6974982 100644 --- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -236,7 +236,7 @@ public class ItemDescriptionFragment extends Fragment { * value is inserted directly into the CSS String. */ private String applyWebviewStyle(String textColor, String data) { - final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.5em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>"; + final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> @font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>"; final int pageMargin = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 8, getResources() .getDisplayMetrics()); diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java index e5845dd76..5d0b1bec8 100644 --- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -2,326 +2,437 @@ package de.danoeh.antennapod.fragment; import android.annotation.SuppressLint; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; import android.support.v4.app.ListFragment; import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.SearchView; import android.util.Log; import android.view.*; -import android.view.ContextMenu.ContextMenuInfo; +import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.ItemviewActivity; -import de.danoeh.antennapod.adapter.ActionButtonCallback; -import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter; +import de.danoeh.antennapod.activity.FeedInfoActivity; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; +import de.danoeh.antennapod.adapter.FeedItemlistAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; +import de.danoeh.antennapod.asynctask.FeedRemover; +import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.dialog.ConfirmationDialog; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.dialog.FeedItemDialog; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.service.download.DownloadService; +import de.danoeh.antennapod.service.download.Downloader; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.QueueAccess; -import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler; +import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; import java.util.List; -/** Displays a list of FeedItems. */ +/** + * Displays a list of FeedItems. + */ @SuppressLint("ValidFragment") public class ItemlistFragment extends ListFragment { - private static final String TAG = "ItemlistFragment"; - - private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED - | EventDistributor.DOWNLOAD_QUEUED - | EventDistributor.QUEUE_UPDATE - | EventDistributor.UNREAD_ITEMS_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"; - protected InternalFeedItemlistAdapter fila; - - private Feed feed; - protected List<Long> queue; - - protected FeedItem selectedItem = null; - protected boolean contextMenuClosed = true; - - /** Argument for FeeditemlistAdapter */ - protected boolean showFeedtitle; - - private AsyncTask<Long, Void, Feed> currentLoadTask; - - public ItemlistFragment(boolean showFeedtitle) { - super(); - this.showFeedtitle = showFeedtitle; - } - - public ItemlistFragment() { - } - - /** - * Creates new ItemlistFragment which shows the Feeditems of a specific - * feed. Sets 'showFeedtitle' to false - * - * @param feedId - * The id of the feed to show - * @return the newly created instance of an ItemlistFragment - */ - public static ItemlistFragment newInstance(long feedId) { - ItemlistFragment i = new ItemlistFragment(); - i.showFeedtitle = false; - Bundle b = new Bundle(); - b.putLong(ARGUMENT_FEED_ID, feedId); - i.setArguments(b); - return i; - } - - private InternalFeedItemlistAdapter.ItemAccess itemAccessRef; - protected InternalFeedItemlistAdapter.ItemAccess itemAccess() { - if (itemAccessRef == null) { - itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() { + private static final String TAG = "ItemlistFragment"; - @Override - public FeedItem getItem(int position) { - return (feed != null) ? feed.getItemAtIndex(true, position) : null; - } + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED + | EventDistributor.DOWNLOAD_QUEUED + | EventDistributor.QUEUE_UPDATE + | EventDistributor.UNREAD_ITEMS_UPDATE; - @Override - public int getCount() { - return (feed != null) ? feed.getNumOfItems(true) : 0; - } + 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"; - @Override - public boolean isInQueue(FeedItem item) { - return (queue != null) && queue.contains(item.getId()); - } - }; - } - return itemAccessRef; + protected FeedItemlistAdapter adapter; + + private long feedID; + private Feed feed; + protected QueueAccess queue; + + private boolean itemsLoaded = false; + private boolean viewsCreated = false; + + private DownloadObserver downloadObserver; + private List<Downloader> downloaderList; + + private FeedItemDialog feedItemDialog; + private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance; + + + /** + * Creates new ItemlistFragment which shows the Feeditems of a specific + * feed. Sets 'showFeedtitle' to false + * + * @param feedId The id of the feed to show + * @return the newly created instance of an ItemlistFragment + */ + public static ItemlistFragment newInstance(long feedId) { + ItemlistFragment i = new ItemlistFragment(); + Bundle b = new Bundle(); + b.putLong(ARGUMENT_FEED_ID, feedId); + i.setArguments(b); + return i; } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.feeditemlist, container, false); - } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + setHasOptionsMenu(true); + + Bundle args = getArguments(); + if (args == null) throw new IllegalArgumentException("args invalid"); + feedID = args.getLong(ARGUMENT_FEED_ID); + } @Override public void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); - loadData(); + if (downloadObserver != null) { + downloadObserver.setActivity(getActivity()); + downloadObserver.onResume(); + } + if (viewsCreated && itemsLoaded) { + onFragmentLoaded(); + } } @Override public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); - if (currentLoadTask != null) { - currentLoadTask.cancel(true); - } + stopItemLoader(); } - protected synchronized void loadData() { - final long feedId; - if (feed == null) { - feedId = getArguments().getLong(ARGUMENT_FEED_ID); - } else { - feedId = feed.getId(); + @Override + public void onResume() { + super.onResume(); + updateProgressBarVisibility(); + startItemLoader(); + } + + @Override + public void onDetach() { + super.onDetach(); + stopItemLoader(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + resetViewState(); + } + + private void resetViewState() { + adapter = null; + viewsCreated = false; + if (downloadObserver != null) { + downloadObserver.onPause(); } - if (currentLoadTask != null) { - currentLoadTask.cancel(true); + if (feedItemDialog != null) { + feedItemDialogSavedInstance = feedItemDialog.save(); } - AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>(){ - private volatile List<Long> queueRef; + feedItemDialog = null; + } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + FeedMenuHandler.onCreateOptionsMenu(inflater, menu); + + final SearchView sv = new SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.search_hint)); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override - protected Feed doInBackground(Long... longs) { - Context context = ItemlistFragment.this.getActivity(); - if (context != null) { - Feed result = DBReader.getFeed(context, longs[0]); - if (result != null) { - result.setItems(DBReader.getFeedItemList(context, result)); - queueRef = DBReader.getQueueIDList(context); - return result; - } + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + if (itemsLoaded) { + ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId())); } - return null; + return true; } @Override - protected void onPostExecute(Feed result) { - super.onPostExecute(result); - if (result != null && result.getItems() != null) { - feed = result; - if (queueRef != null) { - queue = queueRef; - } else { - Log.e(TAG, "Could not load queue"); - } - setEmptyViewIfListIsEmpty(); - if (fila != null) { - fila.notifyDataSetChanged(); + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + FeedMenuHandler.onPrepareOptionsMenu(menu, feed); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (!super.onOptionsItemSelected(item)) { + try { + if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) { + switch (item.getItemId()) { + case R.id.remove_item: + final FeedRemover remover = new FeedRemover( + getActivity(), feed) { + @Override + protected void onPostExecute(Void result) { + super.onPostExecute(result); + ((MainActivity) getActivity()).loadNavFragment(MainActivity.POS_NEW, null); + } + }; + ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), + R.string.remove_feed_label, + R.string.feed_delete_confirmation_msg) { + + @Override + public void onConfirmButtonPressed( + DialogInterface dialog) { + dialog.dismiss(); + remover.executeAsync(); + } + }; + conDialog.createNewDialog().show(); + return true; + default: + return false; + } } else { - if (result == null) { - Log.e(TAG, "Could not load feed with id " + feedId); - } else if (result.getItems() == null) { - Log.e(TAG, "Could not load feed items"); - } + return true; } + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); + return true; } - }; - currentLoadTask = loadTask; - loadTask.execute(feedId); + } else { + return true; + } + } - private void setEmptyViewIfListIsEmpty() { - if (getListView() != null && feed != null && feed.getItems() != null) { - if (feed.getItems().isEmpty()) { - ((TextView) getActivity().findViewById(android.R.id.empty)).setText(R.string.no_items_label); - } + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(""); + + viewsCreated = true; + if (itemsLoaded) { + onFragmentLoaded(); } } - protected InternalFeedItemlistAdapter createListAdapter() { - return new InternalFeedItemlistAdapter(getActivity(), itemAccess(), - adapterCallback, showFeedtitle); - } - - @Override - public void onResume() { - super.onResume(); - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - fila.notifyDataSetChanged(); - } - }); - updateProgressBarVisibility(); - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - FeedItem selection = fila.getItem(position - l.getHeaderViewsCount()); - Intent showItem = new Intent(getActivity(), ItemviewActivity.class); - showItem.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED, selection - .getFeed().getId()); - showItem.putExtra(EXTRA_SELECTED_FEEDITEM, selection.getId()); - - startActivity(showItem); - } - - private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { - - @Override - public void update(EventDistributor eventDistributor, Integer arg) { - if ((EVENTS & arg) != 0) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received contentUpdate Intent."); - if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { - updateProgressBarVisibility(); - } else { - if (feed != null) { - loadData(); - } - updateProgressBarVisibility(); - } - } - } - }; - - private void updateProgressBarVisibility() { - if (feed != null) { - if (DownloadService.isRunning - && DownloadRequester.getInstance().isDownloadingFile(feed)) { + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount()); + feedItemDialog = FeedItemDialog.newInstance(getActivity(), selection, queue); + feedItemDialog.show(); + } + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((EVENTS & arg) != 0) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Received contentUpdate Intent."); + if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { + updateProgressBarVisibility(); + } else { + startItemLoader(); + updateProgressBarVisibility(); + } + } + } + }; + + private void updateProgressBarVisibility() { + if (feed != null) { + if (DownloadService.isRunning + && DownloadRequester.getInstance().isDownloadingFile(feed)) { ((ActionBarActivity) getActivity()) - .setSupportProgressBarIndeterminateVisibility(true); - } else { + .setSupportProgressBarIndeterminateVisibility(true); + } else { ((ActionBarActivity) getActivity()) - .setSupportProgressBarIndeterminateVisibility(false); - } + .setSupportProgressBarIndeterminateVisibility(false); + } getActivity().supportInvalidateOptionsMenu(); - } - } - - protected ActionButtonCallback adapterCallback = new ActionButtonCallback() { - - @Override - public void onActionButtonPressed(FeedItem item) { - selectedItem = item; - contextMenuClosed = true; - getListView().showContextMenu(); - } - }; - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - fila = createListAdapter(); - setListAdapter(fila); - this.getListView().setItemsCanFocus(true); - getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); - registerForContextMenu(getListView()); - getListView().setOnItemLongClickListener(null); - } - - @Override - public void onCreateContextMenu(final ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - if (!contextMenuClosed) { // true if context menu was cancelled before - selectedItem = null; - } - contextMenuClosed = false; - getListView().setOnItemLongClickListener(null); - if (selectedItem != null) { - new MenuInflater(ItemlistFragment.this.getActivity()).inflate( - R.menu.feeditem, menu); - - menu.setHeaderTitle(selectedItem.getTitle()); - FeedItemMenuHandler.onPrepareMenu( - new FeedItemMenuHandler.MenuInterface() { - - @Override - public void setItemVisibility(int id, boolean visible) { - menu.findItem(id).setVisible(visible); - } - }, selectedItem, false, QueueAccess.IDListAccess(queue)); - - } - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - boolean handled = false; - - if (selectedItem != null) { - - try { - handled = FeedItemMenuHandler.onMenuItemClicked( - getActivity(), item.getItemId(), selectedItem); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog( - getActivity(), e.getMessage()); - } - if (handled) { - fila.notifyDataSetChanged(); - } - - } - selectedItem = null; - contextMenuClosed = true; - return handled; - } - - public InternalFeedItemlistAdapter getListAdapter() { - return fila; - } + } + } + + private void onFragmentLoaded() { + if (adapter == null) { + getListView().setAdapter(null); + setupHeaderView(); + adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false); + setListAdapter(adapter); + downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback); + downloadObserver.onResume(); + } + setListShown(true); + adapter.notifyDataSetChanged(); + + if (feedItemDialog != null) { + feedItemDialog.updateContent(queue, feed.getItems()); + } else if (feedItemDialogSavedInstance != null) { + feedItemDialog = FeedItemDialog.newInstance(getActivity(), feedItemDialogSavedInstance); + } + getActivity().supportInvalidateOptionsMenu(); + } + + private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() { + @Override + public void onContentChanged() { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateMenuAppearance(); + } + } + + @Override + public void onDownloadDataAvailable(List<Downloader> downloaderList) { + ItemlistFragment.this.downloaderList = downloaderList; + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + }; + + private void setupHeaderView() { + if (getListView() == null || feed == null) { + Log.e(TAG, "Unable to setup listview: listView = null or feed = null"); + return; + } + LayoutInflater inflater = (LayoutInflater) + getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View header = inflater.inflate(R.layout.feeditemlist_header, null); + getListView().addHeaderView(header); + + TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); + TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor); + ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover); + ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo); + ImageButton butVisitWebsite = (ImageButton) header.findViewById(R.id.butVisitWebsite); + + txtvTitle.setText(feed.getTitle()); + txtvAuthor.setText(feed.getAuthor()); + ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), imgvCover, + (int) getResources().getDimension(R.dimen.thumbnail_length_onlinefeedview)); + if (feed.getLink() == null) { + butVisitWebsite.setVisibility(View.INVISIBLE); + } else { + butVisitWebsite.setVisibility(View.VISIBLE); + butVisitWebsite.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Uri uri = Uri.parse(feed.getLink()); + startActivity(new Intent(Intent.ACTION_VIEW, uri)); + } + }); + } + butShowInfo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (viewsCreated && itemsLoaded) { + Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); + startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, + feed.getId()); + startActivity(startIntent); + } + } + }); + } + private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() { + + @Override + public FeedItem getItem(int position) { + return (feed != null) ? feed.getItemAtIndex(true, position) : null; + } + + @Override + public int getCount() { + return (feed != null) ? feed.getNumOfItems(true) : 0; + } + + @Override + public boolean isInQueue(FeedItem item) { + return (queue != null) && queue.contains(item.getId()); + } + + @Override + public int getItemDownloadProgressPercent(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + return downloader.getDownloadRequest().getProgressPercent(); + } + } + } + return 0; + } + }; + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(feedID); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Long, Void, Object[]> { + @Override + protected Object[] doInBackground(Long... params) { + long feedID = params[0]; + Context context = getActivity(); + if (context != null) { + return new Object[]{DBReader.getFeed(context, feedID), + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } else { + return null; + } + } + + @Override + protected void onPostExecute(Object[] res) { + super.onPostExecute(res); + if (res != null) { + feed = (Feed) res[0]; + queue = (QueueAccess) res[1]; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + } + } } diff --git a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java new file mode 100644 index 000000000..0c42bdd65 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -0,0 +1,442 @@ +package de.danoeh.antennapod.fragment; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.SearchView; +import android.view.*; +import android.widget.AdapterView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import com.mobeta.android.dslv.DragSortListView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; +import de.danoeh.antennapod.adapter.NewEpisodesListAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; +import de.danoeh.antennapod.dialog.FeedItemDialog; +import de.danoeh.antennapod.feed.EventDistributor; +import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.service.download.DownloadService; +import de.danoeh.antennapod.service.download.Downloader; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBTasks; +import de.danoeh.antennapod.storage.DBWriter; +import de.danoeh.antennapod.storage.DownloadRequester; +import de.danoeh.antennapod.util.QueueAccess; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Shows unread or recently published episodes + */ +public class NewEpisodesFragment extends Fragment { + private static final String TAG = "NewEpisodesFragment"; + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | + EventDistributor.DOWNLOAD_QUEUED | + EventDistributor.QUEUE_UPDATE | + EventDistributor.UNREAD_ITEMS_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 DragSortListView listView; + private SwipeRefreshLayout swipeRefreshLayout; + private NewEpisodesListAdapter listAdapter; + private TextView txtvEmpty; + private ProgressBar progLoading; + + private List<FeedItem> unreadItems; + private List<FeedItem> recentItems; + private QueueAccess queueAccess; + private List<Downloader> downloaderList; + + private boolean itemsLoaded = false; + private boolean viewsCreated = false; + private boolean showOnlyNewEpisodes = false; + + private AtomicReference<MainActivity> activity = new AtomicReference<MainActivity>(); + + private DownloadObserver downloadObserver = null; + + private FeedItemDialog feedItemDialog; + private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + setHasOptionsMenu(true); + + updateShowOnlyEpisodes(); + } + + @Override + public void onResume() { + super.onResume(); + startItemLoader(); + } + + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + this.activity.set((MainActivity) getActivity()); + if (downloadObserver != null) { + downloadObserver.setActivity(getActivity()); + downloadObserver.onResume(); + } + if (viewsCreated && itemsLoaded) { + onFragmentLoaded(); + } + } + + @Override + public void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(contentUpdate); + stopItemLoader(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity.set((MainActivity) getActivity()); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + resetViewState(); + } + + private void resetViewState() { + listAdapter = null; + activity.set(null); + viewsCreated = false; + if (downloadObserver != null) { + downloadObserver.onPause(); + } + if (feedItemDialog != null) { + feedItemDialogSavedInstance = feedItemDialog.save(); + } + feedItemDialog = null; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.new_episodes, menu); + + final SearchView sv = new SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.search_hint)); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s)); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + menu.findItem(R.id.mark_all_read_item).setVisible(unreadItems != null && !unreadItems.isEmpty()); + menu.findItem(R.id.episode_filter_item).setChecked(showOnlyNewEpisodes); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (!super.onOptionsItemSelected(item)) { + switch (item.getItemId()) { + case R.id.refresh_item: + List<Feed> feeds = ((MainActivity) getActivity()).getFeeds(); + if (feeds != null) { + DBTasks.refreshAllFeeds(getActivity(), feeds); + } + 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(); + return true; + case R.id.episode_filter_item: + boolean newVal = !item.isChecked(); + setShowOnlyNewEpisodes(newVal); + item.setChecked(newVal); + return true; + default: + return false; + } + } else { + return true; + } + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.all_episodes_label); + + View root = inflater.inflate(R.layout.new_episodes_fragment, container, false); + + swipeRefreshLayout = (SwipeRefreshLayout) root.findViewById(R.id.swipeRefreshLayout); + listView = (DragSortListView) root.findViewById(android.R.id.list); + txtvEmpty = (TextView) root.findViewById(android.R.id.empty); + progLoading = (ProgressBar) root.findViewById(R.id.progLoading); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + FeedItem item = (FeedItem) listAdapter.getItem(position - listView.getHeaderViewsCount()); + if (item != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), item, queueAccess); + feedItemDialog.show(); + } + + } + }); + + final int secondColor = (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) ? R.color.swipe_refresh_secondary_color_dark : R.color.swipe_refresh_secondary_color_light; + swipeRefreshLayout.setColorScheme(R.color.bright_blue, secondColor, R.color.bright_blue, secondColor); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + List<Feed> feeds = ((MainActivity) getActivity()).getFeeds(); + if (feeds != null) { + DBTasks.refreshAllFeeds(getActivity(), feeds); + } + } + }); + + if (!itemsLoaded) { + progLoading.setVisibility(View.VISIBLE); + txtvEmpty.setVisibility(View.GONE); + } + + viewsCreated = true; + + if (itemsLoaded && activity.get() != null) { + onFragmentLoaded(); + } + + return root; + } + + private void onFragmentLoaded() { + if (listAdapter == null) { + listAdapter = new NewEpisodesListAdapter(activity.get(), itemAccess, new DefaultActionButtonCallback(activity.get())); + listView.setAdapter(listAdapter); + listView.setEmptyView(txtvEmpty); + downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback); + downloadObserver.onResume(); + } + if (feedItemDialog != null) { + feedItemDialog.updateContent(queueAccess, unreadItems, recentItems); + } else if (feedItemDialogSavedInstance != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), feedItemDialogSavedInstance); + } + listAdapter.notifyDataSetChanged(); + getActivity().supportInvalidateOptionsMenu(); + updateProgressBarVisibility(); + updateShowOnlyEpisodesListViewState(); + } + + private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() { + @Override + public void onContentChanged() { + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateMenuAppearance(); + } + } + + @Override + public void onDownloadDataAvailable(List<Downloader> downloaderList) { + NewEpisodesFragment.this.downloaderList = downloaderList; + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + }; + + private NewEpisodesListAdapter.ItemAccess itemAccess = new NewEpisodesListAdapter.ItemAccess() { + + @Override + public int getCount() { + if (itemsLoaded) { + return (showOnlyNewEpisodes) ? unreadItems.size() : recentItems.size(); + } + return 0; + } + + @Override + public FeedItem getItem(int position) { + if (itemsLoaded) { + return (showOnlyNewEpisodes) ? unreadItems.get(position) : recentItems.get(position); + } + return null; + } + + @Override + public int getItemDownloadProgressPercent(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + return downloader.getDownloadRequest().getProgressPercent(); + } + } + } + return 0; + } + + @Override + public boolean isInQueue(FeedItem item) { + if (itemsLoaded) { + return queueAccess.contains(item.getId()); + } else { + return false; + } + } + + + }; + + private void updateProgressBarVisibility() { + if (!viewsCreated) { + return; + } + + if (DownloadService.isRunning + && DownloadRequester.getInstance().isDownloadingFeeds()) { + swipeRefreshLayout.setRefreshing(true); + + } else { + swipeRefreshLayout.setRefreshing(false); + + // if case other fragments have set this to true, this fragment should remove the progress indicator + ((ActionBarActivity) getActivity()) + .setSupportProgressBarIndeterminateVisibility(false); + } + } + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EVENTS) != 0) { + startItemLoader(); + updateProgressBarVisibility(); + } + } + }; + + private void updateShowOnlyEpisodes() { + SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + showOnlyNewEpisodes = prefs.getBoolean(PREF_EPISODE_FILTER_BOOL, false); + } + + private void setShowOnlyNewEpisodes(boolean newVal) { + showOnlyNewEpisodes = newVal; + SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(PREF_EPISODE_FILTER_BOOL, showOnlyNewEpisodes); + editor.commit(); + if (itemsLoaded && viewsCreated) { + listAdapter.notifyDataSetChanged(); + activity.get().supportInvalidateOptionsMenu(); + updateShowOnlyEpisodesListViewState(); + } + } + + private void updateShowOnlyEpisodesListViewState() { + if (showOnlyNewEpisodes) { + listView.setEmptyView(null); + txtvEmpty.setVisibility(View.GONE); + } else { + listView.setEmptyView(txtvEmpty); + } + } + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Void, Void, Object[]> { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (viewsCreated && !itemsLoaded) { + listView.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progLoading.setVisibility(View.VISIBLE); + } + } + + @Override + protected Object[] doInBackground(Void... params) { + Context context = activity.get(); + if (context != null) { + return new Object[]{DBReader.getUnreadItemsList(context), + DBReader.getRecentlyPublishedEpisodes(context, RECENT_EPISODES_LIMIT), + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } else { + return null; + } + } + + @Override + protected void onPostExecute(Object[] lists) { + super.onPostExecute(lists); + listView.setVisibility(View.VISIBLE); + progLoading.setVisibility(View.GONE); + + if (lists != null) { + unreadItems = (List<FeedItem>) lists[0]; + recentItems = (List<FeedItem>) lists[1]; + queueAccess = (QueueAccess) lists[2]; + itemsLoaded = true; + if (viewsCreated && activity.get() != null) { + onFragmentLoaded(); + } + } + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index d6524853f..bab5143d5 100644 --- a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -1,112 +1,282 @@ package de.danoeh.antennapod.fragment; +import android.app.Activity; import android.content.Context; +import android.content.res.TypedArray; import android.os.AsyncTask; import android.os.Bundle; -import android.util.Log; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter; +import android.os.Handler; +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 de.danoeh.antennapod.R; +import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; +import de.danoeh.antennapod.adapter.FeedItemlistAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; +import de.danoeh.antennapod.dialog.FeedItemDialog; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.service.download.Downloader; import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBWriter; +import de.danoeh.antennapod.util.QueueAccess; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; -public class PlaybackHistoryFragment extends ItemlistFragment { - private static final String TAG = "PlaybackHistoryFragment"; +public class PlaybackHistoryFragment extends ListFragment { + private static final String TAG = "PlaybackHistoryFragment"; private List<FeedItem> playbackHistory; + private QueueAccess queue; + private FeedItemlistAdapter adapter; - public PlaybackHistoryFragment() { - super(true); - } + private boolean itemsLoaded = false; + private boolean viewsCreated = false; + + private AtomicReference<Activity> activity = new AtomicReference<Activity>(); + + private DownloadObserver downloadObserver; + private List<Downloader> downloaderList; + + private FeedItemDialog feedItemDialog; + private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance; - InternalFeedItemlistAdapter.ItemAccess itemAccessRef; @Override - protected InternalFeedItemlistAdapter.ItemAccess itemAccess() { - if (itemAccessRef == null) { - itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() { + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + setHasOptionsMenu(true); + } - @Override - public FeedItem getItem(int position) { - return (playbackHistory != null) ? playbackHistory.get(position) : null; - } + @Override + public void onResume() { + super.onResume(); + startItemLoader(); + } - @Override - public int getCount() { - return (playbackHistory != null) ? playbackHistory.size() : 0; - } + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + } - @Override - public boolean isInQueue(FeedItem item) { - return (queue != null) ? queue.contains(item.getId()) : false; - } - }; + @Override + public void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(contentUpdate); + stopItemLoader(); + } + + @Override + public void onDetach() { + super.onDetach(); + stopItemLoader(); + activity.set(null); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity.set(activity); + if (downloadObserver != null) { + downloadObserver.setActivity(activity); + downloadObserver.onResume(); + } + if (viewsCreated && itemsLoaded) { + onFragmentLoaded(); } - return itemAccessRef; } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - EventDistributor.getInstance().register(historyUpdate); - } - - @Override - public void onDestroy() { - super.onDestroy(); - EventDistributor.getInstance().unregister(historyUpdate); - } - - private EventDistributor.EventListener historyUpdate = new EventDistributor.EventListener() { - - @Override - public void update(EventDistributor eventDistributor, Integer arg) { - if ((EventDistributor.PLAYBACK_HISTORY_UPDATE & arg) != 0) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received content update"); - loadData(); - } - - } - }; + public void onDestroyView() { + super.onDestroyView(); + adapter = null; + viewsCreated = false; + if (downloadObserver != null) { + downloadObserver.onPause(); + } + if (feedItemDialog != null) { + feedItemDialogSavedInstance = feedItemDialog.save(); + } + feedItemDialog = null; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + viewsCreated = true; + if (itemsLoaded) { + onFragmentLoaded(); + } + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + FeedItem item = adapter.getItem(position - l.getHeaderViewsCount()); + if (item != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), item, queue); + feedItemDialog.show(); + } + } @Override - protected void loadData() { - AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() { - private volatile List<FeedItem> phRef; - private volatile List<Long> queueRef; - - @Override - protected Void doInBackground(Void... voids) { - Context context = PlaybackHistoryFragment.this.getActivity(); - if (context != null) { - queueRef = DBReader.getQueueIDList(context); - phRef = DBReader.getPlaybackHistory(context); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + 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); + menu.findItem(R.id.clear_history_item).setVisible(playbackHistory != null && !playbackHistory.isEmpty()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (!super.onOptionsItemSelected(item)) { + switch(item.getItemId()) { + case R.id.clear_history_item: + DBWriter.clearPlaybackHistory(getActivity()); + return true; + default: + return false; + } + } else { + return true; + } + } + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EventDistributor.PLAYBACK_HISTORY_UPDATE) != 0) { + startItemLoader(); + getActivity().supportInvalidateOptionsMenu(); + } + } + }; + + private void onFragmentLoaded() { + if (adapter == null) { + adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true); + setListAdapter(adapter); + downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback); + downloadObserver.onResume(); + } + setListShown(true); + adapter.notifyDataSetChanged(); + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateContent(queue, playbackHistory); + } else if (feedItemDialogSavedInstance != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), feedItemDialogSavedInstance); + } + getActivity().supportInvalidateOptionsMenu(); + } + + private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() { + @Override + public void onContentChanged() { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateMenuAppearance(); + } + } + + @Override + public void onDownloadDataAvailable(List<Downloader> downloaderList) { + PlaybackHistoryFragment.this.downloaderList = downloaderList; + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + }; + + private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() { + @Override + public boolean isInQueue(FeedItem item) { + return (queue != null) ? queue.contains(item.getId()) : false; + } + + @Override + public int getItemDownloadProgressPercent(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + return downloader.getDownloadRequest().getProgressPercent(); + } } + } + return 0; + } + + @Override + public int getCount() { + return (playbackHistory != null) ? playbackHistory.size() : 0; + } + + @Override + public FeedItem getItem(int position) { + return (playbackHistory != null) ? playbackHistory.get(position) : null; + } + }; + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Void, Void, Object[]> { + + @Override + protected Object[] doInBackground(Void... params) { + Context context = activity.get(); + if (context != null) { + List<FeedItem> ph = DBReader.getPlaybackHistory(context); + DBReader.loadFeedDataOfFeedItemlist(context, ph); + return new Object[]{ph, + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } else { return null; } + } - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - if (queueRef != null && phRef != null) { - queue = queueRef; - playbackHistory = phRef; - Log.i(TAG, "Number of items in playback history: " + playbackHistory.size()); - if (fila != null) { - fila.notifyDataSetChanged(); - } - } else { - if (queueRef == null) { - Log.e(TAG, "Could not load queue"); - } - if (phRef == null) { - Log.e(TAG, "Could not load playback history"); - } + @Override + protected void onPostExecute(Object[] res) { + super.onPostExecute(res); + if (res != null) { + playbackHistory = (List<FeedItem>) res[0]; + queue = (QueueAccess) res[1]; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); } } - }; - loadTask.execute(); + } } } diff --git a/src/de/danoeh/antennapod/fragment/QueueFragment.java b/src/de/danoeh/antennapod/fragment/QueueFragment.java new file mode 100644 index 000000000..e3f0bb19d --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/QueueFragment.java @@ -0,0 +1,394 @@ +package de.danoeh.antennapod.fragment; + +import android.app.Activity; +import android.content.Context; +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.*; +import android.widget.AdapterView; +import android.widget.ProgressBar; +import android.widget.TextView; +import com.mobeta.android.dslv.DragSortListView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; +import de.danoeh.antennapod.adapter.QueueListAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; +import de.danoeh.antennapod.dialog.FeedItemDialog; +import de.danoeh.antennapod.feed.EventDistributor; +import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.service.download.Downloader; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBWriter; +import de.danoeh.antennapod.util.QueueAccess; +import de.danoeh.antennapod.util.UndoBarController; +import de.danoeh.antennapod.util.gui.FeedItemUndoToken; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Shows all items in the queue + */ +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; + + private DragSortListView listView; + private QueueListAdapter listAdapter; + private TextView txtvEmpty; + private ProgressBar progLoading; + private UndoBarController undoBarController; + + private List<FeedItem> queue; + private List<Downloader> downloaderList; + + private boolean itemsLoaded = false; + private boolean viewsCreated = false; + + private AtomicReference<Activity> activity = new AtomicReference<Activity>(); + + private DownloadObserver downloadObserver = null; + + private FeedItemDialog feedItemDialog; + private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance; + + /** + * Download observer updates won't result in an upate of the list adapter if this is true. + */ + private boolean blockDownloadObserverUpdate = false; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + setHasOptionsMenu(true); + } + + @Override + public void onResume() { + super.onResume(); + startItemLoader(); + } + + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + this.activity.set((MainActivity) getActivity()); + if (downloadObserver != null) { + downloadObserver.setActivity(getActivity()); + downloadObserver.onResume(); + } + if (viewsCreated && itemsLoaded) { + onFragmentLoaded(); + } + } + + @Override + public void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(contentUpdate); + stopItemLoader(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity.set((MainActivity) activity); + } + + private void resetViewState() { + unregisterForContextMenu(listView); + listAdapter = null; + undoBarController = null; + activity.set(null); + viewsCreated = false; + blockDownloadObserverUpdate = false; + if (downloadObserver != null) { + downloadObserver.onPause(); + } + if (feedItemDialog != null) { + feedItemDialogSavedInstance = feedItemDialog.save(); + } + feedItemDialog = null; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + resetViewState(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + final SearchView sv = new SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.search_hint)); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s)); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; + FeedItem item = itemAccess.getItem(adapterInfo.position); + + MenuInflater inflater = getActivity().getMenuInflater(); + inflater.inflate(R.menu.queue_context, menu); + + if (item != null) { + menu.setHeaderTitle(item.getTitle()); + } + + menu.findItem(R.id.move_to_top_item).setEnabled(!queue.isEmpty() && queue.get(0) != item); + menu.findItem(R.id.move_to_bottom_item).setEnabled(!queue.isEmpty() && queue.get(queue.size() - 1) != item); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); + FeedItem selectedItem = itemAccess.getItem(menuInfo.position); + + if (selectedItem == null) { + Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection"); + return super.onContextItemSelected(item); + } + + switch (item.getItemId()) { + case R.id.move_to_top_item: + DBWriter.moveQueueItemToTop(getActivity(), selectedItem.getId(), true); + return true; + case R.id.move_to_bottom_item: + DBWriter.moveQueueItemToBottom(getActivity(), selectedItem.getId(), true); + return true; + default: + return super.onContextItemSelected(item); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.queue_label); + + View root = inflater.inflate(R.layout.queue_fragment, container, false); + listView = (DragSortListView) root.findViewById(android.R.id.list); + txtvEmpty = (TextView) root.findViewById(android.R.id.empty); + progLoading = (ProgressBar) root.findViewById(R.id.progLoading); + listView.setEmptyView(txtvEmpty); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + FeedItem item = (FeedItem) listAdapter.getItem(position - listView.getHeaderViewsCount()); + if (item != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), item, QueueAccess.ItemListAccess(queue)); + feedItemDialog.show(); + } + } + }); + + 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); + } + } + }); + + listView.setDragSortListener(new DragSortListView.DragSortListener() { + @Override + public void drag(int from, int to) { + Log.d(TAG, "drag"); + blockDownloadObserverUpdate = true; + } + + @Override + public void drop(int from, int to) { + Log.d(TAG, "drop"); + blockDownloadObserverUpdate = false; + stopItemLoader(); + final FeedItem item = queue.remove(from); + queue.add(to, item); + listAdapter.notifyDataSetChanged(); + DBWriter.moveQueueItem(getActivity(), from, to, true); + } + + @Override + public void remove(int 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) + ); + } + }); + + registerForContextMenu(listView); + + if (!itemsLoaded) { + progLoading.setVisibility(View.VISIBLE); + txtvEmpty.setVisibility(View.GONE); + } + + viewsCreated = true; + + if (itemsLoaded && activity.get() != null) { + onFragmentLoaded(); + } + + return root; + } + + private void onFragmentLoaded() { + if (listAdapter == null) { + listAdapter = new QueueListAdapter(activity.get(), itemAccess, new DefaultActionButtonCallback(activity.get())); + listView.setAdapter(listAdapter); + downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback); + downloadObserver.onResume(); + } + listAdapter.notifyDataSetChanged(); + if (feedItemDialog != null) { + feedItemDialog.updateContent(QueueAccess.ItemListAccess(queue), queue); + } else if (feedItemDialogSavedInstance != null) { + feedItemDialog = FeedItemDialog.newInstance(activity.get(), feedItemDialogSavedInstance); + } + } + + private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() { + @Override + public void onContentChanged() { + if (listAdapter != null && !blockDownloadObserverUpdate) { + listAdapter.notifyDataSetChanged(); + } + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.updateMenuAppearance(); + } + } + + @Override + public void onDownloadDataAvailable(List<Downloader> downloaderList) { + QueueFragment.this.downloaderList = downloaderList; + if (listAdapter != null && !blockDownloadObserverUpdate) { + listAdapter.notifyDataSetChanged(); + } + } + }; + + private QueueListAdapter.ItemAccess itemAccess = new QueueListAdapter.ItemAccess() { + @Override + public int getCount() { + return (itemsLoaded) ? queue.size() : 0; + } + + @Override + public FeedItem getItem(int position) { + return (itemsLoaded) ? queue.get(position) : null; + } + + @Override + public int getItemDownloadProgressPercent(FeedItem item) { + if (downloaderList != null) { + for (Downloader downloader : downloaderList) { + if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { + return downloader.getDownloadRequest().getProgressPercent(); + } + } + } + return 0; + } + }; + + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EVENTS) != 0) { + startItemLoader(); + } + } + }; + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> { + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (viewsCreated && !itemsLoaded) { + listView.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progLoading.setVisibility(View.VISIBLE); + } + } + + @Override + protected void onPostExecute(List<FeedItem> feedItems) { + super.onPostExecute(feedItems); + listView.setVisibility(View.VISIBLE); + progLoading.setVisibility(View.GONE); + + if (feedItems != null) { + queue = feedItems; + itemsLoaded = true; + if (viewsCreated && activity.get() != null) { + onFragmentLoaded(); + } + } + } + + @Override + protected List<FeedItem> doInBackground(Void... params) { + Context context = activity.get(); + if (context != null) { + return DBReader.getQueue(context); + } + return null; + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java new file mode 100644 index 000000000..89c30e34b --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java @@ -0,0 +1,69 @@ +package de.danoeh.antennapod.fragment; + +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.ListFragment; +import android.view.View; +import de.danoeh.antennapod.adapter.DownloadlistAdapter; +import de.danoeh.antennapod.asynctask.DownloadObserver; +import de.danoeh.antennapod.service.download.Downloader; +import de.danoeh.antennapod.storage.DownloadRequester; + +import java.util.List; + +/** + * Displays all running downloads and provides actions to cancel them + */ +public class RunningDownloadsFragment extends ListFragment { + private static final String TAG = "RunningDownloadsFragment"; + + private DownloadObserver downloadObserver; + private List<Downloader> downloaderList; + + + @Override + public void onDetach() { + super.onDetach(); + if (downloadObserver != null) { + downloadObserver.onPause(); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + final DownloadlistAdapter downloadlistAdapter = new DownloadlistAdapter(getActivity(), itemAccess); + setListAdapter(downloadlistAdapter); + + downloadObserver = new DownloadObserver(getActivity(), new Handler(), new DownloadObserver.Callback() { + @Override + public void onContentChanged() { + downloadlistAdapter.notifyDataSetChanged(); + } + + @Override + public void onDownloadDataAvailable(List<Downloader> downloaderList) { + RunningDownloadsFragment.this.downloaderList = downloaderList; + downloadlistAdapter.notifyDataSetChanged(); + } + }); + downloadObserver.onResume(); + } + + private DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() { + @Override + public int getCount() { + return (downloaderList != null) ? downloaderList.size() : 0; + } + + @Override + public Downloader getItem(int position) { + return (downloaderList != null) ? downloaderList.get(position) : null; + } + + @Override + public void onSecondaryActionClick(Downloader downloader) { + DownloadRequester.getInstance().cancelDownload(getActivity(), downloader.getDownloadRequest().getSource()); + } + }; +} diff --git a/src/de/danoeh/antennapod/fragment/SearchFragment.java b/src/de/danoeh/antennapod/fragment/SearchFragment.java new file mode 100644 index 000000000..f89e44717 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/SearchFragment.java @@ -0,0 +1,254 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.SearchView; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.ListView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.SearchlistAdapter; +import de.danoeh.antennapod.dialog.FeedItemDialog; +import de.danoeh.antennapod.feed.*; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.FeedSearcher; +import de.danoeh.antennapod.util.QueueAccess; + +import java.util.List; + +/** + * Performs a search operation on all feeds or one specific feed and displays the search result. + */ +public class SearchFragment extends ListFragment { + private static final String TAG = "SearchFragment"; + + private static final String ARG_QUERY = "query"; + private static final String ARG_FEED = "feed"; + + private SearchlistAdapter searchAdapter; + private List<SearchResult> searchResults; + + private boolean viewCreated = false; + private boolean itemsLoaded = false; + + private QueueAccess queue; + + private FeedItemDialog feedItemDialog; + private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance; + + /** + * Create a new SearchFragment that searches all feeds. + */ + public static SearchFragment newInstance(String query) { + if (query == null) query = ""; + SearchFragment fragment = new SearchFragment(); + Bundle args = new Bundle(); + args.putString(ARG_QUERY, query); + args.putLong(ARG_FEED, 0); + fragment.setArguments(args); + return fragment; + } + + /** + * Create a new SearchFragment that searches one specific feed. + */ + public static SearchFragment newInstance(String query, long feed) { + SearchFragment fragment = newInstance(query); + fragment.getArguments().putLong(ARG_FEED, feed); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + setHasOptionsMenu(true); + startSearchTask(); + } + + @Override + public void onStart() { + super.onStart(); + EventDistributor.getInstance().register(contentUpdate); + } + + @Override + public void onStop() { + super.onStop(); + stopSearchTask(); + EventDistributor.getInstance().unregister(contentUpdate); + } + + @Override + public void onDetach() { + super.onDetach(); + stopSearchTask(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + searchAdapter = null; + viewCreated = false; + if (feedItemDialog != null) { + feedItemDialogSavedInstance = feedItemDialog.save(); + } + feedItemDialog = null; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label); + viewCreated = true; + if (itemsLoaded) { + onFragmentLoaded(); + } + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + SearchResult result = (SearchResult) l.getAdapter().getItem(position); + FeedComponent comp = result.getComponent(); + if (comp.getClass() == Feed.class) { + ((MainActivity)getActivity()).loadFeedFragment(comp.getId()); + } else { + if (comp.getClass() == FeedItem.class) { + feedItemDialog = FeedItemDialog.newInstance(getActivity(), (FeedItem) comp, queue); + feedItemDialog.show(); + } + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + 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); + final SearchView sv = new SearchView(getActivity()); + sv.setQueryHint(getString(R.string.search_hint)); + sv.setQuery(getArguments().getString(ARG_QUERY), false); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + getArguments().putString(ARG_QUERY, s); + itemsLoaded = false; + startSearchTask(); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + MenuItemCompat.setActionView(item, sv); + } + + private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & (EventDistributor.DOWNLOAD_QUEUED)) != 0) { + feedItemDialog.updateMenuAppearance(); + } + if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE + | EventDistributor.DOWNLOAD_HANDLED + | EventDistributor.QUEUE_UPDATE)) != 0) { + startSearchTask(); + } + } + }; + + private void onFragmentLoaded() { + if (searchAdapter == null) { + searchAdapter = new SearchlistAdapter(getActivity(), itemAccess); + setListAdapter(searchAdapter); + } + searchAdapter.notifyDataSetChanged(); + setListShown(true); + if (feedItemDialog != null && feedItemDialog.isShowing()) { + feedItemDialog.setQueue(queue); + for (SearchResult result : searchResults) { + FeedComponent comp = result.getComponent(); + if (comp.getClass() == FeedItem.class && ((FeedItem) comp).getId() == feedItemDialog.getItem().getId()) { + feedItemDialog.setItem((FeedItem) comp); + } + } + feedItemDialog.updateMenuAppearance(); + } else if (feedItemDialogSavedInstance != null) { + feedItemDialog = FeedItemDialog.newInstance(getActivity(), feedItemDialogSavedInstance); + } + } + + private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() { + @Override + public int getCount() { + return (searchResults != null) ? searchResults.size() : 0; + } + + @Override + public SearchResult getItem(int position) { + return (searchResults != null) ? searchResults.get(position) : null; + } + }; + + private SearchTask searchTask; + + private void startSearchTask() { + if (searchTask != null) { + searchTask.cancel(true); + } + searchTask = new SearchTask(); + searchTask.execute(getArguments()); + } + + private void stopSearchTask() { + if (searchTask != null) { + searchTask.cancel(true); + } + } + + private class SearchTask extends AsyncTask<Bundle, Void, Object[]> { + @Override + protected Object[] doInBackground(Bundle... params) { + String query = params[0].getString(ARG_QUERY); + long feed = params[0].getLong(ARG_FEED); + Context context = getActivity(); + if (context != null) { + return new Object[]{FeedSearcher.performSearch(context, query, feed), + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } else { + return null; + } + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (viewCreated && !itemsLoaded) { + setListShown(false); + } + } + + @Override + protected void onPostExecute(Object[] results) { + super.onPostExecute(results); + if (results != null) { + itemsLoaded = true; + searchResults = (List<SearchResult>) results[0]; + queue = (QueueAccess) results[1]; + if (viewCreated) { + onFragmentLoaded(); + } + } + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java new file mode 100644 index 000000000..ec8f69368 --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java @@ -0,0 +1,131 @@ +package de.danoeh.antennapod.fragment.gpodnet; + +import android.app.Activity; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; + +/** + * Main navigation hub for gpodder.net podcast directory + */ +public class GpodnetMainFragment extends Fragment { + + private ViewPager pager; + private MainActivity activity; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View root = inflater.inflate(R.layout.pager_fragment, container, false); + pager = (ViewPager) root.findViewById(R.id.pager); + GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources()); + pager.setAdapter(pagerAdapter); + final ActionBar actionBar = activity.getMainActivtyActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + ActionBar.TabListener tabListener = new ActionBar.TabListener() { + @Override + public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + pager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + + } + + @Override + public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { + + } + }; + actionBar.removeAllTabs(); + actionBar.addTab(actionBar.newTab() + .setText(R.string.gpodnet_taglist_header) + .setTabListener(tabListener)); + actionBar.addTab(actionBar.newTab() + .setText(R.string.gpodnet_toplist_header) + .setTabListener(tabListener)); + actionBar.setTitle(R.string.gpodnet_main_label); + + pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + actionBar.setSelectedNavigationItem(position); + } + }); + return root; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + activity.getMainActivtyActionBar().removeAllTabs(); + activity.getMainActivtyActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity = (MainActivity) activity; + } + + public class GpodnetPagerAdapter extends FragmentPagerAdapter { + + + private static final int NUM_PAGES = 2; + private static final int POS_TAGS = 0; + private static final int POS_TOPLIST = 1; + private static final int POS_SUGGESTIONS = 2; + + Resources resources; + + public GpodnetPagerAdapter(FragmentManager fm, Resources resources) { + super(fm); + this.resources = resources; + } + + @Override + public Fragment getItem(int i) { + switch (i) { + case POS_TAGS: + return new TagListFragment(); + case POS_TOPLIST: + return new PodcastTopListFragment(); + case POS_SUGGESTIONS: + return new SuggestionListFragment(); + default: + return null; + } + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case POS_TAGS: + return getString(R.string.gpodnet_taglist_header); + case POS_TOPLIST: + return getString(R.string.gpodnet_toplist_header); + case POS_SUGGESTIONS: + return getString(R.string.gpodnet_suggestions_header); + default: + return super.getPageTitle(position); + } + } + + @Override + public int getCount() { + return NUM_PAGES; + } + } +} diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java index 4164429b2..837df0594 100644 --- a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java +++ b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java @@ -5,19 +5,22 @@ import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v7.widget.*; import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; +import android.view.*; import android.widget.*; +import android.widget.SearchView; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.adapter.gpodnet.PodcastListAdapter; +import de.danoeh.antennapod.fragment.SearchFragment; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; import java.util.List; @@ -33,8 +36,34 @@ public abstract class PodcastListFragment extends Fragment { private Button butRetry; @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + final android.support.v7.widget.SearchView sv = new android.support.v7.widget.SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.gpodnet_search_hint)); + sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + ((MainActivity) getActivity()).loadChildFragment(SearchListFragment.newInstance(s)); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setRetainInstance(true); View root = inflater.inflate(R.layout.gpodnet_podcast_list, container, false); gridView = (GridView) root.findViewById(R.id.gridView); diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java index 322d13097..79d0c5d6f 100644 --- a/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java +++ b/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java @@ -1,14 +1,21 @@ package de.danoeh.antennapod.fragment.gpodnet; import android.os.Bundle; +import android.support.v7.widget.SearchView; +import android.view.Menu; +import android.view.MenuInflater; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.fragment.SearchFragment; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; import java.util.List; /** - * Created by daniel on 23.08.13. + * Performs a search on the gpodder.net directory and displays the results. */ public class SearchListFragment extends PodcastListFragment { private static final String ARG_QUERY = "query"; @@ -26,6 +33,7 @@ public class SearchListFragment extends PodcastListFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (getArguments() != null && getArguments().containsKey(ARG_QUERY)) { this.query = getArguments().getString(ARG_QUERY); } else { @@ -34,6 +42,27 @@ public class SearchListFragment extends PodcastListFragment { } @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + final SearchView sv = new SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.gpodnet_search_hint)); + sv.setQuery(query, false); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + changeQuery(s); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException { return service.searchPodcasts(query, 0); } diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java new file mode 100644 index 000000000..f016290bf --- /dev/null +++ b/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java @@ -0,0 +1,47 @@ +package de.danoeh.antennapod.fragment.gpodnet; + +import android.os.Bundle; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.gpoddernet.GpodnetService; +import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; +import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; +import de.danoeh.antennapod.gpoddernet.model.GpodnetTag; + +import java.util.List; + +/** + * Shows all podcasts from gpodder.net that belong to a specific tag. + * Use the newInstance method of this class to create a new TagFragment. + */ +public class TagFragment extends PodcastListFragment { + + private static final String TAG = "TagFragment"; + private static final int PODCAST_COUNT = 50; + + private GpodnetTag tag; + + public static TagFragment newInstance(String tagName) { + if (tagName == null) throw new IllegalArgumentException("tagName = null"); + TagFragment fragment = new TagFragment(); + Bundle args = new Bundle(); + args.putString("tag", tagName); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + if (args == null || args.getString("tag") == null) throw new IllegalArgumentException("args invalid"); + + tag = new GpodnetTag(args.getString("tag")); + ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getName()); + } + + @Override + protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException { + return service.getPodcastsForTag(tag, PODCAST_COUNT); + } +} diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java index fcb9d01c5..880726e50 100644 --- a/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java +++ b/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java @@ -1,18 +1,23 @@ package de.danoeh.antennapod.fragment.gpodnet; import android.content.Context; -import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; +import android.support.v7.widget.SearchView; +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 de.danoeh.antennapod.activity.gpoddernet.GpodnetTagActivity; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.fragment.SearchFragment; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.gpoddernet.model.GpodnetTag; +import de.danoeh.antennapod.util.menuhandler.MenuItemUtils; import java.util.ArrayList; import java.util.List; @@ -22,17 +27,42 @@ public class TagListFragment extends ListFragment { private static final int COUNT = 50; @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + final SearchView sv = new SearchView(getActivity()); + MenuItemUtils.addSearchItem(menu, sv); + sv.setQueryHint(getString(R.string.gpodnet_search_hint)); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + ((MainActivity) getActivity()).loadChildFragment(SearchListFragment.newInstance(s)); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + } + + @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - setRetainInstance(true); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String selectedTag = (String) getListAdapter().getItem(position); - Intent intent = new Intent(getActivity(), GpodnetTagActivity.class); - intent.putExtra(GpodnetTagActivity.ARG_TAGNAME, selectedTag); - startActivity(intent); + MainActivity activity = (MainActivity) getActivity(); + activity.loadChildFragment(TagFragment.newInstance(selectedTag)); } }); |