summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--app/build.gradle16
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java1
-rw-r--r--app/src/main/AndroidManifest.xml11
-rw-r--r--app/src/main/assets/about.html2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java182
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java96
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/DBTasksCallbacksImpl.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java445
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java24
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java58
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java442
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java50
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java36
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java29
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java45
-rw-r--r--app/src/main/res/layout-land/audioplayer_activity.xml188
-rw-r--r--app/src/main/res/layout/audioplayer_activity.xml312
-rw-r--r--app/src/main/res/layout/cover_fragment.xml4
-rw-r--r--app/src/main/res/layout/feeditem_dialog.xml73
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml25
-rw-r--r--app/src/main/res/layout/feeditem_fragment_header.xml101
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml17
-rw-r--r--app/src/main/res/layout/main.xml25
-rw-r--r--app/src/main/res/layout/nav_list.xml71
-rw-r--r--app/src/main/res/layout/nav_section_item.xml2
-rw-r--r--app/src/main/res/layout/pager_fragment.xml14
-rw-r--r--app/src/main/res/layout/simplechapter_item.xml78
-rw-r--r--app/src/main/res/menu/feeditem.xml8
-rw-r--r--app/src/main/res/menu/main.xml12
-rw-r--r--app/src/main/res/menu/mediaplayer.xml2
-rw-r--r--app/src/main/res/xml/preferences.xml12
-rw-r--r--build.gradle2
-rw-r--r--core/build.gradle16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/DBTaskLoader.java29
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java251
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java38
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java30
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java105
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java125
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java103
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java133
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java139
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java72
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java178
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java36
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java32
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java2
-rw-r--r--core/src/main/res/drawable-hdpi/ic_settings_grey600_24dp.pngbin0 -> 572 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_settings_white_24dp.pngbin0 -> 561 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_settings_grey600_24dp.pngbin0 -> 704 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_settings_white_24dp.pngbin0 -> 737 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.pngbin0 -> 994 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.pngbin0 -> 974 bytes
-rw-r--r--core/src/main/res/layout/refresh_action_view.xml (renamed from app/src/main/res/layout/refresh_action_view.xml)0
-rw-r--r--core/src/main/res/values/attrs.xml1
-rw-r--r--core/src/main/res/values/colors.xml5
-rw-r--r--core/src/main/res/values/dimens.xml2
-rw-r--r--core/src/main/res/values/strings.xml4
-rw-r--r--core/src/main/res/values/styles.xml95
79 files changed, 2520 insertions, 1566 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0d83fd483..2c8c15bf5 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -9,6 +9,7 @@ wseemann
hzulla
andrewgaul
peschmae0
+TomHennen
Translations:
diff --git a/app/build.gradle b/app/build.gradle
index 14897139b..8f829d0af 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,12 +4,10 @@ repositories {
mavenCentral()
}
dependencies {
- compile 'com.android.support:support-v4:21.0.2'
- compile 'com.android.support:appcompat-v7:21.0.2'
+ compile 'com.android.support:support-v4:21.0.3'
+ compile 'com.android.support:appcompat-v7:21.0.3'
compile 'org.apache.commons:commons-lang3:3.3.2'
- compile('org.shredzone.flattr4j:flattr4j-core:2.11') {
- exclude group: 'org.apache.httpcomponents', module: 'httpcore'
- exclude group: 'org.apache.httpcomponents', module: 'httpclient'
+ compile('org.shredzone.flattr4j:flattr4j-core:2.12') {
exclude group: 'org.json', module: 'json'
}
compile 'commons-io:commons-io:2.4'
@@ -17,15 +15,15 @@ dependencies {
compile 'com.jayway.android.robotium:robotium-solo:5.2.1'
compile 'org.jsoup:jsoup:1.7.3'
compile 'com.squareup.picasso:picasso:2.4.0'
- compile 'com.squareup.okhttp:okhttp:2.1.0'
- compile 'com.squareup.okhttp:okhttp-urlconnection:2.1.0'
- compile 'com.squareup.okio:okio:1.0.1'
+ compile 'com.squareup.okhttp:okhttp:2.2.0'
+ compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
+ compile 'com.squareup.okio:okio:1.2.0'
compile project(':core')
}
android {
compileSdkVersion 21
- buildToolsVersion "21.1.1"
+ buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 10
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
index daae4bd62..2235ee6f4 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
@@ -41,6 +41,7 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
adapter.open();
adapter.close();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
+ prefs.edit().putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false).commit();
prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false).commit();
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 50d1d2874..5b00941de 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="43"
- android:versionName="0.9.9.6">
+ android:versionCode="44"
+ android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@@ -304,6 +304,13 @@
</intent-filter>
</receiver>
+ <receiver android:name=".receiver.PowerConnectionReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+ <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
+ </intent-filter>
+ </receiver>
+
<receiver android:name=".receiver.SPAReceiver">
<intent-filter>
<action android:name="de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE"/>
diff --git a/app/src/main/assets/about.html b/app/src/main/assets/about.html
index 172b49aab..3398dbb67 100644
--- a/app/src/main/assets/about.html
+++ b/app/src/main/assets/about.html
@@ -41,7 +41,7 @@
<div id="header" align="center">
<img src="logo.png" alt="Logo" width="100px" height="100px"/>
- <p>AntennaPod, Version 0.9.9.6</p>
+ <p>AntennaPod, Version 1.0</p>
<p>Copyright © 2014 Daniel Oeh</p>
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index eb7a844db..821c86044 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -11,6 +11,7 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -21,7 +22,6 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
-import android.widget.ImageView.ScaleType;
import android.widget.ListView;
import android.widget.TextView;
@@ -49,6 +49,7 @@ import de.danoeh.antennapod.fragment.CoverFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
+import de.danoeh.antennapod.preferences.PreferenceController;
/**
* Activity for playing audio files.
@@ -59,6 +60,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private static final int POS_DESCR = 1;
private static final int POS_CHAPTERS = 2;
private static final int NUM_CONTENT_FRAGMENTS = 3;
+ private static final int POS_NONE = -1;
final String TAG = "AudioplayerActivity";
private static final String PREFS = "AudioPlayerActivityPreferences";
@@ -68,6 +70,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
private ListView navList;
+ private View navDrawer;
private ActionBarDrawerToggle drawerToggle;
private Fragment[] detachedFragments;
@@ -78,6 +81,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private Fragment currentlyShownFragment;
private int currentlyShownPosition = -1;
+ private int lastShownPosition = POS_NONE;
/**
* Used if onResume was called without loadMediaInfo.
*/
@@ -85,8 +89,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private TextView txtvTitle;
private Button butPlaybackSpeed;
- private ImageButton butNavLeft;
- private ImageButton butNavRight;
+ private ImageButton butNavChaptersShownotes;
+ private ImageButton butShowCover;
private void resetFragmentView() {
FragmentTransaction fT = getSupportFragmentManager().beginTransaction();
@@ -139,9 +143,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
@Override
+ protected void chooseTheme() {
+ setTheme(UserPreferences.getNoTitleTheme());
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayShowTitleEnabled(false);
detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
}
@@ -320,24 +328,32 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
chapterFragment = new ListFragment() {
@Override
- public void onListItemClick(ListView l, View v,
- int position, long id) {
- super.onListItemClick(l, v, position, id);
- Chapter chapter = (Chapter) this
- .getListAdapter().getItem(position);
- controller.seekToChapter(chapter);
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ // add padding
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
}
-
};
chapterFragment.setListAdapter(new ChapterListAdapter(
AudioplayerActivity.this, 0, media
- .getChapters(), media
+ .getChapters(), media, new ChapterListAdapter.Callback() {
+ @Override
+ public void onPlayChapterButtonClicked(int position) {
+ Chapter chapter = (Chapter)
+ chapterFragment.getListAdapter().getItem(position);
+ controller.seekToChapter(chapter);
+ }
+ }
));
}
currentlyShownFragment = chapterFragment;
break;
}
if (currentlyShownFragment != null) {
+ lastShownPosition = currentlyShownPosition;
currentlyShownPosition = pos;
if (detachedFragments[pos] != null) {
if (BuildConfig.DEBUG)
@@ -355,78 +371,70 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
}
+ /**
+ * Switches to the fragment that was displayed before the current one or the description fragment
+ * if no fragment was previously displayed.
+ */
+ public void switchToLastFragment() {
+ if (lastShownPosition != POS_NONE) {
+ switchToFragment(lastShownPosition);
+ } else {
+ switchToFragment(POS_DESCR);
+ }
+ }
+
private void updateNavButtonDrawable() {
final int[] buttonTexts = new int[]{R.string.show_shownotes_label,
- R.string.show_chapters_label, R.string.show_cover_label};
+ R.string.show_chapters_label};
final TypedArray drawables = obtainStyledAttributes(new int[]{
R.attr.navigation_shownotes, R.attr.navigation_chapters});
final Playable media = controller.getMedia();
- if (butNavLeft != null && butNavRight != null && media != null) {
-
- butNavRight.setTag(R.id.imageloader_key, null);
- butNavLeft.setTag(R.id.imageloader_key, null);
+ if (butNavChaptersShownotes != null && butShowCover != null && media != null) {
+ butNavChaptersShownotes.setTag(R.id.imageloader_key, null);
+ setNavButtonVisibility();
switch (currentlyShownPosition) {
case POS_COVER:
- butNavLeft.setScaleType(ScaleType.CENTER);
- butNavLeft.setImageDrawable(drawables.getDrawable(0));
- butNavLeft.setContentDescription(getString(buttonTexts[0]));
-
- butNavRight.setImageDrawable(drawables.getDrawable(1));
- butNavRight.setContentDescription(getString(buttonTexts[1]));
-
+ butShowCover.setVisibility(View.GONE);
+ if (lastShownPosition == POS_CHAPTERS) {
+ butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
+ butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
+ } else {
+ butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
+ butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
+ }
break;
case POS_DESCR:
- butNavLeft.setScaleType(ScaleType.CENTER_CROP);
- butNavLeft.post(new Runnable() {
-
- @Override
- public void run() {
- Picasso.with(AudioplayerActivity.this)
- .load(media.getImageUri())
- .fit()
- .into(butNavLeft);
- }
- });
- butNavLeft.setContentDescription(getString(buttonTexts[2]));
-
- butNavRight.setImageDrawable(drawables.getDrawable(1));
- butNavRight.setContentDescription(getString(buttonTexts[1]));
+ butShowCover.setVisibility(View.VISIBLE);
+ butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
+ butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
break;
case POS_CHAPTERS:
- butNavLeft.setScaleType(ScaleType.CENTER_CROP);
- butNavLeft.post(new Runnable() {
-
- @Override
- public void run() {
- Picasso.with(AudioplayerActivity.this)
- .load(media.getImageUri())
- .fit()
- .into(butNavLeft);
- }
-
- });
- butNavLeft.setContentDescription(getString(buttonTexts[2]));
-
- butNavRight.setImageDrawable(drawables.getDrawable(0));
- butNavRight.setContentDescription(getString(buttonTexts[0]));
+ butShowCover.setVisibility(View.VISIBLE);
+ butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
+ butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
break;
}
}
+ drawables.recycle();
}
@Override
protected void setupGUI() {
super.setupGUI();
resetFragmentView();
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.nav_list);
- txtvTitle = (TextView) findViewById(R.id.txtvTitle);
- butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
- butNavRight = (ImageButton) findViewById(R.id.butNavRight);
+ navDrawer = findViewById(R.id.nav_layout);
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
+ butNavChaptersShownotes = (ImageButton) findViewById(R.id.butNavChaptersShownotes);
+ butShowCover = (ImageButton) findViewById(R.id.butCover);
+ txtvTitle = (TextView) findViewById(R.id.txtvTitle);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close) {
CharSequence currentTitle = getSupportActionBar().getTitle();
@@ -463,38 +471,39 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
intent.putExtra(MainActivity.EXTRA_NAV_INDEX, relPos);
startActivity(intent);
}
- drawerLayout.closeDrawer(navList);
+ drawerLayout.closeDrawer(navDrawer);
}
});
drawerToggle.syncState();
- butNavLeft.setOnClickListener(new OnClickListener() {
-
+ findViewById(R.id.nav_settings).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (currentlyShownFragment == null
- || currentlyShownPosition == POS_DESCR) {
- switchToFragment(POS_COVER);
- } else if (currentlyShownPosition == POS_COVER) {
- switchToFragment(POS_DESCR);
- } else if (currentlyShownPosition == POS_CHAPTERS) {
- switchToFragment(POS_COVER);
- }
+ drawerLayout.closeDrawer(navDrawer);
+ startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
}
});
- butNavRight.setOnClickListener(new OnClickListener() {
-
+ butNavChaptersShownotes.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (currentlyShownPosition == POS_CHAPTERS) {
switchToFragment(POS_DESCR);
- } else {
+ } else if (currentlyShownPosition == POS_DESCR) {
switchToFragment(POS_CHAPTERS);
+ } else if (currentlyShownPosition == POS_COVER) {
+ switchToLastFragment();
}
}
});
+ butShowCover.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ switchToFragment(POS_COVER);
+ }
+ });
+
butPlaybackSpeed.setOnClickListener(new OnClickListener() {
@Override
@@ -539,6 +548,22 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
});
}
+ private void setNavButtonVisibility() {
+ if (butNavChaptersShownotes != null) {
+ if (controller != null) {
+ Playable media = controller.getMedia();
+ if (media != null) {
+ if (media.getChapters() != null || currentlyShownPosition == POS_COVER) {
+ butNavChaptersShownotes.setVisibility(View.VISIBLE);
+ return;
+ }
+ }
+ }
+ butNavChaptersShownotes.setVisibility(View.GONE);
+ }
+
+ }
+
@Override
protected void onPlaybackSpeedChange() {
super.onPlaybackSpeedChange();
@@ -567,12 +592,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
return false;
}
txtvTitle.setText(media.getEpisodeTitle());
- if (media.getChapters() != null) {
- butNavRight.setVisibility(View.VISIBLE);
- } else {
- butNavRight.setVisibility(View.INVISIBLE);
- }
+ getSupportActionBar().setTitle("");
+ Picasso.with(this)
+ .load(media.getImageUri())
+ .fit()
+ .into(butShowCover);
+ setNavButtonVisibility();
if (currentlyShownPosition == -1) {
if (!restoreFromPreferences()) {
@@ -632,7 +658,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
@Override
public boolean isDrawerOpen() {
- return drawerLayout != null && navList != null && drawerLayout.isDrawerOpen(navList);
+ return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index df6ff1046..b3e95f0c0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -14,9 +14,8 @@ import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.widget.Toolbar;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
@@ -62,15 +61,22 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
public static final String EXTRA_NAV_TYPE = "nav_type";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
+ public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
+ public static final String SAVE_SELECTED_NAV_INDEX = "selectedNavIndex";
+ public static final String SAVE_TITLE = "title";
+
+
public static final int POS_NEW = 0,
POS_QUEUE = 1,
POS_DOWNLOADS = 2,
POS_HISTORY = 3,
POS_ADD = 4;
+ private Toolbar toolbar;
private ExternalPlayerFragment externalPlayerFragment;
private DrawerLayout drawerLayout;
+ private View navDrawer;
private ListView navList;
private NavListAdapter navAdapter;
@@ -82,17 +88,22 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
+ setTheme(UserPreferences.getNoTitleTheme());
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setElevation(3.0f);
+
drawerTitle = currentTitle = getTitle();
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.nav_list);
-
+ navDrawer = findViewById(R.id.nav_layout);
+ Log.i(TAG, "");
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close) {
@Override
public void onDrawerOpened(View drawerView) {
@@ -111,8 +122,21 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
};
+ if (savedInstanceState != null) {
+ int backstackCount = savedInstanceState.getInt(SAVE_BACKSTACK_COUNT, 0);
+ drawerToggle.setDrawerIndicatorEnabled(backstackCount == 0);
+ }
+
drawerLayout.setDrawerListener(drawerToggle);
- FragmentManager fm = getSupportFragmentManager();
+
+ final FragmentManager fm = getSupportFragmentManager();
+
+ fm.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
+ @Override
+ public void onBackStackChanged() {
+ drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0);
+ }
+ });
FragmentTransaction transaction = fm.beginTransaction();
@@ -120,7 +144,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
if (mainFragment != null) {
transaction.replace(R.id.main_view, mainFragment);
} else {
- loadFragment(NavListAdapter.VIEW_TYPE_NAV, POS_NEW, null);
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, POS_QUEUE, null);
}
externalPlayerFragment = new ExternalPlayerFragment();
@@ -134,6 +158,14 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
navList.setAdapter(navAdapter);
navList.setOnItemClickListener(navListClickListener);
+ findViewById(R.id.nav_settings).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ drawerLayout.closeDrawer(navDrawer);
+ startActivity(new Intent(MainActivity.this, PreferenceController.getPreferenceActivity()));
+ }
+ });
+
checkFirstLaunch();
}
@@ -143,7 +175,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
- drawerLayout.openDrawer(navList);
+ drawerLayout.openDrawer(navDrawer);
}
}, 1500);
@@ -158,7 +190,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
public boolean isDrawerOpen() {
- return drawerLayout != null && navList != null && drawerLayout.isDrawerOpen(navList);
+ return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
public List<Feed> getFeeds() {
@@ -241,6 +273,14 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
.commit();
}
+ public void dismissChildFragment() {
+ getSupportFragmentManager().popBackStack();
+ }
+
+ public Toolbar getToolbar() {
+ return toolbar;
+ }
+
private AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -251,7 +291,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
selectedNavListIndex = position;
navAdapter.notifyDataSetChanged();
}
- drawerLayout.closeDrawer(navList);
+ drawerLayout.closeDrawer(navDrawer);
}
};
@@ -260,11 +300,11 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
if (savedInstanceState != null) {
- currentTitle = savedInstanceState.getString("title");
- if (!drawerLayout.isDrawerOpen(navList)) {
+ currentTitle = savedInstanceState.getString(SAVE_TITLE);
+ if (!drawerLayout.isDrawerOpen(navDrawer)) {
getSupportActionBar().setTitle(currentTitle);
}
- selectedNavListIndex = savedInstanceState.getInt("selectedNavIndex");
+ selectedNavListIndex = savedInstanceState.getInt(SAVE_SELECTED_NAV_INDEX);
}
}
@@ -277,8 +317,9 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putString("title", getSupportActionBar().getTitle().toString());
- outState.putInt("selectedNavIndex", selectedNavListIndex);
+ outState.putString(SAVE_TITLE, getSupportActionBar().getTitle().toString());
+ outState.putInt(SAVE_SELECTED_NAV_INDEX, selectedNavListIndex);
+ outState.putInt(SAVE_BACKSTACK_COUNT, getSupportFragmentManager().getBackStackEntryCount());
}
@@ -312,29 +353,16 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
- }
- switch (item.getItemId()) {
- case R.id.show_preferences:
- startActivity(new Intent(this, PreferenceController.getPreferenceActivity()));
- return true;
- default:
- return super.onOptionsItemSelected(item);
+ } else if (item.getItemId() == android.R.id.home) {
+ if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
+ dismissChildFragment();
+ }
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
}
}
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return true;
- }
private DBReader.NavDrawerData navDrawerData;
private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 561188291..099e96be9 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -174,7 +174,6 @@ public abstract class MediaplayerActivity extends ActionBarActivity
orientation = getResources().getConfiguration().orientation;
getWindow().setFormat(PixelFormat.TRANSPARENT);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index c40489374..3802de2a6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -73,15 +73,6 @@ public class PreferenceActivity extends ActionBarActivity {
}
@Override
- public void onBackPressed() {
- // The default back button behavior has to be overwritten because changing the theme clears the back stack
- Intent destIntent = new Intent(this, MainActivity.class);
- destIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(destIntent);
- finish();
- }
-
- @Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
@@ -91,9 +82,6 @@ public class PreferenceActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
- Intent destIntent = new Intent(this, MainActivity.class);
- destIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(destIntent);
finish();
return true;
default:
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java
index c58593f77..633f8d66d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java
@@ -84,13 +84,4 @@ public class PreferenceActivityGingerbread extends android.preference.Preference
);
return false;
}
-
- @Override
- public void onBackPressed() {
- // The default back button behavior has to be overwritten because changing the theme clears the back stack
- Intent destIntent = new Intent(this, MainActivity.class);
- destIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(destIntent);
- finish();
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index 727b25296..60eb290b5 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -111,6 +111,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
@Override
protected void setupGUI() {
super.setupGUI();
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
videoOverlay = (LinearLayout) findViewById(R.id.overlay);
videoview = (AspectRatioVideoView) findViewById(R.id.videoview);
progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
index 9e59a2a1a..67fb4c3b1 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
@@ -14,6 +14,7 @@ import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Chapter;
@@ -31,16 +32,18 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
private Playable media;
private int defaultTextColor;
+ private final Callback callback;
public ChapterListAdapter(Context context, int textViewResourceId,
- List<Chapter> objects, Playable media) {
+ List<Chapter> objects, Playable media, Callback callback) {
super(context, textViewResourceId, objects);
this.chapters = objects;
this.media = media;
+ this.callback = callback;
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
+ public View getView(final int position, View convertView, ViewGroup parent) {
Holder holder;
Chapter sc = getItem(position);
@@ -56,6 +59,7 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
defaultTextColor = holder.title.getTextColors().getDefaultColor();
holder.start = (TextView) convertView.findViewById(R.id.txtvStart);
holder.link = (TextView) convertView.findViewById(R.id.txtvLink);
+ holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
@@ -122,6 +126,14 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
}
});
+ holder.butPlayChapter.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (callback != null) {
+ callback.onPlayChapterButtonClicked(position);
+ }
+ }
+ });
Chapter current = ChapterUtils.getCurrentChapter(media);
if (current != null) {
if (current == sc) {
@@ -144,6 +156,7 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
TextView title;
TextView start;
TextView link;
+ ImageButton butPlayChapter;
}
@Override
@@ -177,4 +190,8 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
return super.getItem(position);
}
+ public static interface Callback {
+ public void onPlayChapterButtonClicked(int position);
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
index 8941a5d71..10666aa36 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.config;
+import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig;
/**
@@ -8,12 +9,13 @@ import de.danoeh.antennapod.core.ClientConfig;
public class ClientConfigurator {
static {
- ClientConfig.USER_AGENT = "AntennaPod/0.9.9.6";
+ ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl();
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
ClientConfig.storageCallbacks = new StorageCallbacksImpl();
ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
+ ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/DBTasksCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/DBTasksCallbacksImpl.java
new file mode 100644
index 000000000..75dcb2ef1
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/config/DBTasksCallbacksImpl.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.config;
+
+import de.danoeh.antennapod.core.DBTasksCallbacks;
+import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
+import de.danoeh.antennapod.core.storage.APDownloadAlgorithm;
+import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm;
+import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
+
+public class DBTasksCallbacksImpl implements DBTasksCallbacks {
+
+ @Override
+ public AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm() {
+ return new APDownloadAlgorithm();
+ }
+
+ @Override
+ public EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm() {
+ return new APCleanupAlgorithm();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
index ebb3780b7..10a3c1b32 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
@@ -13,7 +13,7 @@ public class StorageCallbacksImpl implements StorageCallbacks {
@Override
public int getDatabaseVersion() {
- return 13;
+ return 14;
}
@Override
@@ -105,9 +105,24 @@ public class StorageCallbacksImpl implements StorageCallbacks {
}
if (oldVersion <= 12) {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0");
+ + " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_NEXT_PAGE_LINK + " TEXT");
}
+ if (oldVersion <= 13) {
+ // remove duplicate rows in "Chapters" table that were created because of a bug.
+ db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " +
+ "(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)",
+ PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
+ PodDBAdapter.KEY_ID,
+ PodDBAdapter.KEY_ID,
+ PodDBAdapter.KEY_ID,
+ PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
+ PodDBAdapter.KEY_TITLE,
+ PodDBAdapter.KEY_START,
+ PodDBAdapter.KEY_FEEDITEM,
+ PodDBAdapter.KEY_LINK,
+ PodDBAdapter.KEY_CHAPTER_TYPE));
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java
deleted file mode 100644
index eeed10b98..000000000
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java
+++ /dev/null
@@ -1,445 +0,0 @@
-package de.danoeh.antennapod.dialog;
-
-import android.annotation.TargetApi;
-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.text.TextUtils;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-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 org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.Validate;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.QueueAccess;
-import de.danoeh.antennapod.core.util.ShownotesProvider;
-import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
-
-/**
- * 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 ViewGroup contentContainer;
- 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) {
- Validate.notNull(savedInstance);
- 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);
- Validate.notNull(item);
- Validate.notNull(queue);
- 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;
- }
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.feeditem_dialog);
-
- contentContainer = (ViewGroup) findViewById(R.id.contentContainer);
- 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());
-
- if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
- txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
- }
-
- 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) {
- actionButtonCallback.onActionButtonPressed(item);
- FeedMedia media = item.getMedia();
- if (media != null && media.isDownloaded()) {
- // playback was started, dialog should close itself
- dismiss();
- }
-
- }
- }
- );
-
- butAction2.setOnClickListener(new View.OnClickListener()
-
- {
- @Override
- public void onClick(View v) {
- if (item.hasMedia()) {
- FeedMedia media = item.getMedia();
- if (!media.isDownloaded()) {
- DBTasks.playMedia(getContext(), media, true, true, true);
- dismiss();
- } else {
- DBWriter.deleteFeedMediaOfItem(getContext(), media.getId());
- }
- } else if (item.getLink() != null) {
- Uri uri = Uri.parse(item.getLink());
- getContext().startActivity(new Intent(Intent.ACTION_VIEW, uri));
- }
- }
- }
- );
-
- butMore.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- popupMenu.getMenu().clear();
- popupMenu.inflate(R.menu.feeditem_dialog);
- if (item.hasMedia()) {
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue);
- } else {
- // these are already available via button1 and button2
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue,
- R.id.mark_read_item, R.id.visit_website_item);
- }
- 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();
- }
-
- @Override
- public void dismiss() {
- super.dismiss();
- if (contentContainer != null && webvDescription != null) {
- contentContainer.removeAllViews();
- webvDescription.destroy();
- }
- }
-
- 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) {
- TypedArray drawables = getContext().obtainStyledAttributes(new int[]{R.attr.navigation_accept,
- R.attr.location_web_site});
-
- if (!item.isRead()) {
- butAction1.setImageDrawable(drawables.getDrawable(0));
- butAction1.setContentDescription(getContext().getString(R.string.mark_read_label));
- butAction1.setVisibility(View.VISIBLE);
- } else {
- butAction1.setVisibility(View.INVISIBLE);
- }
-
- if (item.getLink() != null) {
- butAction2.setImageDrawable(drawables.getDrawable(1));
- butAction2.setContentDescription(getContext().getString(R.string.visit_website_label));
- } else {
- butAction2.setEnabled(false);
- }
-
- drawables.recycle();
- } else {
- 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) {
- Validate.notNull(item);
- 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) {
- Validate.notNull(queue);
- 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/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index 645e7ebd9..d63d66966 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -8,17 +8,17 @@ import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ListView;
+import java.util.List;
+
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.QueueAccess;
-import java.util.List;
-
/**
* Displays all running downloads and provides a button to delete them
*/
@@ -36,8 +36,6 @@ public class CompletedDownloadsFragment extends ListFragment {
private boolean viewCreated = false;
private boolean itemsLoaded = false;
- private FeedItemDialog feedItemDialog;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -69,7 +67,6 @@ public class CompletedDownloadsFragment extends ListFragment {
super.onDestroyView();
listAdapter = null;
viewCreated = false;
- feedItemDialog = null;
stopItemLoader();
}
@@ -102,8 +99,7 @@ public class CompletedDownloadsFragment extends ListFragment {
super.onListItemClick(l, v, position, id);
FeedItem item = listAdapter.getItem(position - l.getHeaderViewsCount());
if (item != null) {
- feedItemDialog = FeedItemDialog.newInstance(getActivity(), item, queue);
- feedItemDialog.show();
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
@@ -115,12 +111,6 @@ public class CompletedDownloadsFragment extends ListFragment {
}
setListShown(true);
listAdapter.notifyDataSetChanged();
- if (feedItemDialog != null) {
- boolean res = feedItemDialog.updateContent(queue, items);
- if (!res && feedItemDialog.isShowing()) {
- feedItemDialog.dismiss();
- }
- }
}
private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
@@ -143,11 +133,7 @@ public class CompletedDownloadsFragment extends ListFragment {
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) {
+ if ((arg & EVENTS) != 0) {
startItemLoader();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index efe3e7ab4..3076f8136 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.fragment;
+import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -13,6 +14,7 @@ import com.squareup.picasso.Picasso;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -57,6 +59,15 @@ public class CoverFragment extends Fragment implements
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.cover_fragment, container, false);
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
+ imgvCover.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Activity activity = getActivity();
+ if (activity != null && activity instanceof AudioplayerActivity) {
+ ((AudioplayerActivity)activity).switchToLastFragment();
+ }
+ }
+ });
viewCreated = true;
return root;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
index 5a71cb36b..712db1421 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -1,19 +1,16 @@
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
@@ -27,7 +24,6 @@ public class DownloadsFragment extends Fragment {
public static final int POS_LOG = 2;
private ViewPager pager;
- private MainActivity activity;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -36,42 +32,6 @@ public class DownloadsFragment extends Fragment {
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;
}
@@ -84,24 +44,8 @@ public class DownloadsFragment extends Fragment {
}
}
- @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) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index c0222de8e..a7c6d62e6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -12,7 +12,6 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
new file mode 100644
index 000000000..ac9e744ed
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -0,0 +1,442 @@
+package de.danoeh.antennapod.fragment;
+
+import android.annotation.TargetApi;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+import android.support.v4.util.Pair;
+import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.squareup.picasso.Picasso;
+
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.core.asynctask.DBTaskLoader;
+import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.download.Downloader;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.QueueAccess;
+import de.danoeh.antennapod.core.util.playback.Timeline;
+import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
+
+/**
+ * Displays information about a FeedItem and actions.
+ */
+public class ItemFragment extends Fragment implements LoaderManager.LoaderCallbacks<Pair<FeedItem, QueueAccess>> {
+
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOAD_QUEUED |
+ EventDistributor.QUEUE_UPDATE |
+ EventDistributor.UNREAD_ITEMS_UPDATE;
+
+ private static final String ARG_FEEDITEM = "feeditem";
+
+ /**
+ * Creates a new instance of an ItemFragment
+ *
+ * @param feeditem The ID of the FeedItem that should be displayed.
+ * @return The ItemFragment instance
+ */
+ public static ItemFragment newInstance(long feeditem) {
+ ItemFragment fragment = new ItemFragment();
+ Bundle args = new Bundle();
+ args.putLong(ARG_FEEDITEM, feeditem);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ private boolean itemsLoaded = false;
+ private long itemID;
+ private FeedItem item;
+ private QueueAccess queue;
+ private String webviewData;
+ private DownloadObserver downloadObserver;
+ private List<Downloader> downloaderList;
+
+ private ViewGroup root;
+ private View header;
+ private WebView webvDescription;
+ private TextView txtvTitle;
+ private ImageView imgvCover;
+ private ProgressBar progbarDownload;
+ private ProgressBar progbarLoading;
+ private Button butAction1;
+ private Button butAction2;
+ private ImageButton butMore;
+ private PopupMenu popupMenu;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(false);
+
+ itemID = getArguments().getLong(ARG_FEEDITEM, -1);
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getLoaderManager().initLoader(0, null, this);
+ Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
+ toolbar.addView(header);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(getActivity());
+ downloadObserver.onResume();
+ }
+ if (itemsLoaded) {
+ onFragmentLoaded();
+ }
+
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ }
+
+ private void resetViewState() {
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
+ toolbar.removeView(header);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ resetViewState();
+ if (webvDescription != null && root != null) {
+ root.removeView(webvDescription);
+ webvDescription.destroy();
+ }
+ }
+
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle("");
+ Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
+ View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
+
+ header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false);
+ root = (ViewGroup) layout.findViewById(R.id.content_root);
+ txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
+ if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
+ txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
+ }
+ webvDescription = (WebView) layout.findViewById(R.id.webvDescription);
+ 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(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 {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ e.printStackTrace();
+ return true;
+ }
+ return true;
+ }
+ });
+
+ imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
+ progbarDownload = (ProgressBar) header.findViewById(R.id.progbarDownload);
+ progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
+ butAction1 = (Button) header.findViewById(R.id.butAction1);
+ butAction2 = (Button) header.findViewById(R.id.butAction2);
+ butMore = (ImageButton) header.findViewById(R.id.butMoreActions);
+ popupMenu = new PopupMenu(getActivity(), butMore);
+
+ butAction1.setOnClickListener(new View.OnClickListener() {
+ DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
+
+ @Override
+
+ public void onClick(View v) {
+ if (item == null) {
+ return;
+ }
+ actionButtonCallback.onActionButtonPressed(item);
+ FeedMedia media = item.getMedia();
+ if (media != null && media.isDownloaded()) {
+ // playback was started, dialog should close itself
+ ((MainActivity) getActivity()).dismissChildFragment();
+ }
+ }
+
+
+ }
+ );
+
+ butAction2.setOnClickListener(new View.OnClickListener()
+
+ {
+ @Override
+ public void onClick(View v) {
+ if (item == null) {
+ return;
+ }
+
+ if (item.hasMedia()) {
+ FeedMedia media = item.getMedia();
+ if (!media.isDownloaded()) {
+ DBTasks.playMedia(getActivity(), media, true, true, true);
+ ((MainActivity) getActivity()).dismissChildFragment();
+ } else {
+ DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
+ }
+ } else if (item.getLink() != null) {
+ Uri uri = Uri.parse(item.getLink());
+ getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ }
+ }
+ }
+ );
+
+ butMore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (item == null) {
+ return;
+ }
+ popupMenu.getMenu().clear();
+ popupMenu.inflate(R.menu.feeditem_dialog);
+ if (item.hasMedia()) {
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue);
+ } else {
+ // these are already available via button1 and button2
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue,
+ R.id.mark_read_item, R.id.visit_website_item);
+ }
+ popupMenu.show();
+ }
+ }
+ );
+
+ popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem menuItem) {
+
+ try {
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
+ return true;
+ }
+ }
+ }
+ );
+
+ return layout;
+ }
+
+ 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);
+ }
+ }
+ };
+
+
+ private void onFragmentLoaded() {
+ progbarLoading.setVisibility(View.GONE);
+ if (webviewData != null) {
+ webvDescription.loadDataWithBaseURL(null, webviewData, "text/html",
+ "utf-8", "about:blank");
+ }
+ updateAppearance();
+ downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+
+ private void updateAppearance() {
+ txtvTitle.setText(item.getTitle());
+ Picasso.with(getActivity()).load(item.getImageUri())
+ .fit()
+ .into(imgvCover);
+ progbarDownload.setVisibility(View.GONE);
+ if (item.hasMedia() && downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ progbarDownload.setVisibility(View.VISIBLE);
+ progbarDownload.setProgress(downloader.getDownloadRequest().getProgressPercent());
+ }
+ }
+ }
+
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.navigation_accept,
+ R.attr.location_web_site});
+
+ if (!item.isRead()) {
+ butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
+ butAction1.setText(getActivity().getString(R.string.mark_read_label));
+ butAction1.setVisibility(View.VISIBLE);
+ } else {
+ butAction1.setVisibility(View.INVISIBLE);
+ }
+
+ if (item.getLink() != null) {
+ butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null);
+ butAction2.setText(getActivity().getString(R.string.visit_website_label));
+ } else {
+ butAction2.setEnabled(false);
+ }
+
+ drawables.recycle();
+ } else {
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play,
+ R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
+
+ if (!media.isDownloaded()) {
+ butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(2), null, null, null);
+ butAction2.setText(getActivity().getString(R.string.stream_label));
+ } else {
+ butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(3), null, null, null);
+ butAction2.setText(getActivity().getString(R.string.remove_episode_lable));
+ }
+
+ if (isDownloading) {
+ butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(4), null, null, null);
+ butAction1.setText(getActivity().getString(R.string.cancel_download_label));
+ } else if (media.isDownloaded()) {
+ butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
+ butAction1.setText(getActivity().getString(R.string.play_label));
+ } else {
+ butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null);
+ butAction1.setText(getActivity().getString(R.string.download_label));
+ }
+
+ drawables.recycle();
+ }
+ }
+
+
+ @Override
+ public Loader<Pair<FeedItem, QueueAccess>> onCreateLoader(int id, Bundle args) {
+ return new DBTaskLoader<Pair<FeedItem, QueueAccess>>(getActivity()) {
+ @Override
+ public Pair<FeedItem, QueueAccess> loadInBackground() {
+ FeedItem data1 = DBReader.getFeedItem(getContext(), itemID);
+ if (data1 != null) {
+ Timeline t = new Timeline(getActivity(), data1);
+ webviewData = t.processShownotes(false);
+ }
+ QueueAccess data2 = QueueAccess.IDListAccess(DBReader.getQueueIDList(getContext()));
+ return Pair.create(data1, data2);
+ }
+ };
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Pair<FeedItem, QueueAccess>> loader, Pair<FeedItem, QueueAccess> data) {
+
+ if (data != null) {
+ item = data.first;
+ queue = data.second;
+ if (!itemsLoaded) {
+ itemsLoaded = true;
+ onFragmentLoaded();
+ } else {
+ updateAppearance();
+ }
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Pair<FeedItem, QueueAccess>> loader) {
+
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ getLoaderManager().restartLoader(0, null, ItemFragment.this);
+ }
+ }
+ };
+
+ private final DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+
+ @Override
+ public void onContentChanged() {
+ if (itemsLoaded && getActivity() != null) {
+ updateAppearance();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ ItemFragment.this.downloaderList = downloaderList;
+ if (itemsLoaded && getActivity() != null) {
+ updateAppearance();
+ }
+ }
+ };
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index be9a9c12d..5312beeeb 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
@@ -18,6 +19,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
@@ -35,6 +37,7 @@ import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
+import de.danoeh.antennapod.core.asynctask.PicassoProvider;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -49,7 +52,6 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
@@ -81,9 +83,6 @@ public class ItemlistFragment extends ListFragment {
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
- private FeedItemDialog feedItemDialog;
- private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance;
-
private MoreContentListFooterUtil listFooter;
private boolean isUpdatingFeed;
@@ -156,13 +155,10 @@ public class ItemlistFragment extends ListFragment {
private void resetViewState() {
adapter = null;
viewsCreated = false;
+ listFooter = null;
if (downloadObserver != null) {
downloadObserver.onPause();
}
- if (feedItemDialog != null) {
- feedItemDialogSavedInstance = feedItemDialog.save();
- }
- feedItemDialog = null;
}
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker = new MenuItemUtils.UpdateRefreshMenuItemChecker() {
@@ -259,6 +255,15 @@ public class ItemlistFragment extends ListFragment {
}
@Override
+ public void setListAdapter(ListAdapter adapter) {
+ // This workaround prevents the ListFragment from setting a list adapter when its state is restored.
+ // This is only necessary on API 10 because addFooterView throws an internal exception in this case.
+ if (Build.VERSION.SDK_INT > 10 || insideOnFragmentLoaded) {
+ super.setListAdapter(adapter);
+ }
+ }
+
+ @Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("");
@@ -272,8 +277,9 @@ public class ItemlistFragment extends ListFragment {
@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();
+ if (selection != null) {
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(selection.getId()));
+ }
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@@ -303,9 +309,12 @@ public class ItemlistFragment extends ListFragment {
}
+ private boolean insideOnFragmentLoaded = false;
+
private void onFragmentLoaded() {
+ insideOnFragmentLoaded = true;
if (adapter == null) {
- getListView().setAdapter(null);
+ setListAdapter(null);
setupHeaderView();
setupFooterView();
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false);
@@ -316,17 +325,14 @@ public class ItemlistFragment extends ListFragment {
setListShown(true);
adapter.notifyDataSetChanged();
- if (feedItemDialog != null) {
- feedItemDialog.updateContent(queue, feed.getItems());
- } else if (feedItemDialogSavedInstance != null) {
- feedItemDialog = FeedItemDialog.newInstance(getActivity(), feedItemDialogSavedInstance);
- }
getActivity().supportInvalidateOptionsMenu();
if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
getListView().removeFooterView(listFooter.getRoot());
}
+ insideOnFragmentLoaded = false;
+
}
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@@ -335,9 +341,6 @@ public class ItemlistFragment extends ListFragment {
if (adapter != null) {
adapter.notifyDataSetChanged();
}
- if (feedItemDialog != null && feedItemDialog.isShowing()) {
- feedItemDialog.updateMenuAppearance();
- }
}
@Override
@@ -362,6 +365,7 @@ public class ItemlistFragment extends ListFragment {
TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor);
+ ImageView imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground);
ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo);
@@ -370,6 +374,14 @@ public class ItemlistFragment extends ListFragment {
Picasso.with(getActivity())
.load(feed.getImageUri())
+ .placeholder(R.color.image_readability_tint)
+ .error(R.color.image_readability_tint)
+ .transform(PicassoProvider.blurTransformation)
+ .resize(PicassoProvider.BLUR_IMAGE_SIZE, PicassoProvider.BLUR_IMAGE_SIZE)
+ .into(imgvBackground);
+
+ Picasso.with(getActivity())
+ .load(feed.getImageUri())
.fit()
.into(imgvCover);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index d423c335a..d97ede0ef 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -7,21 +7,28 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
-import android.view.*;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
+
import com.mobeta.android.dslv.DragSortListView;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
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.core.asynctask.DownloadObserver;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -37,9 +44,6 @@ import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
/**
* Shows unread or recently published episodes
*/
@@ -73,9 +77,6 @@ public class NewEpisodesFragment extends Fragment {
private DownloadObserver downloadObserver = null;
- private FeedItemDialog feedItemDialog;
- private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance;
-
private boolean isUpdatingFeeds;
@Override
@@ -133,10 +134,6 @@ public class NewEpisodesFragment extends Fragment {
if (downloadObserver != null) {
downloadObserver.onPause();
}
- if (feedItemDialog != null) {
- feedItemDialogSavedInstance = feedItemDialog.save();
- }
- feedItemDialog = null;
}
@@ -226,8 +223,7 @@ public class NewEpisodesFragment extends Fragment {
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();
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
@@ -257,11 +253,6 @@ public class NewEpisodesFragment extends Fragment {
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();
updateShowOnlyEpisodesListViewState();
@@ -273,9 +264,6 @@ public class NewEpisodesFragment extends Fragment {
if (listAdapter != null) {
listAdapter.notifyDataSetChanged();
}
- if (feedItemDialog != null && feedItemDialog.isShowing()) {
- feedItemDialog.updateMenuAppearance();
- }
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index e226c5c4f..f6d2d5d07 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -13,11 +13,15 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -28,9 +32,6 @@ import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
public class PlaybackHistoryFragment extends ListFragment {
private static final String TAG = "PlaybackHistoryFragment";
@@ -46,9 +47,6 @@ public class PlaybackHistoryFragment extends ListFragment {
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
- private FeedItemDialog feedItemDialog;
- private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -103,10 +101,6 @@ public class PlaybackHistoryFragment extends ListFragment {
if (downloadObserver != null) {
downloadObserver.onPause();
}
- if (feedItemDialog != null) {
- feedItemDialogSavedInstance = feedItemDialog.save();
- }
- feedItemDialog = null;
}
@Override
@@ -130,8 +124,7 @@ public class PlaybackHistoryFragment extends ListFragment {
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();
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
@@ -158,7 +151,7 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!super.onOptionsItemSelected(item)) {
- switch(item.getItemId()) {
+ switch (item.getItemId()) {
case R.id.clear_history_item:
DBWriter.clearPlaybackHistory(getActivity());
return true;
@@ -190,11 +183,6 @@ public class PlaybackHistoryFragment extends ListFragment {
}
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();
}
@@ -204,9 +192,6 @@ public class PlaybackHistoryFragment extends ListFragment {
if (adapter != null) {
adapter.notifyDataSetChanged();
}
- if (feedItemDialog != null && feedItemDialog.isShowing()) {
- feedItemDialog.updateMenuAppearance();
- }
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index 3192a84de..ce77229d9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -29,14 +29,12 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.QueueListAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
@@ -64,9 +62,6 @@ public class QueueFragment extends Fragment {
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.
*/
@@ -122,10 +117,6 @@ public class QueueFragment extends Fragment {
if (downloadObserver != null) {
downloadObserver.onPause();
}
- if (feedItemDialog != null) {
- feedItemDialogSavedInstance = feedItemDialog.save();
- }
- feedItemDialog = null;
}
@Override
@@ -215,8 +206,7 @@ public class QueueFragment extends Fragment {
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();
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
});
@@ -268,11 +258,6 @@ public class QueueFragment extends Fragment {
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() {
@@ -281,9 +266,6 @@ public class QueueFragment extends Fragment {
if (listAdapter != null && !blockDownloadObserverUpdate) {
listAdapter.notifyDataSetChanged();
}
- if (feedItemDialog != null && feedItemDialog.isShowing()) {
- feedItemDialog.updateMenuAppearance();
- }
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 0f98a2780..cf96bb094 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -12,19 +12,23 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
+
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SearchlistAdapter;
-import de.danoeh.antennapod.dialog.FeedItemDialog;
-import de.danoeh.antennapod.core.feed.*;
+import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedComponent;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.FeedSearcher;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
-import java.util.List;
-
/**
* Performs a search operation on all feeds or one specific feed and displays the search result.
*/
@@ -42,9 +46,6 @@ public class SearchFragment extends ListFragment {
private QueueAccess queue;
- private FeedItemDialog feedItemDialog;
- private FeedItemDialog.FeedItemDialogSavedInstance feedItemDialogSavedInstance;
-
/**
* Create a new SearchFragment that searches all feeds.
*/
@@ -99,10 +100,6 @@ public class SearchFragment extends ListFragment {
super.onDestroyView();
searchAdapter = null;
viewCreated = false;
- if (feedItemDialog != null) {
- feedItemDialogSavedInstance = feedItemDialog.save();
- }
- feedItemDialog = null;
}
@Override
@@ -128,11 +125,11 @@ public class SearchFragment extends ListFragment {
SearchResult result = (SearchResult) l.getAdapter().getItem(position);
FeedComponent comp = result.getComponent();
if (comp.getClass() == Feed.class) {
- ((MainActivity)getActivity()).loadFeedFragment(comp.getId());
+ ((MainActivity) getActivity()).loadFeedFragment(comp.getId());
} else {
if (comp.getClass() == FeedItem.class) {
- feedItemDialog = FeedItemDialog.newInstance(getActivity(), (FeedItem) comp, queue);
- feedItemDialog.show();
+ FeedItem item = (FeedItem) comp;
+ ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
}
@@ -167,9 +164,6 @@ public class SearchFragment extends ListFragment {
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & (EventDistributor.DOWNLOAD_QUEUED)) != 0 && feedItemDialog != null) {
- feedItemDialog.updateMenuAppearance();
- }
if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE
| EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.QUEUE_UPDATE)) != 0) {
@@ -185,18 +179,6 @@ public class SearchFragment extends ListFragment {
}
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() {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
index ec8f69368..45b2403c8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
@@ -1,85 +1,32 @@
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);
+ ViewPager 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 {
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index a1e666df0..05d6ded4d 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -10,7 +10,7 @@ import de.danoeh.antennapod.core.R;
/**
* Utilities for menu items
*/
-public class MenuItemUtils {
+public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.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);
@@ -28,29 +28,4 @@ public class MenuItemUtils {
public static boolean isActivityDrawerOpen(NavDrawerActivity activity) {
return activity != null && activity.isDrawerOpen();
}
-
- /**
- * Changes the appearance of a MenuItem depending on whether the given UpdateRefreshMenuItemChecker
- * is refreshing or not. If it returns true, the menu item will be replaced by an indeterminate progress
- * bar, otherwise nothing will happen.
- *
- * @param menu The menu that the MenuItem belongs to
- * @param resId The id of the MenuItem
- * @param checker Is used for checking whether to show the progress indicator or not.
- * @return The returned value of the UpdateRefreshMenuItemChecker's isRefreshing() method.
- */
- public static boolean updateRefreshMenuItem(Menu menu, int resId, UpdateRefreshMenuItemChecker checker) {
- // expand actionview if feeds are being downloaded, collapse otherwise
- if (checker.isRefreshing()) {
- MenuItem refreshItem = menu.findItem(resId);
- MenuItemCompat.setActionView(refreshItem, de.danoeh.antennapod.R.layout.refresh_action_view);
- return true;
- } else {
- return false;
- }
- }
-
- public static interface UpdateRefreshMenuItemChecker {
- public boolean isRefreshing();
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index edaba5df3..43f942308 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -24,6 +24,7 @@ import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AboutActivity;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
@@ -176,7 +177,7 @@ public class PreferenceController {
@Override
public boolean onPreferenceChange(
Preference preference, Object newValue) {
- Intent i = activity.getIntent();
+ Intent i = new Intent(activity, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
activity.finish();
@@ -192,6 +193,7 @@ public class PreferenceController {
if (newValue instanceof Boolean) {
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled((Boolean) newValue);
setSelectedNetworksEnabled((Boolean) newValue && UserPreferences.isEnableAutodownloadWifiFilter());
+ ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled((Boolean) newValue);
}
return true;
}
@@ -373,6 +375,8 @@ public class PreferenceController {
setSelectedNetworksEnabled(UserPreferences.isEnableAutodownload()
&& UserPreferences.isEnableAutodownloadWifiFilter());
+ ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY)
+ .setEnabled(UserPreferences.isEnableAutodownload());
}
private void setEpisodeCacheSizeText(int cacheSize) {
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
new file mode 100644
index 000000000..0e7784381
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
@@ -0,0 +1,45 @@
+package de.danoeh.antennapod.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+import android.util.Log;
+
+import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DownloadRequester;
+
+// modified from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
+// and ConnectivityActionReceiver.java
+public class PowerConnectionReceiver extends BroadcastReceiver {
+ private static final String TAG = "PowerConnectionReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+ boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
+ status == BatteryManager.BATTERY_STATUS_FULL;
+
+ if (isCharging) {
+ Log.d(TAG, "charging, starting auto-download");
+ // we're plugged in, this is a great time to auto-download if everything else is
+ // right. So, even if the user allows auto-dl on battery, let's still start
+ // downloading now. They shouldn't mind.
+ // autodownloadUndownloadedItems will make sure we're on the right wifi networks,
+ // etc... so we don't have to worry about it.
+ DBTasks.autodownloadUndownloadedItems(context);
+ } else {
+ // if we're not supposed to be auto-downloading when we're not charging, stop it
+ if (!UserPreferences.isEnableAutodownloadOnBattery()) {
+ Log.d(TAG, "not charging anymore, canceling auto-download");
+ DownloadRequester.getInstance().cancelAllDownloads(context);
+ } else {
+ Log.d(TAG, "not charging anymore, but the user allows auto-download " +
+ "when on battery so we'll keep going");
+ }
+ }
+
+ }
+}
diff --git a/app/src/main/res/layout-land/audioplayer_activity.xml b/app/src/main/res/layout-land/audioplayer_activity.xml
deleted file mode 100644
index 1f78902c9..000000000
--- a/app/src/main/res/layout-land/audioplayer_activity.xml
+++ /dev/null
@@ -1,188 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/drawer_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="0.5">
- </FrameLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="0.5"
- android:background="?attr/non_transparent_background"
- android:orientation="vertical">
-
- <RelativeLayout
- android:id="@+id/navBar"
- android:layout_width="fill_parent"
- android:layout_height="60dp"
- android:layout_alignParentTop="true">
-
- <ImageButton
- android:id="@+id/butNavLeft"
- android:contentDescription="@string/show_shownotes_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:background="?attr/selectableItemBackground"
- android:padding="4dp"/>
-
- <ImageButton
- android:id="@+id/butNavRight"
- android:contentDescription="@string/show_chapters_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:background="?attr/selectableItemBackground"
- android:padding="4dp"/>
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_medium"
- android:textStyle="bold"/>
-
- <TextView
- android:id="@+id/txtvFeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small"/>
- </RelativeLayout>
-
- <View
- android:id="@+id/navBarDivider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/navBar"
- android:background="@color/bright_blue"/>
-
- <RelativeLayout
- android:id="@+id/player_control"
- android:layout_width="match_parent"
- android:layout_height="80dp"
- android:layout_alignParentBottom="true"
- android:background="?attr/overlay_background">
-
- <ImageButton
- android:id="@+id/butPlay"
- android:contentDescription="@string/pause_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_pause"/>
-
- <ImageButton
- android:id="@+id/butRev"
- android:contentDescription="@string/rewind_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butPlay"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_rew_big"/>
-
- <ImageButton
- android:id="@+id/butFF"
- android:contentDescription="@string/fast_forward_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butPlay"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_ff_big"/>
-
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_fast_forward"
- android:textColor="@color/gray"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone"/>
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable">
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"/>
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"/>
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500"/>
- </RelativeLayout>
- </RelativeLayout>
-
- </LinearLayout>
-
- <include layout="@layout/nav_list"/>
-
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/audioplayer_activity.xml b/app/src/main/res/layout/audioplayer_activity.xml
index 770ced350..4d04771dd 100644
--- a/app/src/main/res/layout/audioplayer_activity.xml
+++ b/app/src/main/res/layout/audioplayer_activity.xml
@@ -1,173 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/non_transparent_background"
- android:orientation="vertical">
-
- <RelativeLayout
- android:id="@+id/navBar"
- android:layout_width="fill_parent"
- android:layout_height="60dp"
- android:layout_alignParentTop="true">
-
- <ImageButton
- android:id="@+id/butNavLeft"
- android:contentDescription="@string/show_shownotes_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:background="?attr/selectableItemBackground"
- android:padding="4dp"/>
-
- <ImageButton
- android:id="@+id/butNavRight"
- android:contentDescription="@string/show_chapters_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:background="?attr/selectableItemBackground"
- android:padding="4dp"/>
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="2"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:fontFamily="sans-serif-light"
- />
- </RelativeLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <View
- android:id="@+id/navBarDivider"
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/navBar"
- android:background="@color/bright_blue"/>
+ android:layout_height="wrap_content"
+ android:background="?attr/colorPrimary"
+ android:minHeight="?attr/actionBarSize">
- <RelativeLayout
- android:id="@+id/player_control"
- android:layout_width="match_parent"
- android:layout_height="80dp"
- android:layout_alignParentBottom="true"
- android:background="?attr/overlay_background">
-
- <ImageButton
- android:id="@+id/butPlay"
- android:contentDescription="@string/pause_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_pause"/>
-
- <ImageButton
- android:id="@+id/butRev"
- android:contentDescription="@string/rewind_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butPlay"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_rew_big"/>
-
- <ImageButton
- android:id="@+id/butFF"
- android:contentDescription="@string/fast_forward_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butPlay"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_ff_big"/>
-
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:contentDescription="@string/set_playback_speed_label"
- android:layout_width="80dp"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/selectableItemBackground"
- android:src="?attr/av_fast_forward"
- android:textColor="@color/gray"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone"/>
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
+ android:orientation="horizontal"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp">
+
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:gravity="left"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp" />
+
+ <ImageButton
+ android:id="@+id/butCover"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dp"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/show_cover_label"
+ android:gravity="right" />
+
+
+ </LinearLayout>
+ </android.support.v7.widget.Toolbar>
+
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable">
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?attr/non_transparent_background"
+ android:foreground="?android:windowContentOverlay"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/player_control"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_alignParentBottom="true"
+ android:background="?attr/overlay_background">
+
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/pause_label"
+ android:src="?attr/av_pause" />
+
+ <ImageButton
+ android:id="@+id/butRev"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@id/butPlay"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/rewind_label"
+ android:src="?attr/av_rew_big" />
+
+ <ImageButton
+ android:id="@+id/butFF"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butPlay"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/fast_forward_label"
+ android:src="?attr/av_ff_big" />
+
+ <Button
+ android:id="@+id/butPlaybackSpeed"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butFF"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/set_playback_speed_label"
+ android:src="?attr/av_fast_forward"
+ android:textColor="@color/gray"
+ android:textSize="@dimen/text_size_medium"
+ android:visibility="gone" />
+
+ <ImageButton
+ android:id="@+id/butNavChaptersShownotes"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@id/butRev"
+ android:background="?attr/selectableItemBackground"
+ android:scaleType="centerInside" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/playtime_layout"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_above="@id/player_control"
android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:fontFamily="sans-serif-light"
- android:textSize="@dimen/text_size_micro"/>
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
+ android:background="?attr/overlay_drawable">
+
+ <TextView
+ android:id="@+id/txtvPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro" />
+
+ <TextView
+ android:id="@+id/txtvLength"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro" />
+
+ <SeekBar
+ android:id="@+id/sbPosition"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toRightOf="@id/txtvPosition"
+ android:max="500" />
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/contentView"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_above="@id/playtime_layout"
android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:fontFamily="sans-serif-light"
- android:textSize="@dimen/text_size_micro"/>
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500"/>
+ android:foreground="?android:windowContentOverlay" />
+
</RelativeLayout>
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_above="@id/playtime_layout"
- android:layout_below="@id/navBarDivider">
- </FrameLayout>
- </RelativeLayout>
+ </LinearLayout>
- <include layout="@layout/nav_list"/>
+ <include layout="@layout/nav_list" />
</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index f9c88ac02..e6325da4b 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -11,9 +11,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
android:adjustViewBounds="true"
- android:scaleType="centerInside" />
+ android:scaleType="centerCrop" />
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditem_dialog.xml b/app/src/main/res/layout/feeditem_dialog.xml
deleted file mode 100644
index 5937480df..000000000
--- a/app/src/main/res/layout/feeditem_dialog.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/contentContainer"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/txtvTitle"
- style="@style/AntennaPod.Dialog.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_margin="16dp"
- android:ellipsize="none"
- android:maxLines="5" />
-
- <View
- android:id="@+id/title_divider"
- android:layout_width="match_parent"
- android:layout_height="2dp"
- android:layout_below="@id/txtvTitle"
- android:background="@color/bright_blue" />
-
- <LinearLayout
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/title_divider"
- android:orientation="horizontal">
-
- <ImageButton
- android:id="@+id/butAction1"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground"
- tools:ignore="ContentDescription" />
-
- <ImageButton
- android:id="@+id/butAction2"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground"
- tools:ignore="ContentDescription" />
-
- <ImageButton
- android:id="@+id/butMoreActions"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/butAction_label"
- android:src="?attr/ic_action_overflow" />
- </LinearLayout>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="2dp"
- android:layout_below="@id/header"
- android:background="@color/bright_blue" />
-
- <WebView
- android:id="@+id/webview"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_alignParentBottom="true"
- android:layout_below="@id/divider" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
new file mode 100644
index 000000000..5e1b580d2
--- /dev/null
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <WebView
+ android:id="@+id/webvDescription"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:foreground="?android:windowContentOverlay" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ProgressBar
+ android:id="@+id/progbarLoading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true" />
+ </FrameLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditem_fragment_header.xml b/app/src/main/res/layout/feeditem_fragment_header.xml
new file mode 100644
index 000000000..bab089d3b
--- /dev/null
+++ b/app/src/main/res/layout/feeditem_fragment_header.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="?attr/colorPrimary"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:paddingBottom="8dp">
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="16dp"
+ android:contentDescription="@string/cover_label"
+ android:gravity="center_vertical" />
+
+
+ <ImageButton
+ android:id="@+id/butMoreActions"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/butAction_label"
+ android:paddingTop="4dp"
+ android:src="?attr/ic_action_overflow" />
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:layout_toLeftOf="@id/butMoreActions"
+ android:layout_toRightOf="@id/imgvCover"
+ android:maxLines="5" />
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@+id/progbarDownload"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:layout_marginRight="8dp"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/butAction1"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dp"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:ellipsize="end"
+ android:paddingTop="4dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small" />
+
+ <Button
+ android:id="@+id/butAction2"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:ellipsize="end"
+ android:paddingTop="4dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small" />
+
+ </LinearLayout>
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index fc38c6797..e55ef4c3e 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -7,6 +7,12 @@
tools:context="de.danoeh.antennapod.activity.MainActivity">
<ImageView
+ android:id="@+id/imgvBackground"
+ style="@style/BigBlurryBackground"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <ImageView
android:id="@+id/imgvCover"
android:layout_width="@dimen/thumbnail_length_onlinefeedview"
android:layout_height="@dimen/thumbnail_length_onlinefeedview"
@@ -29,7 +35,7 @@
android:layout_marginTop="8dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_info_label"
- android:src="?attr/action_about" />
+ android:src="@drawable/ic_info_white_24dp" />
<TextView
android:id="@+id/txtvTitle"
@@ -43,7 +49,10 @@
android:layout_toLeftOf="@id/butShowInfo"
android:layout_toRightOf="@id/imgvCover"
android:ellipsize="end"
- android:maxLines="2" />
+ android:maxLines="2"
+ android:shadowColor="@color/black"
+ android:shadowRadius="3"
+ android:textColor="@color/white" />
<TextView
android:id="@+id/txtvAuthor"
@@ -56,7 +65,9 @@
android:layout_toRightOf="@id/imgvCover"
android:ellipsize="end"
android:lines="1"
- android:textColor="?android:attr/textColorSecondary"
+ android:shadowColor="@color/black"
+ android:shadowRadius="3"
+ android:textColor="@color/white"
android:textSize="@dimen/text_size_small" />
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index 0a7b7ef74..914d5fa6f 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -1,31 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<FrameLayout
android:id="@+id/playerFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"/>
+ android:layout_alignParentBottom="true" />
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:background="?attr/colorPrimary"
+ android:minHeight="?attr/actionBarSize"/>
<FrameLayout
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="0px"
- android:layout_alignParentTop="true"
- android:layout_above="@id/playerFragment"/>
+ android:layout_above="@id/playerFragment"
+ android:layout_below="@id/toolbar"
+ android:foreground="?android:windowContentOverlay" />
</RelativeLayout>
- <include layout="@layout/nav_list"/>
+ <include layout="@layout/nav_list" />
</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/nav_list.xml b/app/src/main/res/layout/nav_list.xml
index 536946ca1..a22520b2d 100644
--- a/app/src/main/res/layout/nav_list.xml
+++ b/app/src/main/res/layout/nav_list.xml
@@ -1,14 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/nav_list"
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/nav_layout"
android:layout_width="@dimen/drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="?attr/nav_drawer_background"
- android:choiceMode="singleChoice"
- android:clipToPadding="false"
- android:divider="@android:color/transparent"
- android:dividerHeight="0dp"
- android:paddingBottom="@dimen/list_vertical_padding"
- android:paddingTop="@dimen/list_vertical_padding"
- android:scrollbarStyle="outsideOverlay" /> \ No newline at end of file
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@+id/nav_list"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:choiceMode="singleChoice"
+ android:clipToPadding="false"
+ android:divider="@android:color/transparent"
+ android:dividerHeight="0dp"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:scrollbarStyle="outsideOverlay" />
+
+ <View
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="1dp"
+ android:layout_centerVertical="true"
+ android:background="?android:attr/listDivider" />
+
+ <LinearLayout
+ android:id="@+id/nav_settings"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="@dimen/listitem_iconwithtext_height"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/settings_label"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="@dimen/thumbnail_length_navlist"
+ android:layout_height="@dimen/thumbnail_length_navlist"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="@dimen/listitem_icon_leftpadding"
+ android:layout_marginTop="8dp"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/cover_label"
+ android:cropToPadding="true"
+ android:padding="8dp"
+ android:scaleType="centerCrop"
+ android:src="?attr/ic_settings" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_margin="16dp"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:text="@string/settings_label"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_navdrawer" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/nav_section_item.xml b/app/src/main/res/layout/nav_section_item.xml
index 6eb26291e..3682ca811 100644
--- a/app/src/main/res/layout/nav_section_item.xml
+++ b/app/src/main/res/layout/nav_section_item.xml
@@ -10,5 +10,5 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_centerVertical="true"
- android:background="@color/gray" />
+ android:background="?android:attr/listDivider" />
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/pager_fragment.xml b/app/src/main/res/layout/pager_fragment.xml
index cb7ae0151..ed639a2db 100644
--- a/app/src/main/res/layout/pager_fragment.xml
+++ b/app/src/main/res/layout/pager_fragment.xml
@@ -1,12 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent">
+
+ <android.support.v4.view.PagerTabStrip
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top" />
+ </android.support.v4.view.ViewPager>
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/simplechapter_item.xml b/app/src/main/res/layout/simplechapter_item.xml
index 422458d5d..b7f4cdb18 100644
--- a/app/src/main/res/layout/simplechapter_item.xml
+++ b/app/src/main/res/layout/simplechapter_item.xml
@@ -1,43 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="12dp"
- android:paddingTop="12dp">
+ android:layout_height="@dimen/listitem_threeline_height"
+ android:orientation="horizontal">
<TextView
android:id="@+id/txtvStart"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_margin="8dp"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small"/>
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:gravity="center_vertical" />
- <TextView
- android:id="@+id/txtvTitle"
+ <LinearLayout
android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:padding="8dp"
- android:layout_toLeftOf="@id/txtvStart"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small"/>
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/txtvLink"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/txtvStart"
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp" />
+
+ <TextView
+ android:id="@+id/txtvLink"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:focusableInTouchMode="false"
+ android:maxLines="1"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+ <include layout="@layout/vertical_list_divider" />
+
+ <ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/butPlayChapter"
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/selectableItemBackground"
+ android:clickable="false"
+ android:contentDescription="@string/chapters_label"
android:focusable="false"
android:focusableInTouchMode="false"
- android:visibility="gone"
- android:maxLines="2" />
+ android:src="?attr/av_play" />
-</RelativeLayout> \ No newline at end of file
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/menu/feeditem.xml b/app/src/main/res/menu/feeditem.xml
index 5b25e8f2c..8227f8b14 100644
--- a/app/src/main/res/menu/feeditem.xml
+++ b/app/src/main/res/menu/feeditem.xml
@@ -5,19 +5,19 @@
<item
android:id="@+id/download_item"
android:icon="?attr/av_download"
- custom:showAsAction="ifRoom|collapseActionView"
+ custom:showAsAction="collapseActionView"
android:title="@string/download_label">
</item>
<item
android:id="@+id/stream_item"
android:icon="?attr/action_stream"
- custom:showAsAction="ifRoom|collapseActionView"
+ custom:showAsAction="collapseActionView"
android:title="@string/stream_label">
</item>
<item
android:id="@+id/play_item"
android:icon="?attr/av_play"
- custom:showAsAction="ifRoom|collapseActionView"
+ custom:showAsAction="collapseActionView"
android:title="@string/play_label">
</item>
<item
@@ -65,7 +65,7 @@
<item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
- custom:showAsAction="ifRoom|collapseActionView"
+ custom:showAsAction="collapseActionView"
android:title="@string/visit_website_label">
</item>
<item
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
deleted file mode 100644
index a968f51ce..000000000
--- a/app/src/main/res/menu/main.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:custom="http://schemas.android.com/apk/res-auto">
-
- <item
- android:id="@+id/show_preferences"
- android:title="@string/settings_label"
- android:menuCategory="system"
- custom:showAsAction="collapseActionView"/>
-
-
-</menu>
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 0eb2ab067..288e44401 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -21,7 +21,7 @@
<item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
- custom:showAsAction="ifRoom|collapseActionView"
+ custom:showAsAction="collapseActionView"
android:title="@string/visit_website_label"
android:visible="false">
</item>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 8675e07d7..ce46b93bf 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -41,6 +41,13 @@
android:summary="@string/pref_pauseOnHeadsetDisconnect_sum"
android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
<CheckBoxPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:dependency="prefPauseOnHeadsetDisconnect"
+ android:key="prefUnpauseOnHeadsetReconnect"
+ android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
+ android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
+ <CheckBoxPreference
android:defaultValue="false"
android:enabled="true"
android:key="prefFollowQueue"
@@ -97,6 +104,11 @@
android:title="@string/pref_automatic_download_title"
android:defaultValue="false"/>
<CheckBoxPreference
+ android:key="prefEnableAutoDownloadOnBattery"
+ android:title="@string/pref_automatic_download_on_battery_title"
+ android:summary="@string/pref_automatic_download_on_battery_sum"
+ android:defaultValue="true"/>
+ <CheckBoxPreference
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
diff --git a/build.gradle b/build.gradle
index efa6e1773..9f1a2d6ab 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0-rc4'
+ classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/core/build.gradle b/core/build.gradle
index cfe33c98c..dfe0fb133 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 21
- buildToolsVersion "21.1.1"
+ buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 10
@@ -31,19 +31,17 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:appcompat-v7:21.0.2'
- compile 'com.android.support:support-v4:21.0.2'
+ compile 'com.android.support:appcompat-v7:21.0.3'
+ compile 'com.android.support:support-v4:21.0.3'
compile 'org.apache.commons:commons-lang3:3.3.2'
- compile ('org.shredzone.flattr4j:flattr4j-core:2.11') {
- exclude group: 'org.apache.httpcomponents', module: 'httpcore'
- exclude group: 'org.apache.httpcomponents', module: 'httpclient'
+ compile ('org.shredzone.flattr4j:flattr4j-core:2.12') {
exclude group: 'org.json', module: 'json'
}
compile 'commons-io:commons-io:2.4'
compile 'com.jayway.android.robotium:robotium-solo:5.2.1'
compile 'org.jsoup:jsoup:1.7.3'
compile 'com.squareup.picasso:picasso:2.4.0'
- compile 'com.squareup.okhttp:okhttp:2.1.0'
- compile 'com.squareup.okhttp:okhttp-urlconnection:2.1.0'
- compile 'com.squareup.okio:okio:1.0.1'
+ compile 'com.squareup.okhttp:okhttp:2.2.0'
+ compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
+ compile 'com.squareup.okio:okio:1.2.0'
} \ No newline at end of file
diff --git a/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java
index e5e609f5f..1a2671555 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java
@@ -22,4 +22,6 @@ public class ClientConfig {
public static FlattrCallbacks flattrCallbacks;
public static StorageCallbacks storageCallbacks;
+
+ public static DBTasksCallbacks dbTasksCallbacks;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java
new file mode 100644
index 000000000..edf3e3199
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/DBTasksCallbacks.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.core;
+
+import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm;
+import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
+
+/**
+ * Callbacks for the DBTasks class of the storage module.
+ */
+public interface DBTasksCallbacks {
+
+ /**
+ * Returns the client's implementation of the AutomaticDownloadAlgorithm interface.
+ */
+ public AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm();
+
+ /**
+ * Returns the client's implementation of the EpisodeCacheCleanupAlgorithm interface.
+ */
+ public EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm();
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/DBTaskLoader.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/DBTaskLoader.java
new file mode 100644
index 000000000..0f402f44a
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/DBTaskLoader.java
@@ -0,0 +1,29 @@
+package de.danoeh.antennapod.core.asynctask;
+
+import android.content.Context;
+import android.support.v4.content.AsyncTaskLoader;
+
+/**
+ * Subclass of AsyncTaskLoader that is made for loading data with one of the DB*-classes.
+ * This class will provide a useful default implementation that would otherwise always be necessary when interacting
+ * with the DB*-classes with an AsyncTaskLoader.
+ */
+public abstract class DBTaskLoader<D> extends AsyncTaskLoader<D> {
+
+ public DBTaskLoader(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onStopLoading() {
+ super.onStopLoading();
+ cancelLoad();
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ // according to https://code.google.com/p/android/issues/detail?id=14944, this has to be called manually
+ forceLoad();
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
index 1ed29c23a..b6ece6dc8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
@@ -14,6 +14,7 @@ import com.squareup.picasso.OkHttpDownloader;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Request;
import com.squareup.picasso.RequestHandler;
+import com.squareup.picasso.Transformation;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -209,4 +210,254 @@ public class PicassoProvider {
options.inJustDecodeBounds = false;
}
}
+
+ public static final int BLUR_RADIUS = 1;
+ public static final int BLUR_IMAGE_SIZE = 100;
+ public static final String BLUR_KEY = "blur";
+
+ public static final Transformation blurTransformation = new Transformation() {
+ @Override
+ public Bitmap transform(Bitmap source) {
+ Bitmap result = fastblur(source, BLUR_RADIUS);
+ source.recycle();
+ return result;
+ }
+
+ @Override
+ public String key() {
+ return BLUR_KEY;
+ }
+ };
+
+ public static Bitmap fastblur(Bitmap sentBitmap, int radius) {
+
+ // Stack Blur v1.0 from
+ // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
+ //
+ // Java Author: Mario Klingemann <mario at quasimondo.com>
+ // http://incubator.quasimondo.com
+ // created Feburary 29, 2004
+ // Android port : Yahel Bouaziz <yahel at kayenko.com>
+ // http://www.kayenko.com
+ // ported april 5th, 2012
+
+ // This is a compromise between Gaussian Blur and Box blur
+ // It creates much better looking blurs than Box Blur, but is
+ // 7x faster than my Gaussian Blur implementation.
+ //
+ // I called it Stack Blur because this describes best how this
+ // filter works internally: it creates a kind of moving stack
+ // of colors whilst scanning through the image. Thereby it
+ // just has to add one new block of color to the right side
+ // of the stack and remove the leftmost color. The remaining
+ // colors on the topmost layer of the stack are either added on
+ // or reduced by one, depending on if they are on the right or
+ // on the left side of the stack.
+ //
+ // If you are using this algorithm in your code please add
+ // the following line:
+ //
+ // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
+
+ Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
+
+ if (radius < 1) {
+ return (null);
+ }
+
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+
+ int[] pix = new int[w * h];
+ Log.e("pix", w + " " + h + " " + pix.length);
+ bitmap.getPixels(pix, 0, w, 0, 0, w, h);
+
+ int wm = w - 1;
+ int hm = h - 1;
+ int wh = w * h;
+ int div = radius + radius + 1;
+
+ int r[] = new int[wh];
+ int g[] = new int[wh];
+ int b[] = new int[wh];
+ int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
+ int vmin[] = new int[Math.max(w, h)];
+
+ int divsum = (div + 1) >> 1;
+ divsum *= divsum;
+ int dv[] = new int[256 * divsum];
+ for (i = 0; i < 256 * divsum; i++) {
+ dv[i] = (i / divsum);
+ }
+
+ yw = yi = 0;
+
+ int[][] stack = new int[div][3];
+ int stackpointer;
+ int stackstart;
+ int[] sir;
+ int rbs;
+ int r1 = radius + 1;
+ int routsum, goutsum, boutsum;
+ int rinsum, ginsum, binsum;
+
+ for (y = 0; y < h; y++) {
+ rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
+ for (i = -radius; i <= radius; i++) {
+ p = pix[yi + Math.min(wm, Math.max(i, 0))];
+ sir = stack[i + radius];
+ sir[0] = (p & 0xff0000) >> 16;
+ sir[1] = (p & 0x00ff00) >> 8;
+ sir[2] = (p & 0x0000ff);
+ rbs = r1 - Math.abs(i);
+ rsum += sir[0] * rbs;
+ gsum += sir[1] * rbs;
+ bsum += sir[2] * rbs;
+ if (i > 0) {
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+ } else {
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+ }
+ }
+ stackpointer = radius;
+
+ for (x = 0; x < w; x++) {
+
+ r[yi] = dv[rsum];
+ g[yi] = dv[gsum];
+ b[yi] = dv[bsum];
+
+ rsum -= routsum;
+ gsum -= goutsum;
+ bsum -= boutsum;
+
+ stackstart = stackpointer - radius + div;
+ sir = stack[stackstart % div];
+
+ routsum -= sir[0];
+ goutsum -= sir[1];
+ boutsum -= sir[2];
+
+ if (y == 0) {
+ vmin[x] = Math.min(x + radius + 1, wm);
+ }
+ p = pix[yw + vmin[x]];
+
+ sir[0] = (p & 0xff0000) >> 16;
+ sir[1] = (p & 0x00ff00) >> 8;
+ sir[2] = (p & 0x0000ff);
+
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+
+ rsum += rinsum;
+ gsum += ginsum;
+ bsum += binsum;
+
+ stackpointer = (stackpointer + 1) % div;
+ sir = stack[(stackpointer) % div];
+
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+
+ rinsum -= sir[0];
+ ginsum -= sir[1];
+ binsum -= sir[2];
+
+ yi++;
+ }
+ yw += w;
+ }
+ for (x = 0; x < w; x++) {
+ rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
+ yp = -radius * w;
+ for (i = -radius; i <= radius; i++) {
+ yi = Math.max(0, yp) + x;
+
+ sir = stack[i + radius];
+
+ sir[0] = r[yi];
+ sir[1] = g[yi];
+ sir[2] = b[yi];
+
+ rbs = r1 - Math.abs(i);
+
+ rsum += r[yi] * rbs;
+ gsum += g[yi] * rbs;
+ bsum += b[yi] * rbs;
+
+ if (i > 0) {
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+ } else {
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+ }
+
+ if (i < hm) {
+ yp += w;
+ }
+ }
+ yi = x;
+ stackpointer = radius;
+ for (y = 0; y < h; y++) {
+ // Preserve alpha channel: ( 0xff000000 & pix[yi] )
+ pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
+
+ rsum -= routsum;
+ gsum -= goutsum;
+ bsum -= boutsum;
+
+ stackstart = stackpointer - radius + div;
+ sir = stack[stackstart % div];
+
+ routsum -= sir[0];
+ goutsum -= sir[1];
+ boutsum -= sir[2];
+
+ if (x == 0) {
+ vmin[y] = Math.min(y + r1, hm) * w;
+ }
+ p = x + vmin[y];
+
+ sir[0] = r[p];
+ sir[1] = g[p];
+ sir[2] = b[p];
+
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+
+ rsum += rinsum;
+ gsum += ginsum;
+ bsum += binsum;
+
+ stackpointer = (stackpointer + 1) % div;
+ sir = stack[stackpointer];
+
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+
+ rinsum -= sir[0];
+ ginsum -= sir[1];
+ binsum -= sir[2];
+
+ yi += w;
+ }
+ }
+
+ Log.e("pix", w + " " + h + " " + pix.length);
+ bitmap.setPixels(pix, 0, w, 0, 0, w, h);
+
+ return (bitmap);
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
index 42e4191f6..c63b61f55 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
@@ -143,7 +143,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
paymentLink = other.paymentLink;
}
if (other.chapters != null) {
- if (chapters == null) {
+ if (!hasChapters) {
chapters = other.chapters;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java
new file mode 100644
index 000000000..b8d17bcce
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java
@@ -0,0 +1,38 @@
+package de.danoeh.antennapod.core.menuhandler;
+
+import android.support.v4.view.MenuItemCompat;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import de.danoeh.antennapod.core.R;
+
+/**
+ * Utilities for menu items
+ */
+public class MenuItemUtils {
+
+ /**
+ * Changes the appearance of a MenuItem depending on whether the given UpdateRefreshMenuItemChecker
+ * is refreshing or not. If it returns true, the menu item will be replaced by an indeterminate progress
+ * bar, otherwise nothing will happen.
+ *
+ * @param menu The menu that the MenuItem belongs to
+ * @param resId The id of the MenuItem
+ * @param checker Is used for checking whether to show the progress indicator or not.
+ * @return The returned value of the UpdateRefreshMenuItemChecker's isRefreshing() method.
+ */
+ public static boolean updateRefreshMenuItem(Menu menu, int resId, UpdateRefreshMenuItemChecker checker) {
+ // expand actionview if feeds are being downloaded, collapse otherwise
+ if (checker.isRefreshing()) {
+ MenuItem refreshItem = menu.findItem(resId);
+ MenuItemCompat.setActionView(refreshItem, R.layout.refresh_action_view);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static interface UpdateRefreshMenuItemChecker {
+ public boolean isRefreshing();
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index f18028e8f..a3b9f6049 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -38,6 +38,7 @@ public class UserPreferences implements
private static final String TAG = "UserPreferences";
public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect";
+ public static final String PREF_UNPAUSE_ON_HEADSET_RECONNECT = "prefUnpauseOnHeadsetReconnect";
public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
public static final String PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY = "prefDownloadMediaOnWifiOnly";
public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall";
@@ -50,6 +51,7 @@ public class UserPreferences implements
public static final String PREF_DATA_FOLDER = "prefDataFolder";
public static final String PREF_ENABLE_AUTODL = "prefEnableAutoDl";
public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
+ public static final String PREF_ENABLE_AUTODL_ON_BATTERY = "prefEnableAutoDownloadOnBattery";
private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize";
private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed";
@@ -69,6 +71,7 @@ public class UserPreferences implements
// Preferences
private boolean pauseOnHeadsetDisconnect;
+ private boolean unpauseOnHeadsetReconnect;
private boolean followQueue;
private boolean downloadMediaOnWifiOnly;
private long updateInterval;
@@ -80,6 +83,7 @@ public class UserPreferences implements
private int theme;
private boolean enableAutodownload;
private boolean enableAutodownloadWifiFilter;
+ private boolean enableAutodownloadOnBattery;
private String[] autodownloadSelectedNetworks;
private int episodeCacheSize;
private String playbackSpeed;
@@ -121,6 +125,8 @@ public class UserPreferences implements
R.integer.episode_cache_size_unlimited);
pauseOnHeadsetDisconnect = sp.getBoolean(
PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
+ unpauseOnHeadsetReconnect = sp.getBoolean(
+ PREF_UNPAUSE_ON_HEADSET_RECONNECT, true);
followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false);
downloadMediaOnWifiOnly = sp.getBoolean(
PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY, true);
@@ -140,6 +146,7 @@ public class UserPreferences implements
episodeCacheSize = readEpisodeCacheSizeInternal(sp.getString(
PREF_EPISODE_CACHE_SIZE, "20"));
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
+ enableAutodownloadOnBattery = sp.getBoolean(PREF_ENABLE_AUTODL_ON_BATTERY, true);
playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
playbackSpeedArray = readPlaybackSpeedArray(sp.getString(
PREF_PLAYBACK_SPEED_ARRAY, null));
@@ -221,6 +228,11 @@ public class UserPreferences implements
return instance.pauseOnHeadsetDisconnect;
}
+ public static boolean isUnpauseOnHeadsetReconnect() {
+ instanceAvailable();
+ return instance.unpauseOnHeadsetReconnect;
+ }
+
public static boolean isFollowQueue() {
instanceAvailable();
return instance.followQueue;
@@ -282,6 +294,15 @@ public class UserPreferences implements
return instance.theme;
}
+ public static int getNoTitleTheme() {
+ int theme = getTheme();
+ if (theme == R.style.Theme_AntennaPod_Dark) {
+ return R.style.Theme_AntennaPod_Dark_NoTitle;
+ } else {
+ return R.style.Theme_AntennaPod_Light_NoTitle;
+ }
+ }
+
public static boolean isEnableAutodownloadWifiFilter() {
instanceAvailable();
return instance.enableAutodownloadWifiFilter;
@@ -326,6 +347,11 @@ public class UserPreferences implements
return instance.enableAutodownload;
}
+ public static boolean isEnableAutodownloadOnBattery() {
+ instanceAvailable();
+ return instance.enableAutodownloadOnBattery;
+ }
+
public static boolean shouldPauseForFocusLoss() {
instanceAvailable();
return instance.pauseForFocusLoss;
@@ -377,6 +403,8 @@ public class UserPreferences implements
PREF_EPISODE_CACHE_SIZE, "20"));
} else if (key.equals(PREF_ENABLE_AUTODL)) {
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
+ } else if (key.equals(PREF_ENABLE_AUTODL_ON_BATTERY)) {
+ enableAutodownloadOnBattery = sp.getBoolean(PREF_ENABLE_AUTODL_ON_BATTERY, true);
} else if (key.equals(PREF_PLAYBACK_SPEED)) {
playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
} else if (key.equals(PREF_PLAYBACK_SPEED_ARRAY)) {
@@ -388,6 +416,8 @@ public class UserPreferences implements
seekDeltaSecs = Integer.valueOf(sp.getString(PREF_SEEK_DELTA_SECS, "30"));
} else if (key.equals(PREF_PAUSE_ON_HEADSET_DISCONNECT)) {
pauseOnHeadsetDisconnect = sp.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
+ } else if (key.equals(PREF_UNPAUSE_ON_HEADSET_RECONNECT)) {
+ unpauseOnHeadsetReconnect = sp.getBoolean(PREF_UNPAUSE_ON_HEADSET_RECONNECT, true);
} else if (key.equals(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD)) {
autoFlattrPlayedDurationThreshold = sp.getFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD,
PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD_DEFAULT);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index a5560e3fb..866f1cba3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -144,6 +144,10 @@ public class PlaybackService extends Service {
* Is true if service has received a valid start command.
*/
public static boolean started = false;
+ /**
+ * Is true if the service was running, but paused due to headphone disconnect
+ */
+ public static boolean transientPause = false;
private static final int NOTIFICATION_ID = 1;
@@ -206,6 +210,8 @@ public class PlaybackService extends Service {
Intent.ACTION_HEADSET_PLUG));
registerReceiver(shutdownReceiver, new IntentFilter(
ACTION_SHUTDOWN_PLAYBACK_SERVICE));
+ registerReceiver(bluetoothStateUpdated, new IntentFilter(
+ AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
registerReceiver(audioBecomingNoisy, new IntentFilter(
AudioManager.ACTION_AUDIO_BECOMING_NOISY));
registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter(
@@ -228,6 +234,7 @@ public class PlaybackService extends Service {
unregisterReceiver(headsetDisconnected);
unregisterReceiver(shutdownReceiver);
+ unregisterReceiver(bluetoothStateUpdated);
unregisterReceiver(audioBecomingNoisy);
unregisterReceiver(skipCurrentEpisodeReceiver);
mediaPlayer.shutdown();
@@ -284,7 +291,6 @@ public class PlaybackService extends Service {
private void handleKeycode(int keycode) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Handling keycode: " + keycode);
-
final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
final PlayerStatus status = info.playerStatus;
switch (keycode) {
@@ -315,12 +321,14 @@ public class PlaybackService extends Service {
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
if (status == PlayerStatus.PLAYING) {
- if (UserPreferences.isPersistNotify()) {
- mediaPlayer.pause(false, true);
- } else {
- mediaPlayer.pause(true, true);
- }
+ mediaPlayer.pause(false, true);
+ }
+ if (UserPreferences.isPersistNotify()) {
+ mediaPlayer.pause(false, true);
+ } else {
+ mediaPlayer.pause(true, true);
}
+
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
@@ -333,7 +341,9 @@ public class PlaybackService extends Service {
case KeyEvent.KEYCODE_MEDIA_STOP:
if (status == PlayerStatus.PLAYING) {
mediaPlayer.pause(true, true);
+ started = false;
}
+
stopForeground(true); // gets rid of persistent notification
break;
default:
@@ -411,10 +421,13 @@ public class PlaybackService extends Service {
taskManager.cancelWidgetUpdater();
if (UserPreferences.isPersistNotify() && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// do not remove notification on pause based on user pref and whether android version supports expanded notifications
- } else {
+ // Change [Play] button to [Pause]
+ setupNotification(newInfo);
+ } else if (!UserPreferences.isPersistNotify()) {
// remove notifcation on pause
stopForeground(true);
}
+
break;
case STOPPED:
@@ -431,6 +444,7 @@ public class PlaybackService extends Service {
taskManager.startPositionSaver();
taskManager.startWidgetUpdater();
setupNotification(newInfo);
+ started = true;
break;
case ERROR:
writePlaybackPreferencesNoMediaPlaying();
@@ -734,8 +748,9 @@ public class PlaybackService extends Service {
PlaybackServiceMediaPlayer.PSMPInfo newInfo = mediaPlayer.getPSMPInfo();
final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext());
- if (!isCancelled() && info.playerStatus == PlayerStatus.PLAYING
- && info.playable != null) {
+ if (!isCancelled() &&
+ started &&
+ info.playable != null) {
String contentText = info.playable.getFeedTitle();
String contentTitle = info.playable.getEpisodeTitle();
Notification notification = null;
@@ -775,16 +790,30 @@ public class PlaybackService extends Service {
.setContentIntent(pIntent)
.setLargeIcon(icon)
.setSmallIcon(smallIcon)
- .setPriority(UserPreferences.getNotifyPriority()) // set notification priority
- .addAction(android.R.drawable.ic_media_play, //play action
- getString(R.string.play_label),
- playButtonPendingIntent)
- .addAction(android.R.drawable.ic_media_pause, //pause action
- getString(R.string.pause_label),
- pauseButtonPendingIntent)
- .addAction(android.R.drawable.ic_menu_close_clear_cancel, // stop action
- getString(R.string.stop_label),
- stopButtonPendingIntent);
+ .setPriority(UserPreferences.getNotifyPriority()); // set notification priority
+ if (newInfo.playerStatus == PlayerStatus.PLAYING) {
+ notificationBuilder.addAction(android.R.drawable.ic_media_pause, //pause action
+ getString(R.string.pause_label),
+ pauseButtonPendingIntent);
+ } else {
+ notificationBuilder.addAction(android.R.drawable.ic_media_play, //play action
+ getString(R.string.play_label),
+ playButtonPendingIntent);
+ }
+ if (UserPreferences.isPersistNotify()) {
+ notificationBuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, // stop action
+ getString(R.string.stop_label),
+ stopButtonPendingIntent);
+ }
+
+ if (Build.VERSION.SDK_INT >= 21) {
+ notificationBuilder.setStyle(new Notification.MediaStyle()
+ .setMediaSession((android.media.session.MediaSession.Token) mediaPlayer.getSessionToken().getToken())
+ .setShowActionsInCompactView(0))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setColor(Notification.COLOR_DEFAULT);
+ }
+
notification = notificationBuilder.build();
} else {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
@@ -793,11 +822,9 @@ public class PlaybackService extends Service {
.setContentText(contentText).setOngoing(true)
.setContentIntent(pIntent).setLargeIcon(icon)
.setSmallIcon(smallIcon);
- notification = notificationBuilder.getNotification();
- }
- if (newInfo.playerStatus == PlayerStatus.PLAYING) {
- startForeground(NOTIFICATION_ID, notification);
+ notification = notificationBuilder.build();
}
+ startForeground(NOTIFICATION_ID, notification);
if (BuildConfig.DEBUG)
Log.d(TAG, "Notification set up");
}
@@ -966,6 +993,7 @@ public class PlaybackService extends Service {
private BroadcastReceiver headsetDisconnected = new BroadcastReceiver() {
private static final String TAG = "headsetDisconnected";
private static final int UNPLUGGED = 0;
+ private static final int PLUGGED = 1;
@Override
public void onReceive(Context context, Intent intent) {
@@ -978,6 +1006,10 @@ public class PlaybackService extends Service {
if (BuildConfig.DEBUG)
Log.d(TAG, "Headset was unplugged during playback.");
pauseIfPauseOnDisconnect();
+ } else if (state == PLUGGED) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Headset was plugged in during playback.");
+ unpauseIfPauseOnDisconnect();
}
} else {
Log.e(TAG, "Received invalid ACTION_HEADSET_PLUG intent");
@@ -986,6 +1018,21 @@ public class PlaybackService extends Service {
}
};
+ private BroadcastReceiver bluetoothStateUpdated = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (StringUtils.equals(intent.getAction(), AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
+ int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
+ int prevState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, -1);
+ if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Received bluetooth connection intent");
+ unpauseIfPauseOnDisconnect();
+ }
+ }
+ }
+ };
+
private BroadcastReceiver audioBecomingNoisy = new BroadcastReceiver() {
@Override
@@ -1003,6 +1050,9 @@ public class PlaybackService extends Service {
*/
private void pauseIfPauseOnDisconnect() {
if (UserPreferences.isPauseOnHeadsetDisconnect()) {
+ if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) {
+ transientPause = true;
+ }
if (UserPreferences.isPersistNotify()) {
mediaPlayer.pause(false, true);
} else {
@@ -1011,6 +1061,15 @@ public class PlaybackService extends Service {
}
}
+ private void unpauseIfPauseOnDisconnect() {
+ if (transientPause) {
+ transientPause = false;
+ if (UserPreferences.isPauseOnHeadsetDisconnect() && UserPreferences.isUnpauseOnHeadsetReconnect()) {
+ mediaPlayer.resume();
+ }
+ }
+ }
+
private BroadcastReceiver shutdownReceiver = new BroadcastReceiver() {
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index dbf870eac..c143d7f2c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -6,6 +6,9 @@ import android.media.AudioManager;
import android.media.RemoteControlClient;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
@@ -48,6 +51,10 @@ public class PlaybackServiceMediaPlayer {
private volatile PlayerStatus statusBeforeSeeking;
private volatile IPlayer mediaPlayer;
private volatile Playable media;
+ /**
+ * Only used for Lollipop notifications.
+ */
+ private final MediaSessionCompat mediaSession;
private volatile boolean stream;
private volatile MediaType mediaType;
@@ -89,6 +96,10 @@ public class PlaybackServiceMediaPlayer {
}
);
+ mediaSession = new MediaSessionCompat(context, TAG);
+ mediaSession.setCallback(sessionCallback);
+ mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+
mediaPlayer = null;
statusBeforeSeeking = null;
pausedBecauseOfTransientAudiofocusLoss = false;
@@ -181,6 +192,7 @@ public class PlaybackServiceMediaPlayer {
setPlayerStatus(PlayerStatus.INITIALIZING, media);
try {
media.loadMetadata();
+ mediaSession.setMetadata(getMediaSessionMetadata(media));
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else {
@@ -211,6 +223,13 @@ public class PlaybackServiceMediaPlayer {
}
}
+ private MediaMetadataCompat getMediaSessionMetadata(Playable p) {
+ MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
+ builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
+ return builder.build();
+ }
+
/**
* Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
@@ -586,6 +605,10 @@ public class PlaybackServiceMediaPlayer {
return mediaType;
}
+ public PlayerStatus getPlayerStatus() {
+ return playerStatus;
+ }
+
public boolean isStreaming() {
return stream;
}
@@ -599,6 +622,9 @@ public class PlaybackServiceMediaPlayer {
if (mediaPlayer != null) {
mediaPlayer.release();
}
+ if (mediaSession != null) {
+ mediaSession.release();
+ }
releaseWifiLockIfNecessary();
}
@@ -663,6 +689,16 @@ public class PlaybackServiceMediaPlayer {
}
/**
+ * Returns a token to this object's MediaSession. The MediaSession should only be used for notifications
+ * at the moment.
+ *
+ * @return The MediaSessionCompat.Token object.
+ */
+ public MediaSessionCompat.Token getSessionToken() {
+ return mediaSession.getSessionToken();
+ }
+
+ /**
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
* <p/>
@@ -679,6 +715,45 @@ public class PlaybackServiceMediaPlayer {
this.playerStatus = newStatus;
this.media = newMedia;
+
+ PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
+
+ int state;
+ if (playerStatus != null) {
+ switch (playerStatus) {
+ case PLAYING:
+ state = PlaybackStateCompat.STATE_PLAYING;
+ break;
+ case PREPARED:
+ case PAUSED:
+ state = PlaybackStateCompat.STATE_PAUSED;
+ break;
+ case STOPPED:
+ state = PlaybackStateCompat.STATE_STOPPED;
+ break;
+ case SEEKING:
+ state = PlaybackStateCompat.STATE_FAST_FORWARDING;
+ break;
+ case PREPARING:
+ case INITIALIZING:
+ state = PlaybackStateCompat.STATE_CONNECTING;
+ break;
+ case INITIALIZED:
+ case INDETERMINATE:
+ state = PlaybackStateCompat.STATE_NONE;
+ break;
+ case ERROR:
+ state = PlaybackStateCompat.STATE_ERROR;
+ break;
+ default:
+ state = PlaybackStateCompat.STATE_NONE;
+ break;
+ }
+ } else {
+ state = PlaybackStateCompat.STATE_NONE;
+ }
+ sessionState.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, getPlaybackSpeed());
+
callback.statusChanged(new PSMPInfo(playerStatus, media));
}
@@ -976,4 +1051,54 @@ public class PlaybackServiceMediaPlayer {
}
});
}
+
+ private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
+
+ @Override
+ public void onPlay() {
+ if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
+ resume();
+ } else if (playerStatus == PlayerStatus.INITIALIZED) {
+ setStartWhenPrepared(true);
+ prepare();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (playerStatus == PlayerStatus.PLAYING) {
+ pause(false, true);
+ }
+ if (UserPreferences.isPersistNotify()) {
+ pause(false, true);
+ } else {
+ pause(true, true);
+ }
+ }
+
+ @Override
+ public void onSkipToNext() {
+ super.onSkipToNext();
+ endPlayback();
+ }
+
+ @Override
+ public void onFastForward() {
+ super.onFastForward();
+ seekDelta(UserPreferences.getSeekDeltaMs());
+ }
+
+ @Override
+ public void onRewind() {
+ super.onRewind();
+ seekDelta(-UserPreferences.getSeekDeltaMs());
+ }
+
+ @Override
+ public void onSeekTo(long pos) {
+ super.onSeekTo(pos);
+ seekTo((int) pos);
+ }
+ };
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
new file mode 100644
index 000000000..499fddf74
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
@@ -0,0 +1,103 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.QueueAccess;
+
+/**
+ * Implementation of the EpisodeCleanupAlgorithm interface used by AntennaPod.
+ */
+public class APCleanupAlgorithm implements EpisodeCleanupAlgorithm<Integer> {
+ private static final String TAG = "APCleanupAlgorithm";
+
+ @Override
+ public int performCleanup(Context context, Integer episodeNumber) {
+ List<FeedItem> candidates = new ArrayList<FeedItem>();
+ List<FeedItem> downloadedItems = DBReader.getDownloadedItems(context);
+ QueueAccess queue = QueueAccess.IDListAccess(DBReader.getQueueIDList(context));
+ List<FeedItem> delete;
+ for (FeedItem item : downloadedItems) {
+ if (item.hasMedia() && item.getMedia().isDownloaded()
+ && !queue.contains(item.getId()) && item.isRead()) {
+ candidates.add(item);
+ }
+
+ }
+
+ Collections.sort(candidates, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ Date l = lhs.getMedia().getPlaybackCompletionDate();
+ Date r = rhs.getMedia().getPlaybackCompletionDate();
+
+ if (l == null) {
+ l = new Date(0);
+ }
+ if (r == null) {
+ r = new Date(0);
+ }
+ return l.compareTo(r);
+ }
+ });
+
+ if (candidates.size() > episodeNumber) {
+ delete = candidates.subList(0, episodeNumber);
+ } else {
+ delete = candidates;
+ }
+
+ for (FeedItem item : delete) {
+ try {
+ DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ int counter = delete.size();
+
+
+ Log.i(TAG, String.format(
+ "Auto-delete deleted %d episodes (%d requested)", counter,
+ episodeNumber));
+
+ return counter;
+ }
+
+ @Override
+ public Integer getDefaultCleanupParameter(Context context) {
+ return 0;
+ }
+
+ @Override
+ public Integer getPerformCleanupParameter(Context context, List<FeedItem> items) {
+ return getPerformAutoCleanupArgs(context, items.size());
+ }
+
+ static int getPerformAutoCleanupArgs(Context context,
+ final int episodeNumber) {
+ if (episodeNumber >= 0
+ && UserPreferences.getEpisodeCacheSize() != UserPreferences
+ .getEpisodeCacheSizeUnlimited()) {
+ int downloadedEpisodes = DBReader
+ .getNumberOfDownloadedEpisodes(context);
+ if (downloadedEpisodes + episodeNumber >= UserPreferences
+ .getEpisodeCacheSize()) {
+
+ return downloadedEpisodes + episodeNumber
+ - UserPreferences.getEpisodeCacheSize();
+ }
+ }
+ return 0;
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java
new file mode 100644
index 000000000..c5f871f48
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java
@@ -0,0 +1,133 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.core.util.PowerUtils;
+
+/**
+ * Implements the automatic download algorithm used by AntennaPod. This class assumes that
+ * the client uses the APEpisodeCleanupAlgorithm.
+ */
+public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm {
+ private static final String TAG = "APDownloadAlgorithm";
+
+ private final APCleanupAlgorithm cleanupAlgorithm = new APCleanupAlgorithm();
+
+ /**
+ * Looks for undownloaded episodes in the queue or list of unread items and request a download if
+ * 1. Network is available
+ * 2. The device is charging or the user allows auto download on battery
+ * 3. There is free space in the episode cache
+ * This method is executed on an internal single thread executor.
+ *
+ * @param context Used for accessing the DB.
+ * @param mediaIds If this list is not empty, the method will only download a candidate for automatic downloading if
+ * its media ID is in the mediaIds list.
+ * @return A Runnable that will be submitted to an ExecutorService.
+ */
+ @Override
+ public Runnable autoDownloadUndownloadedItems(final Context context, final long... mediaIds) {
+ return new Runnable() {
+ @Override
+ public void run() {
+
+ // true if we should auto download based on network status
+ boolean networkShouldAutoDl = NetworkUtils.autodownloadNetworkAvailable(context)
+ && UserPreferences.isEnableAutodownload();
+
+ // true if we should auto download based on power status
+ boolean powerShouldAutoDl = PowerUtils.deviceCharging(context)
+ || UserPreferences.isEnableAutodownloadOnBattery();
+
+ // we should only auto download if both network AND power are happy
+ if (networkShouldAutoDl && powerShouldAutoDl) {
+
+ Log.d(TAG, "Performing auto-dl of undownloaded episodes");
+
+ final List<FeedItem> queue = DBReader.getQueue(context);
+ final List<FeedItem> unreadItems = DBReader
+ .getUnreadItemsList(context);
+
+ int undownloadedEpisodes = DBTasks.getNumberOfUndownloadedEpisodes(queue,
+ unreadItems);
+ int downloadedEpisodes = DBReader
+ .getNumberOfDownloadedEpisodes(context);
+ int deletedEpisodes = cleanupAlgorithm.performCleanup(context,
+ APCleanupAlgorithm.getPerformAutoCleanupArgs(context, undownloadedEpisodes));
+ int episodeSpaceLeft = undownloadedEpisodes;
+ boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
+ .getEpisodeCacheSizeUnlimited();
+
+ if (!cacheIsUnlimited
+ && UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
+ + undownloadedEpisodes) {
+ episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
+ - (downloadedEpisodes - deletedEpisodes);
+ }
+
+ Arrays.sort(mediaIds); // sort for binary search
+ final boolean ignoreMediaIds = mediaIds.length == 0;
+ List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
+
+ if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
+ for (int i = 0; i < queue.size(); i++) { // ignore playing item
+ FeedItem item = queue.get(i);
+ long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
+ if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
+ && item.hasMedia()
+ && !item.getMedia().isDownloaded()
+ && !item.getMedia().isPlaying()
+ && item.getFeed().getPreferences().getAutoDownload()) {
+ itemsToDownload.add(item);
+ episodeSpaceLeft--;
+ undownloadedEpisodes--;
+ if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
+ for (FeedItem item : unreadItems) {
+ long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
+ if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
+ && item.hasMedia()
+ && !item.getMedia().isDownloaded()
+ && item.getFeed().getPreferences().getAutoDownload()) {
+ itemsToDownload.add(item);
+ episodeSpaceLeft--;
+ undownloadedEpisodes--;
+ if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Enqueueing " + itemsToDownload.size()
+ + " items for download");
+
+ try {
+ DBTasks.downloadFeedItems(false, context,
+ itemsToDownload.toArray(new FeedItem[itemsToDownload
+ .size()])
+ );
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ }
+
+ }
+ }
+ };
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java
new file mode 100644
index 000000000..420bbc09d
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java
@@ -0,0 +1,139 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+/**
+ * Implementation of the EpisodeCleanupAlgorithm interface used by AntennaPodSP apps.
+ */
+public class APSPCleanupAlgorithm implements EpisodeCleanupAlgorithm<Integer> {
+ private static final String TAG = "APSPCleanupAlgorithm";
+
+ final int numberOfNewAutomaticallyDownloadedEpisodes;
+
+ public APSPCleanupAlgorithm(int numberOfNewAutomaticallyDownloadedEpisodes) {
+ this.numberOfNewAutomaticallyDownloadedEpisodes = numberOfNewAutomaticallyDownloadedEpisodes;
+ }
+
+ /**
+ * Performs an automatic cleanup. Episodes that have been downloaded first will also be deleted first.
+ * The episode that is currently playing as well as the n most recent episodes (the exact value is determined
+ * by AppPreferences.numberOfNewAutomaticallyDownloadedEpisodes) will never be deleted.
+ *
+ * @param context
+ * @param episodeSize The maximum amount of space that should be freed by this method
+ * @return The number of episodes that have been deleted
+ */
+ @Override
+ public int performCleanup(Context context, Integer episodeSize) {
+ Log.i(TAG, String.format("performAutoCleanup(%d)", episodeSize));
+ if (episodeSize <= 0) {
+ return 0;
+ }
+
+ List<FeedItem> candidates = getAutoCleanupCandidates(context);
+ List<FeedItem> deleteList = new ArrayList<FeedItem>();
+ long deletedEpisodesSize = 0;
+ Collections.sort(candidates, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ File lFile = new File(lhs.getMedia().getFile_url());
+ File rFile = new File(rhs.getMedia().getFile_url());
+ if (!lFile.exists() || !rFile.exists()) {
+ return 0;
+ }
+ if (FileUtils.isFileOlder(lFile, rFile)) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ });
+ // listened episodes will be deleted first
+ Iterator<FeedItem> it = candidates.iterator();
+ if (it.hasNext()) {
+ for (FeedItem i = it.next(); it.hasNext() && deletedEpisodesSize <= episodeSize; i = it.next()) {
+ if (!i.getMedia().isPlaying() && i.getMedia().getPlaybackCompletionDate() != null) {
+ it.remove();
+ deleteList.add(i);
+ deletedEpisodesSize += i.getMedia().getSize();
+ }
+ }
+ }
+
+ // delete unlistened old episodes if necessary
+ it = candidates.iterator();
+ if (it.hasNext()) {
+ for (FeedItem i = it.next(); it.hasNext() && deletedEpisodesSize <= episodeSize; i = it.next()) {
+ if (!i.getMedia().isPlaying()) {
+ it.remove();
+ deleteList.add(i);
+ deletedEpisodesSize += i.getMedia().getSize();
+ }
+ }
+ }
+ for (FeedItem item : deleteList) {
+ try {
+ DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+ Log.i(TAG, String.format("performAutoCleanup(%d) deleted %d episodes and freed %d bytes of memory",
+ episodeSize, deleteList.size(), deletedEpisodesSize));
+ return deleteList.size();
+ }
+
+ @Override
+ public Integer getDefaultCleanupParameter(Context context) {
+ return 0;
+ }
+
+ @Override
+ public Integer getPerformCleanupParameter(Context context, List<FeedItem> items) {
+ int episodeSize = 0;
+ for (FeedItem item : items) {
+ if (item.hasMedia() && !item.getMedia().isDownloaded()) {
+ episodeSize += item.getMedia().getSize();
+ }
+ }
+ return episodeSize;
+ }
+
+ /**
+ * Returns list of FeedItems that have been downloaded, but are not one of the
+ * [numberOfNewAutomaticallyDownloadedEpisodes] most recent items.
+ */
+ private List<FeedItem> getAutoCleanupCandidates(Context context) {
+ List<FeedItem> downloaded = new ArrayList<FeedItem>(DBReader.getDownloadedItems(context));
+ List<FeedItem> recent = new ArrayList<FeedItem>(DBReader.getRecentlyPublishedEpisodes(context,
+ numberOfNewAutomaticallyDownloadedEpisodes));
+ for (FeedItem r : recent) {
+ if (r.hasMedia() && r.getMedia().isDownloaded()) {
+ for (int i = 0; i < downloaded.size(); i++) {
+ if (downloaded.get(i).getId() == r.getId()) {
+ downloaded.remove(i);
+ break;
+ }
+ }
+ }
+ }
+
+ return downloaded;
+
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java
new file mode 100644
index 000000000..f760ec0ce
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java
@@ -0,0 +1,72 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+
+/**
+ * Implements the automatic download algorithm used by AntennaPodSP apps.
+ */
+public class APSPDownloadAlgorithm implements AutomaticDownloadAlgorithm {
+ private static final String TAG = "APSPDownloadAlgorithm";
+
+ private final int numberOfNewAutomaticallyDownloadedEpisodes;
+
+ public APSPDownloadAlgorithm(int numberOfNewAutomaticallyDownloadedEpisodes) {
+ this.numberOfNewAutomaticallyDownloadedEpisodes = numberOfNewAutomaticallyDownloadedEpisodes;
+ }
+
+ /**
+ * Downloads the most recent episodes automatically. The exact number of
+ * episodes that will be downloaded can be set in the AppPreferences.
+ *
+ * @param context Used for accessing the DB.
+ * @return A Runnable that will be submitted to an ExecutorService.
+ */
+ @Override
+ public Runnable autoDownloadUndownloadedItems(final Context context, final long... mediaIds) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Performing auto-dl of undownloaded episodes");
+ if (NetworkUtils.autodownloadNetworkAvailable(context)
+ && UserPreferences.isEnableAutodownload()) {
+
+ Arrays.sort(mediaIds);
+ List<FeedItem> itemsToDownload = DBReader.getRecentlyPublishedEpisodes(context,
+ numberOfNewAutomaticallyDownloadedEpisodes);
+ Iterator<FeedItem> it = itemsToDownload.iterator();
+
+ for (FeedItem item = it.next(); it.hasNext(); item = it.next()) {
+ if (!item.hasMedia()
+ || item.getMedia().isDownloaded()
+ || Arrays.binarySearch(mediaIds, item.getMedia().getId()) < 0) {
+ it.remove();
+ }
+ }
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Enqueueing " + itemsToDownload.size()
+ + " items for automatic download");
+ if (!itemsToDownload.isEmpty()) {
+ try {
+ DBTasks.downloadFeedItems(false, context,
+ itemsToDownload.toArray(new FeedItem[itemsToDownload
+ .size()]));
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ };
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java
new file mode 100644
index 000000000..9ca9620a7
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+
+public interface AutomaticDownloadAlgorithm {
+
+ /**
+ * Looks for undownloaded episodes and request a download if
+ * 1. Network is available
+ * 2. The device is charging or the user allows auto download on battery
+ * 3. There is free space in the episode cache
+ * This method is executed on an internal single thread executor.
+ *
+ * @param context Used for accessing the DB.
+ * @param mediaIds If this list is not empty, the method will only download a candidate for automatic downloading if
+ * its media ID is in the mediaIds list.
+ * @return A Runnable that will be submitted to an ExecutorService.
+ */
+ public Runnable autoDownloadUndownloadedItems(Context context, long... mediaIds);
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index b1aff5594..e73f9599d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -8,7 +8,6 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@@ -35,7 +34,6 @@ import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
import de.danoeh.antennapod.core.util.exception.MediaFileNotFoundException;
@@ -386,8 +384,8 @@ public final class DBTasks {
downloadFeedItems(true, context, items);
}
- private static void downloadFeedItems(boolean performAutoCleanup,
- final Context context, final FeedItem... items)
+ static void downloadFeedItems(boolean performAutoCleanup,
+ final Context context, final FeedItem... items)
throws DownloadRequestException {
final DownloadRequester requester = DownloadRequester.getInstance();
@@ -396,8 +394,10 @@ public final class DBTasks {
@Override
public void run() {
- performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, items.length));
+ ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm()
+ .performCleanup(context,
+ ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm()
+ .getPerformCleanupParameter(context, Arrays.asList(items)));
}
}.start();
@@ -427,7 +427,7 @@ public final class DBTasks {
}
}
- private static int getNumberOfUndownloadedEpisodes(
+ static int getNumberOfUndownloadedEpisodes(
final List<FeedItem> queue, final List<FeedItem> unreadItems) {
int counter = 0;
for (FeedItem item : queue) {
@@ -449,7 +449,8 @@ public final class DBTasks {
/**
* Looks for undownloaded episodes in the queue or list of unread items and request a download if
* 1. Network is available
- * 2. There is free space in the episode cache
+ * 2. The device is charging or the user allows auto download on battery
+ * 3. There is free space in the episode cache
* This method is executed on an internal single thread executor.
*
* @param context Used for accessing the DB.
@@ -458,107 +459,9 @@ public final class DBTasks {
* @return A Future that can be used for waiting for the methods completion.
*/
public static Future<?> autodownloadUndownloadedItems(final Context context, final long... mediaIds) {
- return autodownloadExec.submit(new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Performing auto-dl of undownloaded episodes");
- if (NetworkUtils.autodownloadNetworkAvailable(context)
- && UserPreferences.isEnableAutodownload()) {
- final List<FeedItem> queue = DBReader.getQueue(context);
- final List<FeedItem> unreadItems = DBReader
- .getUnreadItemsList(context);
-
- int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(queue,
- unreadItems);
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- int deletedEpisodes = performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, undownloadedEpisodes));
- int episodeSpaceLeft = undownloadedEpisodes;
- boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
- .getEpisodeCacheSizeUnlimited();
-
- if (!cacheIsUnlimited
- && UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
- + undownloadedEpisodes) {
- episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
- - (downloadedEpisodes - deletedEpisodes);
- }
-
- Arrays.sort(mediaIds); // sort for binary search
- final boolean ignoreMediaIds = mediaIds.length == 0;
- List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (int i = 0; i < queue.size(); i++) { // ignore playing item
- FeedItem item = queue.get(i);
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && !item.getMedia().isPlaying()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (FeedItem item : unreadItems) {
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Enqueueing " + itemsToDownload.size()
- + " items for download");
-
- try {
- downloadFeedItems(false, context,
- itemsToDownload.toArray(new FeedItem[itemsToDownload
- .size()])
- );
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
+ return autodownloadExec.submit(ClientConfig.dbTasksCallbacks.getAutomaticDownloadAlgorithm()
+ .autoDownloadUndownloadedItems(context, mediaIds));
- }
- }
- });
-
- }
-
- private static int getPerformAutoCleanupArgs(Context context,
- final int episodeNumber) {
- if (episodeNumber >= 0
- && UserPreferences.getEpisodeCacheSize() != UserPreferences
- .getEpisodeCacheSizeUnlimited()) {
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- if (downloadedEpisodes + episodeNumber >= UserPreferences
- .getEpisodeCacheSize()) {
-
- return downloadedEpisodes + episodeNumber
- - UserPreferences.getEpisodeCacheSize();
- }
- }
- return 0;
}
/**
@@ -570,63 +473,8 @@ public final class DBTasks {
* @param context Used for accessing the DB.
*/
public static void performAutoCleanup(final Context context) {
- performAutoCleanup(context, getPerformAutoCleanupArgs(context, 0));
- }
-
- private static int performAutoCleanup(final Context context,
- final int episodeNumber) {
- List<FeedItem> candidates = new ArrayList<FeedItem>();
- List<FeedItem> downloadedItems = DBReader.getDownloadedItems(context);
- QueueAccess queue = QueueAccess.IDListAccess(DBReader.getQueueIDList(context));
- List<FeedItem> delete;
- for (FeedItem item : downloadedItems) {
- if (item.hasMedia() && item.getMedia().isDownloaded()
- && !queue.contains(item.getId()) && item.isRead()) {
- candidates.add(item);
- }
-
- }
-
- Collections.sort(candidates, new Comparator<FeedItem>() {
- @Override
- public int compare(FeedItem lhs, FeedItem rhs) {
- Date l = lhs.getMedia().getPlaybackCompletionDate();
- Date r = rhs.getMedia().getPlaybackCompletionDate();
-
- if (l == null) {
- l = new Date(0);
- }
- if (r == null) {
- r = new Date(0);
- }
- return l.compareTo(r);
- }
- });
-
- if (candidates.size() > episodeNumber) {
- delete = candidates.subList(0, episodeNumber);
- } else {
- delete = candidates;
- }
-
- for (FeedItem item : delete) {
- try {
- DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- int counter = delete.size();
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, String.format(
- "Auto-delete deleted %d episodes (%d requested)", counter,
- episodeNumber));
-
- return counter;
+ ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm().performCleanup(context,
+ ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm().getDefaultCleanupParameter(context));
}
/**
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
index f5ee9e28c..d0cdad649 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
@@ -92,8 +92,9 @@ public class DownloadRequester {
private void download(Context context, FeedFile item, FeedFile container, File dest,
boolean overwriteIfExists, String username, String password, boolean deleteOnFailure, Bundle arguments) {
+ final boolean partiallyDownloadedFileExists = item.getFile_url() != null;
if (!isDownloadingFile(item)) {
- if (!isFilenameAvailable(dest.toString()) || (deleteOnFailure && dest.exists())) {
+ if (!isFilenameAvailable(dest.toString()) || (!partiallyDownloadedFileExists && dest.exists())) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Filename already used.");
if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
@@ -254,8 +255,7 @@ public class DownloadRequester {
* Cancels all running downloads
*/
public synchronized void cancelAllDownloads(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling all running downloads");
+ Log.d(TAG, "Cancelling all running downloads");
context.sendBroadcast(new Intent(
DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
}
@@ -377,10 +377,13 @@ public class DownloadRequester {
String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(),
null, media.getMime_type());
- ;
- if (titleBaseFilename != "") {
+ if (!titleBaseFilename.equals("")) {
// Append extension
+ final int FILENAME_MAX_LENGTH = 220;
+ if (titleBaseFilename.length() > FILENAME_MAX_LENGTH) {
+ titleBaseFilename = titleBaseFilename.substring(0, FILENAME_MAX_LENGTH);
+ }
filename = titleBaseFilename + FilenameUtils.EXTENSION_SEPARATOR +
FilenameUtils.getExtension(URLBaseFilename);
} else {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java
new file mode 100644
index 000000000..6a8b4a441
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java
@@ -0,0 +1,36 @@
+package de.danoeh.antennapod.core.storage;
+
+import android.content.Context;
+
+import java.util.List;
+
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+public interface EpisodeCleanupAlgorithm<T> {
+
+ /**
+ * Deletes downloaded episodes that are no longer needed. What episodes are deleted and how many
+ * of them depends on the implementation.
+ *
+ * @param context Can be used for accessing the database
+ * @param parameter An additional parameter. This parameter is either returned by getDefaultCleanupParameter
+ * or getPerformCleanupParameter.
+ * @return The number of episodes that were deleted.
+ */
+ public int performCleanup(Context context, T parameter);
+
+ /**
+ * Returns a parameter for performCleanup. The implementation of this interface should decide how much
+ * space to free to satisfy the episode cache conditions. If the conditions are already satisfied, this
+ * method should not have any effects.
+ */
+ public T getDefaultCleanupParameter(Context context);
+
+ /**
+ * Returns a parameter for performCleanup.
+ *
+ * @param items A list of FeedItems that are about to be downloaded. The implementation of this interface
+ * should decide how much space to free to satisfy the episode cache conditions.
+ */
+ public T getPerformCleanupParameter(Context context, List<FeedItem> items);
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java
new file mode 100644
index 000000000..39deea36a
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java
@@ -0,0 +1,32 @@
+package de.danoeh.antennapod.core.util;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+
+/**
+ * Created by Tom on 1/5/15.
+ */
+public class PowerUtils {
+
+ private static final String TAG = "PowerUtils";
+
+ private PowerUtils() {
+
+ }
+
+ /**
+ * @return true if the device is charging
+ */
+ public static boolean deviceCharging(Context context) {
+ // from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
+ IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatus = context.registerReceiver(null, iFilter);
+
+ int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+ return (status == BatteryManager.BATTERY_STATUS_CHARGING ||
+ status == BatteryManager.BATTERY_STATUS_FULL);
+
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 443ff0ad1..f31297b41 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -28,7 +28,7 @@ import de.danoeh.antennapod.core.util.ShownotesProvider;
public class Timeline {
private static final String TAG = "Timeline";
- private static final String WEBVIEW_STYLE = "@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; } a.timecode { color: #669900; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }";
+ private static final String WEBVIEW_STYLE = "@font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 13pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } a.timecode { color: #669900; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }";
private ShownotesProvider shownotesProvider;
diff --git a/core/src/main/res/drawable-hdpi/ic_settings_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_settings_grey600_24dp.png
new file mode 100644
index 000000000..20d2b66e0
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_settings_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_settings_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_settings_white_24dp.png
new file mode 100644
index 000000000..f9a8915fd
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_settings_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_settings_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_settings_grey600_24dp.png
new file mode 100644
index 000000000..2251d2bbb
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_settings_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png
new file mode 100644
index 000000000..12e5d100d
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png
new file mode 100644
index 000000000..6a70402b4
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png
new file mode 100644
index 000000000..6bb8f6e08
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png
Binary files differ
diff --git a/app/src/main/res/layout/refresh_action_view.xml b/core/src/main/res/layout/refresh_action_view.xml
index 66148a553..66148a553 100644
--- a/app/src/main/res/layout/refresh_action_view.xml
+++ b/core/src/main/res/layout/refresh_action_view.xml
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index c46a2118f..f36119c8d 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -35,6 +35,7 @@
<attr name="av_pause_big" format="reference"/>
<attr name="av_ff_big" format="reference"/>
<attr name="av_rew_big" format="reference"/>
+ <attr name="ic_settings" format="reference"/>
<!-- Used in itemdescription -->
<attr name="non_transparent_background" format="reference"/>
diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml
index ab48fafe7..e558a5c4e 100644
--- a/core/src/main/res/values/colors.xml
+++ b/core/src/main/res/values/colors.xml
@@ -11,11 +11,12 @@
<color name="download_failed_red">#CC0000</color>
<color name="status_progress">#E033B5E5</color>
<color name="status_playing">#E0EE5F52</color>
- <color name="overlay_dark">#262C31</color>
- <color name="overlay_light">#DDDDDD</color>
+ <color name="overlay_dark">#2C2C2C</color>
+ <color name="overlay_light">#FFFFFF</color>
<color name="swipe_refresh_secondary_color_light">#EDEDED</color>
<color name="swipe_refresh_secondary_color_dark">#060708</color>
<color name="new_indicator_green">#669900</color>
+ <color name="image_readability_tint">#80000000</color>
<!-- Use Gingerbread-orange -->
<color name="selection_background_color_dark">#FEBB20</color>
diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml
index 38c14b024..81a55142a 100644
--- a/core/src/main/res/values/dimens.xml
+++ b/core/src/main/res/values/dimens.xml
@@ -33,4 +33,6 @@
<dimen name="listitem_icon_leftpadding">16dp</dimen>
<dimen name="listitem_icon_rightpadding">16dp</dimen>
+ <dimen name="audioplayer_playercontrols_length">64dp</dimen>
+
</resources> \ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 532b5d75d..86208becb 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -205,6 +205,7 @@
<string name="services_label">Services</string>
<string name="flattr_label">Flattr</string>
<string name="pref_pauseOnHeadsetDisconnect_sum">Pause playback when the headphones are disconnected</string>
+ <string name="pref_unpauseOnHeadsetReconnect_sum">Resume playback when the headphones are reconnected</string>
<string name="pref_followQueue_sum">Jump to next queue item when playback completes</string>
<string name="playback_pref">Playback</string>
<string name="network_pref">Network</string>
@@ -214,6 +215,7 @@
<string name="pref_followQueue_title">Continuous playback</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi media download</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones disconnect</string>
+ <string name="pref_unpauseOnHeadsetReconnect_title">Headphones reconnect</string>
<string name="pref_mobileUpdate_title">Mobile updates</string>
<string name="pref_mobileUpdate_sum">Allow updates over the mobile data connection</string>
<string name="refreshing_label">Refreshing</string>
@@ -233,6 +235,8 @@
<string name="pref_automatic_download_sum">Configure the automatic download of episodes.</string>
<string name="pref_autodl_wifi_filter_title">Enable Wi-Fi filter</string>
<string name="pref_autodl_wifi_filter_sum">Allow automatic download only for selected Wi-Fi networks.</string>
+ <string name="pref_automatic_download_on_battery_title">Automatic download on battery</string>
+ <string name="pref_automatic_download_on_battery_sum">Allow automatic download while on battery</string>
<string name="pref_episode_cache_title">Episode cache</string>
<string name="pref_theme_title_light">Light</string>
<string name="pref_theme_title_dark">Dark</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index df7ae385c..a2f180395 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -40,6 +40,7 @@
<item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark" parent="@style/Theme.AppCompat">
@@ -80,6 +81,94 @@
<item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
+ </style>
+
+ <style name="Theme.AntennaPod.Light.NoTitle" parent="@style/Theme.AppCompat.Light.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="colorPrimary">@color/primary_light</item>
+ <item name="colorAccent">@color/color_accent</item>
+ <item name="attr/action_about">@drawable/ic_info_grey600_24dp</item>
+ <item name="attr/action_search">@drawable/ic_search_grey600_24dp</item>
+ <item name="attr/action_stream">@drawable/ic_settings_input_antenna_grey600_24dp</item>
+ <item name="attr/av_download">@drawable/ic_file_download_grey600_24dp</item>
+ <item name="attr/av_fast_forward">@drawable/ic_fast_forward_grey600_24dp</item>
+ <item name="attr/av_pause">@drawable/ic_pause_grey600_24dp</item>
+ <item name="attr/av_play">@drawable/ic_play_arrow_grey600_24dp</item>
+ <item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
+ <item name="attr/content_discard">@drawable/ic_delete_grey600_24dp</item>
+ <item name="attr/content_new">@drawable/ic_add_grey600_24dp</item>
+ <item name="attr/device_access_time">@drawable/ic_timer_grey600_24dp</item>
+ <item name="attr/location_web_site">@drawable/ic_web_grey600_24dp</item>
+ <item name="attr/navigation_accept">@drawable/ic_done_grey600_24dp</item>
+ <item name="attr/navigation_cancel">@drawable/ic_cancel_grey600_24dp</item>
+ <item name="attr/navigation_expand">@drawable/ic_expand_more_grey600_36dp</item>
+ <item name="attr/navigation_refresh">@drawable/ic_refresh_grey600_24dp</item>
+ <item name="attr/navigation_up">@drawable/navigation_up</item>
+ <item name="attr/navigation_shownotes">@drawable/ic_description_grey600_36dp</item>
+ <item name="attr/navigation_chapters">@drawable/ic_toc_grey600_36dp</item>
+ <item name="attr/social_share">@drawable/ic_share_grey600_24dp</item>
+ <item name="attr/stat_playlist">@drawable/ic_list_grey600_24dp</item>
+ <item name="attr/type_audio">@drawable/ic_hearing_grey600_18dp</item>
+ <item name="attr/type_video">@drawable/ic_remove_red_eye_grey600_18dp</item>
+ <item name="attr/non_transparent_background">@color/white</item>
+ <item name="attr/overlay_background">@color/overlay_light</item>
+ <item name="attr/overlay_drawable">@drawable/overlay_drawable</item>
+ <item name="attr/dragview_background">@drawable/ic_drag_handle</item>
+ <item name="attr/dragview_float_background">@color/white</item>
+ <item name="attr/nav_drawer_background">@color/white</item>
+ <item name="attr/ic_action_overflow">@drawable/ic_more_vert_grey600_24dp</item>
+ <item name="attr/ic_new">@drawable/ic_new_releases_grey600_24dp</item>
+ <item name="attr/ic_history">@drawable/ic_history_grey600_24dp</item>
+ <item name="attr/av_play_big">@drawable/ic_play_arrow_grey600_36dp</item>
+ <item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
+ <item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
+ <item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
+ </style>
+
+ <style name="Theme.AntennaPod.Dark.NoTitle" parent="@style/Theme.AppCompat.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="colorAccent">@color/color_accent</item>
+ <item name="attr/action_about">@drawable/ic_info_white_24dp</item>
+ <item name="attr/action_search">@drawable/ic_search_white_24dp</item>
+ <item name="attr/action_stream">@drawable/ic_settings_input_antenna_white_24dp</item>
+ <item name="attr/av_download">@drawable/ic_file_download_white_24dp</item>
+ <item name="attr/av_fast_forward">@drawable/ic_fast_forward_white_24dp</item>
+ <item name="attr/av_pause">@drawable/ic_pause_white_24dp</item>
+ <item name="attr/av_play">@drawable/ic_play_arrow_white_24dp</item>
+ <item name="attr/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
+ <item name="attr/content_discard">@drawable/ic_delete_white_24dp</item>
+ <item name="attr/content_new">@drawable/ic_add_white_24dp</item>
+ <item name="attr/device_access_time">@drawable/ic_timer_white_24dp</item>
+ <item name="attr/location_web_site">@drawable/ic_web_white_24dp</item>
+ <item name="attr/navigation_accept">@drawable/ic_done_white_24dp</item>
+ <item name="attr/navigation_cancel">@drawable/ic_cancel_white_24dp</item>
+ <item name="attr/navigation_expand">@drawable/ic_expand_more_white_36dp</item>
+ <item name="attr/navigation_refresh">@drawable/ic_refresh_white_24dp</item>
+ <item name="attr/navigation_up">@drawable/navigation_up_dark</item>
+ <item name="attr/navigation_shownotes">@drawable/ic_description_white_36dp</item>
+ <item name="attr/navigation_chapters">@drawable/ic_toc_white_36dp</item>
+ <item name="attr/social_share">@drawable/ic_share_white_24dp</item>
+ <item name="attr/stat_playlist">@drawable/ic_list_white_24dp</item>
+ <item name="attr/type_audio">@drawable/ic_hearing_white_18dp</item>
+ <item name="attr/type_video">@drawable/ic_remove_red_eye_white_18dp</item>
+ <item name="attr/non_transparent_background">@color/black</item>
+ <item name="attr/overlay_background">@color/overlay_dark</item>
+ <item name="attr/overlay_drawable">@drawable/overlay_drawable_dark</item>
+ <item name="attr/dragview_background">@drawable/ic_drag_handle_dark</item>
+ <item name="attr/dragview_float_background">@color/black</item>
+ <item name="attr/nav_drawer_background">#3B3B3B</item>
+ <item name="attr/ic_action_overflow">@drawable/ic_more_vert_white_24dp</item>
+ <item name="attr/ic_new">@drawable/ic_new_releases_white_24dp</item>
+ <item name="attr/ic_history">@drawable/ic_history_white_24dp</item>
+ <item name="attr/av_play_big">@drawable/ic_play_arrow_white_36dp</item>
+ <item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
+ <item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
+ <item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
</style>
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">
@@ -157,4 +246,10 @@
<item name="android:text">@string/new_label</item>
</style>
+ <style name="BigBlurryBackground">
+ <item name="android:scaleType">centerCrop</item>
+ <item name="android:tint">@color/image_readability_tint</item>
+
+ </style>
+
</resources>