summaryrefslogtreecommitdiff
path: root/src/de/danoeh
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/danoeh')
-rw-r--r--src/de/danoeh/antennapod/AppConfig.java2
-rw-r--r--src/de/danoeh/antennapod/activity/AddFeedActivity.java144
-rw-r--r--src/de/danoeh/antennapod/activity/AudioplayerActivity.java171
-rw-r--r--src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java62
-rw-r--r--src/de/danoeh/antennapod/activity/DownloadActivity.java190
-rw-r--r--src/de/danoeh/antennapod/activity/DownloadLogActivity.java123
-rw-r--r--src/de/danoeh/antennapod/activity/FeedInfoActivity.java52
-rw-r--r--src/de/danoeh/antennapod/activity/FeedItemlistActivity.java232
-rw-r--r--src/de/danoeh/antennapod/activity/ItemviewActivity.java205
-rw-r--r--src/de/danoeh/antennapod/activity/MainActivity.java632
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java110
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java198
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java168
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java90
-rw-r--r--src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java40
-rw-r--r--src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java307
-rw-r--r--src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java56
-rw-r--r--src/de/danoeh/antennapod/activity/SearchActivity.java198
-rw-r--r--src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java45
-rw-r--r--src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java88
-rw-r--r--src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java63
-rw-r--r--src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java63
-rw-r--r--src/de/danoeh/antennapod/adapter/ActionButtonUtils.java67
-rw-r--r--src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java49
-rw-r--r--src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java129
-rw-r--r--src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java119
-rw-r--r--src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java207
-rw-r--r--src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java4
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java243
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedlistAdapter.java2
-rw-r--r--src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java230
-rw-r--r--src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java50
-rw-r--r--src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java58
-rw-r--r--src/de/danoeh/antennapod/adapter/NavListAdapter.java198
-rw-r--r--src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java160
-rw-r--r--src/de/danoeh/antennapod/adapter/QueueListAdapter.java130
-rw-r--r--src/de/danoeh/antennapod/adapter/SearchlistAdapter.java38
-rw-r--r--src/de/danoeh/antennapod/asynctask/DownloadObserver.java40
-rw-r--r--src/de/danoeh/antennapod/backup/OpmlBackupAgent.java212
-rw-r--r--src/de/danoeh/antennapod/dialog/FeedItemDialog.java398
-rw-r--r--src/de/danoeh/antennapod/dialog/TimeDialog.java5
-rw-r--r--src/de/danoeh/antennapod/feed/Feed.java2
-rw-r--r--src/de/danoeh/antennapod/feed/FeedFile.java150
-rw-r--r--src/de/danoeh/antennapod/feed/FeedItem.java13
-rw-r--r--src/de/danoeh/antennapod/feed/FeedMedia.java12
-rw-r--r--src/de/danoeh/antennapod/fragment/AddFeedFragment.java76
-rw-r--r--src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java195
-rw-r--r--src/de/danoeh/antennapod/fragment/DownloadLogFragment.java121
-rw-r--r--src/de/danoeh/antennapod/fragment/DownloadsFragment.java145
-rw-r--r--src/de/danoeh/antennapod/fragment/EpisodesFragment.java327
-rw-r--r--src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java14
-rw-r--r--src/de/danoeh/antennapod/fragment/FeedlistFragment.java292
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java2
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemlistFragment.java627
-rw-r--r--src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java266
-rw-r--r--src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java442
-rw-r--r--src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java328
-rw-r--r--src/de/danoeh/antennapod/fragment/QueueFragment.java394
-rw-r--r--src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java69
-rw-r--r--src/de/danoeh/antennapod/fragment/SearchFragment.java254
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java131
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java37
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java31
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java47
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java42
-rw-r--r--src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java129
-rw-r--r--src/de/danoeh/antennapod/miroguide/conn/MiroGuideException.java23
-rw-r--r--src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java153
-rw-r--r--src/de/danoeh/antennapod/miroguide/model/MiroGuideChannel.java75
-rw-r--r--src/de/danoeh/antennapod/miroguide/model/MiroGuideItem.java40
-rw-r--r--src/de/danoeh/antennapod/preferences/UserPreferences.java6
-rw-r--r--src/de/danoeh/antennapod/service/GpodnetSyncService.java7
-rw-r--r--src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java2
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadRequest.java96
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java386
-rw-r--r--src/de/danoeh/antennapod/service/download/HttpDownloader.java49
-rw-r--r--src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java8
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java37
-rw-r--r--src/de/danoeh/antennapod/storage/DBTasks.java170
-rw-r--r--src/de/danoeh/antennapod/storage/DBWriter.java22
-rw-r--r--src/de/danoeh/antennapod/storage/DownloadRequester.java34
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java26
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/FeedHandler.java4
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/FeedHandlerResult.java19
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/HandlerState.java150
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/TypeGetter.java2
-rw-r--r--src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java12
-rw-r--r--src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java21
-rw-r--r--src/de/danoeh/antennapod/util/URLChecker.java27
-rw-r--r--src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java55
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java6
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java20
92 files changed, 5946 insertions, 5228 deletions
diff --git a/src/de/danoeh/antennapod/AppConfig.java b/src/de/danoeh/antennapod/AppConfig.java
index 98a231330..1f55e73a6 100644
--- a/src/de/danoeh/antennapod/AppConfig.java
+++ b/src/de/danoeh/antennapod/AppConfig.java
@@ -2,5 +2,5 @@ package de.danoeh.antennapod;
public final class AppConfig {
/** Should be used when setting User-Agent header for HTTP-requests. */
- public final static String USER_AGENT = "AntennaPod/0.9.8.3";
+ public final static String USER_AGENT = "AntennaPod/0.9.9.0";
}
diff --git a/src/de/danoeh/antennapod/activity/AddFeedActivity.java b/src/de/danoeh/antennapod/activity/AddFeedActivity.java
deleted file mode 100644
index a77689ddb..000000000
--- a/src/de/danoeh/antennapod/activity/AddFeedActivity.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.gpoddernet.GpodnetMainActivity;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.util.StorageUtils;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * Activity for adding a Feed
- */
-public class AddFeedActivity extends ActionBarActivity {
- private static final String TAG = "AddFeedActivity";
-
- private EditText etxtFeedurl;
- private Button butBrowseMiroGuide;
- private Button butBrowserGpoddernet;
- private Button butOpmlImport;
- private Button butConfirm;
-
- private ProgressDialog progDialog;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Was started with Intent " + getIntent().getAction()
- + " and Data " + getIntent().getDataString());
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- StorageUtils.checkStorageAvailability(this);
- setContentView(R.layout.addfeed);
-
- progDialog = new ProgressDialog(this);
-
- etxtFeedurl = (EditText) findViewById(R.id.etxtFeedurl);
- if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
- etxtFeedurl.setText(getIntent().getDataString());
- }
-
- butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide);
- butBrowserGpoddernet = (Button) findViewById(R.id.butBrowseGpoddernet);
- butOpmlImport = (Button) findViewById(R.id.butOpmlImport);
- butConfirm = (Button) findViewById(R.id.butConfirm);
-
- butBrowseMiroGuide.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- startActivity(new Intent(AddFeedActivity.this,
- MiroGuideMainActivity.class));
- }
- });
- butBrowserGpoddernet.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(new Intent(AddFeedActivity.this,
- GpodnetMainActivity.class));
- }
- });
-
- butOpmlImport.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- startActivity(new Intent(AddFeedActivity.this,
- OpmlImportFromPathActivity.class));
- }
- });
-
- butConfirm.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(AddFeedActivity.this, DefaultOnlineFeedViewActivity.class);
- intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString());
- intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getSupportActionBar().getTitle());
- startActivity(intent);
- }
- });
-
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- StorageUtils.checkStorageAvailability(this);
- Intent intent = getIntent();
- if (intent.getAction() != null
- && intent.getAction().equals(Intent.ACTION_SEND)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resuming with ACTION_SEND intent");
- String text = intent.getStringExtra(Intent.EXTRA_TEXT);
- if (text != null) {
- etxtFeedurl.setText(text);
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "No text was sent");
- }
- }
-
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Stopping Activity");
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- return false;
- }
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
index de989fa46..2ffaae967 100644
--- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -4,11 +4,15 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
+import android.support.v4.widget.DrawerLayout;
import android.util.Log;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
@@ -18,18 +22,20 @@ import android.widget.ImageView.ScaleType;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChapterListAdapter;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.MediaType;
-import de.danoeh.antennapod.feed.SimpleChapter;
+import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.fragment.CoverFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.playback.PlaybackService;
+import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.playback.ExternalMedia;
import de.danoeh.antennapod.util.playback.Playable;
+import java.util.List;
+
/**
* Activity for playing audio files.
*/
@@ -44,6 +50,11 @@ public class AudioplayerActivity extends MediaplayerActivity {
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
private static final String PREF_PLAYABLE_ID = "playableId";
+ private DrawerLayout drawerLayout;
+ private NavListAdapter navAdapter;
+ private ListView navList;
+ private ActionBarDrawerToggle drawerToggle;
+
private Fragment[] detachedFragments;
private CoverFragment coverFragment;
@@ -58,7 +69,6 @@ public class AudioplayerActivity extends MediaplayerActivity {
private int savedPosition = -1;
private TextView txtvTitle;
- private TextView txtvFeed;
private Button butPlaybackSpeed;
private ImageButton butNavLeft;
private ImageButton butNavRight;
@@ -108,6 +118,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
super.onStop();
if (BuildConfig.DEBUG)
Log.d(TAG, "onStop");
+ cancelLoadTask();
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@@ -142,6 +154,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ drawerToggle.onConfigurationChanged(newConfig);
}
@Override
@@ -149,6 +162,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
// super.onSaveInstanceState(outState); would cause crash
if (BuildConfig.DEBUG)
Log.d(TAG, "onSaveInstanceState");
+
}
@Override
@@ -193,7 +207,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
if (BuildConfig.DEBUG)
Log.d(TAG,
"Couldn't restore from preferences: savedPosition was -1 or saved identifier and playable identifier didn't match.\nsavedPosition: "
- + savedPosition + ", id: " + playableId);
+ + savedPosition + ", id: " + playableId
+ );
}
return false;
@@ -223,6 +238,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
switchToFragment(savedPosition);
}
+ EventDistributor.getInstance().register(contentUpdate);
+ loadData();
}
@Override
@@ -233,7 +250,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
protected void onAwaitingVideoSurface() {
- if (BuildConfig.DEBUG) Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player");
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player");
startActivity(new Intent(this, VideoplayerActivity.class));
}
@@ -297,7 +315,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
};
chapterFragment.setListAdapter(new ChapterListAdapter(
AudioplayerActivity.this, 0, media
- .getChapters(), media));
+ .getChapters(), media
+ ));
}
currentlyShownFragment = chapterFragment;
break;
@@ -323,8 +342,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
private void updateNavButtonDrawable() {
- final int[] buttonTexts = new int[] {R.string.show_shownotes_label,
- R.string.show_chapters_label, R.string.show_cover_label};
+ final int[] buttonTexts = new int[]{R.string.show_shownotes_label,
+ R.string.show_chapters_label, R.string.show_cover_label};
final TypedArray drawables = obtainStyledAttributes(new int[]{
R.attr.navigation_shownotes, R.attr.navigation_chapters});
@@ -382,12 +401,53 @@ public class AudioplayerActivity extends MediaplayerActivity {
protected void setupGUI() {
super.setupGUI();
resetFragmentView();
+ drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ navList = (ListView) findViewById(R.id.nav_list);
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
- txtvFeed = (TextView) findViewById(R.id.txtvFeed);
butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
butNavRight = (ImageButton) findViewById(R.id.butNavRight);
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
+ TypedArray typedArray = obtainStyledAttributes(new int[]{R.attr.nav_drawer_toggle});
+ drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, typedArray.getResourceId(0, 0), R.string.drawer_open, R.string.drawer_close) {
+ String currentTitle = getSupportActionBar().getTitle().toString();
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ currentTitle = getSupportActionBar().getTitle().toString();
+ getSupportActionBar().setTitle(R.string.app_name);
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ getSupportActionBar().setTitle(currentTitle);
+ supportInvalidateOptionsMenu();
+ }
+ };
+ typedArray.recycle();
+ drawerToggle.setDrawerIndicatorEnabled(false);
+
+ navAdapter = new NavListAdapter(itemAccess, this);
+ navList.setAdapter(navAdapter);
+ navList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ int viewType = parent.getAdapter().getItemViewType(position);
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
+ int relPos = (viewType == NavListAdapter.VIEW_TYPE_NAV) ? position : position - NavListAdapter.SUBSCRIPTION_OFFSET;
+ Intent intent = new Intent(AudioplayerActivity.this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, viewType);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, relPos);
+ startActivity(intent);
+ }
+ drawerLayout.closeDrawer(navList);
+ }
+ });
+ drawerToggle.syncState();
+
butNavLeft.setOnClickListener(new OnClickListener() {
@Override
@@ -466,11 +526,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
}
private void updateButPlaybackSpeed() {
- if (controller == null
- || (controller.getCurrentPlaybackSpeedMultiplier() == -1)) {
- butPlaybackSpeed.setVisibility(View.GONE);
- } else {
- butPlaybackSpeed.setVisibility(View.VISIBLE);
+ if (controller != null && controller.canSetPlaybackSpeed()) {
butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed());
}
}
@@ -491,11 +547,10 @@ public class AudioplayerActivity extends MediaplayerActivity {
return false;
}
txtvTitle.setText(media.getEpisodeTitle());
- txtvFeed.setText(media.getFeedTitle());
if (media.getChapters() != null) {
butNavRight.setVisibility(View.VISIBLE);
} else {
- butNavRight.setVisibility(View.GONE);
+ butNavRight.setVisibility(View.INVISIBLE);
}
@@ -508,6 +563,14 @@ public class AudioplayerActivity extends MediaplayerActivity {
((AudioplayerContentFragment) currentlyShownFragment)
.onDataSetChanged(media);
}
+
+ if (controller == null
+ || !controller.canSetPlaybackSpeed()) {
+ butPlaybackSpeed.setVisibility(View.GONE);
+ } else {
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
+ }
+
updateButPlaybackSpeed();
return true;
}
@@ -551,4 +614,78 @@ public class AudioplayerActivity extends MediaplayerActivity {
return R.layout.audioplayer_activity;
}
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (drawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private List<Feed> feeds;
+ private AsyncTask<Void, Void, List<Feed>> loadTask;
+
+ private void loadData() {
+ loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ @Override
+ protected List<Feed> doInBackground(Void... params) {
+ return DBReader.getFeedList(AudioplayerActivity.this);
+ }
+
+ @Override
+ protected void onPostExecute(List<Feed> result) {
+ super.onPostExecute(result);
+ feeds = result;
+ if (navAdapter != null) {
+ navAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+ loadTask.execute();
+ }
+
+ private void cancelLoadTask() {
+ if (loadTask != null) {
+ loadTask.cancel(true);
+ }
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EventDistributor.FEED_LIST_UPDATE & arg) != 0) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ loadData();
+ }
+ }
+ };
+
+ private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ if (feeds != null) {
+ return feeds.size();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public Feed getItem(int position) {
+ if (feeds != null && position < feeds.size()) {
+ return feeds.get(position);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getSelectedItemIndex() {
+ return -1;
+ }
+ };
}
diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
index 5709fc958..597189885 100644
--- a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
+++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
@@ -1,15 +1,14 @@
package de.danoeh.antennapod.activity;
import android.content.Context;
+import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.v4.app.NavUtils;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
+import android.widget.*;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
import de.danoeh.antennapod.asynctask.ImageDiskCache;
@@ -20,8 +19,10 @@ import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Map;
/**
* Created by daniel on 24.08.13.
@@ -31,6 +32,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE;
private volatile List<Feed> feeds;
private Feed feed;
+ private String selectedDownloadUrl;
private Button subscribeButton;
@@ -44,7 +46,12 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
- finish();
+ Intent destIntent = new Intent(this, MainActivity.class);
+ if (NavUtils.shouldUpRecreateTask(this, destIntent)) {
+ startActivity(destIntent);
+ } else {
+ NavUtils.navigateUpFromSameTask(this);
+ }
return true;
}
return super.onOptionsItemSelected(item);
@@ -57,11 +64,12 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
}
@Override
- protected void showFeedInformation(final Feed feed) {
- super.showFeedInformation(feed);
+ protected void showFeedInformation(final Feed feed, final Map<String, String> alternateFeedUrls) {
+ super.showFeedInformation(feed, alternateFeedUrls);
setContentView(R.layout.listview_activity);
this.feed = feed;
+ this.selectedDownloadUrl = feed.getDownload_url();
EventDistributor.getInstance().register(listener);
ListView listView = (ListView) findViewById(R.id.listview);
LayoutInflater inflater = (LayoutInflater)
@@ -75,6 +83,8 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
TextView title = (TextView) header.findViewById(R.id.txtvTitle);
TextView author = (TextView) header.findViewById(R.id.txtvAuthor);
TextView description = (TextView) header.findViewById(R.id.txtvDescription);
+ Spinner spAlternateUrls = (Spinner) header.findViewById(R.id.spinnerAlternateUrls);
+
subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
if (feed.getImage() != null) {
@@ -89,8 +99,10 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
@Override
public void onClick(View v) {
try {
- Feed f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle());
+ Feed f = new Feed(selectedDownloadUrl, new Date(), feed.getTitle());
f.setPreferences(feed.getPreferences());
+ DefaultOnlineFeedViewActivity.this.feed = f;
+
DownloadRequester.getInstance().downloadFeed(
DefaultOnlineFeedViewActivity.this,
f);
@@ -102,6 +114,40 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
setSubscribeButtonState(feed);
}
});
+
+ if (alternateFeedUrls.isEmpty()) {
+ spAlternateUrls.setVisibility(View.GONE);
+ } else {
+ spAlternateUrls.setVisibility(View.VISIBLE);
+
+ final List<String> alternateUrlsList = new ArrayList<String>();
+ final List<String> alternateUrlsTitleList = new ArrayList<String>();
+
+ alternateUrlsList.add(feed.getDownload_url());
+ alternateUrlsTitleList.add(feed.getTitle());
+
+
+ alternateUrlsList.addAll(alternateFeedUrls.keySet());
+ for (String url : alternateFeedUrls.keySet()) {
+ alternateUrlsTitleList.add(alternateFeedUrls.get(url));
+ }
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, alternateUrlsTitleList);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spAlternateUrls.setAdapter(adapter);
+ spAlternateUrls.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ selectedDownloadUrl = alternateUrlsList.get(position);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ });
+
+
+ }
setSubscribeButtonState(feed);
}
diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java
deleted file mode 100644
index 996929cdb..000000000
--- a/src/de/danoeh/antennapod/activity/DownloadActivity.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.view.ActionMode;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemLongClickListener;
-import android.widget.ListView;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.DownloadlistAdapter;
-import de.danoeh.antennapod.asynctask.DownloadObserver;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.download.DownloadRequest;
-import de.danoeh.antennapod.service.download.Downloader;
-import de.danoeh.antennapod.storage.DownloadRequester;
-
-import java.util.List;
-
-/**
- * Shows all running downloads in a list. The list objects are DownloadStatus
- * objects created by a DownloadObserver.
- */
-public class DownloadActivity extends ActionBarActivity implements
- ActionMode.Callback {
-
- private static final String TAG = "DownloadActivity";
- private static final int MENU_SHOW_LOG = 0;
- private static final int MENU_CANCEL_ALL_DOWNLOADS = 1;
- private DownloadlistAdapter dla;
- private DownloadRequester requester;
-
- private ActionMode mActionMode;
- private DownloadRequest selectedDownload;
-
- private ListView listview;
-
- private DownloadObserver downloadObserver;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.listview_activity);
-
- listview = (ListView) findViewById(R.id.listview);
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating Activity");
- requester = DownloadRequester.getInstance();
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- downloadObserver = new DownloadObserver(this, new Handler(), observerCallback);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- downloadObserver.onPause();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- downloadObserver.onResume();
- if (dla != null) {
- dla.notifyDataSetChanged();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Stopping Activity");
- }
-
-
- @Override
- protected void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- listview.setOnItemLongClickListener(new OnItemLongClickListener() {
-
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int position, long id) {
- DownloadRequest selection = dla.getItem(position)
- .getDownloadRequest();
- if (selection != null && mActionMode != null) {
- mActionMode.finish();
- }
- dla.setSelectedItemIndex(position);
- selectedDownload = selection;
- mActionMode = startSupportActionMode(DownloadActivity.this);
- return true;
- }
-
- });
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, MENU_SHOW_LOG, Menu.NONE,
- R.string.show_download_log),
- MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, MENU_CANCEL_ALL_DOWNLOADS, Menu.NONE,
- R.string.cancel_all_downloads_label),
- MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- break;
- case MENU_SHOW_LOG:
- startActivity(new Intent(this, DownloadLogActivity.class));
- break;
- case MENU_CANCEL_ALL_DOWNLOADS:
- requester.cancelAllDownloads(this);
- break;
- }
- return true;
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- if (selectedDownload != null) {
- TypedArray drawables = obtainStyledAttributes(new int[]{R.attr.navigation_cancel});
- menu.add(Menu.NONE, R.id.cancel_download_item, Menu.NONE,
- R.string.cancel_download_label).setIcon(
- drawables.getDrawable(0));
- }
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- boolean handled = false;
- switch (item.getItemId()) {
- case R.id.cancel_download_item:
- requester.cancelDownload(this, selectedDownload.getSource());
- handled = true;
- break;
- }
- mActionMode.finish();
- return handled;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- mActionMode = null;
- selectedDownload = null;
- dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE);
- }
-
-
- private DownloadObserver.Callback observerCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged() {
- if (dla != null) {
- dla.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
- dla = new DownloadlistAdapter(DownloadActivity.this, 0,
- downloaderList);
- listview.setAdapter(dla);
- dla.notifyDataSetChanged();
- }
- };
-
-}
diff --git a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java b/src/de/danoeh/antennapod/activity/DownloadLogActivity.java
deleted file mode 100644
index 4629b8670..000000000
--- a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.ListView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.DownloadLogAdapter;
-import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.download.DownloadStatus;
-import de.danoeh.antennapod.storage.DBReader;
-
-import java.util.List;
-
-/**
- * Displays completed and failed downloads in a list.
- */
-public class DownloadLogActivity extends ActionBarActivity {
- private static final String TAG = "DownloadLogActivity";
-
- private List<DownloadStatus> downloadLog;
- private DownloadLogAdapter dla;
-
- private ListView listview;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.listview_activity);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
-
- listview = (ListView) findViewById(R.id.listview);
-
- dla = new DownloadLogAdapter(this, itemAccess);
- listview.setAdapter(dla);
- loadData();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- EventDistributor.getInstance().unregister(contentUpdate);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- EventDistributor.getInstance().register(contentUpdate);
- dla.notifyDataSetChanged();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- break;
- default:
- return false;
- }
- return true;
- }
-
- private void loadData() {
- AsyncTask<Void, Void, List<DownloadStatus>> loadTask = new AsyncTask<Void, Void, List<DownloadStatus>>() {
- @Override
- protected List<DownloadStatus> doInBackground(Void... voids) {
- return DBReader.getDownloadLog(DownloadLogActivity.this);
- }
-
- @Override
- protected void onPostExecute(List<DownloadStatus> downloadStatuses) {
- super.onPostExecute(downloadStatuses);
- if (downloadStatuses != null) {
- downloadLog = downloadStatuses;
- if (dla != null) {
- dla.notifyDataSetChanged();
- }
- } else {
- Log.e(TAG, "Could not load download log");
- }
- }
- };
- loadTask.execute();
- }
-
- 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) {
- loadData();
- }
- }
- };
-
-}
diff --git a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
index db0755ccd..f00ce13e8 100644
--- a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -3,21 +3,22 @@ package de.danoeh.antennapod.activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.TextView;
+import android.widget.*;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedPreferences;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.util.LangUtils;
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
@@ -37,6 +38,8 @@ public class FeedInfoActivity extends ActionBarActivity {
private TextView txtvDescription;
private TextView txtvLanguage;
private TextView txtvAuthor;
+ private EditText etxtUsername;
+ private EditText etxtPassword;
private CheckBox cbxAutoDownload;
@Override
@@ -53,6 +56,8 @@ public class FeedInfoActivity extends ActionBarActivity {
txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
cbxAutoDownload = (CheckBox) findViewById(R.id.cbxAutoDownload);
+ etxtUsername = (EditText) findViewById(R.id.etxtUsername);
+ etxtPassword = (EditText) findViewById(R.id.etxtPassword);
AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>() {
@@ -98,6 +103,12 @@ public class FeedInfoActivity extends ActionBarActivity {
}
});
+ etxtUsername.setText(feed.getPreferences().getUsername());
+ etxtPassword.setText(feed.getPreferences().getPassword());
+
+ etxtUsername.addTextChangedListener(authTextWatcher);
+ etxtPassword.addTextChangedListener(authTextWatcher);
+
supportInvalidateOptionsMenu();
} else {
@@ -108,6 +119,39 @@ public class FeedInfoActivity extends ActionBarActivity {
loadTask.execute(feedId);
}
+
+ private boolean authInfoChanged = false;
+
+ private TextWatcher authTextWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ authInfoChanged = true;
+ }
+ };
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (feed != null && authInfoChanged) {
+ Log.d(TAG, "Auth info changed, saving credentials");
+ FeedPreferences prefs = feed.getPreferences();
+ prefs.setUsername(etxtUsername.getText().toString());
+ prefs.setPassword(etxtPassword.getText().toString());
+ DBWriter.setFeedPreferences(this, prefs);
+ authInfoChanged = false;
+ }
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
diff --git a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
deleted file mode 100644
index d0305eada..000000000
--- a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.annotation.SuppressLint;
-import android.app.SearchManager;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.media.AudioManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.NavUtils;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.widget.SearchView;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.Window;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedRemover;
-import de.danoeh.antennapod.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
-import de.danoeh.antennapod.fragment.FeedlistFragment;
-import de.danoeh.antennapod.fragment.ItemlistFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.util.StorageUtils;
-import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
-
-/**
- * Displays a List of FeedItems
- */
-public class FeedItemlistActivity extends ActionBarActivity {
- private static final String TAG = "FeedItemlistActivity";
-
- /**
- * The feed which the activity displays
- */
- private Feed feed;
- private ItemlistFragment filf;
- private ExternalPlayerFragment externalPlayerFragment;
-
- private AsyncTask<?, ?, ?> currentLoadTask;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- StorageUtils.checkStorageAvailability(this);
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.feeditemlist_activity);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- long feedId = getIntent().getLongExtra(
- FeedlistFragment.EXTRA_SELECTED_FEED, -1);
- if (feedId == -1) {
- Log.e(TAG, "Received invalid feed selection.");
- } else {
- loadData(feedId);
- }
-
- }
-
- private synchronized void loadData(long id) {
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
- }
- AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>() {
-
- @Override
- protected Feed doInBackground(Long... longs) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading feed data in background");
- return DBReader.getFeed(FeedItemlistActivity.this, longs[0]);
- }
-
- @Override
- protected void onCancelled(Feed feed) {
- super.onCancelled(feed);
- if (BuildConfig.DEBUG) Log.d(TAG, "load task was cancelled");
- }
-
- @Override
- protected void onPostExecute(Feed result) {
- super.onPostExecute(result);
- if (result != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Finished loading feed data");
- feed = result;
- setTitle(feed.getTitle());
-
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fT = fragmentManager.beginTransaction();
-
- filf = ItemlistFragment.newInstance(feed.getId());
- fT.replace(R.id.feeditemlistFragment, filf);
-
- externalPlayerFragment = new ExternalPlayerFragment();
- fT.replace(R.id.playerFragment, externalPlayerFragment);
- fT.commit();
- supportInvalidateOptionsMenu();
- } else {
- Log.e(TAG, "Error: Feed was null");
- }
- }
- };
- currentLoadTask = loadTask;
- loadTask.execute(id);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- StorageUtils.checkStorageAvailability(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- if (feed != null) {
- TypedArray drawables = obtainStyledAttributes(new int[]{R.attr.action_search});
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
- .setIcon(drawables.getDrawable(0)),
- MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
- MenuItemCompat.setActionView(menu.findItem(R.id.search_item), new SearchView(this));
-
- SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search_item));
-
-
- searchView.setIconifiedByDefault(true);
-
- searchView.setSearchableInfo(
- searchManager.getSearchableInfo(getComponentName()));
- FeedMenuHandler
- .onCreateOptionsMenu(getMenuInflater(), menu);
- }
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- return FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
- }
-
- @SuppressLint("NewApi")
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- try {
- if (FeedMenuHandler.onOptionsItemClicked(this, item, feed)) {
- filf.getListAdapter().notifyDataSetChanged();
- } else {
- switch (item.getItemId()) {
- case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(
- FeedItemlistActivity.this, feed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- finish();
- }
- };
- ConfirmationDialog conDialog = new ConfirmationDialog(this,
- R.string.remove_feed_label,
- R.string.feed_delete_confirmation_msg) {
-
- @Override
- public void onConfirmButtonPressed(
- DialogInterface dialog) {
- dialog.dismiss();
- remover.executeAsync();
- }
- };
- conDialog.createNewDialog().show();
- break;
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- break;
- }
- }
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
- return true;
- }
-
- @Override
- public boolean onSearchRequested() {
- if (feed != null) {
- Bundle bundle = new Bundle();
- bundle.putLong(SearchActivity.EXTRA_FEED_ID, feed.getId());
- startSearch(null, false, bundle, false);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public void startActivity(Intent intent) {
- if (intent.getAction() != null &&
- intent.getAction().equals(Intent.ACTION_SEARCH)) {
- addSearchInformation(intent);
- }
- super.startActivity(intent);
- }
-
- private void addSearchInformation(Intent startIntent) {
- startIntent.putExtra(SearchActivity.EXTRA_FEED_ID, feed.getId());
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/ItemviewActivity.java b/src/de/danoeh/antennapod/activity/ItemviewActivity.java
deleted file mode 100644
index 699ba84ea..000000000
--- a/src/de/danoeh/antennapod/activity/ItemviewActivity.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.media.AudioManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.ActionBarActivity;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.Window;
-import android.widget.TextView;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
-import de.danoeh.antennapod.fragment.ItemlistFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.util.QueueAccess;
-import de.danoeh.antennapod.util.StorageUtils;
-import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
-
-import java.text.DateFormat;
-
-/**
- * Displays a single FeedItem and provides various actions
- */
-public class ItemviewActivity extends ActionBarActivity {
- private static final String TAG = "ItemviewActivity";
-
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED;
-
- private FeedItem item;
- private boolean guiInitialized;
- private AsyncTask<?, ?, ?> currentLoadTask;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- StorageUtils.checkStorageAvailability(this);
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- getSupportActionBar().setDisplayShowTitleEnabled(false);
- EventDistributor.getInstance().register(contentUpdate);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- guiInitialized = false;
-
- long itemId = getIntent().getLongExtra(
- ItemlistFragment.EXTRA_SELECTED_FEEDITEM, -1);
- if (itemId == -1) {
- Log.e(TAG, "Received invalid selection of either feeditem or feed.");
- } else {
- loadData(itemId);
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- StorageUtils.checkStorageAvailability(this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- EventDistributor.getInstance().unregister(contentUpdate);
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Stopping Activity");
- }
-
- private synchronized void loadData(long itemId) {
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
- }
- AsyncTask<Long, Void, FeedItem> loadTask = new AsyncTask<Long, Void, FeedItem>() {
-
- @Override
- protected FeedItem doInBackground(Long... longs) {
- return DBReader.getFeedItem(ItemviewActivity.this, longs[0]);
- }
-
- @Override
- protected void onCancelled(FeedItem feedItem) {
- super.onCancelled(feedItem);
- if (BuildConfig.DEBUG) Log.d(TAG, "loadTask was cancelled");
- }
-
- @Override
- protected void onPostExecute(FeedItem feedItem) {
- super.onPostExecute(feedItem);
- if (feedItem != null && feedItem.getFeed() != null) {
- item = feedItem;
- populateUI();
- supportInvalidateOptionsMenu();
- } else {
- if (feedItem == null) {
- Log.e(TAG, "Error: FeedItem was null");
- } else if (feedItem.getFeed() == null) {
- Log.e(TAG, "Error: Feed was null");
- }
- }
- }
- };
- loadTask.execute(itemId);
- currentLoadTask = loadTask;
- }
-
- private synchronized void populateUI() {
- if (!guiInitialized) {
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.feeditemview);
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fragmentTransaction = fragmentManager
- .beginTransaction();
- ItemDescriptionFragment fragment = ItemDescriptionFragment
- .newInstance(item, false);
- fragmentTransaction.replace(R.id.description_fragment, fragment);
- fragmentTransaction.commit();
- }
- TextView txtvTitle = (TextView) findViewById(R.id.txtvItemname);
- TextView txtvPublished = (TextView) findViewById(R.id.txtvPublished);
- setTitle(item.getFeed().getTitle());
-
- txtvPublished.setText(DateUtils.formatSameDayTime(item.getPubDate()
- .getTime(), System.currentTimeMillis(), DateFormat.MEDIUM,
- DateFormat.SHORT));
- txtvTitle.setText(item.getTitle());
-
- guiInitialized = true;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- if (item != null) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.feeditem, menu);
- }
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (item == null) {
- return false;
- }
- try {
- if (!FeedItemMenuHandler.onMenuItemClicked(this,
- menuItem.getItemId(), item)) {
- switch (menuItem.getItemId()) {
- case android.R.id.home:
- finish();
- break;
- }
- }
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
- supportInvalidateOptionsMenu();
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(final Menu menu) {
- super.onPrepareOptionsMenu(menu);
- FeedItemMenuHandler.onPrepareMenu(
- new FeedItemMenuHandler.MenuInterface() {
-
- @Override
- public void setItemVisibility(int id, boolean visible) {
- menu.findItem(id).setVisible(visible);
- }
- }, item, true, QueueAccess.NotInQueueAccess());
- return true;
- }
-
- 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 (item != null) {
- loadData(item.getId());
- }
- }
- }
- };
-
-
-}
diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java
index 29e36abc8..92afea77c 100644
--- a/src/de/danoeh/antennapod/activity/MainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MainActivity.java
@@ -1,284 +1,414 @@
package de.danoeh.antennapod.activity;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
-import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.media.AudioManager;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.view.ViewPager;
+import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
-import android.support.v7.widget.SearchView;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.Window;
+import android.view.*;
+import android.widget.AdapterView;
+import android.widget.ListView;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.fragment.EpisodesFragment;
-import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
-import de.danoeh.antennapod.fragment.FeedlistFragment;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.fragment.*;
import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.download.DownloadService;
-import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DBTasks;
-import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.StorageUtils;
-import java.util.ArrayList;
+import java.util.List;
-/** The activity that is shown when the user launches the app. */
+/**
+ * The activity that is shown when the user launches the app.
+ */
public class MainActivity extends ActionBarActivity {
- private static final String TAG = "MainActivity";
+ private static final String TAG = "MainActivity";
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED
+ | EventDistributor.FEED_LIST_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE;
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED;
+ private static final String PREF_NAME = "MainActivityPrefs";
+ private static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
- private ViewPager viewpager;
- private TabsAdapter pagerAdapter;
- private ExternalPlayerFragment externalPlayerFragment;
+ public static final String EXTRA_NAV_INDEX = "nav_index";
+ public static final String EXTRA_NAV_TYPE = "nav_type";
+ public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
- private static boolean appLaunched = false;
+ public static final int POS_NEW = 0,
+ POS_QUEUE = 1,
+ POS_DOWNLOADS = 2,
+ POS_HISTORY = 3,
+ POS_ADD = 4;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- StorageUtils.checkStorageAvailability(this);
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.main);
+ private ExternalPlayerFragment externalPlayerFragment;
+ private DrawerLayout drawerLayout;
+
+ private ListView navList;
+ private NavListAdapter navAdapter;
+
+ private ActionBarDrawerToggle drawerToogle;
+
+ private CharSequence drawerTitle;
+ private CharSequence currentTitle;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ StorageUtils.checkStorageAvailability(this);
+ setContentView(R.layout.main);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
- getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
- viewpager = (ViewPager) findViewById(R.id.viewpager);
- pagerAdapter = new TabsAdapter(this, viewpager);
-
- viewpager.setAdapter(pagerAdapter);
-
- ActionBar.Tab feedsTab = getSupportActionBar().newTab();
- feedsTab.setText(R.string.podcasts_label);
- ActionBar.Tab episodesTab = getSupportActionBar().newTab();
- episodesTab.setText(R.string.episodes_label);
-
- pagerAdapter.addTab(feedsTab, FeedlistFragment.class, null);
- pagerAdapter.addTab(episodesTab, EpisodesFragment.class, null);
-
- FragmentTransaction transaction = getSupportFragmentManager()
- .beginTransaction();
- externalPlayerFragment = new ExternalPlayerFragment();
- transaction.replace(R.id.playerFragment, externalPlayerFragment);
- transaction.commit();
-
- // executed on application start
- if (!appLaunched && getIntent().getAction() != null
- && getIntent().getAction().equals(Intent.ACTION_MAIN)) {
- appLaunched = true;
- if (DBReader.getNumberOfUnreadItems(this) > 0) {
- // select 'episodes' tab
- getSupportActionBar().setSelectedNavigationItem(1);
- }
- }
- if (savedInstanceState != null) {
- getSupportActionBar().setSelectedNavigationItem(
- savedInstanceState.getInt("tab", 0));
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt("tab", getSupportActionBar()
- .getSelectedNavigationIndex());
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- EventDistributor.getInstance().unregister(contentUpdate);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- StorageUtils.checkStorageAvailability(this);
- updateProgressBarVisibility();
- EventDistributor.getInstance().register(contentUpdate);
-
- }
-
- 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.");
- updateProgressBarVisibility();
- }
- }
- };
-
- private void updateProgressBarVisibility() {
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFeeds()) {
- setSupportProgressBarIndeterminateVisibility(true);
- } else {
- setSupportProgressBarIndeterminateVisibility(false);
- }
- supportInvalidateOptionsMenu();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.add_feed:
- startActivity(new Intent(this, AddFeedActivity.class));
- return true;
- case R.id.all_feed_refresh:
- DBTasks.refreshAllFeeds(this, null);
- return true;
- case R.id.show_downloads:
- startActivity(new Intent(this, DownloadActivity.class));
- return true;
- case R.id.show_preferences:
- startActivity(new Intent(this, PreferenceActivity.class));
- return true;
- case R.id.show_player:
- startActivity(PlaybackService.getPlayerActivityIntent(this));
- return true;
- case R.id.show_playback_history:
- startActivity(new Intent(this, PlaybackHistoryActivity.class));
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
+ drawerTitle = currentTitle = getTitle();
+
+ drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ navList = (ListView) findViewById(R.id.nav_list);
+
+ TypedArray typedArray = obtainStyledAttributes(new int[]{R.attr.nav_drawer_toggle});
+ drawerToogle = new ActionBarDrawerToggle(this, drawerLayout, typedArray.getResourceId(0, 0), R.string.drawer_open, R.string.drawer_close) {
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ currentTitle = getSupportActionBar().getTitle();
+ getSupportActionBar().setTitle(drawerTitle);
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ getSupportActionBar().setTitle(currentTitle);
+ supportInvalidateOptionsMenu();
+
+ }
+ };
+ typedArray.recycle();
+
+ drawerLayout.setDrawerListener(drawerToogle);
+ FragmentManager fm = getSupportFragmentManager();
+
+ FragmentTransaction transaction = fm.beginTransaction();
+
+ Fragment mainFragment = fm.findFragmentByTag("main");
+ if (mainFragment != null) {
+ transaction.replace(R.id.main_view, mainFragment);
+ } else {
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, POS_NEW, null);
+ }
+
+ externalPlayerFragment = new ExternalPlayerFragment();
+ transaction.replace(R.id.playerFragment, externalPlayerFragment);
+ transaction.commit();
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+
+ navAdapter = new NavListAdapter(itemAccess, this);
+ navList.setAdapter(navAdapter);
+ navList.setOnItemClickListener(navListClickListener);
+
+ checkFirstLaunch();
+ }
+
+ private void checkFirstLaunch() {
+ SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
+ if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) {
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ drawerLayout.openDrawer(navList);
+ }
+ }, 1500);
+
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
+ edit.commit();
+ }
+ }
+
+ public ActionBar getMainActivtyActionBar() {
+ return getSupportActionBar();
+ }
+
+ public List<Feed> getFeeds() {
+ return feeds;
+ }
+
+ private void loadFragment(int viewType, int relPos, Bundle args) {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ // clear back stack
+ for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
+ fragmentManager.popBackStack();
+ }
+
+ FragmentTransaction fT = fragmentManager.beginTransaction();
+ Fragment fragment = null;
+ if (viewType == NavListAdapter.VIEW_TYPE_NAV) {
+ switch (relPos) {
+ case POS_NEW:
+ fragment = new NewEpisodesFragment();
+ break;
+ case POS_QUEUE:
+ fragment = new QueueFragment();
+ break;
+ case POS_DOWNLOADS:
+ fragment = new DownloadsFragment();
+ break;
+ case POS_HISTORY:
+ fragment = new PlaybackHistoryFragment();
+ break;
+ case POS_ADD:
+ fragment = new AddFeedFragment();
+ break;
+
+ }
+ currentTitle = getString(NavListAdapter.NAV_TITLES[relPos]);
+ selectedNavListIndex = relPos;
+
+ } else if (viewType == NavListAdapter.VIEW_TYPE_SUBSCRIPTION) {
+ Feed feed = itemAccess.getItem(relPos);
+ currentTitle = "";
+ fragment = ItemlistFragment.newInstance(feed.getId());
+ selectedNavListIndex = NavListAdapter.SUBSCRIPTION_OFFSET + relPos;
+
+ }
+ if (fragment != null) {
+ if (args != null) {
+ fragment.setArguments(args);
+ }
+ fT.replace(R.id.main_view, fragment, "main");
+ fragmentManager.popBackStack();
+ }
+ fT.commit();
+ getSupportActionBar().setTitle(currentTitle);
+ if (navAdapter != null) {
+ navAdapter.notifyDataSetChanged();
+ }
+ }
+
+ public void loadNavFragment(int position, Bundle args) {
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, position, args);
+ }
+
+ public void loadFeedFragment(long feedID) {
+ if (feeds != null) {
+ for (int i = 0; i < feeds.size(); i++) {
+ if (feeds.get(i).getId() == feedID) {
+ loadFragment(NavListAdapter.VIEW_TYPE_SUBSCRIPTION, i, null);
+ break;
+ }
+ }
+ }
+ }
+
+ public void loadChildFragment(Fragment fragment) {
+ if (fragment == null) throw new IllegalArgumentException("fragment = null");
+ FragmentManager fm = getSupportFragmentManager();
+ fm.beginTransaction()
+ .replace(R.id.main_view, fragment, "main")
+ .addToBackStack(null)
+ .commit();
+ }
+
+ private AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ int viewType = parent.getAdapter().getItemViewType(position);
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER && position != selectedNavListIndex) {
+ int relPos = (viewType == NavListAdapter.VIEW_TYPE_NAV) ? position : position - NavListAdapter.SUBSCRIPTION_OFFSET;
+ loadFragment(viewType, relPos, null);
+ selectedNavListIndex = position;
+ navAdapter.notifyDataSetChanged();
+ }
+ drawerLayout.closeDrawer(navList);
+ }
+ };
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ drawerToogle.syncState();
+ if (savedInstanceState != null) {
+ currentTitle = savedInstanceState.getString("title");
+ if (!drawerLayout.isDrawerOpen(navList)) {
+ getSupportActionBar().setTitle(currentTitle);
+ }
+ selectedNavListIndex = savedInstanceState.getInt("selectedNavIndex");
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ drawerToogle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString("title", getSupportActionBar().getTitle().toString());
+ outState.putInt("selectedNavIndex", selectedNavListIndex);
+
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ StorageUtils.checkStorageAvailability(this);
+ EventDistributor.getInstance().register(contentUpdate);
+
+ Intent intent = getIntent();
+ if (feeds != null && intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
+ handleNavIntent();
+ }
+
+ loadData();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ cancelLoadTask();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (drawerToogle.onOptionsItemSelected(item)) {
+ return true;
+ }
+ switch (item.getItemId()) {
+ case R.id.show_preferences:
+ startActivity(new Intent(this, PreferenceActivity.class));
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- MenuItem refreshAll = menu.findItem(R.id.all_feed_refresh);
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFeeds()) {
- refreshAll.setVisible(false);
- } else {
- refreshAll.setVisible(true);
- }
- return true;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
+
+ return true;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
-
- SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- MenuItem searchItem = menu.findItem(R.id.search_item);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
- if (searchView == null) {
- MenuItemCompat.setActionView(searchItem, new SearchView(this));
- searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main, menu);
+ return true;
+ }
+
+ private List<Feed> feeds;
+ private AsyncTask<Void, Void, List<Feed>> loadTask;
+ private int selectedNavListIndex = 0;
+
+ private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ if (feeds != null) {
+ return feeds.size();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public Feed getItem(int position) {
+ if (feeds != null && position < feeds.size()) {
+ return feeds.get(position);
+ } else {
+ return null;
+ }
}
- searchView.setIconifiedByDefault(true);
- SearchableInfo info = searchManager.getSearchableInfo(getComponentName());
- searchView.setSearchableInfo(
- searchManager.getSearchableInfo(getComponentName()));
+ @Override
+ public int getSelectedItemIndex() {
+ return selectedNavListIndex;
+ }
- return true;
- }
-
- public static class TabsAdapter extends FragmentPagerAdapter implements
- ActionBar.TabListener, ViewPager.OnPageChangeListener {
- private final Context mContext;
- private final ActionBar mActionBar;
- private final ViewPager mViewPager;
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
-
- static final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
-
- TabInfo(Class<?> _class, Bundle _args) {
- clss = _class;
- args = _args;
- }
- }
-
- public TabsAdapter(MainActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- mContext = activity;
- mActionBar = activity.getSupportActionBar();
- mViewPager = pager;
- mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
- }
-
- public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
- TabInfo info = new TabInfo(clss, args);
- tab.setTag(info);
- tab.setTabListener(this);
- mTabs.add(info);
- mActionBar.addTab(tab);
- notifyDataSetChanged();
- }
-
- @Override
- public int getCount() {
- return mTabs.size();
- }
-
- @Override
- public Fragment getItem(int position) {
- TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(),
- info.args);
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- }
-
- @Override
- public void onPageSelected(int position) {
- mActionBar.setSelectedNavigationItem(position);
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- }
-
- @Override
- public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
- Object tag = tab.getTag();
- for (int i = 0; i < mTabs.size(); i++) {
- if (mTabs.get(i) == tag) {
- mViewPager.setCurrentItem(i);
- }
- }
- }
-
- @Override
- public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
-
- }
-
- @Override
- public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
- }
- }
+ };
+
+ private void loadData() {
+ cancelLoadTask();
+ loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ @Override
+ protected List<Feed> doInBackground(Void... params) {
+ return DBReader.getFeedList(MainActivity.this);
+ }
+
+ @Override
+ protected void onPostExecute(List<Feed> result) {
+ super.onPostExecute(result);
+ boolean handleIntent = (feeds == null);
+
+ feeds = result;
+ navAdapter.notifyDataSetChanged();
+
+ if (handleIntent) {
+ handleNavIntent();
+ }
+ }
+ };
+ loadTask.execute();
+ }
+ private void cancelLoadTask() {
+ if (loadTask != null) {
+ loadTask.cancel(true);
+ }
+ }
+
+ 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.");
+ loadData();
+ }
+ }
+ };
+
+ private void handleNavIntent() {
+ Intent intent = getIntent();
+ if (intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
+ int index = intent.getIntExtra(EXTRA_NAV_INDEX, 0);
+ int type = intent.getIntExtra(EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
+ loadFragment(type, index, args);
+ }
+ setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
}
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java
deleted file mode 100644
index 6d732b9ff..000000000
--- a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.NavUtils;
-import android.support.v4.view.ViewPager;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.MiroGuideChannellistFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-
-/**
- * Shows channels of a category sorted by different criteria in lists. The
- * activity uses MiroGuideChannelListFragments for these lists. If the user
- * selects a channel, the MiroGuideChannelViewActivity is started.
- */
-public class MiroGuideCategoryActivity extends ActionBarActivity {
- private static final String TAG = "MiroGuideCategoryActivity";
-
- public static final String EXTRA_CATEGORY = "category";
-
- private ViewPager viewpager;
- private CategoryPagerAdapter pagerAdapter;
-
- private String category;
-
- @Override
- protected void onCreate(Bundle arg0) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(arg0);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.miroguide_category);
-
- viewpager = (ViewPager) findViewById(R.id.viewpager);
-
- category = getIntent().getStringExtra(EXTRA_CATEGORY);
- if (category != null) {
- getSupportActionBar().setTitle(category);
- pagerAdapter = new CategoryPagerAdapter(getSupportFragmentManager());
- viewpager.setAdapter(pagerAdapter);
- } else {
- Log.e(TAG, "Activity was started with invalid arguments");
- }
-
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- default:
- return false;
- }
- }
-
- public class CategoryPagerAdapter extends FragmentStatePagerAdapter {
-
- public CategoryPagerAdapter(FragmentManager fm) {
- super(fm);
- }
-
- private static final int NUM_ITEMS = 2;
- private static final int POS_RATING = 0;
- private static final int POS_POPULAR = 1;
-
- @Override
- public Fragment getItem(int position) {
- switch (position) {
- case POS_RATING:
- return MiroGuideChannellistFragment.newInstance("category",
- category, "rating");
- case POS_POPULAR:
- return MiroGuideChannellistFragment.newInstance("category",
- category, "popular");
- default:
- return null;
- }
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- switch (position) {
- case POS_RATING:
- return getString(R.string.best_rating_label);
- case POS_POPULAR:
- return getString(R.string.popular_label);
- default:
- return null;
- }
- }
-
- @Override
- public int getCount() {
- return NUM_ITEMS;
- }
- }
-}
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java
deleted file mode 100644
index 96c8385ce..000000000
--- a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.*;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.MiroGuideItemlistAdapter;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideException;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideService;
-import de.danoeh.antennapod.miroguide.model.MiroGuideChannel;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.storage.DownloadRequester;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * Displays information about one channel and lets the user add this channel to
- * his library.
- */
-public class MiroGuideChannelViewActivity extends ActionBarActivity {
- private static final String TAG = "MiroGuideChannelViewActivity";
-
- public static final String EXTRA_CHANNEL_ID = "id";
- public static final String EXTRA_CHANNEL_URL = "url";
-
- private RelativeLayout layoutContent;
- private ProgressBar progLoading;
- private TextView txtvTitle;
- private TextView txtVDescription;
- private ListView listEntries;
-
- private long channelId;
- private String channelUrl;
- private MiroGuideChannel channel;
- private volatile List<Feed> feeds;
-
- @Override
- protected void onPause() {
- super.onPause();
- channelLoader.cancel(true);
- }
-
- @SuppressLint("NewApi")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.miroguide_channelview);
-
- layoutContent = (RelativeLayout) findViewById(R.id.layout_content);
- progLoading = (ProgressBar) findViewById(R.id.progLoading);
- txtvTitle = (TextView) findViewById(R.id.txtvTitle);
- txtVDescription = (TextView) findViewById(R.id.txtvDescription);
- listEntries = (ListView) findViewById(R.id.itemlist);
-
- channelId = getIntent().getLongExtra(EXTRA_CHANNEL_ID, -1);
- channelUrl = getIntent().getStringExtra(EXTRA_CHANNEL_URL);
-
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- channelLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- channelLoader.execute();
- }
-
- }
-
- /**
- * Is used to load channel information asynchronously.
- */
- private AsyncTask<Void, Void, Void> channelLoader = new AsyncTask<Void, Void, Void>() {
- private static final String TAG = "ChannelLoader";
- private Exception exception;
-
- @Override
- protected Void doInBackground(Void... params) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting background task");
- feeds = DBReader.getFeedList(MiroGuideChannelViewActivity.this);
- MiroGuideService service = new MiroGuideService();
- try {
- channel = service.getChannel(channelId);
- } catch (MiroGuideException e) {
- e.printStackTrace();
- exception = e;
- }
- return null;
- }
-
- @SuppressLint("NewApi")
- @Override
- protected void onPostExecute(Void result) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading finished");
- if (exception == null) {
- txtvTitle.setText(channel.getName());
- txtVDescription.setText(channel.getDescription());
-
- MiroGuideItemlistAdapter listAdapter = new MiroGuideItemlistAdapter(
- MiroGuideChannelViewActivity.this, 0,
- channel.getItems());
- listEntries.setAdapter(listAdapter);
- progLoading.setVisibility(View.GONE);
- layoutContent.setVisibility(View.VISIBLE);
- supportInvalidateOptionsMenu();
- } else {
- finish();
- }
- }
-
- };
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.channelview, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- boolean channelLoaded = channel != null;
- boolean beingDownloaded = channelLoaded
- && DownloadRequester.getInstance().isDownloadingFile(
- channel.getDownloadUrl());
- boolean notAdded = channelLoaded
- && !((feedExists(
- channel.getDownloadUrl()) || beingDownloaded));
- menu.findItem(R.id.add_feed).setVisible(notAdded);
- menu.findItem(R.id.visit_website_item).setVisible(
- channelLoaded && channel.getWebsiteUrl() != null);
- return true;
- }
-
- @SuppressLint("NewApi")
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- case R.id.visit_website_item:
- Uri uri = Uri.parse(channel.getWebsiteUrl());
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
- return true;
- case R.id.add_feed:
- try {
- DownloadRequester.getInstance().downloadFeed(
- this,
- new Feed(channel.getDownloadUrl(), new Date(), channel
- .getName()));
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
- Toast toast = Toast.makeText(this, R.string.miro_feed_added,
- Toast.LENGTH_LONG);
- toast.show();
- supportInvalidateOptionsMenu();
- return true;
- default:
- return false;
- }
- }
-
- private boolean feedExists(String downloadUrl) {
- if (feeds == null) {
- return false;
- }
-
- for (Feed feed : feeds) {
- if (feed.getDownload_url().equals(downloadUrl)) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java
deleted file mode 100644
index 9f74e77b6..000000000
--- a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.annotation.SuppressLint;
-import android.app.SearchManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.NavUtils;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.widget.SearchView;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideException;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideService;
-import de.danoeh.antennapod.preferences.UserPreferences;
-
-/**
- * Shows a list of available categories and offers a search button. If the user
- * selects a category, the MiroGuideCategoryActivity is started.
- */
-public class MiroGuideMainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
- private static final String TAG = "MiroGuideMainActivity";
-
- private static String[] categories;
- private ArrayAdapter<String> listAdapter;
-
- private TextView txtvStatus;
- private ListView listView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.miroguide_categorylist);
-
- txtvStatus = (TextView) findViewById(android.R.id.empty);
- listView = (ListView) findViewById(android.R.id.list);
- listView.setOnItemClickListener(this);
- listView.setEmptyView(txtvStatus);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (categories != null) {
- createAdapter();
- } else {
- loadCategories();
- }
- }
-
- private void createAdapter() {
- if (categories != null) {
- listAdapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1, categories);
- txtvStatus.setText(R.string.no_items_label);
- listView.setAdapter(listAdapter);
- }
- }
-
- /**
- * Launches an AsyncTask to load the available categories in the background.
- */
- @SuppressLint("NewApi")
- private void loadCategories() {
- AsyncTask<Void, Void, Void> listLoader = new AsyncTask<Void, Void, Void>() {
-
- private String[] c;
- private MiroGuideException exception;
-
- @Override
- protected void onPostExecute(Void result) {
- if (exception == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Successfully loaded categories");
- categories = c;
- createAdapter();
- } else {
- Log.e(TAG, "Error happened while trying to load categories");
- txtvStatus.setText(exception.getMessage());
- }
- }
-
- @Override
- protected void onPreExecute() {
- txtvStatus.setText(R.string.loading_categories_label);
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- MiroGuideService service = new MiroGuideService();
- try {
- c = service.getCategories();
- } catch (MiroGuideException e) {
- e.printStackTrace();
- exception = e;
- } finally {
- service.close();
- }
- return null;
- }
-
- };
-
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- listLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- listLoader.execute();
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
- .setIcon(
- obtainStyledAttributes(
- new int[]{R.attr.action_search})
- .getDrawable(0)),
- MenuItem.SHOW_AS_ACTION_IF_ROOM);
- MenuItemCompat.setActionView(menu.findItem(R.id.search_item), new SearchView(this));
-
- SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search_item));
- searchView.setIconifiedByDefault(true);
- searchView.setSearchableInfo(
- searchManager.getSearchableInfo(getComponentName()));
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
- String selection = listAdapter.getItem(position);
- Intent launchIntent = new Intent(this, MiroGuideCategoryActivity.class);
- launchIntent.putExtra(MiroGuideCategoryActivity.EXTRA_CATEGORY,
- selection);
- startActivity(launchIntent);
- }
-}
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java
deleted file mode 100644
index e20253dc6..000000000
--- a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.MiroGuideChannellistFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-
-/**
- * Displays results when a search for miroguide channels has been performed. It
- * uses a MiroGuideChannelListFragment to display the results.
- */
-public class MiroGuideSearchActivity extends ActionBarActivity {
- private static final String TAG = "MiroGuideSearchActivity";
-
- private MiroGuideChannellistFragment listFragment;
-
- @Override
- protected void onCreate(Bundle arg0) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(arg0);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.miroguidesearch);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Intent intent = getIntent();
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- String query = intent.getStringExtra(SearchManager.QUERY);
- getSupportActionBar()
- .setSubtitle(
- getString(R.string.search_term_label) + "\""
- + query + "\"");
- handleSearchRequest(query);
- }
- }
-
- private void handleSearchRequest(String query) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Performing search");
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- listFragment = MiroGuideChannellistFragment.newInstance("name", query,
- "name");
- ft.replace(R.id.channellistFragment, listFragment);
- ft.commit();
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- setIntent(intent);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
- .setIcon(
- obtainStyledAttributes(
- new int[]{R.attr.action_search})
- .getDrawable(0)),
- MenuItem.SHOW_AS_ACTION_IF_ROOM);
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- case R.id.search_item:
- onSearchRequested();
- return true;
- default:
- return false;
- }
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index 6bd5e4eb9..6dd4b4edc 100644
--- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -5,6 +5,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
@@ -22,17 +23,20 @@ import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.service.download.HttpDownloader;
import de.danoeh.antennapod.syndication.handler.FeedHandler;
+import de.danoeh.antennapod.syndication.handler.FeedHandlerResult;
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.FileNameGenerator;
import de.danoeh.antennapod.util.StorageUtils;
import de.danoeh.antennapod.util.URLChecker;
+import org.apache.commons.lang3.StringUtils;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.Date;
+import java.util.Map;
/**
* Downloads a feed from a feed URL and parses it. Subclasses can display the
@@ -46,12 +50,15 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
private static final String TAG = "OnlineFeedViewActivity";
public static final String ARG_FEEDURL = "arg.feedurl";
- /** Optional argument: specify a title for the actionbar. */
+ /**
+ * Optional argument: specify a title for the actionbar.
+ */
public static final String ARG_TITLE = "title";
public static final int RESULT_ERROR = 2;
private Feed feed;
+ private Map<String, String> alternateFeedUrls;
private Downloader downloader;
@Override
@@ -64,11 +71,21 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
}
StorageUtils.checkStorageAvailability(this);
- final String feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
- if (feedUrl == null) {
+
+ final String feedUrl;
+ if (getIntent().hasExtra(ARG_FEEDURL)) {
+ feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
+ } else if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
+ || StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
+ feedUrl = (StringUtils.equals(getIntent().getAction(), Intent.ACTION_SEND))
+ ? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString();
+
+ getSupportActionBar().setTitle(R.string.add_new_feed_label);
+ } else {
throw new IllegalArgumentException(
"Activity must be started with feedurl argument!");
}
+
if (BuildConfig.DEBUG)
Log.d(TAG, "Activity was started with url " + feedUrl);
setLoadingLayout();
@@ -146,7 +163,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
.toString();
feed.setFile_url(fileUrl);
final DownloadRequest request = new DownloadRequest(feed.getFile_url(),
- feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED, username, password);
+ feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED, username, password, true);
downloader = new HttpDownloader(
request);
new Thread() {
@@ -181,7 +198,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
}
private void parseFeed() {
- if (feed == null || feed.getFile_url() == null) {
+ if (feed == null || feed.getFile_url() == null && feed.isDownloaded()) {
throw new IllegalStateException(
"feed must be non-null and downloaded when parseFeed is called");
}
@@ -197,7 +214,9 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
boolean successful = false;
FeedHandler handler = new FeedHandler();
try {
- handler.parseFeed(feed);
+ FeedHandlerResult result = handler.parseFeed(feed);
+ feed = result.feed;
+ alternateFeedUrls = result.alternateFeedUrls;
successful = true;
} catch (SAXException e) {
e.printStackTrace();
@@ -221,7 +240,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
runOnUiThread(new Runnable() {
@Override
public void run() {
- showFeedInformation(feed);
+ showFeedInformation(feed, alternateFeedUrls);
}
});
} else {
@@ -244,7 +263,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
/**
* Can be used to load data asynchronously.
- * */
+ */
protected void loadData() {
}
@@ -252,7 +271,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
/**
* Called when feed parsed successfully
*/
- protected void showFeedInformation(Feed feed) {
+ protected void showFeedInformation(Feed feed, Map<String, String> alternateFeedUrls) {
}
@@ -271,7 +290,8 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
- });
+ }
+ );
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
diff --git a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java
deleted file mode 100644
index 6e2cf597f..000000000
--- a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java
+++ /dev/null
@@ -1,307 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.*;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import com.mobeta.android.dslv.DragSortListView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.ImageLoader;
-import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DBTasks;
-import de.danoeh.antennapod.storage.DBWriter;
-import de.danoeh.antennapod.util.UndoBarController;
-
-import java.util.List;
-
-public class OrganizeQueueActivity extends ActionBarActivity implements
- UndoBarController.UndoListener {
- private static final String TAG = "OrganizeQueueActivity";
-
- private static final int MENU_ID_ACCEPT = 2;
-
- private List<FeedItem> queue;
-
- private OrganizeAdapter adapter;
- private UndoBarController undoBarController;
-
- private DragSortListView listView;
- private TextView emptyView;
- private ProgressBar progLoading;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.organize_queue);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- listView = (DragSortListView) findViewById(android.R.id.list);
- emptyView = (TextView) findViewById(android.R.id.empty);
- progLoading = (ProgressBar) findViewById(R.id.progLoading);
-
- listView.setDropListener(dropListener);
- listView.setRemoveListener(removeListener);
- listView.setEmptyView(findViewById(android.R.id.empty));
-
- loadData();
- undoBarController = new UndoBarController(findViewById(R.id.undobar),
- this);
- }
-
- private void loadData() {
- AsyncTask<Void, Void, List<FeedItem>> loadTask = new AsyncTask<Void, Void, List<FeedItem>>() {
-
- @Override
- protected List<FeedItem> doInBackground(Void... voids) {
- return DBReader.getQueue(OrganizeQueueActivity.this);
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- // do not show loading animation if queue is already loaded
- if (queue == null) {
- progLoading.setVisibility(View.VISIBLE);
- listView.setVisibility(View.GONE);
- emptyView.setVisibility(View.GONE);
- }
- }
-
- @Override
- protected void onPostExecute(List<FeedItem> feedItems) {
- super.onPostExecute(feedItems);
- if (feedItems != null) {
- queue = feedItems;
- if (adapter == null) {
- adapter = new OrganizeAdapter(OrganizeQueueActivity.this);
- listView.setAdapter(adapter);
- }
- adapter.notifyDataSetChanged();
- } else {
- Log.e(TAG, "Queue was null");
- }
- progLoading.setVisibility(View.GONE);
- listView.setVisibility(View.VISIBLE);
- }
- };
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- loadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- loadTask.execute();
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- EventDistributor.getInstance().unregister(contentUpdate);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- DBTasks.autodownloadUndownloadedItems(getApplicationContext());
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- EventDistributor.getInstance().register(contentUpdate);
- }
-
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if (((EventDistributor.QUEUE_UPDATE | EventDistributor.FEED_LIST_UPDATE) & arg) != 0) {
- loadData();
- }
- }
- };
-
- private DragSortListView.DropListener dropListener = new DragSortListView.DropListener() {
-
- @Override
- public void drop(int from, int to) {
- final FeedItem item = queue.remove(from);
- queue.add(to, item);
- adapter.notifyDataSetChanged();
- DBWriter.moveQueueItem(OrganizeQueueActivity.this, from, to, true);
- }
- };
-
- private DragSortListView.RemoveListener removeListener = new DragSortListView.RemoveListener() {
-
- @Override
- public void remove(int which) {
- FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
- DBWriter.removeQueueItem(OrganizeQueueActivity.this, item.getId(), true);
- undoBarController.showUndoBar(false,
- getString(R.string.removed_from_queue), new UndoToken(item,
- which));
- }
- };
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public void onUndo(Parcelable token) {
- // Perform the undo
- UndoToken undoToken = (UndoToken) token;
- if (token != null) {
- long itemId = undoToken.getFeedItemId();
- int position = undoToken.getPosition();
- DBWriter.addQueueItemAt(OrganizeQueueActivity.this, itemId, position, false);
- }
- }
-
- private static class OrganizeAdapter extends BaseAdapter {
-
- private OrganizeQueueActivity organizeQueueActivity;
-
- public OrganizeAdapter(OrganizeQueueActivity organizeQueueActivity) {
- super();
- this.organizeQueueActivity = organizeQueueActivity;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- final FeedItem item = getItem(position);
-
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) organizeQueueActivity
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(
- R.layout.organize_queue_listitem, null);
- holder.title = (TextView) convertView
- .findViewById(R.id.txtvTitle);
- holder.feedTitle = (TextView) convertView
- .findViewById(R.id.txtvFeedname);
-
- holder.feedImage = (ImageView) convertView
- .findViewById(R.id.imgvFeedimage);
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- holder.title.setText(item.getTitle());
- holder.feedTitle.setText(item.getFeed().getTitle());
-
- holder.feedImage.setTag(item.getImageLoaderCacheKey());
- ImageLoader.getInstance().loadThumbnailBitmap(
- item,
- holder.feedImage,
- (int) convertView.getResources().getDimension(
- R.dimen.thumbnail_length));
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView feedTitle;
- ImageView feedImage;
- }
-
- @Override
- public int getCount() {
- if (organizeQueueActivity.queue != null) {
- return organizeQueueActivity.queue.size();
- } else {
- return 0;
- }
- }
-
- @Override
- public FeedItem getItem(int position) {
- if (organizeQueueActivity.queue != null) {
- return organizeQueueActivity.queue.get(position);
- } else {
- return null;
- }
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- }
-
- private static class UndoToken implements Parcelable {
- private long itemId;
- private long feedId;
- private int position;
-
- public UndoToken(FeedItem item, int position) {
- this.itemId = item.getId();
- this.feedId = item.getFeed().getId();
- this.position = position;
- }
-
- private UndoToken(Parcel in) {
- itemId = in.readLong();
- feedId = in.readLong();
- position = in.readInt();
- }
-
- public static final Parcelable.Creator<UndoToken> CREATOR = new Parcelable.Creator<UndoToken>() {
- public UndoToken createFromParcel(Parcel in) {
- return new UndoToken(in);
- }
-
- public UndoToken[] newArray(int size) {
- return new UndoToken[size];
- }
- };
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(itemId);
- out.writeLong(feedId);
- out.writeInt(position);
- }
-
- public long getFeedItemId() {
- return itemId;
- }
-
- public int getPosition() {
- return position;
- }
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java
deleted file mode 100644
index ba3d12105..000000000
--- a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.DBWriter;
-
-public class PlaybackHistoryActivity extends ActionBarActivity {
- private static final String TAG = "PlaybackHistoryActivity";
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.clear_history_item, Menu.NONE,
- R.string.clear_history_label),
- MenuItem.SHOW_AS_ACTION_IF_ROOM);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- case R.id.clear_history_item:
- DBWriter.clearPlaybackHistory(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- protected void onCreate(Bundle arg0) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(arg0);
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Activity created");
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.playbackhistory_activity);
-
- FragmentTransaction fT = getSupportFragmentManager().beginTransaction();
- fT.replace(R.id.playbackhistory_fragment, new PlaybackHistoryFragment());
- fT.commit();
- }
-
-}
diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java
deleted file mode 100644
index f330aeb7d..000000000
--- a/src/de/danoeh/antennapod/activity/SearchActivity.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.TextView;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.SearchlistAdapter;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.SearchResult;
-import de.danoeh.antennapod.fragment.FeedlistFragment;
-import de.danoeh.antennapod.fragment.ItemlistFragment;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.storage.FeedSearcher;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Displays the results when the user searches for FeedItems or Feeds.
- */
-public class SearchActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
- private static final String TAG = "SearchActivity";
-
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.searchactivity.extra.feedId";
-
- private SearchlistAdapter searchAdapter;
-
- /**
- * ID of the feed that is being searched or null if the search is global.
- */
- private long feedID;
-
- private ListView listView;
- private TextView txtvStatus;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.searchlist);
- listView = (ListView) findViewById(android.R.id.list);
- txtvStatus = (TextView) findViewById(android.R.id.empty);
-
- listView.setOnItemClickListener(this);
- searchAdapter = new SearchlistAdapter(this, 0, new ArrayList<SearchResult>());
- listView.setAdapter(searchAdapter);
- listView.setEmptyView(txtvStatus);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- setIntent(intent);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Intent intent = getIntent();
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- if (intent.hasExtra(SearchActivity.EXTRA_FEED_ID)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Found bundle extra");
- feedID = intent.getLongExtra(SearchActivity.EXTRA_FEED_ID, 0);
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting search");
- String query = intent.getStringExtra(SearchManager.QUERY);
- getSupportActionBar()
- .setSubtitle(
- getString(R.string.search_term_label) + "\""
- + query + "\"");
- handleSearchRequest(query);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
- .setIcon(
- obtainStyledAttributes(
- new int[]{R.attr.action_search})
- .getDrawable(0)),
- (MenuItem.SHOW_AS_ACTION_IF_ROOM));
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- Intent intent = new Intent(this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- return true;
- case R.id.search_item:
- onSearchRequested();
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public boolean onSearchRequested() {
- Bundle extra = null;
- if (feedID != 0) {
- extra = new Bundle();
- extra.putLong(EXTRA_FEED_ID, feedID);
- }
- startSearch(null, false, extra, false);
- return true;
- }
-
- @SuppressLint({"NewApi", "NewApi"})
- private void handleSearchRequest(final String query) {
- if (searchAdapter != null) {
- searchAdapter.clear();
- searchAdapter.notifyDataSetChanged();
- }
- txtvStatus.setText(R.string.search_status_searching);
-
- Thread thread = new Thread() {
-
- @Override
- public void run() {
- Log.d(TAG, "Starting background work");
- final Activity activity = SearchActivity.this;
- final List<SearchResult> result = FeedSearcher
- .performSearch(activity, query, feedID);
- activity.runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Background work finished");
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Found " + result.size()
- + " results");
-
- searchAdapter.clear();
- for (SearchResult s : result) {
- searchAdapter.add(s);
- }
- searchAdapter.notifyDataSetChanged();
- txtvStatus
- .setText(R.string.search_status_no_results);
- if (!searchAdapter.isEmpty()) {
- txtvStatus.setVisibility(View.GONE);
- } else {
- txtvStatus.setVisibility(View.VISIBLE);
- }
- }
- });
-
- }
- };
- thread.start();
-
- }
-
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
- SearchResult selection = searchAdapter.getItem(position);
- if (selection.getComponent().getClass() == Feed.class) {
- Feed feed = (Feed) selection.getComponent();
- Intent launchIntent = new Intent(this, FeedItemlistActivity.class);
- launchIntent.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED,
- feed.getId());
- startActivity(launchIntent);
-
- } else if (selection.getComponent().getClass() == FeedItem.class) {
- FeedItem item = (FeedItem) selection.getComponent();
- Intent launchIntent = new Intent(this, ItemviewActivity.class);
- launchIntent.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED, item
- .getFeed().getId());
- launchIntent.putExtra(ItemlistFragment.EXTRA_SELECTED_FEEDITEM,
- item.getId());
- startActivity(launchIntent);
- }
- }
-}
diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java
deleted file mode 100644
index 7ee0a9ac9..000000000
--- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package de.danoeh.antennapod.activity.gpoddernet;
-
-import android.app.SearchManager;
-import android.content.Context;
-import android.os.Bundle;
-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.MenuItem;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.preferences.UserPreferences;
-
-/**
- * Created by daniel on 23.08.13.
- */
-public class GpodnetActivity extends ActionBarActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
- .setIcon(
- obtainStyledAttributes(
- new int[]{R.attr.action_search})
- .getDrawable(0)),
- MenuItem.SHOW_AS_ACTION_IF_ROOM);
- MenuItemCompat.setActionView(menu.findItem(R.id.search_item), new SearchView(this));
-
- SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search_item));
- searchView.setIconifiedByDefault(true);
- searchView.setSearchableInfo(
- searchManager.getSearchableInfo(getComponentName()));
-
- return true;
- }
-}
diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java
deleted file mode 100644
index e77a6a7a3..000000000
--- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package de.danoeh.antennapod.activity.gpoddernet;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.NavUtils;
-import android.support.v4.view.ViewPager;
-import android.view.MenuItem;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.gpodnet.PodcastTopListFragment;
-import de.danoeh.antennapod.fragment.gpodnet.SuggestionListFragment;
-import de.danoeh.antennapod.fragment.gpodnet.TagListFragment;
-
-/**
- * Created by daniel on 22.08.13.
- */
-public class GpodnetMainActivity extends GpodnetActivity {
- private static final String TAG = "GPodnetMainActivity";
-
- private static final int POS_TAGS = 0;
- private static final int POS_TOPLIST = 1;
- private static final int POS_SUGGESTIONS = 2;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.gpodnet_main);
- ViewPager viewpager = (ViewPager) findViewById(R.id.viewpager);
- viewpager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private class PagerAdapter extends FragmentStatePagerAdapter {
-
- private static final int NUM_PAGES_LOGGED_OUT = 2;
- private static final int NUM_PAGES_LOGGED_IN = 3;
- private final int NUM_PAGES;
-
- public PagerAdapter(FragmentManager fm) {
- super(fm);
- NUM_PAGES = NUM_PAGES_LOGGED_OUT;
- }
-
- @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/activity/gpoddernet/GpodnetSearchActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java
deleted file mode 100644
index 199b45dc9..000000000
--- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package de.danoeh.antennapod.activity.gpoddernet;
-
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.NavUtils;
-import android.view.MenuItem;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.gpodnet.SearchListFragment;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * Created by daniel on 23.08.13.
- */
-public class GpodnetSearchActivity extends GpodnetActivity {
-
- private SearchListFragment searchFragment;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.gpodnet_search);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Intent intent = getIntent();
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_SEARCH)) {
- handleSearchRequest(intent.getStringExtra(SearchManager.QUERY));
- }
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- setIntent(intent);
- }
-
- private void handleSearchRequest(String query) {
- getSupportActionBar().setSubtitle(getString(R.string.search_term_label) + query);
- if (searchFragment == null) {
- FragmentTransaction transaction = getSupportFragmentManager()
- .beginTransaction();
- searchFragment = SearchListFragment.newInstance(query);
- transaction.replace(R.id.searchListFragment, searchFragment);
- transaction.commit();
- } else {
- searchFragment.changeQuery(query);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java
deleted file mode 100644
index 14897c60c..000000000
--- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package de.danoeh.antennapod.activity.gpoddernet;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.NavUtils;
-import android.view.MenuItem;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.fragment.gpodnet.PodcastListFragment;
-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;
-
-/**
- * Created by daniel on 23.08.13.
- */
-public class GpodnetTagActivity extends GpodnetActivity{
-
- private static final int PODCAST_COUNT = 50;
- public static final String ARG_TAGNAME = "tagname";
-
- private GpodnetTag tag;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.gpodnet_tag_activity);
-
- if (!getIntent().hasExtra(ARG_TAGNAME)) {
- throw new IllegalArgumentException("No tagname argument");
- }
- tag = new GpodnetTag(getIntent().getStringExtra(ARG_TAGNAME));
- getSupportActionBar().setTitle(tag.getName());
-
- FragmentTransaction transaction = getSupportFragmentManager()
- .beginTransaction();
- Fragment taglistFragment = new TaglistFragment();
- transaction.replace(R.id.taglistFragment, taglistFragment);
- transaction.commit();
- }
-
- private class TaglistFragment extends PodcastListFragment {
-
- @Override
- protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException {
- return service.getPodcastsForTag(tag, PODCAST_COUNT);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java
new file mode 100644
index 000000000..17c61a86c
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -0,0 +1,67 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.view.View;
+import android.widget.ImageButton;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+/**
+ * Utility methods for the action button that is displayed on the right hand side
+ * of a listitem.
+ */
+public class ActionButtonUtils {
+
+ private final int[] labels;
+ private final TypedArray drawables;
+ private final Context context;
+
+ public ActionButtonUtils(Context context) {
+ if (context == null) throw new IllegalArgumentException("context = null");
+ this.context = context;
+ drawables = context.obtainStyledAttributes(new int[]{
+ R.attr.av_play, R.attr.navigation_cancel, R.attr.av_download, R.attr.navigation_chapters});
+ labels = new int[]{R.string.play_label, R.string.cancel_download_label, R.string.download_label};
+ }
+
+ /**
+ * Sets the displayed bitmap and content description of the given
+ * action button so that it matches the state of the FeedItem.
+ */
+ public void configureActionButton(ImageButton butSecondary, FeedItem item) {
+ if (butSecondary == null || item == null) throw new IllegalArgumentException("butSecondary or item was null");
+ final FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ butSecondary.setImageDrawable(drawables
+ .getDrawable(1));
+ butSecondary.setContentDescription(context.getString(labels[1]));
+ } else {
+ // item is not downloaded and not being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ butSecondary.setImageDrawable(drawables.getDrawable(2));
+ butSecondary.setContentDescription(context.getString(labels[2]));
+ }
+ } else {
+ // item is not being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ if (media.isPlaying()) {
+ butSecondary.setImageDrawable(drawables.getDrawable(3));
+ } else {
+ butSecondary
+ .setImageDrawable(drawables.getDrawable(0));
+ }
+ butSecondary.setContentDescription(context.getString(labels[0]));
+ }
+ } else {
+ butSecondary.setVisibility(View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
new file mode 100644
index 000000000..3acd587af
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.widget.Toast;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DBTasks;
+import de.danoeh.antennapod.storage.DownloadRequestException;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+/**
+ * Default implementation of an ActionButtonCallback
+ */
+public class DefaultActionButtonCallback implements ActionButtonCallback {
+ private static final String TAG = "DefaultActionButtonCallback";
+
+ private final Context context;
+
+ public DefaultActionButtonCallback(Context context) {
+ if (context == null) throw new IllegalArgumentException("context = null");
+ this.context = context;
+ }
+
+ @Override
+ public void onActionButtonPressed(final FeedItem item) {
+ final FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ if (!isDownloading && !media.isDownloaded()) {
+ try {
+ DBTasks.downloadFeedItems(context, item);
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ } else if (isDownloading) {
+ DownloadRequester.getInstance().cancelDownload(context, media);
+ Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show();
+ } else { // media is downloaded
+ DBTasks.playMedia(context, media, true, true, false);
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java
deleted file mode 100644
index e384ecffc..000000000
--- a/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Adapter;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.MediaType;
-import de.danoeh.antennapod.util.Converter;
-
-public class DefaultFeedItemlistAdapter extends BaseAdapter {
-
- ItemAccess itemAccess;
- private Context context;
-
- public DefaultFeedItemlistAdapter(Context context, ItemAccess itemAccess) {
- super();
- this.context = context;
- if (itemAccess == null) {
- throw new IllegalArgumentException("itemAccess must not be null");
- }
- this.itemAccess = itemAccess;
- }
-
- @Override
- public int getCount() {
- return itemAccess.getCount();
-
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public FeedItem getItem(int position) {
- return itemAccess.getItem(position);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- final FeedItem item = getItem(position);
-
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.default_feeditemlist_item, null);
- holder.title = (TextView) convertView
- .findViewById(R.id.txtvItemname);
- holder.lenSize = (TextView) convertView
- .findViewById(R.id.txtvLenSize);
-
- holder.published = (TextView) convertView
- .findViewById(R.id.txtvPublished);
- holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
- convertView.setTag(holder);
-
- } else {
- holder = (Holder) convertView.getTag();
- }
- if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) {
- convertView.setVisibility(View.VISIBLE);
- holder.title.setText(item.getTitle());
- holder.published.setText(convertView.getResources().getString(
- R.string.published_prefix)
- + DateUtils.getRelativeTimeSpanString(
- item.getPubDate().getTime(),
- System.currentTimeMillis(), 0, 0));
- if (item.getMedia() == null) {
- holder.type.setVisibility(View.GONE);
- holder.lenSize.setVisibility(View.GONE);
- } else {
- holder.lenSize.setVisibility(View.VISIBLE);
- holder.lenSize.setText(convertView.getResources().getString(
- R.string.size_prefix)
- + Converter.byteToString(item.getMedia().getSize()));
-
- TypedArray typeDrawables = context
- .obtainStyledAttributes(new int[] { R.attr.type_audio,
- R.attr.type_video });
- MediaType mediaType = item.getMedia().getMediaType();
- if (mediaType == MediaType.AUDIO) {
- holder.type.setImageDrawable(typeDrawables.getDrawable(0));
- holder.type.setContentDescription(context.getString(R.string.media_type_audio_label));
- holder.type.setVisibility(View.VISIBLE);
- } else if (mediaType == MediaType.VIDEO) {
- holder.type.setImageDrawable(typeDrawables.getDrawable(1));
- holder.type.setContentDescription(context.getString(R.string.media_type_video_label));
- holder.type.setVisibility(View.VISIBLE);
- } else {
- holder.type.setImageBitmap(null);
- holder.type.setVisibility(View.GONE);
- }
- }
-
- } else {
- convertView.setVisibility(View.GONE);
- }
- return convertView;
- }
-
- protected static class Holder {
- TextView title;
- TextView published;
- TextView lenSize;
- ImageView type;
-
- }
-
- public static interface ItemAccess {
- int getCount();
-
- FeedItem getItem(int position);
- }
-
- protected Context getContext() {
- return context;
- }
-}
diff --git a/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
new file mode 100644
index 000000000..0bf770df2
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -0,0 +1,119 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * Shows a list of downloaded episodes
+ */
+public class DownloadedEpisodesListAdapter extends BaseAdapter {
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+
+ public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.downloaded_episodeslist_item,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+ holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize()));
+ FeedItem.State state = item.getState();
+
+ if (state == FeedItem.State.PLAYING) {
+ holder.butSecondary.setEnabled(false);
+ } else {
+ holder.butSecondary.setEnabled(true);
+ }
+
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ itemAccess.onFeedItemSecondaryAction(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ TextView pubDate;
+ ImageView imageView;
+ TextView txtvSize;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ void onFeedItemSecondaryAction(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
index 2739d2f27..fa2e5a0a7 100644
--- a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
@@ -4,7 +4,8 @@ import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
@@ -14,86 +15,128 @@ import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ThemeUtils;
-import java.util.List;
-
-public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
- private int selectedItemIndex;
-
- public static final int SELECTION_NONE = -1;
-
- public DownloadlistAdapter(Context context, int textViewResourceId,
- List<Downloader> objects) {
- super(context, textViewResourceId, objects);
- this.selectedItemIndex = SELECTION_NONE;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- DownloadRequest request = getItem(position).getDownloadRequest();
- // Inflate layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.downloadlist_item, null);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.message = (TextView) convertView
- .findViewById(R.id.txtvMessage);
- holder.downloaded = (TextView) convertView
- .findViewById(R.id.txtvDownloaded);
- holder.percent = (TextView) convertView
- .findViewById(R.id.txtvPercent);
- holder.progbar = (ProgressBar) convertView
- .findViewById(R.id.progProgress);
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources().getColor(
- ThemeUtils.getSelectionBackgroundColor()));
- } else {
- convertView.setBackgroundResource(0);
- }
-
- holder.title.setText(request.getTitle());
- if (request.getStatusMsg() != 0) {
- holder.message.setText(request.getStatusMsg());
- }
- String strDownloaded = Converter.byteToString(request.getSoFar());
- if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
- strDownloaded += " / " + Converter.byteToString(request.getSize());
- holder.percent.setText(request.getProgressPercent() + "%");
- holder.progbar.setProgress(request.getProgressPercent());
- holder.percent.setVisibility(View.VISIBLE);
- } else {
- holder.progbar.setProgress(0);
- holder.percent.setVisibility(View.INVISIBLE);
- }
-
- holder.downloaded.setText(strDownloaded);
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView message;
- TextView downloaded;
- TextView percent;
- ProgressBar progbar;
- }
-
- public int getSelectedItemIndex() {
- return selectedItemIndex;
- }
-
- public void setSelectedItemIndex(int selectedItemIndex) {
- this.selectedItemIndex = selectedItemIndex;
- notifyDataSetChanged();
- }
+public class DownloadlistAdapter extends BaseAdapter {
+
+ public static final int SELECTION_NONE = -1;
+
+ private int selectedItemIndex;
+ private ItemAccess itemAccess;
+ private Context context;
+
+ public DownloadlistAdapter(Context context,
+ ItemAccess itemAccess) {
+ super();
+ this.selectedItemIndex = SELECTION_NONE;
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Downloader getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ Downloader downloader = getItem(position);
+ DownloadRequest request = downloader.getDownloadRequest();
+ // Inflate layout
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.downloadlist_item, null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.message = (TextView) convertView
+ .findViewById(R.id.txtvMessage);
+ holder.downloaded = (TextView) convertView
+ .findViewById(R.id.txtvDownloaded);
+ holder.percent = (TextView) convertView
+ .findViewById(R.id.txtvPercent);
+ holder.progbar = (ProgressBar) convertView
+ .findViewById(R.id.progProgress);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ if (position == selectedItemIndex) {
+ convertView.setBackgroundColor(convertView.getResources().getColor(
+ ThemeUtils.getSelectionBackgroundColor()));
+ } else {
+ convertView.setBackgroundResource(0);
+ }
+
+ holder.title.setText(request.getTitle());
+ if (request.getStatusMsg() != 0) {
+ holder.message.setText(request.getStatusMsg());
+ }
+ String strDownloaded = Converter.byteToString(request.getSoFar());
+ if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
+ strDownloaded += " / " + Converter.byteToString(request.getSize());
+ holder.percent.setText(request.getProgressPercent() + "%");
+ holder.progbar.setProgress(request.getProgressPercent());
+ holder.percent.setVisibility(View.VISIBLE);
+ } else {
+ holder.progbar.setProgress(0);
+ holder.percent.setVisibility(View.INVISIBLE);
+ }
+
+ holder.downloaded.setText(strDownloaded);
+
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(downloader);
+ holder.butSecondary.setOnClickListener(butSecondaryListener);
+
+ return convertView;
+ }
+
+ private View.OnClickListener butSecondaryListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Downloader downloader = (Downloader) v.getTag();
+ itemAccess.onSecondaryActionClick(downloader);
+ }
+ };
+
+ static class Holder {
+ TextView title;
+ TextView message;
+ TextView downloaded;
+ TextView percent;
+ ProgressBar progbar;
+ ImageButton butSecondary;
+ }
+
+ public int getSelectedItemIndex() {
+ return selectedItemIndex;
+ }
+
+ public void setSelectedItemIndex(int selectedItemIndex) {
+ this.selectedItemIndex = selectedItemIndex;
+ notifyDataSetChanged();
+ }
+
+ public interface ItemAccess {
+ public int getCount();
+
+ public Downloader getItem(int position);
+
+ public void onSecondaryActionClick(Downloader downloader);
+ }
}
diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
index aa724f991..9a7b607aa 100644
--- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
@@ -227,10 +227,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feeditemlist_header, null);
TextView headerTitle = (TextView) convertView
- .findViewById(R.id.txtvHeaderTitle);
+ .findViewById(0);
ImageButton actionButton = (ImageButton) convertView
.findViewById(R.id.butAction);
- TextView numItems = (TextView) convertView.findViewById(R.id.txtvNumItems);
+ TextView numItems = (TextView) convertView.findViewById(0);
String headerString = null;
int childrenCount = 0;
diff --git a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
new file mode 100644
index 000000000..5475f122f
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -0,0 +1,243 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.feed.MediaType;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.Converter;
+import de.danoeh.antennapod.util.ThemeUtils;
+
+/**
+ * List adapter for items of feeds that the user has already subscribed to.
+ */
+public class FeedItemlistAdapter extends BaseAdapter {
+
+ private ActionButtonCallback callback;
+ private final ItemAccess itemAccess;
+ private final Context context;
+ private boolean showFeedtitle;
+ private int selectedItemIndex;
+ private final ActionButtonUtils actionButtonUtils;
+
+ public static final int SELECTION_NONE = -1;
+
+ public FeedItemlistAdapter(Context context,
+ ItemAccess itemAccess,
+ ActionButtonCallback callback, boolean showFeedtitle) {
+ super();
+ this.callback = callback;
+ this.context = context;
+ this.itemAccess = itemAccess;
+ this.showFeedtitle = showFeedtitle;
+ this.selectedItemIndex = SELECTION_NONE;
+ this.actionButtonUtils = new ActionButtonUtils(context);
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = getItem(position);
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.feeditemlist_item, null);
+ holder.title = (TextView) convertView
+ .findViewById(R.id.txtvItemname);
+ holder.lenSize = (TextView) convertView
+ .findViewById(R.id.txtvLenSize);
+ holder.butAction = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.published = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.inPlaylist = (ImageView) convertView
+ .findViewById(R.id.imgvInPlaylist);
+ holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
+ holder.statusUnread = (View) convertView
+ .findViewById(R.id.statusUnread);
+ holder.episodeProgress = (ProgressBar) convertView
+ .findViewById(R.id.pbar_episode_progress);
+
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+ if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) {
+ convertView.setVisibility(View.VISIBLE);
+ if (position == selectedItemIndex) {
+ convertView.setBackgroundColor(convertView.getResources()
+ .getColor(ThemeUtils.getSelectionBackgroundColor()));
+ } else {
+ convertView.setBackgroundResource(0);
+ }
+
+ StringBuilder buffer = new StringBuilder(item.getTitle());
+ if (showFeedtitle) {
+ buffer.append("(");
+ buffer.append(item.getFeed().getTitle());
+ buffer.append(")");
+ }
+ holder.title.setText(buffer.toString());
+
+ FeedItem.State state = item.getState();
+ switch (state) {
+ case PLAYING:
+ holder.statusUnread.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ break;
+ case IN_PROGRESS:
+ holder.statusUnread.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ break;
+ case NEW:
+ holder.statusUnread.setVisibility(View.VISIBLE);
+ break;
+ default:
+ holder.statusUnread.setVisibility(View.GONE);
+ break;
+ }
+
+ holder.published.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+
+
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ holder.episodeProgress.setVisibility(View.GONE);
+ holder.inPlaylist.setVisibility(View.INVISIBLE);
+ holder.type.setVisibility(View.INVISIBLE);
+ holder.lenSize.setVisibility(View.INVISIBLE);
+ } else {
+
+ if (state == FeedItem.State.PLAYING
+ || state == FeedItem.State.IN_PROGRESS) {
+ if (media.getDuration() > 0) {
+ holder.episodeProgress
+ .setProgress((int) (((double) media
+ .getPosition()) / media.getDuration() * 100));
+ holder.lenSize.setText(Converter
+ .getDurationStringLong(media.getDuration()
+ - media.getPosition()));
+ }
+ } else if (!media.isDownloaded()) {
+ holder.lenSize.setText(context.getString(
+ R.string.size_prefix)
+ + Converter.byteToString(media.getSize()));
+ } else {
+ holder.lenSize.setText(context.getString(
+ R.string.length_prefix)
+ + Converter.getDurationStringLong(media
+ .getDuration()));
+ }
+
+ holder.lenSize.setVisibility(View.VISIBLE);
+ if (((ItemAccess) itemAccess).isInQueue(item)) {
+ holder.inPlaylist.setVisibility(View.VISIBLE);
+ } else {
+ holder.inPlaylist.setVisibility(View.INVISIBLE);
+ }
+
+ if (DownloadRequester.getInstance().isDownloadingFile(
+ item.getMedia())) {
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ holder.episodeProgress.setProgress(((ItemAccess) itemAccess).getItemDownloadProgressPercent(item));
+ } else if (!(state == FeedItem.State.IN_PROGRESS
+ || state == FeedItem.State.PLAYING)) {
+ holder.episodeProgress.setVisibility(View.GONE);
+ }
+
+ TypedArray typeDrawables = context.obtainStyledAttributes(
+ new int[]{R.attr.type_audio, R.attr.type_video});
+ final int[] labels = new int[]{R.string.media_type_audio_label, R.string.media_type_video_label};
+
+ MediaType mediaType = item.getMedia().getMediaType();
+ if (mediaType == MediaType.AUDIO) {
+ holder.type.setImageDrawable(typeDrawables.getDrawable(0));
+ holder.type.setContentDescription(context.getString(labels[0]));
+ holder.type.setVisibility(View.VISIBLE);
+ } else if (mediaType == MediaType.VIDEO) {
+ holder.type.setImageDrawable(typeDrawables.getDrawable(1));
+ holder.type.setContentDescription(context.getString(labels[1]));
+ holder.type.setVisibility(View.VISIBLE);
+ } else {
+ holder.type.setImageBitmap(null);
+ holder.type.setVisibility(View.GONE);
+ }
+ }
+
+ actionButtonUtils.configureActionButton(holder.butAction, item);
+ holder.butAction.setFocusable(false);
+ holder.butAction.setTag(item);
+ holder.butAction.setOnClickListener(butActionListener);
+
+ } else {
+ convertView.setVisibility(View.GONE);
+ }
+ return convertView;
+
+ }
+
+ private final OnClickListener butActionListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ callback.onActionButtonPressed(item);
+ }
+ };
+
+ static class Holder {
+ TextView title;
+ TextView published;
+ TextView lenSize;
+ ImageView type;
+ ImageView inPlaylist;
+ ImageButton butAction;
+ View statusUnread;
+ ProgressBar episodeProgress;
+ }
+
+ public int getSelectedItemIndex() {
+ return selectedItemIndex;
+ }
+
+ public void setSelectedItemIndex(int selectedItemIndex) {
+ this.selectedItemIndex = selectedItemIndex;
+ notifyDataSetChanged();
+ }
+
+ public static interface ItemAccess {
+ public boolean isInQueue(FeedItem item);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+
+ int getCount();
+
+ FeedItem getItem(int position);
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
index 37600838e..30c1ff880 100644
--- a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
@@ -118,7 +118,7 @@ public class FeedlistAdapter extends BaseAdapter {
holder.inProgressEpisodesLabel.setVisibility(View.INVISIBLE);
}
}
- final String imageUrl = (feed.getImage() != null) ? feed.getImage()
+ final String imageUrl = (feed.getImage() != null && feed.getImage().isDownloaded()) ? feed.getImage()
.getFile_url() : null;
imageLoader.loadThumbnailBitmap(
feed.getImage(),
diff --git a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java
deleted file mode 100644
index 4681284f5..000000000
--- a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java
+++ /dev/null
@@ -1,230 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.*;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.FeedMedia;
-import de.danoeh.antennapod.feed.MediaType;
-import de.danoeh.antennapod.storage.DownloadRequester;
-import de.danoeh.antennapod.util.Converter;
-import de.danoeh.antennapod.util.ThemeUtils;
-
-/** List adapter for items of feeds that the user has already subscribed to. */
-public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
-
- private ActionButtonCallback callback;
- private boolean showFeedtitle;
- private int selectedItemIndex;
-
- public static final int SELECTION_NONE = -1;
-
- public InternalFeedItemlistAdapter(Context context,
- ItemAccess itemAccess,
- ActionButtonCallback callback, boolean showFeedtitle) {
- super(context, itemAccess);
- this.callback = callback;
- this.showFeedtitle = showFeedtitle;
- this.selectedItemIndex = SELECTION_NONE;
- }
-
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- Holder holder;
- final FeedItem item = getItem(position);
-
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.feeditemlist_item, null);
- holder.title = (TextView) convertView
- .findViewById(R.id.txtvItemname);
- holder.lenSize = (TextView) convertView
- .findViewById(R.id.txtvLenSize);
- holder.butAction = (ImageButton) convertView
- .findViewById(R.id.butAction);
- holder.published = (TextView) convertView
- .findViewById(R.id.txtvPublished);
- holder.inPlaylist = (ImageView) convertView
- .findViewById(R.id.imgvInPlaylist);
- holder.downloaded = (ImageView) convertView
- .findViewById(R.id.imgvDownloaded);
- holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
- holder.downloading = (ImageView) convertView
- .findViewById(R.id.imgvDownloading);
- if (showFeedtitle) {
- holder.feedtitle = (TextView) convertView
- .findViewById(R.id.txtvFeedname);
- }
- holder.statusPlaying = (View) convertView
- .findViewById(R.id.statusPlaying);
- holder.statusUnread = (View) convertView
- .findViewById(R.id.statusUnread);
- holder.episodeProgress = (ProgressBar) convertView
- .findViewById(R.id.pbar_episode_progress);
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
- if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) {
- convertView.setVisibility(View.VISIBLE);
- if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources()
- .getColor(ThemeUtils.getSelectionBackgroundColor()));
- } else {
- convertView.setBackgroundResource(0);
- }
-
- holder.title.setText(item.getTitle());
- if (showFeedtitle) {
- holder.feedtitle.setVisibility(View.VISIBLE);
- holder.feedtitle.setText(item.getFeed().getTitle());
- }
-
- FeedItem.State state = item.getState();
- switch (state) {
- case PLAYING:
- holder.statusPlaying.setVisibility(View.VISIBLE);
- holder.statusUnread.setVisibility(View.GONE);
- holder.episodeProgress.setVisibility(View.VISIBLE);
- break;
- case IN_PROGRESS:
- holder.statusPlaying.setVisibility(View.GONE);
- holder.statusUnread.setVisibility(View.GONE);
- holder.episodeProgress.setVisibility(View.VISIBLE);
- break;
- case NEW:
- holder.statusPlaying.setVisibility(View.GONE);
- holder.statusUnread.setVisibility(View.VISIBLE);
- holder.episodeProgress.setVisibility(View.GONE);
- break;
- default:
- holder.statusPlaying.setVisibility(View.GONE);
- holder.statusUnread.setVisibility(View.GONE);
- holder.episodeProgress.setVisibility(View.GONE);
- break;
- }
-
- holder.published.setText(convertView.getResources().getString(
- R.string.published_prefix)
- + DateUtils.getRelativeTimeSpanString(
- item.getPubDate().getTime(),
- System.currentTimeMillis(), 0, 0));
-
- FeedMedia media = item.getMedia();
- if (media == null) {
- holder.downloaded.setVisibility(View.GONE);
- holder.downloading.setVisibility(View.GONE);
- holder.inPlaylist.setVisibility(View.GONE);
- holder.type.setVisibility(View.GONE);
- holder.lenSize.setVisibility(View.GONE);
- } else {
-
- if (state == FeedItem.State.PLAYING
- || state == FeedItem.State.IN_PROGRESS) {
- if (media.getDuration() > 0) {
- holder.episodeProgress
- .setProgress((int) (((double) media
- .getPosition()) / media.getDuration() * 100));
- holder.lenSize.setText(Converter
- .getDurationStringLong(media.getDuration()
- - media.getPosition()));
- }
- } else if (!media.isDownloaded()) {
- holder.lenSize.setText(getContext().getString(
- R.string.size_prefix)
- + Converter.byteToString(media.getSize()));
- } else {
- holder.lenSize.setText(getContext().getString(
- R.string.length_prefix)
- + Converter.getDurationStringLong(media
- .getDuration()));
- }
-
- holder.lenSize.setVisibility(View.VISIBLE);
- if (((ItemAccess) itemAccess).isInQueue(item)) {
- holder.inPlaylist.setVisibility(View.VISIBLE);
- } else {
- holder.inPlaylist.setVisibility(View.GONE);
- }
- if (item.getMedia().isDownloaded()) {
- holder.downloaded.setVisibility(View.VISIBLE);
- } else {
- holder.downloaded.setVisibility(View.GONE);
- }
-
- if (DownloadRequester.getInstance().isDownloadingFile(
- item.getMedia())) {
- holder.downloading.setVisibility(View.VISIBLE);
- } else {
- holder.downloading.setVisibility(View.GONE);
- }
-
- TypedArray typeDrawables = getContext().obtainStyledAttributes(
- new int[] { R.attr.type_audio, R.attr.type_video });
- final int[] labels = new int[] {R.string.media_type_audio_label, R.string.media_type_video_label};
-
- MediaType mediaType = item.getMedia().getMediaType();
- if (mediaType == MediaType.AUDIO) {
- holder.type.setImageDrawable(typeDrawables.getDrawable(0));
- holder.type.setContentDescription(getContext().getString(labels[0]));
- holder.type.setVisibility(View.VISIBLE);
- } else if (mediaType == MediaType.VIDEO) {
- holder.type.setImageDrawable(typeDrawables.getDrawable(1));
- holder.type.setContentDescription(getContext().getString(labels[1]));
- holder.type.setVisibility(View.VISIBLE);
- } else {
- holder.type.setImageBitmap(null);
- holder.type.setVisibility(View.GONE);
- }
- }
-
- holder.butAction.setFocusable(false);
- holder.butAction.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- callback.onActionButtonPressed(item);
- }
- });
-
- } else {
- convertView.setVisibility(View.GONE);
- }
- return convertView;
-
- }
-
- static class Holder extends DefaultFeedItemlistAdapter.Holder {
- TextView feedtitle;
- ImageView inPlaylist;
- ImageView downloaded;
- ImageView downloading;
- ImageButton butAction;
- View statusUnread;
- View statusPlaying;
- ProgressBar episodeProgress;
- }
-
- public int getSelectedItemIndex() {
- return selectedItemIndex;
- }
-
- public void setSelectedItemIndex(int selectedItemIndex) {
- this.selectedItemIndex = selectedItemIndex;
- notifyDataSetChanged();
- }
-
- public static interface ItemAccess extends DefaultFeedItemlistAdapter.ItemAccess {
- public boolean isInQueue(FeedItem item);
- }
-
-}
diff --git a/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java b/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java
deleted file mode 100644
index 4361b3af8..000000000
--- a/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.miroguide.model.MiroGuideChannel;
-
-import java.util.List;
-
-public class MiroGuideChannelListAdapter extends ArrayAdapter<MiroGuideChannel> {
-
- public MiroGuideChannelListAdapter(Context context, int textViewResourceId,
- List<MiroGuideChannel> objects) {
- super(context, textViewResourceId, objects);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- MiroGuideChannel channel = getItem(position);
-
- // Inflate Layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.miroguide_channellist_item, null);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- holder.title.setText(channel.getName());
- return convertView;
- }
-
- static class Holder {
- TextView title;
- }
-
-
-
-}
diff --git a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java
deleted file mode 100644
index 18a4b42cc..000000000
--- a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.miroguide.model.MiroGuideItem;
-
-import java.util.List;
-
-public class MiroGuideItemlistAdapter extends ArrayAdapter<MiroGuideItem> {
-
- public MiroGuideItemlistAdapter(Context context, int textViewResourceId,
- List<MiroGuideItem> objects) {
- super(context, textViewResourceId, objects);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- MiroGuideItem item = getItem(position);
-
- // Inflate Layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.miroguide_itemlist_item,
- null);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- holder.title.setText(item.getName());
- if (item.getDate() != null) {
- holder.date.setText(DateUtils.getRelativeTimeSpanString(
- item.getDate().getTime(), System.currentTimeMillis(), 0, 0));
- holder.date.setVisibility(View.VISIBLE);
- } else {
- holder.date.setVisibility(View.GONE);
- }
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView date;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/adapter/NavListAdapter.java b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
new file mode 100644
index 000000000..928ec5dde
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -0,0 +1,198 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.Feed;
+
+/**
+ * BaseAdapter for the navigation drawer
+ */
+public class NavListAdapter extends BaseAdapter {
+ public static final int VIEW_TYPE_COUNT = 3;
+ public static final int VIEW_TYPE_NAV = 0;
+ public static final int VIEW_TYPE_SECTION_DIVIDER = 1;
+ public static final int VIEW_TYPE_SUBSCRIPTION = 2;
+
+ public static final int[] NAV_TITLES = {R.string.all_episodes_label, R.string.queue_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label};
+
+ private final Drawable[] drawables;
+
+ public static final int SUBSCRIPTION_OFFSET = 1 + NAV_TITLES.length;
+
+ private ItemAccess itemAccess;
+ private Context context;
+
+ public NavListAdapter(ItemAccess itemAccess, Context context) {
+ this.itemAccess = itemAccess;
+ this.context = context;
+
+ TypedArray ta = context.obtainStyledAttributes(new int[] {R.attr.ic_new, R.attr.stat_playlist,
+ R.attr.av_download, R.attr.device_access_time, R.attr.content_new});
+ drawables = new Drawable[] {ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2),
+ ta.getDrawable(3), ta.getDrawable(4)};
+ ta.recycle();
+ }
+
+ @Override
+ public int getCount() {
+ return NAV_TITLES.length + 1 + itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ int viewType = getItemViewType(position);
+ if (viewType == VIEW_TYPE_NAV) {
+ return context.getString(NAV_TITLES[position]);
+ } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
+ return context.getString(R.string.podcasts_label);
+ } else {
+ return itemAccess.getItem(position);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (0 <= position && position < NAV_TITLES.length) {
+ return VIEW_TYPE_NAV;
+ } else if (position < NAV_TITLES.length + 1) {
+ return VIEW_TYPE_SECTION_DIVIDER;
+ } else {
+ return VIEW_TYPE_SUBSCRIPTION;
+ }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return VIEW_TYPE_COUNT;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int viewType = getItemViewType(position);
+ View v = null;
+ if (viewType == VIEW_TYPE_NAV) {
+ v = getNavView((String) getItem(position), position, convertView, parent);
+ } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
+ v = getSectionDividerView((String) getItem(position), position, convertView, parent);
+ } else {
+ v = getFeedView(position - SUBSCRIPTION_OFFSET, convertView, parent);
+ }
+ if (v != null) {
+ TextView txtvTitle = (TextView) v.findViewById(R.id.txtvTitle);
+ if (position == itemAccess.getSelectedItemIndex()) {
+ txtvTitle.setTypeface(null, Typeface.BOLD);
+ } else {
+ txtvTitle.setTypeface(null, Typeface.NORMAL);
+ }
+ }
+ return v;
+ }
+
+ private View getNavView(String title, int position, View convertView, ViewGroup parent) {
+ NavHolder holder;
+ if (convertView == null) {
+ holder = new NavHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_listitem, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
+ convertView.setTag(holder);
+ } else {
+ holder = (NavHolder) convertView.getTag();
+ }
+
+ holder.title.setText(title);
+ holder.image.setImageDrawable(drawables[position]);
+
+ return convertView;
+ }
+
+ private View getSectionDividerView(String title, int position, View convertView, ViewGroup parent) {
+ SectionHolder holder;
+ if (convertView == null) {
+ holder = new SectionHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_section_item, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ convertView.setTag(holder);
+ } else {
+ holder = (SectionHolder) convertView.getTag();
+ }
+
+ holder.title.setText(title);
+
+ convertView.setEnabled(false);
+ convertView.setOnClickListener(null);
+
+ return convertView;
+ }
+
+ private View getFeedView(int feedPos, View convertView, ViewGroup parent) {
+ FeedHolder holder;
+ Feed feed = itemAccess.getItem(feedPos);
+
+ if (convertView == null) {
+ holder = new FeedHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_feedlistitem, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
+ convertView.setTag(holder);
+ } else {
+ holder = (FeedHolder) convertView.getTag();
+ }
+
+ holder.title.setText(feed.getTitle());
+ ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), holder.image, (int) context.getResources().getDimension(R.dimen.thumbnail_length_navlist));
+
+ return convertView;
+ }
+
+ static class NavHolder {
+ TextView title;
+ ImageView image;
+ }
+
+ static class SectionHolder {
+ TextView title;
+ }
+
+ static class FeedHolder {
+ TextView title;
+ ImageView image;
+ }
+
+
+ public interface ItemAccess {
+ public int getCount();
+
+ public Feed getItem(int position);
+
+ public int getSelectedItemIndex();
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
new file mode 100644
index 000000000..4a959dfd2
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
@@ -0,0 +1,160 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * List adapter for the list of new episodes
+ */
+public class NewEpisodesListAdapter extends BaseAdapter {
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+ private final ActionButtonCallback actionButtonCallback;
+ private final ActionButtonUtils actionButtonUtils;
+
+ public NewEpisodesListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ this.actionButtonUtils = new ActionButtonUtils(context);
+ this.actionButtonCallback = actionButtonCallback;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.new_episodes_listitem,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.queueStatus = (ImageView) convertView
+ .findViewById(R.id.imgvInPlaylist);
+ holder.downloadProgress = (ProgressBar) convertView
+ .findViewById(R.id.pbar_download_progress);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.txtvDuration = (TextView) convertView.findViewById(R.id.txtvDuration);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+
+ FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+
+ if (media.getDuration() > 0) {
+ holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
+ } else {
+ holder.txtvDuration.setText("");
+ }
+
+ if (isDownloadingMedia) {
+ holder.downloadProgress.setVisibility(View.VISIBLE);
+ holder.txtvDuration.setVisibility(View.GONE);
+ } else {
+ holder.txtvDuration.setVisibility(View.VISIBLE);
+ holder.downloadProgress.setVisibility(View.GONE);
+ }
+
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ }
+ }
+ }
+ if (itemAccess.isInQueue(item)) {
+ holder.queueStatus.setVisibility(View.VISIBLE);
+ } else {
+ holder.queueStatus.setVisibility(View.INVISIBLE);
+ }
+
+ actionButtonUtils.configureActionButton(holder.butSecondary, item);
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ actionButtonCallback.onActionButtonPressed(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ TextView pubDate;
+ ImageView queueStatus;
+ ImageView imageView;
+ ProgressBar downloadProgress;
+ TextView txtvDuration;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+
+ boolean isInQueue(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
new file mode 100644
index 000000000..fb6848a1e
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -0,0 +1,130 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+/**
+ * List adapter for the queue.
+ */
+public class QueueListAdapter extends BaseAdapter {
+
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+ private final ActionButtonCallback actionButtonCallback;
+ private final ActionButtonUtils actionButtonUtils;
+
+ public QueueListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ this.actionButtonUtils = new ActionButtonUtils(context);
+ this.actionButtonCallback = actionButtonCallback;
+
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.queue_listitem,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.downloadProgress = (ProgressBar) convertView
+ .findViewById(R.id.pbar_download_progress);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+
+ FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+
+
+ if (isDownloadingMedia) {
+ holder.downloadProgress.setVisibility(View.VISIBLE);
+ } else {
+ holder.downloadProgress.setVisibility(View.GONE);
+ }
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ }
+ }
+ }
+
+ actionButtonUtils.configureActionButton(holder.butSecondary, item);
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ actionButtonCallback.onActionButtonPressed(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ ImageView imageView;
+ ProgressBar downloadProgress;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
index 926a5a5ad..5c6af3943 100644
--- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
@@ -5,6 +5,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.danoeh.antennapod.R;
@@ -17,14 +18,32 @@ import de.danoeh.antennapod.feed.SearchResult;
import java.util.List;
/** List adapter for search activity. */
-public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
+public class SearchlistAdapter extends BaseAdapter {
- public SearchlistAdapter(Context context, int textViewResourceId,
- List<SearchResult> objects) {
- super(context, textViewResourceId, objects);
- }
+ private final Context context;
+ private final ItemAccess itemAccess;
+
+ public SearchlistAdapter(Context context, ItemAccess itemAccess) {
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
- @Override
+ @Override
+ public SearchResult getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
final Holder holder;
SearchResult result = getItem(position);
@@ -33,7 +52,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
// Inflate Layout
if (convertView == null) {
holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
+ LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.searchlist_item, null);
@@ -78,4 +97,9 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
TextView subtitle;
}
+ public static interface ItemAccess {
+ int getCount();
+ SearchResult getItem(int position);
+ }
+
}
diff --git a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
index 40388cde5..1c5003ab3 100644
--- a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
+++ b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
@@ -23,9 +23,9 @@ public class DownloadObserver {
/**
* Time period between update notifications.
*/
- public static final int WAITING_INTERVAL_MS = 1000;
+ public static final int WAITING_INTERVAL_MS = 3000;
- private final Activity activity;
+ private volatile Activity activity;
private final Handler handler;
private final Callback callback;
@@ -57,19 +57,31 @@ public class DownloadObserver {
public void onResume() {
if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed");
activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
- activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
+ connectToDownloadService();
}
public void onPause() {
if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver paused");
- activity.unregisterReceiver(contentChangedReceiver);
- activity.unbindService(mConnection);
+ try {
+ activity.unregisterReceiver(contentChangedReceiver);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ try {
+ activity.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
stopRefresher();
}
private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // reconnect to DownloadService if connection has been closed
+ if (downloadService == null) {
+ connectToDownloadService();
+ }
callback.onContentChanged();
startRefresher();
}
@@ -81,6 +93,10 @@ public class DownloadObserver {
void onDownloadDataAvailable(List<Downloader> downloaderList);
}
+ private void connectToDownloadService() {
+ activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
+ }
+
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName className) {
downloadService = null;
@@ -138,13 +154,21 @@ public class DownloadObserver {
@Override
public void run() {
callback.onContentChanged();
- List<Downloader> downloaderList = downloadService.getDownloads();
- if (downloaderList == null || downloaderList.isEmpty()) {
- Thread.currentThread().interrupt();
+ if (downloadService != null) {
+ List<Downloader> downloaderList = downloadService.getDownloads();
+ if (downloaderList == null || downloaderList.isEmpty()) {
+ Thread.currentThread().interrupt();
+ }
}
}
});
}
}
+ public void setActivity(Activity activity) {
+ if (activity == null) throw new IllegalArgumentException("activity = null");
+ this.activity = activity;
+ }
+
}
+
diff --git a/src/de/danoeh/antennapod/backup/OpmlBackupAgent.java b/src/de/danoeh/antennapod/backup/OpmlBackupAgent.java
new file mode 100644
index 000000000..56d1ca092
--- /dev/null
+++ b/src/de/danoeh/antennapod/backup/OpmlBackupAgent.java
@@ -0,0 +1,212 @@
+package de.danoeh.antennapod.backup;
+
+import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import de.danoeh.antennapod.BuildConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.math.BigInteger;
+import java.security.DigestInputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.opml.OpmlElement;
+import de.danoeh.antennapod.opml.OpmlReader;
+import de.danoeh.antennapod.opml.OpmlWriter;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DownloadRequestException;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.LangUtils;
+
+public class OpmlBackupAgent extends BackupAgentHelper {
+ private static final String OPML_BACKUP_KEY = "opml";
+
+ @Override
+ public void onCreate() {
+ addHelper(OPML_BACKUP_KEY, new OpmlBackupHelper(this));
+ }
+
+ private static final void LOGD(String tag, String msg) {
+ if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, msg);
+ }
+ }
+
+ private static final void LOGD(String tag, String msg, Throwable tr) {
+ if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, msg, tr);
+ }
+ }
+
+ /** Class for backing up and restoring the OPML file. */
+ private static class OpmlBackupHelper implements BackupHelper {
+ private static final String TAG = "OpmlBackupHelper";
+
+ private static final String OPML_ENTITY_KEY = "antennapod-feeds.opml";
+
+ private final Context mContext;
+
+ /** Checksum of restored OPML file */
+ private byte[] mChecksum;
+
+ public OpmlBackupHelper(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
+ Log.d(TAG, "Performing backup");
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ MessageDigest digester = null;
+ Writer writer;
+
+ try {
+ digester = MessageDigest.getInstance("MD5");
+ writer = new OutputStreamWriter(new DigestOutputStream(byteStream, digester),
+ LangUtils.UTF_8);
+ } catch (NoSuchAlgorithmException e) {
+ writer = new OutputStreamWriter(byteStream, LangUtils.UTF_8);
+ }
+
+ try {
+ // Write OPML
+ new OpmlWriter().writeDocument(DBReader.getFeedList(mContext), writer);
+
+ // Compare checksum of new and old file to see if we need to perform a backup at all
+ if (digester != null) {
+ byte[] newChecksum = digester.digest();
+ LOGD(TAG, "New checksum: " + new BigInteger(1, newChecksum).toString(16));
+
+ // Get the old checksum
+ if (oldState != null) {
+ FileInputStream inState = new FileInputStream(oldState.getFileDescriptor());
+ int len = inState.read();
+
+ if (len != -1) {
+ byte[] oldChecksum = new byte[len];
+ inState.read(oldChecksum);
+ LOGD(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16));
+
+ if (Arrays.equals(oldChecksum, newChecksum)) {
+ LOGD(TAG, "Checksums are the same; won't backup");
+ return;
+ }
+ }
+ }
+
+ writeNewStateDescription(newState, newChecksum);
+ }
+
+ LOGD(TAG, "Backing up OPML");
+ byte[] bytes = byteStream.toByteArray();
+ data.writeEntityHeader(OPML_ENTITY_KEY, bytes.length);
+ data.writeEntityData(bytes, bytes.length);
+ } catch (IOException e) {
+ Log.e(TAG, "Error during backup", e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void restoreEntity(BackupDataInputStream data) {
+ LOGD(TAG, "Backup restore");
+
+ if (!OPML_ENTITY_KEY.equals(data.getKey())) {
+ LOGD(TAG, "Unknown entity key: " + data.getKey());
+ return;
+ }
+
+ MessageDigest digester = null;
+ Reader reader;
+
+ try {
+ digester = MessageDigest.getInstance("MD5");
+ reader = new InputStreamReader(new DigestInputStream(data, digester),
+ LangUtils.UTF_8);
+ } catch (NoSuchAlgorithmException e) {
+ reader = new InputStreamReader(data, LangUtils.UTF_8);
+ }
+
+ try {
+ ArrayList<OpmlElement> opmlElements = new OpmlReader().readDocument(reader);
+ mChecksum = digester == null ? null : digester.digest();
+ DownloadRequester downloader = DownloadRequester.getInstance();
+ Date lastUpdated = new Date();
+
+ for (OpmlElement opmlElem : opmlElements) {
+ Feed feed = new Feed(opmlElem.getXmlUrl(), lastUpdated, opmlElem.getText());
+
+ try {
+ downloader.downloadFeed(mContext, feed);
+ } catch (DownloadRequestException e) {
+ LOGD(TAG, "Error while restoring/downloading feed", e);
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Error while parsing the OPML file", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to restore OPML backup", e);
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void writeNewStateDescription(ParcelFileDescriptor newState) {
+ writeNewStateDescription(newState, mChecksum);
+ }
+
+ /**
+ * Writes the new state description, which is the checksum of the OPML file.
+ *
+ * @param newState
+ * @param checksum
+ */
+ private void writeNewStateDescription(ParcelFileDescriptor newState, byte[] checksum) {
+ if (checksum == null) {
+ return;
+ }
+
+ try {
+ FileOutputStream outState = new FileOutputStream(newState.getFileDescriptor());
+ outState.write(checksum.length);
+ outState.write(checksum);
+ outState.flush();
+ outState.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write new state description", e);
+ }
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/dialog/FeedItemDialog.java b/src/de/danoeh/antennapod/dialog/FeedItemDialog.java
new file mode 100644
index 000000000..8db4c9d19
--- /dev/null
+++ b/src/de/danoeh/antennapod/dialog/FeedItemDialog.java
@@ -0,0 +1,398 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.widget.PopupMenu;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ImageButton;
+import android.widget.TextView;
+import android.widget.Toast;
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.storage.DBTasks;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.storage.DownloadRequestException;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.ShownotesProvider;
+import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
+import org.apache.commons.lang3.StringEscapeUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Shows information about a specific FeedItem and provides actions like playing, downloading, etc.
+ */
+public class FeedItemDialog extends Dialog {
+ private static final String TAG = "FeedItemDialog";
+
+ private FeedItem item;
+ private QueueAccess queue;
+
+ private View header;
+ private TextView txtvTitle;
+ private WebView webvDescription;
+ private ImageButton butAction1;
+ private ImageButton butAction2;
+ private ImageButton butMore;
+ private PopupMenu popupMenu;
+
+ public static FeedItemDialog newInstance(Context context, FeedItemDialogSavedInstance savedInstance) {
+ if (savedInstance == null) throw new IllegalArgumentException("savedInstance = null");
+ FeedItemDialog dialog = newInstance(context, savedInstance.item, savedInstance.queueAccess);
+ if (savedInstance.isShowing) {
+ dialog.show();
+ }
+ return dialog;
+ }
+
+ public static FeedItemDialog newInstance(Context context, FeedItem item, QueueAccess queue) {
+ if (useDarkThemeWorkAround()) {
+ return new FeedItemDialog(context, R.style.Theme_AntennaPod_Dark, item, queue);
+ } else {
+ return new FeedItemDialog(context, item, queue);
+ }
+ }
+
+ public FeedItemDialog(Context context, int theme, FeedItem item, QueueAccess queue) {
+ super(context, theme);
+ if (item == null) throw new IllegalArgumentException("item = null");
+ if (queue == null) throw new IllegalArgumentException("queue = null");
+ this.item = item;
+ this.queue = queue;
+ }
+
+ private FeedItemDialog(Context context, FeedItem item, QueueAccess queue) {
+ this(context, 0, item, queue);
+ }
+
+ /**
+ * Returns true if the dialog should use a dark theme. This has to be done on Gingerbread devices
+ * because dialogs are only available in a dark theme.
+ */
+ private static boolean useDarkThemeWorkAround() {
+ return Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1
+ && UserPreferences.getTheme() != R.style.Theme_AntennaPod_Dark;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.feeditem_dialog);
+
+ txtvTitle = (TextView) findViewById(R.id.txtvTitle);
+ header = findViewById(R.id.header);
+ webvDescription = (WebView) findViewById(R.id.webview);
+ butAction1 = (ImageButton) findViewById(R.id.butAction1);
+ butAction2 = (ImageButton) findViewById(R.id.butAction2);
+ butMore = (ImageButton) findViewById(R.id.butMoreActions);
+ popupMenu = new PopupMenu(getContext(), butMore);
+
+ webvDescription.setWebViewClient(new WebViewClient());
+ txtvTitle.setText(item.getTitle());
+
+ if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
+ if (Build.VERSION.SDK_INT >= 11
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+ webvDescription.setBackgroundColor(getContext().getResources().getColor(
+ R.color.black));
+ }
+ webvDescription.getSettings().setUseWideViewPort(false);
+ webvDescription.getSettings().setLayoutAlgorithm(
+ WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
+ webvDescription.getSettings().setLoadWithOverviewMode(true);
+ webvDescription.setWebViewClient(new WebViewClient() {
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ try {
+ getContext().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+ });
+
+ loadDescriptionWebview(item);
+
+ butAction1.setOnClickListener(new View.OnClickListener() {
+ DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getContext());
+
+ @Override
+
+ public void onClick(View v) {
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+ actionButtonCallback.onActionButtonPressed(item);
+
+ }
+ }
+ );
+
+ butAction2.setOnClickListener(new View.OnClickListener()
+
+ {
+ @Override
+ public void onClick(View v) {
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ if (!media.isDownloaded()) {
+ DBTasks.playMedia(getContext(), media, true, true, true);
+ dismiss();
+ } else {
+ DBWriter.deleteFeedMediaOfItem(getContext(), media.getId());
+ }
+ }
+ }
+ );
+
+ butMore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ popupMenu.getMenu().clear();
+ popupMenu.inflate(R.menu.feeditem_dialog);
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue);
+ popupMenu.show();
+ }
+ }
+ );
+
+ popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem menuItem) {
+
+ try {
+ return FeedItemMenuHandler.onMenuItemClicked(getContext(), menuItem.getItemId(), item);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
+ return true;
+ }
+ }
+ }
+ );
+
+ updateMenuAppearance();
+ }
+
+
+ private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
+ @Override
+ public void setItemVisibility(int id, boolean visible) {
+ MenuItem item = popupMenu.getMenu().findItem(id);
+ if (item != null) {
+ item.setVisible(visible);
+ }
+ }
+ };
+
+ public void updateMenuAppearance() {
+ if (item == null || queue == null) {
+ Log.w(TAG, "UpdateMenuAppearance called while item or queue was null");
+ return;
+ }
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ header.setVisibility(View.GONE);
+ } else {
+ header.setVisibility(View.VISIBLE);
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ TypedArray drawables = getContext().obtainStyledAttributes(new int[]{R.attr.av_play,
+ R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
+
+ if (!media.isDownloaded()) {
+ butAction2.setImageDrawable(drawables.getDrawable(2));
+ butAction2.setContentDescription(getContext().getString(R.string.stream_label));
+ } else {
+ butAction2.setImageDrawable(drawables.getDrawable(3));
+ butAction2.setContentDescription(getContext().getString(R.string.remove_episode_lable));
+ }
+
+ if (isDownloading) {
+ butAction1.setImageDrawable(drawables.getDrawable(4));
+ butAction1.setContentDescription(getContext().getString(R.string.cancel_download_label));
+ } else if (media.isDownloaded()) {
+ butAction1.setImageDrawable(drawables.getDrawable(0));
+ butAction1.setContentDescription(getContext().getString(R.string.play_label));
+ } else {
+ butAction1.setImageDrawable(drawables.getDrawable(1));
+ butAction1.setContentDescription(getContext().getString(R.string.download_label));
+ }
+
+ drawables.recycle();
+ }
+ }
+
+
+ private void loadDescriptionWebview(final ShownotesProvider shownotesProvider) {
+ AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
+ String data;
+
+
+ private String applyWebviewStyle(String textColor, String data) {
+ 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, getContext().getResources()
+ .getDisplayMetrics()
+ );
+ return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin,
+ pageMargin, pageMargin, pageMargin, data);
+ }
+
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ // /webvDescription.loadData(url, "text/html", "utf-8");
+ if (FeedItemDialog.this.isShowing() && webvDescription != null) {
+ webvDescription.loadDataWithBaseURL(null, data, "text/html",
+ "utf-8", "about:blank");
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Webview loaded");
+ }
+ }
+
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Loading Webview");
+ try {
+ Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes();
+ final String shownotes = shownotesLoadTask.call();
+
+ data = StringEscapeUtils.unescapeHtml4(shownotes);
+ TypedArray res = getContext()
+ .getTheme()
+ .obtainStyledAttributes(
+ new int[]{android.R.attr.textColorPrimary});
+ int colorResource;
+ if (useDarkThemeWorkAround()) {
+ colorResource = getContext().getResources().getColor(R.color.black);
+ } else {
+ colorResource = res.getColor(0, 0);
+ }
+ String colorString = String.format("#%06X",
+ 0xFFFFFF & colorResource);
+ Log.i(TAG, "text color: " + colorString);
+ res.recycle();
+ data = applyWebviewStyle(colorString, data);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ };
+ loadTask.execute();
+ }
+
+ /**
+ * Convenience method that calls setQueue() and setItemFromCollection() with
+ * the given arguments.
+ *
+ * @return true if one of the calls to setItemFromCollection returned true,
+ * false otherwise.
+ */
+ public boolean updateContent(QueueAccess queue, List<FeedItem>... collections) {
+ setQueue(queue);
+
+ boolean setItemFromCollectionResult = false;
+ if (collections != null) {
+ for (List<FeedItem> list : collections) {
+ setItemFromCollectionResult |= setItemFromCollection(list);
+ }
+ }
+ if (isShowing()) {
+ updateMenuAppearance();
+ }
+
+ return setItemFromCollectionResult;
+ }
+
+
+ public void setItem(FeedItem item) {
+ if (item == null) throw new IllegalArgumentException("item = null");
+ this.item = item;
+ }
+
+ /**
+ * Finds the FeedItem of this dialog in a collection and updates its state from that
+ * collection.
+ *
+ * @return true if the FeedItem was found, false otherwise.
+ */
+ public boolean setItemFromCollection(Collection<FeedItem> items) {
+ for (FeedItem item : items) {
+ if (item.getId() == this.item.getId()) {
+ setItem(item);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void setQueue(QueueAccess queue) {
+ if (queue == null) throw new IllegalArgumentException("queue = null");
+ this.queue = queue;
+ }
+
+ public FeedItem getItem() {
+ return item;
+ }
+
+ public QueueAccess getQueue() {
+ return queue;
+ }
+
+ public FeedItemDialogSavedInstance save() {
+ return new FeedItemDialogSavedInstance(item, queue, isShowing());
+ }
+
+ /**
+ * Used to save the FeedItemDialog's state across configuration changes
+ * */
+ public static class FeedItemDialogSavedInstance {
+ final FeedItem item;
+ final QueueAccess queueAccess;
+ final boolean isShowing;
+
+ private FeedItemDialogSavedInstance(FeedItem item, QueueAccess queueAccess, boolean isShowing) {
+ this.item = item;
+ this.queueAccess = queueAccess;
+ this.isShowing = isShowing;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/dialog/TimeDialog.java b/src/de/danoeh/antennapod/dialog/TimeDialog.java
index 353a50adb..cb3ebf0ab 100644
--- a/src/de/danoeh/antennapod/dialog/TimeDialog.java
+++ b/src/de/danoeh/antennapod/dialog/TimeDialog.java
@@ -26,7 +26,6 @@ public abstract class TimeDialog extends Dialog {
private Button butConfirm;
private Button butCancel;
- private String[] spinnerContent = { "s", "min", "h" };
private TimeUnit[] units = { TimeUnit.SECONDS, TimeUnit.MINUTES,
TimeUnit.HOURS };
@@ -39,6 +38,10 @@ public abstract class TimeDialog extends Dialog {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
+ String[] spinnerContent = new String[]{context.getString(R.string.time_unit_seconds),
+ context.getString(R.string.time_unit_minutes),
+ context.getString(R.string.time_unit_hours)};
+
setContentView(R.layout.time_dialog);
etxtTime = (EditText) findViewById(R.id.etxtTime);
spTimeUnit = (Spinner) findViewById(R.id.spTimeUnit);
diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java
index 9e423ff8b..f9da65e03 100644
--- a/src/de/danoeh/antennapod/feed/Feed.java
+++ b/src/de/danoeh/antennapod/feed/Feed.java
@@ -223,6 +223,8 @@ public class Feed extends FeedFile implements FlattrThing {
public String getIdentifyingValue() {
if (feedIdentifier != null && !feedIdentifier.isEmpty()) {
return feedIdentifier;
+ } else if (download_url != null && !download_url.isEmpty()) {
+ return download_url;
} else if (title != null && !title.isEmpty()) {
return title;
} else {
diff --git a/src/de/danoeh/antennapod/feed/FeedFile.java b/src/de/danoeh/antennapod/feed/FeedFile.java
index 28a9b1e10..a05533ebc 100644
--- a/src/de/danoeh/antennapod/feed/FeedFile.java
+++ b/src/de/danoeh/antennapod/feed/FeedFile.java
@@ -2,84 +2,104 @@ package de.danoeh.antennapod.feed;
import java.io.File;
-/** Represents a component of a Feed that has to be downloaded */
+/**
+ * Represents a component of a Feed that has to be downloaded
+ */
public abstract class FeedFile extends FeedComponent {
- protected String file_url;
- protected String download_url;
- protected boolean downloaded;
+ protected String file_url;
+ protected String download_url;
+ protected boolean downloaded;
- public FeedFile(String file_url, String download_url, boolean downloaded) {
- super();
- this.file_url = file_url;
- this.download_url = download_url;
- this.downloaded = downloaded;
- }
+ /**
+ * Creates a new FeedFile object.
+ *
+ * @param file_url The location of the FeedFile. If this is null, the downloaded-attribute
+ * will automatically be set to false.
+ * @param download_url The location where the FeedFile can be downloaded.
+ * @param downloaded true if the FeedFile has been downloaded, false otherwise. This parameter
+ * will automatically be interpreted as false if the file_url is null.
+ */
+ public FeedFile(String file_url, String download_url, boolean downloaded) {
+ super();
+ this.file_url = file_url;
+ this.download_url = download_url;
+ this.downloaded = (file_url != null) && downloaded;
+ }
- public FeedFile() {
+ public FeedFile() {
this(null, null, false);
}
- public abstract int getTypeAsInt();
+ public abstract int getTypeAsInt();
- /**
- * Update this FeedFile's attributes with the attributes from another
- * FeedFile. This method should only update attributes which where read from
- * the feed.
- */
- public void updateFromOther(FeedFile other) {
- super.updateFromOther(other);
- this.download_url = other.download_url;
- }
+ /**
+ * Update this FeedFile's attributes with the attributes from another
+ * FeedFile. This method should only update attributes which where read from
+ * the feed.
+ */
+ public void updateFromOther(FeedFile other) {
+ super.updateFromOther(other);
+ this.download_url = other.download_url;
+ }
- /**
- * Compare's this FeedFile's attribute values with another FeedFile's
- * attribute values. This method will only compare attributes which were
- * read from the feed.
- *
- * @return true if attribute values are different, false otherwise
- */
- public boolean compareWithOther(FeedFile other) {
- if (super.compareWithOther(other)) {
- return true;
- }
- if (!download_url.equals(other.download_url)) {
- return true;
- }
- return false;
- }
-
- /** Returns true if the file exists at file_url. */
- public boolean fileExists() {
- if (file_url == null) {
- return false;
- } else {
- File f = new File(file_url);
- return f.exists();
- }
- }
+ /**
+ * Compare's this FeedFile's attribute values with another FeedFile's
+ * attribute values. This method will only compare attributes which were
+ * read from the feed.
+ *
+ * @return true if attribute values are different, false otherwise
+ */
+ public boolean compareWithOther(FeedFile other) {
+ if (super.compareWithOther(other)) {
+ return true;
+ }
+ if (!download_url.equals(other.download_url)) {
+ return true;
+ }
+ return false;
+ }
- public String getFile_url() {
- return file_url;
- }
+ /**
+ * Returns true if the file exists at file_url.
+ */
+ public boolean fileExists() {
+ if (file_url == null) {
+ return false;
+ } else {
+ File f = new File(file_url);
+ return f.exists();
+ }
+ }
- public void setFile_url(String file_url) {
- this.file_url = file_url;
- }
+ public String getFile_url() {
+ return file_url;
+ }
- public String getDownload_url() {
- return download_url;
- }
+ /**
+ * Changes the file_url of this FeedFile. Setting this value to
+ * null will also set the downloaded-attribute to false.
+ */
+ public void setFile_url(String file_url) {
+ this.file_url = file_url;
+ if (file_url == null) {
+ downloaded = false;
+ }
+ }
- public void setDownload_url(String download_url) {
- this.download_url = download_url;
- }
+ public String getDownload_url() {
+ return download_url;
+ }
- public boolean isDownloaded() {
- return downloaded;
- }
+ public void setDownload_url(String download_url) {
+ this.download_url = download_url;
+ }
- public void setDownloaded(boolean downloaded) {
- this.downloaded = downloaded;
- }
+ public boolean isDownloaded() {
+ return downloaded;
+ }
+
+ public void setDownloaded(boolean downloaded) {
+ this.downloaded = downloaded;
+ }
}
diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java
index 921a03bff..956131ab2 100644
--- a/src/de/danoeh/antennapod/feed/FeedItem.java
+++ b/src/de/danoeh/antennapod/feed/FeedItem.java
@@ -280,7 +280,7 @@ public class FeedItem extends FeedComponent implements
@Override
public InputStream openImageInputStream() {
InputStream out = null;
- if (hasItemImage()) {
+ if (hasItemImageDownloaded()) {
out = image.openImageInputStream();
} else if (hasMedia()) {
out = media.openImageInputStream();
@@ -293,7 +293,7 @@ public class FeedItem extends FeedComponent implements
@Override
public InputStream reopenImageInputStream(InputStream input) {
InputStream out = null;
- if (hasItemImage()) {
+ if (hasItemImageDownloaded()) {
out = image.reopenImageInputStream(input);
} else if (hasMedia()) {
out = media.reopenImageInputStream(input);
@@ -306,7 +306,7 @@ public class FeedItem extends FeedComponent implements
@Override
public String getImageLoaderCacheKey() {
String out = null;
- if (hasItemImage()) {
+ if (hasItemImageDownloaded()) {
out = image.getImageLoaderCacheKey();
} else if (hasMedia()) {
out = media.getImageLoaderCacheKey();
@@ -346,6 +346,13 @@ public class FeedItem extends FeedComponent implements
return image != null;
}
+ /**
+ * Returns true if this FeedItem has its own image and the image has been downloaded.
+ */
+ public boolean hasItemImageDownloaded() {
+ return image != null && image.isDownloaded();
+ }
+
@Override
public String getHumanReadableIdentifier() {
return title;
diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java
index f38e92398..1f8e7f8f8 100644
--- a/src/de/danoeh/antennapod/feed/FeedMedia.java
+++ b/src/de/danoeh/antennapod/feed/FeedMedia.java
@@ -204,7 +204,7 @@ public class FeedMedia extends FeedFile implements Playable {
public FeedImage getImage() {
if (item != null) {
- return (item.hasItemImage()) ? item.getImage() : item.getFeed().getImage();
+ return (item.hasItemImageDownloaded()) ? item.getImage() : item.getFeed().getImage();
}
return null;
}
@@ -384,7 +384,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public InputStream openImageInputStream() {
InputStream out;
- if (item.hasItemImage()) {
+ if (item.hasItemImageDownloaded()) {
out = item.openImageInputStream();
} else {
out = new Playable.DefaultPlayableImageLoader(this)
@@ -401,7 +401,7 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public String getImageLoaderCacheKey() {
String out;
- if (item.hasItemImage()) {
+ if (item.hasItemImageDownloaded()) {
out = item.getImageLoaderCacheKey();
} else {
out = new Playable.DefaultPlayableImageLoader(this)
@@ -418,7 +418,11 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public InputStream reopenImageInputStream(InputStream input) {
if (input instanceof FileInputStream) {
- return item.getImage().reopenImageInputStream(input);
+ if (item.hasItemImageDownloaded()) {
+ return item.getImage().reopenImageInputStream(input);
+ } else {
+ return item.getFeed().getImage().reopenImageInputStream(input);
+ }
} else {
return new Playable.DefaultPlayableImageLoader(this)
.reopenImageInputStream(input);
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/EpisodesFragment.java b/src/de/danoeh/antennapod/fragment/EpisodesFragment.java
deleted file mode 100644
index 3c79a8c10..000000000
--- a/src/de/danoeh/antennapod/fragment/EpisodesFragment.java
+++ /dev/null
@@ -1,327 +0,0 @@
-package de.danoeh.antennapod.fragment;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.view.*;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.ExpandableListView;
-import android.widget.ExpandableListView.OnChildClickListener;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.ItemviewActivity;
-import de.danoeh.antennapod.activity.OrganizeQueueActivity;
-import de.danoeh.antennapod.adapter.ActionButtonCallback;
-import de.danoeh.antennapod.adapter.ExternalEpisodesListAdapter;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DBTasks;
-import de.danoeh.antennapod.storage.DBWriter;
-import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.util.QueueAccess;
-import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
-
-import java.util.List;
-
-public class EpisodesFragment extends Fragment {
- private static final String TAG = "EpisodesFragment";
-
- private static final int EVENTS = EventDistributor.QUEUE_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE
- | EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED;
-
- private ExpandableListView listView;
- private ExternalEpisodesListAdapter adapter;
-
- private List<FeedItem> queue;
- private List<FeedItem> unreadItems;
-
- protected FeedItem selectedItem = null;
- protected long selectedGroupId = -1;
- protected boolean contextMenuClosed = true;
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- EventDistributor.getInstance().unregister(contentUpdate);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- EventDistributor.getInstance().register(contentUpdate);
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.episodes_fragment, null);
- listView = (ExpandableListView) v.findViewById(android.R.id.list);
- return v;
- }
-
- protected ActionButtonCallback adapterCallback = new ActionButtonCallback() {
-
- @Override
- public void onActionButtonPressed(FeedItem item) {
- resetContextMenuSelection();
- selectedItem = item;
- listView.showContextMenu();
- }
- };
-
- protected ExternalEpisodesListAdapter.OnGroupActionClicked groupActionCallback = new ExternalEpisodesListAdapter.OnGroupActionClicked() {
-
- @Override
- public void onClick(long groupId) {
- resetContextMenuSelection();
- selectedGroupId = groupId;
- listView.showContextMenu();
- }
- };
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- adapter = new ExternalEpisodesListAdapter(getActivity(),
- adapterCallback, groupActionCallback, itemAccess);
- listView.setAdapter(adapter);
- listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_QUEUE);
- listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_UNREAD);
- listView.setOnChildClickListener(new OnChildClickListener() {
-
- @Override
- public boolean onChildClick(ExpandableListView parent, View v,
- int groupPosition, int childPosition, long id) {
- FeedItem selection = adapter.getChild(groupPosition,
- childPosition);
- if (selection != null) {
- Intent showItem = new Intent(getActivity(),
- ItemviewActivity.class);
- showItem.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED,
- selection.getFeed().getId());
- showItem.putExtra(ItemlistFragment.EXTRA_SELECTED_FEEDITEM,
- selection.getId());
-
- startActivity(showItem);
- return true;
- }
- return true;
- }
- });
- loadData();
- registerForContextMenu(listView);
-
- }
-
- ExternalEpisodesListAdapter.ItemAccess itemAccess = new ExternalEpisodesListAdapter.ItemAccess() {
-
- @Override
- public int getQueueSize() {
- return (queue != null) ? queue.size() : 0;
- }
-
- @Override
- public int getUnreadItemsSize() {
- return (unreadItems != null) ? unreadItems.size() : 0;
- }
-
- @Override
- public FeedItem getQueueItemAt(int position) {
- return (queue != null) ? queue.get(position) : null;
- }
-
- @Override
- public FeedItem getUnreadItemAt(int position) {
- return (unreadItems != null) ? unreadItems.get(position) : null;
- }
- };
-
- private void loadData() {
- AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
- private volatile List<FeedItem> queueRef;
- private volatile List<FeedItem> unreadItemsRef;
-
- @Override
- protected Void doInBackground(Void... voids) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Starting to load list data");
- Context context = EpisodesFragment.this.getActivity();
- if (context != null) {
- queueRef = DBReader.getQueue(context);
- unreadItemsRef = DBReader.getUnreadItemsList(context);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void aVoid) {
- super.onPostExecute(aVoid);
- if (queueRef != null && unreadItemsRef != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Done loading list data");
- queue = queueRef;
- unreadItems = unreadItemsRef;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- } else {
- if (queueRef == null) {
- Log.e(TAG, "Could not load queue");
- }
- if (unreadItemsRef == null) {
- Log.e(TAG, "Could not load unread items");
- }
- }
- }
- };
- loadTask.execute();
- }
-
- 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.");
- loadData();
- }
- }
- };
-
- @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
- resetContextMenuSelection();
- }
- contextMenuClosed = false;
- listView.setOnItemLongClickListener(null);
- if (selectedItem != null) {
- new MenuInflater(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.ItemListAccess(queue));
-
- // check to see if the item is in the queue, if so add queue menu items
- int itemIndex = queue.indexOf(selectedItem);
- if (itemIndex != -1) {
- addQueueOnlyMenus(menu, itemIndex);
- }
-
- } else if (selectedGroupId == ExternalEpisodesListAdapter.GROUP_POS_QUEUE) {
- menu.add(Menu.NONE, R.id.organize_queue_item, Menu.NONE,
- R.string.organize_queue_label);
- menu.add(Menu.NONE, R.id.clear_queue_item, Menu.NONE, getActivity()
- .getString(R.string.clear_queue_label));
- menu.add(Menu.NONE, R.id.download_all_item, Menu.NONE,
- getActivity().getString(R.string.download_all));
- } else if (selectedGroupId == ExternalEpisodesListAdapter.GROUP_POS_UNREAD) {
- menu.add(Menu.NONE, R.id.mark_all_read_item, Menu.NONE,
- getActivity().getString(R.string.mark_all_read_label));
- menu.add(Menu.NONE, R.id.enqueue_all_item, Menu.NONE, getActivity()
- .getString(R.string.enqueue_all_new));
- }
- }
-
- /**
- * Adds submenus to the ContextMenu if the item selected is in the queue.
- * @param menu the ContextMenu to add the submenus to
- * @param itemIndex the index of the selected item within the queue.
- */
- private void addQueueOnlyMenus(ContextMenu menu, int itemIndex) {
- if (itemIndex != 0) {
- // don't add move to top if this item is already on the top
- menu.add(Menu.NONE, R.id.move_to_top_item, Menu.NONE, getActivity()
- .getString(R.string.move_to_top_label));
- }
- if (itemIndex != queue.size() - 1) {
- // don't add move to bottom if this item is already on the bottom
- menu.add(Menu.NONE, R.id.move_to_bottom_item, Menu.NONE, getActivity()
- .getString(R.string.move_to_bottom_label));
- }
- }
-
- @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) {
- // if it wasn't handled by the FeedItemMenuHandler it might be one of ours
- switch (item.getItemId()) {
- case R.id.move_to_top_item:
- DBWriter.moveQueueItemToTop(getActivity(), selectedItem.getId(), true);
- handled = true;
- break;
- case R.id.move_to_bottom_item:
- DBWriter.moveQueueItemToBottom(getActivity(), selectedItem.getId(), true);
- handled = true;
- break;
- }
- }
- } else if (selectedGroupId == ExternalEpisodesListAdapter.GROUP_POS_QUEUE) {
- handled = true;
- switch (item.getItemId()) {
- case R.id.organize_queue_item:
- startActivity(new Intent(getActivity(),
- OrganizeQueueActivity.class));
- break;
- case R.id.clear_queue_item:
- DBWriter.clearQueue(getActivity());
- break;
- case R.id.download_all_item:
- DBTasks.downloadAllItemsInQueue(getActivity());
- break;
- default:
- handled = false;
- }
- } else if (selectedGroupId == ExternalEpisodesListAdapter.GROUP_POS_UNREAD) {
- handled = true;
- switch (item.getItemId()) {
- case R.id.mark_all_read_item:
- DBWriter.markAllItemsRead(getActivity());
- break;
- case R.id.enqueue_all_item:
- DBTasks.enqueueAllNewItems(getActivity());
- break;
- default:
- handled = false;
- }
- }
-
- resetContextMenuSelection();
- return handled;
- }
-
- private void resetContextMenuSelection() {
- selectedItem = null;
- selectedGroupId = -1;
- contextMenuClosed = true;
- }
-}
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/FeedlistFragment.java b/src/de/danoeh/antennapod/fragment/FeedlistFragment.java
deleted file mode 100644
index 0d2f0d079..000000000
--- a/src/de/danoeh/antennapod/fragment/FeedlistFragment.java
+++ /dev/null
@@ -1,292 +0,0 @@
-package de.danoeh.antennapod.fragment;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.view.ActionMode;
-import android.util.Log;
-import android.view.*;
-import android.widget.*;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.FeedItemlistActivity;
-import de.danoeh.antennapod.adapter.FeedlistAdapter;
-import de.danoeh.antennapod.asynctask.FeedRemover;
-import de.danoeh.antennapod.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
-import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.storage.FeedItemStatistics;
-import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
-
-import java.util.List;
-
-public class FeedlistFragment extends Fragment implements
- ActionMode.Callback, AdapterView.OnItemClickListener,
- AdapterView.OnItemLongClickListener {
- private static final String TAG = "FeedlistFragment";
-
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED
- | EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
-
- public static final String EXTRA_SELECTED_FEED = "extra.de.danoeh.antennapod.activity.selected_feed";
-
- private FeedlistAdapter fla;
- private List<Feed> feeds;
- private List<FeedItemStatistics> feedItemStatistics;
-
- private Feed selectedFeed;
- private ActionMode mActionMode;
-
- private GridView gridView;
- private ListView listView;
- private TextView emptyView;
-
- private FeedlistAdapter.ItemAccess itemAccess = new FeedlistAdapter.ItemAccess() {
-
- @Override
- public Feed getItem(int position) {
- if (feeds != null) {
- return feeds.get(position);
- } else {
- return null;
- }
- }
-
- @Override
- public FeedItemStatistics getFeedItemStatistics(int position) {
- if (feedItemStatistics != null && position < feedItemStatistics.size()) {
- return feedItemStatistics.get(position);
- } else {
- return null;
- }
- }
-
- @Override
- public int getCount() {
- if (feeds != null) {
- return feeds.size();
- } else {
- return 0;
- }
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating");
- fla = new FeedlistAdapter(getActivity(), itemAccess);
- loadFeeds();
- }
-
- private void loadFeeds() {
- AsyncTask<Void, Void, List[]> loadTask = new AsyncTask<Void, Void, List[]>() {
- @Override
- protected List[] doInBackground(Void... params) {
- Context context = getActivity();
- if (context != null) {
- return new List[]{DBReader.getFeedList(context),
- DBReader.getFeedStatisticsList(context)};
- } else {
- return null;
- }
- }
-
-
- @Override
- protected void onPostExecute(List[] result) {
- super.onPostExecute(result);
- if (result != null) {
- feeds = result[0];
- feedItemStatistics = result[1];
- setEmptyViewIfListIsEmpty();
- if (fla != null) {
- fla.notifyDataSetChanged();
- }
- } else {
- Log.e(TAG, "Failed to load feeds");
- }
- }
- };
- loadTask.execute();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View result = inflater.inflate(R.layout.feedlist, container, false);
- listView = (ListView) result.findViewById(android.R.id.list);
- gridView = (GridView) result.findViewById(R.id.grid);
- emptyView = (TextView) result.findViewById(android.R.id.empty);
-
- return result;
-
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- if (listView != null) {
- listView.setOnItemClickListener(this);
- listView.setOnItemLongClickListener(this);
- listView.setAdapter(fla);
- listView.setEmptyView(emptyView);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Using ListView");
- } else {
- gridView.setOnItemClickListener(this);
- gridView.setOnItemLongClickListener(this);
- gridView.setAdapter(fla);
- gridView.setEmptyView(emptyView);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Using GridView");
- }
- setEmptyViewIfListIsEmpty();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Resuming");
- EventDistributor.getInstance().register(contentUpdate);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- EventDistributor.getInstance().unregister(contentUpdate);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (mActionMode != null) {
- mActionMode.finish();
- }
- }
-
- 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.");
- loadFeeds();
- }
- }
- };
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- FeedMenuHandler.onCreateOptionsMenu(mode.getMenuInflater(), menu);
- mode.setTitle(selectedFeed.getTitle());
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return FeedMenuHandler.onPrepareOptionsMenu(menu, selectedFeed);
- }
-
- @SuppressLint("NewApi")
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- try {
- if (FeedMenuHandler.onOptionsItemClicked(getActivity(),
- item, selectedFeed)) {
- loadFeeds();
- } else {
- switch (item.getItemId()) {
- case R.id.remove_item:
- final FeedRemover remover = new FeedRemover(
- getActivity(), selectedFeed) {
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- loadFeeds();
- }
- };
- 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();
- break;
- }
- }
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(
- getActivity(), e.getMessage());
- }
- mode.finish();
- return true;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- mActionMode = null;
- selectedFeed = null;
- fla.setSelectedItemIndex(FeedlistAdapter.SELECTION_NONE);
- }
-
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int position,
- long id) {
- Feed selection = fla.getItem(position);
- Intent showFeed = new Intent(getActivity(), FeedItemlistActivity.class);
- showFeed.putExtra(EXTRA_SELECTED_FEED, selection.getId());
-
- getActivity().startActivity(showFeed);
- }
-
- @Override
- public boolean onItemLongClick(AdapterView<?> parent, View view,
- int position, long id) {
- Feed selection = fla.getItem(position);
- if (selection != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Selected Feed with title " + selection.getTitle());
- if (mActionMode != null) {
- mActionMode.finish();
- }
- fla.setSelectedItemIndex(position);
- selectedFeed = selection;
- mActionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(FeedlistFragment.this);
-
- }
- return true;
- }
-
- private AbsListView getMainView() {
- return (listView != null) ? listView : gridView;
- }
-
- private void setEmptyViewIfListIsEmpty() {
- if (getMainView() != null && emptyView != null && feeds != null) {
- if (feeds.isEmpty()) {
- emptyView.setText(R.string.no_feeds_label);
- }
- }
- }
-}
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/MiroGuideChannellistFragment.java b/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java
deleted file mode 100644
index 53910b673..000000000
--- a/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package de.danoeh.antennapod.fragment;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.ListView;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MiroGuideChannelViewActivity;
-import de.danoeh.antennapod.adapter.MiroGuideChannelListAdapter;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideException;
-import de.danoeh.antennapod.miroguide.conn.MiroGuideService;
-import de.danoeh.antennapod.miroguide.model.MiroGuideChannel;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Displays a list of MiroGuideChannel objects that were results of a certain
- * MiroGuideService query. If the user reaches the bottom of the list, more
- * entries will be loaded until all entries have been loaded or the maximum
- * number of channels has been reached.
- * */
-public class MiroGuideChannellistFragment extends ListFragment {
- private static final String TAG = "MiroGuideChannellistFragment";
-
- private static final String ARG_FILTER = "filter";
- private static final String ARG_FILTER_VALUE = "filter_value";
- private static final String ARG_SORT = "sort";
-
- private static final int MAX_CHANNELS = 200;
- private static final int CHANNELS_PER_QUERY = MiroGuideService.DEFAULT_CHANNEL_LIMIT;
-
- private ArrayList<MiroGuideChannel> channels;
- private MiroGuideChannelListAdapter listAdapter;
- private int offset;
-
- private boolean isLoadingChannels;
- /**
- * True if there are no more entries to load or if the maximum number of
- * channels in the channellist has been reached
- */
- private boolean stopLoading;
-
- private View footer;
-
- private String filter;
- private String filterValue;
- private String sort;
-
- private AsyncTask<Void, Void, List<MiroGuideChannel>> channelLoader;
-
- /**
- * Creates a new instance of Channellist fragment.
- *
- * @throws IllegalArgumentException
- * if filter, filterValue or sort is null
- * */
- public static MiroGuideChannellistFragment newInstance(String filter,
- String filterValue, String sort) {
- if (filter == null) {
- throw new IllegalArgumentException("filter cannot be null");
- }
- if (filterValue == null) {
- throw new IllegalArgumentException("filter value cannot be null");
- }
- if (sort == null) {
- throw new IllegalArgumentException("sort cannot be null");
- }
- MiroGuideChannellistFragment cf = new MiroGuideChannellistFragment();
- Bundle args = new Bundle();
- args.putString(ARG_FILTER, filter);
- args.putString(ARG_FILTER_VALUE, filterValue);
- args.putString(ARG_SORT, sort);
- cf.setArguments(args);
- return cf;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- offset = 0;
- channels = new ArrayList<MiroGuideChannel>();
-
- Bundle args = getArguments();
- filter = args.getString(ARG_FILTER);
- filterValue = args.getString(ARG_FILTER_VALUE);
- sort = args.getString(ARG_SORT);
-
- LayoutInflater inflater = (LayoutInflater) getActivity()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- footer = inflater.inflate(R.layout.loading_footer, null);
- listAdapter = new MiroGuideChannelListAdapter(getActivity(), 0,
- channels);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (channels.isEmpty()) {
- setListShown(false);
- loadChannels();
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (channelLoader != null) {
- channelLoader.cancel(true);
- }
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- getListView().addFooterView(footer); // footer has to be added before
- // the adapter has been set
- getListView().setAdapter(listAdapter);
- getListView().removeFooterView(footer);
-
- getListView().setOnScrollListener(new OnScrollListener() {
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- int lastVisibleItem = firstVisibleItem + visibleItemCount;
- if (lastVisibleItem == totalItemCount) {
- if (BuildConfig.DEBUG)
- loadChannels();
- }
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
- });
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- super.onListItemClick(l, v, position, id);
- if (listAdapter != null) {
- MiroGuideChannel selection = listAdapter.getItem(position);
- Intent launchIntent = new Intent(getActivity(),
- MiroGuideChannelViewActivity.class);
- launchIntent.putExtra(
- MiroGuideChannelViewActivity.EXTRA_CHANNEL_ID,
- selection.getId());
- launchIntent.putExtra(
- MiroGuideChannelViewActivity.EXTRA_CHANNEL_URL,
- selection.getDownloadUrl());
- startActivity(launchIntent);
- }
- }
-
- @SuppressLint("NewApi")
- private void loadChannels() {
- if (!isLoadingChannels) {
- if (!stopLoading) {
- isLoadingChannels = true;
- channelLoader = new AsyncTask<Void, Void, List<MiroGuideChannel>>() {
- private MiroGuideException exception;
-
- @Override
- protected void onCancelled() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Channel loader was cancelled");
- }
-
- @Override
- protected void onPostExecute(List<MiroGuideChannel> result) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Channel loading finished");
- if (exception == null) {
- getListView().removeFooterView(footer);
- for (MiroGuideChannel channel : result) {
- channels.add(channel);
- }
- listAdapter.notifyDataSetChanged();
- offset += CHANNELS_PER_QUERY;
- // check if fragment should not send any more
- // queries
- if (result.size() < CHANNELS_PER_QUERY) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Query result was less than requested number of channels. Stopping to send any more queries");
- stopLoading = true;
- }
- if (offset >= MAX_CHANNELS) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Maximum number of feeds has been reached. Stopping to send any more queries");
- stopLoading = true;
- }
-
- setListShown(true);
- } else {
- AlertDialog.Builder dialog = new AlertDialog.Builder(
- getActivity());
- dialog.setTitle(R.string.error_label);
- dialog.setMessage(exception.getMessage());
- dialog.setNeutralButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(
- DialogInterface dialog,
- int which) {
- dialog.dismiss();
- }
- });
- dialog.create().show();
- }
- isLoadingChannels = false;
- }
-
- @Override
- protected void onPreExecute() {
- getListView().addFooterView(footer);
- }
-
- @Override
- protected List<MiroGuideChannel> doInBackground(
- Void... params) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Background channel loader started");
- MiroGuideService service = new MiroGuideService();
- try {
- return service.getChannelList(filter, filterValue,
- sort, CHANNELS_PER_QUERY, offset);
- } catch (MiroGuideException e) {
- exception = e;
- e.printStackTrace();
- } finally {
- // service.close();
- }
- return null;
- }
- };
-
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- channelLoader
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- channelLoader.execute();
- }
- }
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Channels are already being loaded");
- }
- }
-}
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));
}
});
diff --git a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java
deleted file mode 100644
index b4c06c340..000000000
--- a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package de.danoeh.antennapod.miroguide.conn;
-
-import android.net.Uri;
-import de.danoeh.antennapod.util.LangUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/** Executes HTTP requests and returns the results. */
-public class MiroGuideConnector {
- private HttpClient httpClient;
-
- private static final String HOST_URL = "http://www.miroguide.com/api/";
- private static final String PATH_GET_CHANNELS = "get_channels";
- private static final String PATH_LIST_CATEGORIES = "list_categories";
- private static final String PATH_GET_CHANNEL = "get_channel";
-
- public MiroGuideConnector() {
- httpClient = new DefaultHttpClient();
- }
-
- public void shutdown() {
- httpClient.getConnectionManager().shutdown();
- }
-
- private Uri.Builder getBaseURIBuilder(String path) {
- Uri.Builder builder = Uri.parse(HOST_URL).buildUpon();
- builder.appendPath(path).appendQueryParameter("datatype", "json");
- return builder;
- }
-
- public JSONArray getArrayResponse(Uri uri) throws MiroGuideException {
- try {
- JSONArray result = new JSONArray(executeRequest(uri));
- return result;
- } catch (JSONException e) {
- e.printStackTrace();
- throw new MiroGuideException();
- }
- }
-
- public JSONObject getSingleObjectResponse(Uri uri) throws MiroGuideException {
- try {
- JSONObject result = new JSONObject(executeRequest(uri));
- return result;
- } catch (JSONException e) {
- e.printStackTrace();
- throw new MiroGuideException();
- }
- }
-
- /**
- * Executes a HTTP GET request with the given URI and returns the content of
- * the return value.
- *
- * @throws MiroGuideException
- */
- private String executeRequest(Uri uri) throws MiroGuideException {
- HttpGet httpGet = new HttpGet(uri.toString());
- String result = null;
- try {
- HttpResponse response = httpClient.execute(httpGet);
- if (response.getStatusLine().getStatusCode() == 200) {
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(entity.getContent(),
- LangUtils.UTF_8));
- try {
- result = reader.readLine();
- } finally {
- reader.close();
- }
- }
- } else {
- throw new MiroGuideException(response.getStatusLine()
- .getReasonPhrase());
- }
- } catch (IOException e) {
- e.printStackTrace();
- throw new MiroGuideException(e.getMessage());
- }
- return result;
-
- }
-
- public Uri createGetChannelsUri(String filter, String filterValue,
- String sort, String limit, String offset) throws MiroGuideException {
- Uri.Builder resultBuilder = getBaseURIBuilder(PATH_GET_CHANNELS);
- resultBuilder.appendQueryParameter("filter", filter)
- .appendQueryParameter("filter_value", filterValue);
-
- if (sort != null) {
- resultBuilder.appendQueryParameter("sort", sort);
- }
- if (limit != null) {
- resultBuilder.appendQueryParameter("limit", limit);
- }
- if (offset != null) {
- resultBuilder.appendQueryParameter("offset", offset);
- }
- Uri result = resultBuilder.build();
- return result;
- }
-
- public Uri createListCategoriesURI() throws MiroGuideException {
- Uri.Builder resultBuilder = getBaseURIBuilder(PATH_LIST_CATEGORIES);
- Uri result = resultBuilder.build();
-
- return result;
- }
-
- public Uri createGetChannelUri(String id) throws MiroGuideException {
- Uri.Builder resultBuilder = getBaseURIBuilder(PATH_GET_CHANNEL)
- .appendQueryParameter("id", id);
- Uri result = resultBuilder.build();
- return result;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideException.java b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideException.java
deleted file mode 100644
index 6097761d8..000000000
--- a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.danoeh.antennapod.miroguide.conn;
-
-public class MiroGuideException extends Exception {
- private static final long serialVersionUID = -8834656185748713194L;
-
- public MiroGuideException() {
- super();
- }
-
- public MiroGuideException(String arg0, Throwable arg1) {
- super(arg0, arg1);
- }
-
- public MiroGuideException(String arg0) {
- super(arg0);
- }
-
- public MiroGuideException(Throwable arg0) {
- super(arg0);
- }
-
-
-}
diff --git a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java
deleted file mode 100644
index bdb4ec5dd..000000000
--- a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package de.danoeh.antennapod.miroguide.conn;
-
-import de.danoeh.antennapod.miroguide.model.MiroGuideChannel;
-import de.danoeh.antennapod.miroguide.model.MiroGuideItem;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-
-/** Provides methods to communicate with the Miroguide API on an abstract level. */
-public class MiroGuideService {
- private static final String TAG = "MiroGuideService";
-
- public static final int DEFAULT_CHANNEL_LIMIT = 20;
-
- public static final String FILTER_CATEGORY = "category";
- public static final String FILTER_NAME = "name";
- public static final String SORT_NAME = "name";
- public static final String SORT_POPULAR = "popular";
- public static final String SORT_RATING = "rating";
-
- public static final String JSON_DATE_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";
-
- private MiroGuideConnector connector;
-
- private static ThreadLocal<SimpleDateFormat> jSONDateFormat = new ThreadLocal<SimpleDateFormat>() {
- @Override
- protected SimpleDateFormat initialValue() {
- return new SimpleDateFormat(JSON_DATE_FORMAT_STRING, Locale.US);
- }
-
- };
-
- public MiroGuideService() {
- connector = new MiroGuideConnector();
- }
-
- public void close() {
- connector.shutdown();
- }
-
- public String[] getCategories() throws MiroGuideException {
- JSONArray resultArray = connector.getArrayResponse(connector
- .createListCategoriesURI());
- String[] result = new String[resultArray.length()];
- for (int i = 0; i < resultArray.length(); i++) {
- try {
- result[i] = resultArray.getJSONObject(i).getString("name");
- } catch (JSONException e) {
- e.printStackTrace();
- throw new MiroGuideException();
- }
- }
- return result;
- }
-
- /** Get a list of MiroGuideChannel objects without their items. */
- public List<MiroGuideChannel> getChannelList(String filter, String filterValue,
- String sort, int limit, int offset) throws MiroGuideException {
- JSONArray resultArray = connector.getArrayResponse(connector
- .createGetChannelsUri(filter, filterValue, sort,
- Integer.toString(limit), Integer.toString(offset)));
- int resultLen = resultArray.length();
- List<MiroGuideChannel> channels = new ArrayList<MiroGuideChannel>(resultLen);
- for (int i = 0; i < resultLen; i++) {
- JSONObject content = null;
- try {
- content = resultArray.getJSONObject(i);
- MiroGuideChannel channel = extractMiroChannel(content, false);
- channels.add(channel);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new MiroGuideException();
- }
- }
-
- return channels;
- }
-
- /**
- * Get a single channel with its items.
- *
- * @throws MiroGuideException
- */
- public MiroGuideChannel getChannel(long id) throws MiroGuideException {
- JSONObject resultObject = connector.getSingleObjectResponse(connector
- .createGetChannelUri(Long.toString(id)));
- MiroGuideChannel result = null;
- try {
- result = extractMiroChannel(resultObject, true);
- } catch (JSONException e) {
- e.printStackTrace();
- throw new MiroGuideException();
- }
- return result;
- }
-
- /**
- * Get a MiroGuideChannel object from it's JSON source. The itemlist of the
- * channel can be included or excluded
- *
- * @throws JSONException
- */
- private MiroGuideChannel extractMiroChannel(JSONObject content, boolean withItems)
- throws JSONException {
- long id = content.getLong("id");
- String name = content.getString("name");
- String description = content.getString("description");
- String thumbnailUrl = content.optString("thumbnail_url");
- String downloadUrl = content.getString("url");
- String websiteUrl = content.getString("website_url");
- if (!withItems) {
- return new MiroGuideChannel(id, name, thumbnailUrl, downloadUrl,
- websiteUrl, description);
- } else {
- JSONArray itemData = content.getJSONArray("item");
- int numItems = itemData.length();
- ArrayList<MiroGuideItem> items = new ArrayList<MiroGuideItem>(numItems);
- for (int i = 0; i < numItems; i++) {
- items.add(extractMiroItem(itemData.getJSONObject(i)));
- }
-
- return new MiroGuideChannel(id, name, thumbnailUrl, downloadUrl,
- websiteUrl, description, items);
- }
- }
-
- /** Get a MiroGuideItem from its JSON source. */
- private MiroGuideItem extractMiroItem(JSONObject content) throws JSONException {
- Date date = parseMiroItemDate(content.getString("date"));
- String description = content.getString("description");
- String name = content.getString("name");
- String url = content.getString("url");
- return new MiroGuideItem(name, description, date, url);
- }
-
- private Date parseMiroItemDate(String s) {
- try {
- return jSONDateFormat.get().parse(s);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/miroguide/model/MiroGuideChannel.java b/src/de/danoeh/antennapod/miroguide/model/MiroGuideChannel.java
deleted file mode 100644
index f5d62d2e8..000000000
--- a/src/de/danoeh/antennapod/miroguide/model/MiroGuideChannel.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package de.danoeh.antennapod.miroguide.model;
-
-import java.util.ArrayList;
-
-public class MiroGuideChannel {
- private long id;
- private String name;
- private String thumbnailUrl;
- private String downloadUrl;
- private String websiteUrl;
- private String description;
- private ArrayList<MiroGuideItem> items;
-
- public MiroGuideChannel(long id, String name, String thumbnailUrl,
- String downloadUrl, String websiteUrl, String description) {
- super();
- this.id = id;
- this.name = name;
- this.thumbnailUrl = thumbnailUrl;
- this.downloadUrl = downloadUrl;
- this.websiteUrl = websiteUrl;
- this.description = description;
- }
-
- public MiroGuideChannel(long id, String name, String thumbnailUrl,
- String downloadUrl, String websiteUrl, String description,
- ArrayList<MiroGuideItem> items) {
- super();
- this.id = id;
- this.name = name;
- this.thumbnailUrl = thumbnailUrl;
- this.downloadUrl = downloadUrl;
- this.websiteUrl = websiteUrl;
- this.description = description;
- this.items = items;
- }
-
- @Override
- public String toString() {
- return id + " " + name;
- }
-
- public long getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- public String getThumbnailUrl() {
- return thumbnailUrl;
- }
-
- public String getDownloadUrl() {
- return downloadUrl;
- }
-
- public String getWebsiteUrl() {
- return websiteUrl;
- }
-
- public String getDescription() {
- return description;
- }
-
- public ArrayList<MiroGuideItem> getItems() {
- return items;
- }
-
- public void setThumbnailUrl(String thumbnailUrl) {
- this.thumbnailUrl = thumbnailUrl;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/miroguide/model/MiroGuideItem.java b/src/de/danoeh/antennapod/miroguide/model/MiroGuideItem.java
deleted file mode 100644
index cb5b15c56..000000000
--- a/src/de/danoeh/antennapod/miroguide/model/MiroGuideItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package de.danoeh.antennapod.miroguide.model;
-
-import java.util.Date;
-
-public class MiroGuideItem {
- private String name;
- private String description;
- private Date date;
- private String url;
-
- public MiroGuideItem(String name, String description, Date date, String url) {
- super();
- this.name = name;
- this.description = description;
- this.date = (Date) date.clone();
- this.url = url;
- }
-
- @Override
- public String toString() {
- return name + " " + date.toString();
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public Date getDate() {
- return (Date) date.clone();
- }
-
- public String getUrl() {
- return url;
- }
-
-}
diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java
index 3662b646e..31250bcd9 100644
--- a/src/de/danoeh/antennapod/preferences/UserPreferences.java
+++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java
@@ -74,6 +74,7 @@ public class UserPreferences implements
private String playbackSpeed;
private String[] playbackSpeedArray;
private boolean pauseForFocusLoss;
+ private boolean isFreshInstall;
private UserPreferences(Context context) {
this.context = context;
@@ -282,6 +283,11 @@ public class UserPreferences implements
return instance.pauseForFocusLoss;
}
+ public static boolean isFreshInstall() {
+ instanceAvailable();
+ return instance.isFreshInstall;
+ }
+
@Override
public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
if (BuildConfig.DEBUG)
diff --git a/src/de/danoeh/antennapod/service/GpodnetSyncService.java b/src/de/danoeh/antennapod/service/GpodnetSyncService.java
index 4cb0e4cc8..1d652323a 100644
--- a/src/de/danoeh/antennapod/service/GpodnetSyncService.java
+++ b/src/de/danoeh/antennapod/service/GpodnetSyncService.java
@@ -8,6 +8,7 @@ import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
+import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.Feed;
@@ -93,7 +94,6 @@ public class GpodnetSyncService extends Service {
GpodnetUploadChangesResponse uploadChangesResponse =
service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), localSubscriptions, new LinkedList<String>());
if (BuildConfig.DEBUG) Log.d(TAG, "Uploading changes response: " + uploadChangesResponse);
- DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, uploadChangesResponse.updatedUrls).get();
GpodnetPreferences.removeAddedFeeds(localSubscriptions);
GpodnetPreferences.removeRemovedFeeds(GpodnetPreferences.getRemovedFeedsCopy());
GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
@@ -114,7 +114,6 @@ public class GpodnetSyncService extends Service {
GpodnetPreferences.removeAddedFeeds(added);
GpodnetPreferences.removeRemovedFeeds(removed);
- DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, uploadChangesResponse.updatedUrls).get();
GpodnetPreferences.setLastSyncTimestamp(uploadChangesResponse.timestamp);
}
clearErrorNotifications();
@@ -123,10 +122,6 @@ public class GpodnetSyncService extends Service {
updateErrorNotification(e);
} catch (DownloadRequestException e) {
e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
}
}
stopSelf();
diff --git a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java
index 7b3f014e8..be331ce9b 100644
--- a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java
+++ b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java
@@ -33,7 +33,7 @@ public class AntennapodHttpClient {
public static final int CONNECTION_TIMEOUT = 30000;
public static final int SOCKET_TIMEOUT = 30000;
- public static final int MAX_CONNECTIONS = 6;
+ public static final int MAX_CONNECTIONS = 8;
private static volatile HttpClient httpClient = null;
diff --git a/src/de/danoeh/antennapod/service/download/DownloadRequest.java b/src/de/danoeh/antennapod/service/download/DownloadRequest.java
index be22bbebb..7ff9bc01c 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadRequest.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadRequest.java
@@ -10,6 +10,7 @@ public class DownloadRequest implements Parcelable {
private final String title;
private String username;
private String password;
+ private boolean deleteOnFailure;
private final long feedfileId;
private final int feedfileType;
@@ -19,7 +20,7 @@ public class DownloadRequest implements Parcelable {
protected int statusMsg;
public DownloadRequest(String destination, String source, String title,
- long feedfileId, int feedfileType, String username, String password) {
+ long feedfileId, int feedfileType, String username, String password, boolean deleteOnFailure) {
if (destination == null) {
throw new IllegalArgumentException("Destination must not be null");
}
@@ -37,11 +38,12 @@ public class DownloadRequest implements Parcelable {
this.feedfileType = feedfileType;
this.username = username;
this.password = password;
+ this.deleteOnFailure = deleteOnFailure;
}
public DownloadRequest(String destination, String source, String title,
long feedfileId, int feedfileType) {
- this(destination, source, title, feedfileId, feedfileType, null, null);
+ this(destination, source, title, feedfileId, feedfileType, null, null, true);
}
private DownloadRequest(Parcel in) {
@@ -50,6 +52,7 @@ public class DownloadRequest implements Parcelable {
title = in.readString();
feedfileId = in.readLong();
feedfileType = in.readInt();
+ deleteOnFailure = (in.readByte() > 0);
if (in.dataAvail() > 0) {
username = in.readString();
} else {
@@ -74,6 +77,7 @@ public class DownloadRequest implements Parcelable {
dest.writeString(title);
dest.writeLong(feedfileId);
dest.writeInt(feedfileType);
+ dest.writeByte((deleteOnFailure) ? (byte) 1 : 0);
if (username != null) {
dest.writeString(username);
}
@@ -93,59 +97,43 @@ public class DownloadRequest implements Parcelable {
};
@Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((destination == null) ? 0 : destination.hashCode());
- result = prime * result + (int) (feedfileId ^ (feedfileId >>> 32));
- result = prime * result + feedfileType;
- result = prime * result + progressPercent;
- result = prime * result + (int) (size ^ (size >>> 32));
- result = prime * result + (int) (soFar ^ (soFar >>> 32));
- result = prime * result + ((source == null) ? 0 : source.hashCode());
- result = prime * result + statusMsg;
- result = prime * result + ((title == null) ? 0 : title.hashCode());
- return result;
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ DownloadRequest that = (DownloadRequest) o;
+
+ if (deleteOnFailure != that.deleteOnFailure) return false;
+ if (feedfileId != that.feedfileId) return false;
+ if (feedfileType != that.feedfileType) return false;
+ if (progressPercent != that.progressPercent) return false;
+ if (size != that.size) return false;
+ if (soFar != that.soFar) return false;
+ if (statusMsg != that.statusMsg) return false;
+ if (destination != null ? !destination.equals(that.destination) : that.destination != null) return false;
+ if (password != null ? !password.equals(that.password) : that.password != null) return false;
+ if (source != null ? !source.equals(that.source) : that.source != null) return false;
+ if (title != null ? !title.equals(that.title) : that.title != null) return false;
+ if (username != null ? !username.equals(that.username) : that.username != null) return false;
+
+ return true;
}
@Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- DownloadRequest other = (DownloadRequest) obj;
- if (destination == null) {
- if (other.destination != null)
- return false;
- } else if (!destination.equals(other.destination))
- return false;
- if (feedfileId != other.feedfileId)
- return false;
- if (feedfileType != other.feedfileType)
- return false;
- if (progressPercent != other.progressPercent)
- return false;
- if (size != other.size)
- return false;
- if (soFar != other.soFar)
- return false;
- if (source == null) {
- if (other.source != null)
- return false;
- } else if (!source.equals(other.source))
- return false;
- if (statusMsg != other.statusMsg)
- return false;
- if (title == null) {
- if (other.title != null)
- return false;
- } else if (!title.equals(other.title))
- return false;
- return true;
+ public int hashCode() {
+ int result = destination != null ? destination.hashCode() : 0;
+ result = 31 * result + (source != null ? source.hashCode() : 0);
+ result = 31 * result + (title != null ? title.hashCode() : 0);
+ result = 31 * result + (username != null ? username.hashCode() : 0);
+ result = 31 * result + (password != null ? password.hashCode() : 0);
+ result = 31 * result + (deleteOnFailure ? 1 : 0);
+ result = 31 * result + (int) (feedfileId ^ (feedfileId >>> 32));
+ result = 31 * result + feedfileType;
+ result = 31 * result + progressPercent;
+ result = 31 * result + (int) (soFar ^ (soFar >>> 32));
+ result = 31 * result + (int) (size ^ (size >>> 32));
+ result = 31 * result + statusMsg;
+ return result;
}
public String getDestination() {
@@ -215,4 +203,8 @@ public class DownloadRequest implements Parcelable {
public void setPassword(String password) {
this.password = password;
}
+
+ public boolean isDeleteOnFailure() {
+ return deleteOnFailure;
+ }
}
diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java
index 72e0852bb..ed2f5d532 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadService.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadService.java
@@ -13,6 +13,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
@@ -20,26 +21,26 @@ import android.util.Log;
import android.webkit.URLUtil;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.DownloadActivity;
import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
-import de.danoeh.antennapod.activity.DownloadLogActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.feed.*;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.storage.*;
import de.danoeh.antennapod.syndication.handler.FeedHandler;
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
import de.danoeh.antennapod.util.ChapterUtils;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.InvalidFeedException;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpStatus;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
@@ -87,10 +88,12 @@ public class DownloadService extends Service {
private ExecutorService syncExecutor;
private CompletionService<Downloader> downloadExecutor;
+ private FeedSyncThread feedSyncThread;
+
/**
* Number of threads of downloadExecutor.
*/
- private static final int NUM_PARALLEL_DOWNLOADS = 4;
+ private static final int NUM_PARALLEL_DOWNLOADS = 6;
private DownloadRequester requester;
@@ -160,9 +163,16 @@ public class DownloadService extends Service {
if (!status.isCancelled()) {
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
postAuthenticationNotification(downloader.getDownloadRequest());
+ } else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
+ && Integer.valueOf(status.getReasonDetailed()) == HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
+
+ Log.d(TAG, "Requested invalid range, restarting download from the beginning");
+ FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
+ DownloadRequester.getInstance().download(DownloadService.this, downloader.getDownloadRequest());
} else {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
+ handleFailedDownload(status, downloader.getDownloadRequest());
}
}
sendDownloadHandledIntent();
@@ -245,6 +255,9 @@ public class DownloadService extends Service {
}
);
downloadCompletionThread.start();
+ feedSyncThread = new FeedSyncThread();
+ feedSyncThread.start();
+
setupNotificationBuilders();
requester = DownloadRequester.getInstance();
}
@@ -268,17 +281,27 @@ public class DownloadService extends Service {
downloadCompletionThread.interrupt();
syncExecutor.shutdown();
schedExecutor.shutdown();
+ feedSyncThread.shutdown();
cancelNotificationUpdater();
unregisterReceiver(cancelDownloadReceiver);
+
+ DBTasks.autodownloadUndownloadedItems(getApplicationContext());
}
@SuppressLint("NewApi")
private void setupNotificationBuilders() {
- PendingIntent pIntent = PendingIntent.getActivity(this, 0, new Intent(
- this, DownloadActivity.class),
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_RUNNING);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+
+ PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT
);
+
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.stat_notify_sync);
@@ -305,8 +328,14 @@ public class DownloadService extends Service {
@SuppressLint("NewApi")
private Notification updateNotifications() {
String contentTitle = getString(R.string.download_notification_title);
- String downloadsLeft = requester.getNumberOfDownloads()
- + getString(R.string.downloads_left);
+ int numDownloads = requester.getNumberOfDownloads();
+ String downloadsLeft;
+ if (numDownloads > 0) {
+ downloadsLeft = requester.getNumberOfDownloads()
+ + getString(R.string.downloads_left);
+ } else {
+ downloadsLeft = getString(R.string.downloads_processing);
+ }
if (android.os.Build.VERSION.SDK_INT >= 16) {
if (notificationBuilder != null) {
@@ -346,7 +375,7 @@ public class DownloadService extends Service {
if (notificationCompatBuilder != null) {
notificationCompatBuilder.setContentTitle(contentTitle);
notificationCompatBuilder.setContentText(downloadsLeft);
- return notificationCompatBuilder.getNotification();
+ return notificationCompatBuilder.build();
}
}
return null;
@@ -490,6 +519,13 @@ public class DownloadService extends Service {
if (createReport) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Creating report");
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+
// create notification object
Notification notification = new NotificationCompat.Builder(this)
.setTicker(
@@ -507,10 +543,9 @@ public class DownloadService extends Service {
R.drawable.stat_notify_sync)
)
.setContentIntent(
- PendingIntent.getActivity(this, 0, new Intent(this,
- DownloadLogActivity.class), 0)
+ PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
)
- .setAutoCancel(true).getNotification();
+ .setAutoCancel(true).build();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(REPORT_ID, notification);
} else {
@@ -586,7 +621,7 @@ public class DownloadService extends Service {
private void handleCompletedFeedDownload(DownloadRequest request) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Handling completed Feed Download");
- syncExecutor.execute(new FeedSyncThread(request));
+ feedSyncThread.submitCompletedDownload(request);
}
@@ -608,102 +643,217 @@ public class DownloadService extends Service {
syncExecutor.execute(new MediaHandlerThread(status, request));
}
+ private void handleFailedDownload(DownloadStatus status, DownloadRequest request) {
+ if (BuildConfig.DEBUG) Log.d(TAG, "Handling failed download");
+ syncExecutor.execute(new FailedDownloadHandler(status, request));
+ }
+
/**
* Takes a single Feed, parses the corresponding file and refreshes
* information in the manager
*/
- class FeedSyncThread implements Runnable {
+ class FeedSyncThread extends Thread {
private static final String TAG = "FeedSyncThread";
- private DownloadRequest request;
+ private BlockingQueue<DownloadRequest> completedRequests = new LinkedBlockingDeque<DownloadRequest>();
+ private CompletionService<Feed> parserService = new ExecutorCompletionService<Feed>(Executors.newSingleThreadExecutor());
+ private ExecutorService dbService = Executors.newSingleThreadExecutor();
+ private Future<?> dbUpdateFuture;
+ private volatile boolean isActive = true;
+ private volatile boolean isCollectingRequests = false;
- private DownloadError reason;
- private boolean successful;
+ private final long WAIT_TIMEOUT = 3000;
- public FeedSyncThread(DownloadRequest request) {
- if (request == null) {
- throw new IllegalArgumentException("Request must not be null");
+
+ /**
+ * Waits for completed requests. Once the first request has been taken, the method will wait WAIT_TIMEOUT ms longer to
+ * collect more completed requests.
+ *
+ * @return Collected feeds or null if the method has been interrupted during the first waiting period.
+ */
+ private List<Feed> collectCompletedRequests() {
+ List<Feed> results = new LinkedList<Feed>();
+ DownloadRequester requester = DownloadRequester.getInstance();
+ int tasks = 0;
+
+ try {
+ DownloadRequest request = completedRequests.take();
+ parserService.submit(new FeedParserTask(request));
+ tasks++;
+ } catch (InterruptedException e) {
+ return null;
}
- this.request = request;
+ tasks += pollCompletedDownloads();
+
+ isCollectingRequests = true;
+
+ if (requester.isDownloadingFeeds()) {
+ // wait for completion of more downloads
+ long startTime = System.currentTimeMillis();
+ long currentTime = startTime;
+ while (requester.isDownloadingFeeds() && (currentTime - startTime) < WAIT_TIMEOUT) {
+ try {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Waiting for " + (startTime + WAIT_TIMEOUT - currentTime) + " ms");
+ sleep(startTime + WAIT_TIMEOUT - currentTime);
+ } catch (InterruptedException e) {
+ if (BuildConfig.DEBUG) Log.d(TAG, "interrupted while waiting for more downloads");
+ tasks += pollCompletedDownloads();
+ } finally {
+ currentTime = System.currentTimeMillis();
+ }
+ }
+
+ tasks += pollCompletedDownloads();
+
+ }
+
+ isCollectingRequests = false;
+
+ for (int i = 0; i < tasks; i++) {
+ try {
+ Feed f = parserService.take().get();
+ if (f != null) {
+ results.add(f);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return results;
}
+ private int pollCompletedDownloads() {
+ int tasks = 0;
+ for (int i = 0; i < completedRequests.size(); i++) {
+ parserService.submit(new FeedParserTask(completedRequests.poll()));
+ tasks++;
+ }
+ return tasks;
+ }
+
+ @Override
public void run() {
+ while (isActive) {
+ final List<Feed> feeds = collectCompletedRequests();
+
+ if (feeds == null) {
+ continue;
+ }
+
+ if (BuildConfig.DEBUG) Log.d(TAG, "Bundling " + feeds.size() + " feeds");
+
+ for (Feed feed : feeds) {
+ removeDuplicateImages(feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet.
+ }
+
+ // Save information of feed in DB
+ if (dbUpdateFuture != null) {
+ try {
+ dbUpdateFuture.get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ dbUpdateFuture = dbService.submit(new Runnable() {
+ @Override
+ public void run() {
+ Feed[] savedFeeds = DBTasks.updateFeed(DownloadService.this, feeds.toArray(new Feed[feeds.size()]));
+
+ for (Feed savedFeed : savedFeeds) {
+ // Download Feed Image if provided and not downloaded
+ if (savedFeed.getImage() != null
+ && savedFeed.getImage().isDownloaded() == false) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Feed has image; Downloading....");
+ savedFeed.getImage().setOwner(savedFeed);
+ final Feed savedFeedRef = savedFeed;
+ try {
+ requester.downloadImage(DownloadService.this,
+ savedFeedRef.getImage());
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DBWriter.addDownloadStatus(
+ DownloadService.this,
+ new DownloadStatus(
+ savedFeedRef.getImage(),
+ savedFeedRef
+ .getImage()
+ .getHumanReadableIdentifier(),
+ DownloadError.ERROR_REQUEST_ERROR,
+ false, e.getMessage()
+ )
+ );
+ }
+ }
+ numberOfDownloads.decrementAndGet();
+ }
+
+ sendDownloadHandledIntent();
+
+ queryDownloadsAsync();
+ }
+ });
+
+ }
+
+ if (dbUpdateFuture != null) {
+ try {
+ dbUpdateFuture.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (BuildConfig.DEBUG) Log.d(TAG, "Shutting down");
+
+ }
+
+ private class FeedParserTask implements Callable<Feed> {
+
+ private DownloadRequest request;
+
+ private FeedParserTask(DownloadRequest request) {
+ this.request = request;
+ }
+
+ @Override
+ public Feed call() throws Exception {
+ return parseFeed(request);
+ }
+ }
+
+ private Feed parseFeed(DownloadRequest request) {
Feed savedFeed = null;
Feed feed = new Feed(request.getSource(), new Date());
feed.setFile_url(request.getDestination());
+ feed.setId(request.getFeedfileId());
feed.setDownloaded(true);
feed.setPreferences(new FeedPreferences(0, true, request.getUsername(), request.getPassword()));
- reason = null;
+ DownloadError reason = null;
String reasonDetailed = null;
- successful = true;
+ boolean successful = true;
FeedHandler feedHandler = new FeedHandler();
try {
- feed = feedHandler.parseFeed(feed);
+ feed = feedHandler.parseFeed(feed).feed;
if (BuildConfig.DEBUG)
Log.d(TAG, feed.getTitle() + " parsed");
if (checkFeedData(feed) == false) {
throw new InvalidFeedException();
}
- removeDuplicateImages(feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet.
-
- // Save information of feed in DB
- savedFeed = DBTasks.updateFeed(DownloadService.this, feed);
- // Download Feed Image if provided and not downloaded
- if (savedFeed.getImage() != null
- && savedFeed.getImage().isDownloaded() == false) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed has image; Downloading....");
- savedFeed.getImage().setOwner(savedFeed);
- final Feed savedFeedRef = savedFeed;
- try {
- requester.downloadImage(DownloadService.this,
- savedFeedRef.getImage());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- DownloadService.this,
- new DownloadStatus(
- savedFeedRef.getImage(),
- savedFeedRef
- .getImage()
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()
- )
- );
- }
- }
- // download FeedItem images if provided and not downloaded
- for (FeedItem item : savedFeed.getItems()) {
- if (item.hasItemImage() && (!item.getImage().isDownloaded())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Item has image; Downloading....");
- try {
- requester.downloadImage(DownloadService.this,
- item.getImage());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- DownloadService.this,
- new DownloadStatus(
- item.getImage(),
- item
- .getImage()
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()
- )
- );
- }
- }
- }
-
-
} catch (SAXException e) {
successful = false;
e.printStackTrace();
@@ -736,14 +886,18 @@ public class DownloadService extends Service {
savedFeed = feed;
}
- saveDownloadStatus(new DownloadStatus(savedFeed,
- savedFeed.getHumanReadableIdentifier(), reason, successful,
- reasonDetailed));
- sendDownloadHandledIntent();
- numberOfDownloads.decrementAndGet();
- queryDownloadsAsync();
+
+ if (successful) {
+ return savedFeed;
+ } else {
+ saveDownloadStatus(new DownloadStatus(savedFeed,
+ savedFeed.getHumanReadableIdentifier(), reason, successful,
+ reasonDetailed));
+ return null;
+ }
}
+
/**
* Checks if the feed was parsed correctly.
*/
@@ -756,8 +910,6 @@ public class DownloadService extends Service {
Log.e(TAG, "Feed has invalid items");
return false;
}
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed appears to be valid.");
return true;
}
@@ -815,6 +967,60 @@ public class DownloadService extends Service {
}
}
+ public void shutdown() {
+ isActive = false;
+ if (isCollectingRequests) {
+ interrupt();
+ }
+ }
+
+ public void submitCompletedDownload(DownloadRequest request) {
+ completedRequests.offer(request);
+ if (isCollectingRequests) {
+ interrupt();
+ }
+ }
+
+ }
+
+ /**
+ * Handles failed downloads.
+ * <p/>
+ * If the file has been partially downloaded, this handler will set the file_url of the FeedFile to the location
+ * of the downloaded file.
+ * <p/>
+ * Currently, this handler only handles FeedMedia objects, because Feeds and FeedImages are deleted if the download fails.
+ */
+ class FailedDownloadHandler implements Runnable {
+
+ private DownloadRequest request;
+ private DownloadStatus status;
+
+ FailedDownloadHandler(DownloadStatus status, DownloadRequest request) {
+ this.request = request;
+ this.status = status;
+ }
+
+ @Override
+ public void run() {
+ if (request.isDeleteOnFailure()) {
+ if (BuildConfig.DEBUG) Log.d(TAG, "Ignoring failed download, deleteOnFailure=true");
+ } else {
+ File dest = new File(request.getDestination());
+ if (dest.exists() && request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ Log.d(TAG, "File has been partially downloaded. Writing file url");
+ FeedMedia media = DBReader.getFeedMedia(DownloadService.this, request.getFeedfileId());
+ media.setFile_url(request.getDestination());
+ try {
+ DBWriter.setFeedMedia(DownloadService.this, media).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
}
/**
diff --git a/src/de/danoeh/antennapod/service/download/HttpDownloader.java b/src/de/danoeh/antennapod/service/download/HttpDownloader.java
index 84bafb027..7ae96dc07 100644
--- a/src/de/danoeh/antennapod/service/download/HttpDownloader.java
+++ b/src/de/danoeh/antennapod/service/download/HttpDownloader.java
@@ -14,10 +14,12 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.message.BasicHeader;
import java.io.*;
import java.net.HttpURLConnection;
@@ -36,7 +38,9 @@ public class HttpDownloader extends Downloader {
@Override
protected void download() {
File destination = new File(request.getDestination());
- if (destination.exists()) {
+ final boolean fileExists = destination.exists();
+
+ if (request.isDeleteOnFailure() && fileExists) {
Log.w(TAG, "File already exists");
if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
onFail(DownloadError.ERROR_FILE_EXISTS, null);
@@ -48,10 +52,12 @@ public class HttpDownloader extends Downloader {
}
HttpClient httpClient = AntennapodHttpClient.getHttpClient();
- BufferedOutputStream out = null;
+ RandomAccessFile out = null;
InputStream connection = null;
try {
HttpGet httpGet = new HttpGet(URIUtil.getURIFromRequestUrl(request.getSource()));
+
+ // add authentication information
String userInfo = httpGet.getURI().getUserInfo();
if (userInfo != null) {
String[] parts = userInfo.split(":");
@@ -64,6 +70,15 @@ public class HttpDownloader extends Downloader {
httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(request.getUsername(),
request.getPassword()), "UTF-8", false));
}
+
+ // add range header if necessary
+ if (fileExists) {
+ request.setSoFar(destination.length());
+ httpGet.addHeader(new BasicHeader("Range",
+ "bytes=" + request.getSoFar() + "-"));
+ if (BuildConfig.DEBUG) Log.d(TAG, "Adding range header: " + request.getSoFar());
+ }
+
HttpResponse response = httpClient.execute(httpGet);
HttpEntity httpEntity = response.getEntity();
int responseCode = response.getStatusLine().getStatusCode();
@@ -75,7 +90,7 @@ public class HttpDownloader extends Downloader {
if (BuildConfig.DEBUG)
Log.d(TAG, "Response code is " + responseCode);
- if (responseCode != HttpURLConnection.HTTP_OK || httpEntity == null) {
+ if (responseCode / 100 != 2 || httpEntity == null) {
final DownloadError error;
final String details;
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
@@ -96,14 +111,31 @@ public class HttpDownloader extends Downloader {
connection = new BufferedInputStream(AndroidHttpClient
.getUngzippedContent(httpEntity));
- out = new BufferedOutputStream(new FileOutputStream(
- destination));
+
+ Header[] contentRangeHeaders = (fileExists) ? response.getHeaders("Content-Range") : null;
+
+ if (fileExists && responseCode == HttpStatus.SC_PARTIAL_CONTENT
+ && contentRangeHeaders != null && contentRangeHeaders.length > 0) {
+ String start = contentRangeHeaders[0].getValue().substring("bytes ".length(),
+ contentRangeHeaders[0].getValue().indexOf("-"));
+ request.setSoFar(Long.valueOf(start));
+ Log.d(TAG, "Starting download at position " + request.getSoFar());
+
+ out = new RandomAccessFile(destination, "rw");
+ out.seek(request.getSoFar());
+ } else {
+ destination.delete();
+ destination.createNewFile();
+ out = new RandomAccessFile(destination, "rw");
+ }
+
+
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0;
request.setStatusMsg(R.string.download_running);
if (BuildConfig.DEBUG)
Log.d(TAG, "Getting size of download");
- request.setSize(httpEntity.getContentLength());
+ request.setSize(httpEntity.getContentLength() + request.getSoFar());
if (BuildConfig.DEBUG)
Log.d(TAG, "Size is " + request.getSize());
if (request.getSize() < 0) {
@@ -133,7 +165,6 @@ public class HttpDownloader extends Downloader {
if (cancelled) {
onCancelled();
} else {
- out.flush();
// check if size specified in the response header is the same as the size of the
// written file. This check cannot be made if compression was used
if (!isGzip && request.getSize() != DownloadStatus.SIZE_UNKNOWN &&
@@ -182,7 +213,9 @@ public class HttpDownloader extends Downloader {
Log.d(TAG, "Download failed");
}
result.setFailed(reason, reasonDetailed);
- cleanup();
+ if (request.isDeleteOnFailure()) {
+ cleanup();
+ }
}
private void onCancelled() {
diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
index 82759a902..24ff9b3fa 100644
--- a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
+++ b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
@@ -509,19 +509,13 @@ public class PlaybackServiceMediaPlayer {
}
/**
- * Returns true if the playback speed can be adjusted. This method can also return false if the PSMP object's
- * internal MediaPlayer cannot be accessed at the moment.
+ * Returns true if the playback speed can be adjusted.
*/
public boolean canSetSpeed() {
- if (!playerLock.tryLock()) {
- return false;
- }
boolean retVal = false;
if (mediaPlayer != null && media != null && media.getMediaType() == MediaType.AUDIO) {
retVal = (mediaPlayer).canSetSpeed();
}
-
- playerLock.unlock();
return retVal;
}
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
index 8d4785bd4..4aeca7cd6 100644
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ b/src/de/danoeh/antennapod/storage/DBReader.java
@@ -504,6 +504,32 @@ public final class DBReader {
return itemIds;
}
+
+ /**
+ * Loads a list of FeedItems sorted by pubDate in descending order.
+ *
+ * @param context A context that is used for opening a database connection.
+ * @param limit The maximum number of episodes that should be loaded.
+ * */
+ public static List<FeedItem> getRecentlyPublishedEpisodes(Context context, int limit) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Extracting recently published items list");
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+
+ Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit);
+ List<FeedItem> items = extractItemlistFromCursor(adapter,
+ itemlistCursor);
+ itemlistCursor.close();
+
+ loadFeedDataOfFeedItemlist(context, items);
+
+ adapter.close();
+
+ return items;
+ }
+
/**
* Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
* has been completed at least once.
@@ -619,12 +645,18 @@ public final class DBReader {
* database and the items-attribute will be set correctly.
*/
public static Feed getFeed(final Context context, final long feedId) {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ Feed result = getFeed(context, feedId, adapter);
+ adapter.close();
+ return result;
+ }
+
+ static Feed getFeed(final Context context, final long feedId, PodDBAdapter adapter) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Loading feed with id " + feedId);
Feed feed = null;
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
Cursor feedCursor = adapter.getFeedCursor(feedId);
if (feedCursor.moveToFirst()) {
feed = extractFeedFromCursorRow(adapter, feedCursor);
@@ -633,7 +665,6 @@ public final class DBReader {
Log.e(TAG, "getFeed could not find feed with id " + feedId);
}
feedCursor.close();
- adapter.close();
return feed;
}
diff --git a/src/de/danoeh/antennapod/storage/DBTasks.java b/src/de/danoeh/antennapod/storage/DBTasks.java
index 92efeea62..c6a34aeea 100644
--- a/src/de/danoeh/antennapod/storage/DBTasks.java
+++ b/src/de/danoeh/antennapod/storage/DBTasks.java
@@ -228,7 +228,9 @@ public final class DBTasks {
new DownloadStatus(feed, feed
.getHumanReadableIdentifier(),
DownloadError.ERROR_REQUEST_ERROR, false, e
- .getMessage()));
+ .getMessage()
+ )
+ );
}
}
@@ -249,7 +251,7 @@ public final class DBTasks {
f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle(),
feed.getPreferences().getUsername(), feed.getPreferences().getPassword());
}
-
+ f.setId(feed.getId());
DownloadRequester.getInstance().downloadFeed(context, f);
}
@@ -347,7 +349,9 @@ public final class DBTasks {
.getMedia()
.getHumanReadableIdentifier(),
DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()));
+ false, e.getMessage()
+ )
+ );
}
} else {
requester.downloadMedia(context, item.getMedia());
@@ -449,7 +453,8 @@ public final class DBTasks {
try {
downloadFeedItems(false, context,
itemsToDownload.toArray(new FeedItem[itemsToDownload
- .size()]));
+ .size()])
+ );
} catch (DownloadRequestException e) {
e.printStackTrace();
}
@@ -595,12 +600,17 @@ public final class DBTasks {
return QueueAccess.IDListAccess(queue).contains(feedItemId);
}
- private static Feed searchFeedByIdentifyingValue(Context context,
- String identifier) {
- List<Feed> feeds = DBReader.getFeedList(context);
- for (Feed feed : feeds) {
- if (feed.getIdentifyingValue().equals(identifier)) {
- return feed;
+ private static Feed searchFeedByIdentifyingValueOrID(Context context, PodDBAdapter adapter,
+ Feed feed) {
+ if (feed.getId() != 0) {
+ return DBReader.getFeed(context, feed.getId(), adapter);
+ } else {
+ List<Feed> feeds = DBReader.getFeedList(context);
+ for (Feed f : feeds) {
+ if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
+ f.setItems(DBReader.getFeedItemList(context, f));
+ return f;
+ }
}
}
return null;
@@ -620,79 +630,97 @@ public final class DBTasks {
}
/**
- * Adds a new Feed to the database or updates the old version if it already exists. If another Feed with the same
+ * Adds new Feeds to the database or updates the old versions if they already exists. If another Feed with the same
* identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
* These FeedItems will be marked as unread.
+ * <p/>
+ * This method can update multiple feeds at once. Submitting a feed twice in the same method call can result in undefined behavior.
+ * <p/>
* This method should NOT be executed on the GUI thread.
*
- * @param context Used for accessing the DB.
- * @param newFeed The new Feed object.
- * @return The updated Feed from the database if it already existed, or the new Feed from the parameters otherwise.
+ * @param context Used for accessing the DB.
+ * @param newFeeds The new Feed objects.
+ * @return The updated Feeds from the database if it already existed, or the new Feed from the parameters otherwise.
*/
- public static synchronized Feed updateFeed(final Context context,
- final Feed newFeed) {
- // Look up feed in the feedslist
- final Feed savedFeed = searchFeedByIdentifyingValue(context,
- newFeed.getIdentifyingValue());
- if (savedFeed == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Found no existing Feed with title "
- + newFeed.getTitle() + ". Adding as new one.");
- // Add a new Feed
- try {
- DBWriter.addNewFeed(context, newFeed).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- return newFeed;
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed with title " + newFeed.getTitle()
- + " already exists. Syncing new with existing one.");
+ public static synchronized Feed[] updateFeed(final Context context,
+ final Feed... newFeeds) {
+ List<Feed> newFeedsList = new ArrayList<Feed>();
+ List<Feed> updatedFeedsList = new ArrayList<Feed>();
+ Feed[] resultFeeds = new Feed[newFeeds.length];
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
- Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
- savedFeed.setItems(DBReader.getFeedItemList(context, savedFeed));
- if (savedFeed.compareWithOther(newFeed)) {
+ for (int feedIdx = 0; feedIdx < newFeeds.length; feedIdx++) {
+
+ final Feed newFeed = newFeeds[feedIdx];
+
+ // Look up feed in the feedslist
+ final Feed savedFeed = searchFeedByIdentifyingValueOrID(context, adapter,
+ newFeed);
+ if (savedFeed == null) {
if (BuildConfig.DEBUG)
Log.d(TAG,
- "Feed has updated attribute values. Updating old feed's attributes");
- savedFeed.updateFromOther(newFeed);
- }
- if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
+ "Found no existing Feed with title "
+ + newFeed.getTitle() + ". Adding as new one."
+ );
+ // Add a new Feed
+ newFeedsList.add(newFeed);
+ resultFeeds[feedIdx] = newFeed;
+ } else {
if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
- savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
- }
- // Look for new or updated Items
- for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
- final FeedItem item = newFeed.getItems().get(idx);
- FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed,
- item.getIdentifyingValue());
- if (oldItem == null) {
- // item is new
- final int i = idx;
- item.setFeed(savedFeed);
- savedFeed.getItems().add(i, item);
- item.setRead(false);
- } else {
- oldItem.updateFromOther(item);
+ Log.d(TAG, "Feed with title " + newFeed.getTitle()
+ + " already exists. Syncing new with existing one.");
+
+ Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
+ if (savedFeed.compareWithOther(newFeed)) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG,
+ "Feed has updated attribute values. Updating old feed's attributes");
+ savedFeed.updateFromOther(newFeed);
}
+ if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
+ savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
+ }
+ // Look for new or updated Items
+ for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
+ final FeedItem item = newFeed.getItems().get(idx);
+ FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed,
+ item.getIdentifyingValue());
+ if (oldItem == null) {
+ // item is new
+ final int i = idx;
+ item.setFeed(savedFeed);
+ savedFeed.getItems().add(i, item);
+ item.setRead(false);
+ } else {
+ oldItem.updateFromOther(item);
+ }
+ }
+ // update attributes
+ savedFeed.setLastUpdate(newFeed.getLastUpdate());
+ savedFeed.setType(newFeed.getType());
+
+ updatedFeedsList.add(savedFeed);
+ resultFeeds[feedIdx] = savedFeed;
}
- // update attributes
- savedFeed.setLastUpdate(newFeed.getLastUpdate());
- savedFeed.setType(newFeed.getType());
- try {
- DBWriter.setCompleteFeed(context, savedFeed).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- return savedFeed;
}
+
+ adapter.close();
+
+ try {
+ DBWriter.addNewFeed(context, newFeedsList.toArray(new Feed[newFeedsList.size()])).get();
+ DBWriter.setCompleteFeed(context, updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ EventDistributor.getInstance().sendFeedUpdateBroadcast();
+
+ return resultFeeds;
}
/**
diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java
index c1ce9da36..ffdfc65fd 100644
--- a/src/de/danoeh/antennapod/storage/DBWriter.java
+++ b/src/de/danoeh/antennapod/storage/DBWriter.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.storage;
+import android.app.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -197,6 +198,9 @@ public class DBWriter {
GpodnetPreferences.addRemovedFeed(feed.getDownload_url());
EventDistributor.getInstance().sendFeedUpdateBroadcast();
+
+ BackupManager backupManager = new BackupManager(context);
+ backupManager.dataChanged();
}
}
});
@@ -683,33 +687,36 @@ public class DBWriter {
}
- static Future<?> addNewFeed(final Context context, final Feed feed) {
+ static Future<?> addNewFeed(final Context context, final Feed... feeds) {
return dbExec.submit(new Runnable() {
@Override
public void run() {
final PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
- adapter.setCompleteFeed(feed);
+ adapter.setCompleteFeed(feeds);
adapter.close();
- GpodnetPreferences.addAddedFeed(feed.getDownload_url());
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
+ for (Feed feed : feeds) {
+ GpodnetPreferences.addAddedFeed(feed.getDownload_url());
+ }
+
+ BackupManager backupManager = new BackupManager(context);
+ backupManager.dataChanged();
}
});
}
- static Future<?> setCompleteFeed(final Context context, final Feed feed) {
+ static Future<?> setCompleteFeed(final Context context, final Feed... feeds) {
return dbExec.submit(new Runnable() {
@Override
public void run() {
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
- adapter.setCompleteFeed(feed);
+ adapter.setCompleteFeed(feeds);
adapter.close();
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
}
});
@@ -830,6 +837,7 @@ public class DBWriter {
adapter.open();
adapter.setFeedPreferences(preferences);
adapter.close();
+ EventDistributor.getInstance().sendFeedUpdateBroadcast();
}
});
}
diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java
index 0a1747253..7bf21352a 100644
--- a/src/de/danoeh/antennapod/storage/DownloadRequester.java
+++ b/src/de/danoeh/antennapod/storage/DownloadRequester.java
@@ -12,6 +12,7 @@ import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.util.FileNameGenerator;
import de.danoeh.antennapod.util.URLChecker;
import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@@ -72,9 +73,9 @@ public class DownloadRequester {
}
private void download(Context context, FeedFile item, File dest,
- boolean overwriteIfExists, String username, String password) {
+ boolean overwriteIfExists, String username, String password, boolean deleteOnFailure) {
if (!isDownloadingFile(item)) {
- if (!isFilenameAvailable(dest.toString()) || dest.exists()) {
+ if (!isFilenameAvailable(dest.toString()) || (deleteOnFailure && dest.exists())) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Filename already used.");
if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
@@ -113,8 +114,8 @@ public class DownloadRequester {
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
DownloadRequest request = new DownloadRequest(dest.toString(),
- item.getDownload_url(), item.getHumanReadableIdentifier(),
- item.getId(), item.getTypeAsInt(), username, password);
+ URLChecker.prepareURL(item.getDownload_url()), item.getHumanReadableIdentifier(),
+ item.getId(), item.getTypeAsInt(), username, password, deleteOnFailure);
download(context, request);
} else {
@@ -149,7 +150,7 @@ public class DownloadRequester {
String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null;
download(context, feed, new File(getFeedfilePath(context),
- getFeedfileName(feed)), true, username, password);
+ getFeedfileName(feed)), true, username, password, true);
}
}
@@ -157,16 +158,33 @@ public class DownloadRequester {
throws DownloadRequestException {
if (feedFileValid(image)) {
download(context, image, new File(getImagefilePath(context),
- getImagefileName(image)), false, null, null);
+ getImagefileName(image)), false, null, null, false);
}
}
public void downloadMedia(Context context, FeedMedia feedmedia)
throws DownloadRequestException {
if (feedFileValid(feedmedia)) {
+ Feed feed = feedmedia.getItem().getFeed();
+ String username;
+ String password;
+ if (feed != null && feed.getPreferences() != null) {
+ username = feed.getPreferences().getUsername();
+ password = feed.getPreferences().getPassword();
+ } else {
+ username = null;
+ password = null;
+ }
+
+ File dest;
+ if (feedmedia.getFile_url() != null) {
+ dest = new File(feedmedia.getFile_url());
+ } else {
+ dest = new File(getMediafilePath(context, feedmedia),
+ getMediafilename(feedmedia));
+ }
download(context, feedmedia,
- new File(getMediafilePath(context, feedmedia),
- getMediafilename(feedmedia)), false, null, null
+ dest, false, username, password, false
);
}
}
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index 825b5ac30..285709537 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.storage;
+import android.app.backup.BackupManager;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -386,6 +387,7 @@ public class PodDBAdapter {
Log.d(this.toString(), "Updating existing Feed in db");
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?",
new String[]{String.valueOf(feed.getId())});
+
}
return feed.getId();
}
@@ -495,16 +497,18 @@ public class PodDBAdapter {
* Insert all FeedItems of a feed and the feed object itself in a single
* transaction
*/
- public void setCompleteFeed(Feed feed) {
+ public void setCompleteFeed(Feed... feeds) {
db.beginTransaction();
- setFeed(feed);
- if (feed.getItems() != null) {
- for (FeedItem item : feed.getItems()) {
- setFeedItem(item, false);
+ for (Feed feed : feeds) {
+ setFeed(feed);
+ if (feed.getItems() != null) {
+ for (FeedItem item : feed.getItems()) {
+ setFeedItem(item, false);
+ }
+ }
+ if (feed.getPreferences() != null) {
+ setFeedPreferences(feed.getPreferences());
}
- }
- if (feed.getPreferences() != null) {
- setFeedPreferences(feed.getPreferences());
}
db.setTransactionSuccessful();
db.endTransaction();
@@ -844,6 +848,7 @@ public class PodDBAdapter {
removeFeedItem(item);
}
}
+
db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?",
new String[]{String.valueOf(feed.getId())});
db.setTransactionSuccessful();
@@ -996,6 +1001,11 @@ public class PodDBAdapter {
}
+ public final Cursor getRecentlyPublishedItemsCursor(int limit) {
+ Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit);
+ return c;
+ }
+
public Cursor getDownloadedItemsCursor() {
final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
+ " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
diff --git a/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java b/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java
index 5576603b6..aafa1c209 100644
--- a/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java
+++ b/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java
@@ -14,7 +14,7 @@ import java.io.Reader;
public class FeedHandler {
- public Feed parseFeed(Feed feed) throws SAXException, IOException,
+ public FeedHandlerResult parseFeed(Feed feed) throws SAXException, IOException,
ParserConfigurationException, UnsupportedFeedtypeException {
TypeGetter tg = new TypeGetter();
TypeGetter.Type type = tg.getType(feed);
@@ -29,6 +29,6 @@ public class FeedHandler {
saxParser.parse(inputSource, handler);
inputStreamReader.close();
- return handler.state.feed;
+ return new FeedHandlerResult(handler.state.feed, handler.state.alternateUrls);
}
}
diff --git a/src/de/danoeh/antennapod/syndication/handler/FeedHandlerResult.java b/src/de/danoeh/antennapod/syndication/handler/FeedHandlerResult.java
new file mode 100644
index 000000000..41aa29b52
--- /dev/null
+++ b/src/de/danoeh/antennapod/syndication/handler/FeedHandlerResult.java
@@ -0,0 +1,19 @@
+package de.danoeh.antennapod.syndication.handler;
+
+import de.danoeh.antennapod.feed.Feed;
+
+import java.util.Map;
+
+/**
+ * Container for results returned by the Feed parser
+ */
+public class FeedHandlerResult {
+
+ public Feed feed;
+ public Map<String, String> alternateFeedUrls;
+
+ public FeedHandlerResult(Feed feed, Map<String, String> alternateFeedUrls) {
+ this.feed = feed;
+ this.alternateFeedUrls = alternateFeedUrls;
+ }
+}
diff --git a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
index a9a8bb934..17f84724f 100644
--- a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
+++ b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
@@ -5,9 +5,7 @@ import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.syndication.namespace.Namespace;
import de.danoeh.antennapod.syndication.namespace.SyndElement;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Stack;
+import java.util.*;
/**
* Contains all relevant information to describe the current state of a
@@ -15,70 +13,86 @@ import java.util.Stack;
*/
public class HandlerState {
- /** Feed that the Handler is currently processing. */
- protected Feed feed;
- protected ArrayList<FeedItem> items;
- protected FeedItem currentItem;
- protected Stack<SyndElement> tagstack;
- /** Namespaces that have been defined so far. */
- protected HashMap<String, Namespace> namespaces;
- protected Stack<Namespace> defaultNamespaces;
- /** Buffer for saving characters. */
- protected StringBuffer contentBuf;
-
- public HandlerState(Feed feed) {
- this.feed = feed;
- items = new ArrayList<FeedItem>();
- tagstack = new Stack<SyndElement>();
- namespaces = new HashMap<String, Namespace>();
- defaultNamespaces = new Stack<Namespace>();
- }
-
- public Feed getFeed() {
- return feed;
- }
-
- public ArrayList<FeedItem> getItems() {
- return items;
- }
-
- public FeedItem getCurrentItem() {
- return currentItem;
- }
-
- public Stack<SyndElement> getTagstack() {
- return tagstack;
- }
-
- public void setFeed(Feed feed) {
- this.feed = feed;
- }
-
- public void setCurrentItem(FeedItem currentItem) {
- this.currentItem = currentItem;
- }
-
- /**
- * Returns the SyndElement that comes after the top element of the tagstack.
- */
- public SyndElement getSecondTag() {
- SyndElement top = tagstack.pop();
- SyndElement second = tagstack.peek();
- tagstack.push(top);
- return second;
- }
-
- public SyndElement getThirdTag() {
- SyndElement top = tagstack.pop();
- SyndElement second = tagstack.pop();
- SyndElement third = tagstack.peek();
- tagstack.push(second);
- tagstack.push(top);
- return third;
- }
-
- public StringBuffer getContentBuf() {
- return contentBuf;
- }
+ /**
+ * Feed that the Handler is currently processing.
+ */
+ protected Feed feed;
+ /**
+ * Contains links to related feeds, e.g. feeds with enclosures in other formats. The key of the map is the
+ * URL of the feed, the value is the title
+ */
+ protected Map<String, String> alternateUrls;
+ protected ArrayList<FeedItem> items;
+ protected FeedItem currentItem;
+ protected Stack<SyndElement> tagstack;
+ /**
+ * Namespaces that have been defined so far.
+ */
+ protected HashMap<String, Namespace> namespaces;
+ protected Stack<Namespace> defaultNamespaces;
+ /**
+ * Buffer for saving characters.
+ */
+ protected StringBuffer contentBuf;
+
+ public HandlerState(Feed feed) {
+ this.feed = feed;
+ alternateUrls = new LinkedHashMap<String, String>();
+ items = new ArrayList<FeedItem>();
+ tagstack = new Stack<SyndElement>();
+ namespaces = new HashMap<String, Namespace>();
+ defaultNamespaces = new Stack<Namespace>();
+ }
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public ArrayList<FeedItem> getItems() {
+ return items;
+ }
+
+ public FeedItem getCurrentItem() {
+ return currentItem;
+ }
+
+ public Stack<SyndElement> getTagstack() {
+ return tagstack;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ public void setCurrentItem(FeedItem currentItem) {
+ this.currentItem = currentItem;
+ }
+
+ /**
+ * Returns the SyndElement that comes after the top element of the tagstack.
+ */
+ public SyndElement getSecondTag() {
+ SyndElement top = tagstack.pop();
+ SyndElement second = tagstack.peek();
+ tagstack.push(top);
+ return second;
+ }
+
+ public SyndElement getThirdTag() {
+ SyndElement top = tagstack.pop();
+ SyndElement second = tagstack.pop();
+ SyndElement third = tagstack.peek();
+ tagstack.push(second);
+ tagstack.push(top);
+ return third;
+ }
+
+ public StringBuffer getContentBuf() {
+ return contentBuf;
+ }
+
+ public void addAlternateFeedUrl(String title, String url) {
+ alternateUrls.put(url, title);
+ }
}
diff --git a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java
index 0ac1b7ae2..5ed9ff2b0 100644
--- a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java
+++ b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java
@@ -17,7 +17,7 @@ import java.io.Reader;
public class TypeGetter {
private static final String TAG = "TypeGetter";
- enum Type {
+ public enum Type {
RSS20, RSS091, ATOM, INVALID
}
diff --git a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
index 383b29fc8..2c8e232ff 100644
--- a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
+++ b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
@@ -92,7 +92,8 @@ public class NSAtom extends Namespace {
.getValidMimeTypeFromUrl(href)) != null) {
state.getCurrentItem().setMedia(
new FeedMedia(state.getCurrentItem(), href,
- size, type));
+ size, type)
+ );
}
} else if (rel.equals(LINK_REL_PAYMENT)) {
state.getCurrentItem().setPaymentLink(href);
@@ -101,13 +102,20 @@ public class NSAtom extends Namespace {
if (rel == null || rel.equals(LINK_REL_ALTERNATE)) {
String type = attributes.getValue(LINK_TYPE);
/*
- * Use as link if a) no type-attribute is given and
+ * Use as link if a) no type-attribute is given and
* feed-object has no link yet b) type of link is
* LINK_TYPE_HTML or LINK_TYPE_XHTML
*/
if ((type == null && state.getFeed().getLink() == null)
|| (type != null && (type.equals(LINK_TYPE_HTML) || type.equals(LINK_TYPE_XHTML)))) {
state.getFeed().setLink(href);
+ } else if (type != null && (type.equals(LINK_TYPE_ATOM) || type.equals(LINK_TYPE_RSS))) {
+ // treat as podlove alternate feed
+ String title = attributes.getValue(LINK_TITLE);
+ if (title == null) {
+ title = href;
+ }
+ state.addAlternateFeedUrl(title, href);
}
} else if (rel.equals(LINK_REL_PAYMENT)) {
state.getFeed().setPaymentLink(href);
diff --git a/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java b/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java
index 2c1cff914..3138f087a 100644
--- a/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java
+++ b/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java
@@ -79,7 +79,7 @@ public class SyndDateUtils {
second = date.substring(date.indexOf("-"));
}
}
-
+
date = first + second;
}
if (isLocal) {
@@ -131,4 +131,23 @@ public class SyndDateUtils {
result += (Float.valueOf(parts[idx])) * 1000L;
return result;
}
+
+ public static String formatRFC822Date(Date date) {
+ SimpleDateFormat format = RFC822Formatter.get();
+ return format.format(date);
+ }
+
+ public static String formatRFC3339Local(Date date) {
+ SimpleDateFormat format = RFC3339Formatter.get();
+ format.applyPattern(RFC3339LOCAL);
+ String result = format.format(date);
+ format.applyPattern(RFC3339UTC);
+ return result;
+ }
+
+ public static String formatRFC3339UTC(Date date) {
+ SimpleDateFormat format = RFC3339Formatter.get();
+ format.applyPattern(RFC3339UTC);
+ return format.format(date);
+ }
}
diff --git a/src/de/danoeh/antennapod/util/URLChecker.java b/src/de/danoeh/antennapod/util/URLChecker.java
index a3c675899..eb522ffa8 100644
--- a/src/de/danoeh/antennapod/util/URLChecker.java
+++ b/src/de/danoeh/antennapod/util/URLChecker.java
@@ -3,25 +3,36 @@ package de.danoeh.antennapod.util;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
-/** Provides methods for checking and editing a URL.*/
+/**
+ * Provides methods for checking and editing a URL.
+ */
public final class URLChecker {
- /**Class shall not be instantiated.*/
+ /**
+ * Class shall not be instantiated.
+ */
private URLChecker() {
}
- /**Logging tag.*/
+ /**
+ * Logging tag.
+ */
private static final String TAG = "URLChecker";
- /** Checks if URL is valid and modifies it if necessary.
- * @param url The url which is going to be prepared
- * @return The prepared url
- * */
+ /**
+ * Checks if URL is valid and modifies it if necessary.
+ *
+ * @param url The url which is going to be prepared
+ * @return The prepared url
+ */
public static String prepareURL(String url) {
StringBuilder builder = new StringBuilder();
if (url.startsWith("feed://")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://");
- url = url.replace("feed://", "http://");
+ url = url.replaceFirst("feed://", "http://");
+ } else if (url.startsWith("pcast://")) {
+ if (BuildConfig.DEBUG) Log.d(TAG, "Replacing pcast:// with http://");
+ url = url.replaceFirst("pcast://", "http://");
} else if (!(url.startsWith("http://") || url.startsWith("https://"))) {
if (BuildConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL");
builder.append("http://");
diff --git a/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
new file mode 100644
index 000000000..b920559db
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.util.gui;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import de.danoeh.antennapod.feed.FeedItem;
+
+/**
+ * Used by an UndoBarController for saving a removed FeedItem
+ */
+public class FeedItemUndoToken implements Parcelable {
+ private long itemId;
+ private long feedId;
+ private int position;
+
+ public FeedItemUndoToken(FeedItem item, int position) {
+ this.itemId = item.getId();
+ this.feedId = item.getFeed().getId();
+ this.position = position;
+ }
+
+ private FeedItemUndoToken(Parcel in) {
+ itemId = in.readLong();
+ feedId = in.readLong();
+ position = in.readInt();
+ }
+
+ public static final Parcelable.Creator<FeedItemUndoToken> CREATOR = new Parcelable.Creator<FeedItemUndoToken>() {
+ public FeedItemUndoToken createFromParcel(Parcel in) {
+ return new FeedItemUndoToken(in);
+ }
+
+ public FeedItemUndoToken[] newArray(int size) {
+ return new FeedItemUndoToken[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(itemId);
+ out.writeLong(feedId);
+ out.writeInt(position);
+ }
+
+ public long getFeedItemId() {
+ return itemId;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+}
+
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
index ae8b3ac1e..a3adec66d 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
@@ -60,12 +60,6 @@ public class FeedMenuHandler {
public static boolean onOptionsItemClicked(Context context, MenuItem item,
Feed selectedFeed) throws DownloadRequestException {
switch (item.getItemId()) {
- case R.id.show_info_item:
- Intent startIntent = new Intent(context, FeedInfoActivity.class);
- startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
- selectedFeed.getId());
- context.startActivity(startIntent);
- break;
case R.id.refresh_item:
DBTasks.refreshFeed(context, selectedFeed);
break;
diff --git a/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java b/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java
new file mode 100644
index 000000000..e75fa394a
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.util.menuhandler;
+
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.SearchView;
+import android.view.Menu;
+import android.view.MenuItem;
+import de.danoeh.antennapod.R;
+
+/**
+ * Utilities for menu items
+ */
+public class MenuItemUtils {
+
+ public static MenuItem addSearchItem(Menu menu, SearchView searchView) {
+ MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
+ MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ MenuItemCompat.setActionView(item, searchView);
+ return item;
+ }
+}