summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/AndroidManifest.xml6
-rw-r--r--app/src/main/assets/Roboto.ttfbin114976 -> 0 bytes
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/UpdateManager.java97
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java39
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java94
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java323
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java47
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml3
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml21
-rw-r--r--app/src/main/res/layout/proxy_settings.xml90
-rw-r--r--app/src/main/res/menu/opml_selection_options.xml19
-rw-r--r--app/src/main/res/xml/preferences.xml9
29 files changed, 744 insertions, 253 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 96539936c..b20aab7b0 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="1050104"
- android:versionName="1.5.1.4">
+ android:versionCode="1050200"
+ android:versionName="1.5.2.0">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
@@ -179,7 +179,7 @@
<activity
android:name=".activity.VideoplayerActivity"
android:configChanges="keyboardHidden|orientation"
- android:screenOrientation="landscape">
+ android:screenOrientation="sensorLandscape">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.danoeh.antennapod.activity.MainActivity"/>
diff --git a/app/src/main/assets/Roboto.ttf b/app/src/main/assets/Roboto.ttf
deleted file mode 100644
index 0ba95c98c..000000000
--- a/app/src/main/assets/Roboto.ttf
+++ /dev/null
Binary files differ
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 829a49a15..f6a8db5fb 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -8,11 +8,8 @@ import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule;
import com.joanzapata.iconify.fonts.MaterialModule;
+import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.feed.EventDistributor;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.spa.SPAUtil;
/** Main application class. */
@@ -56,11 +53,8 @@ public class PodcastApp extends Application {
singleton = this;
- PodDBAdapter.init(this);
- UserPreferences.init(this);
- UpdateManager.init(this);
- PlaybackPreferences.init(this);
- NetworkUtils.init(this);
+ ClientConfig.initialize(this);
+
EventDistributor.getInstance();
Iconify.with(new FontAwesomeModule());
Iconify.with(new MaterialModule());
diff --git a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
deleted file mode 100644
index 0b3c43381..000000000
--- a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.danoeh.antennapod;
-
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.util.Log;
-
-import org.antennapod.audio.MediaPlayer;
-
-import java.io.File;
-import java.util.List;
-
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedImage;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-
-/*
- * This class's job is do perform maintenance tasks whenever the app has been updated
- */
-public class UpdateManager {
-
- public static final String TAG = UpdateManager.class.getSimpleName();
-
- private static final String PREF_NAME = "app_version";
- private static final String KEY_VERSION_CODE = "version_code";
-
- private static int currentVersionCode;
-
- private static Context context;
- private static SharedPreferences prefs;
-
- public static void init(Context context) {
- UpdateManager.context = context;
- prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
- currentVersionCode = info.versionCode;
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Failed to obtain package info for package name: " + context.getPackageName(), e);
- currentVersionCode = 0;
- return;
- }
- final int oldVersionCode = getStoredVersionCode();
- Log.d(TAG, "old: " + oldVersionCode + ", current: " + currentVersionCode);
- if(oldVersionCode < currentVersionCode) {
- onUpgrade(oldVersionCode, currentVersionCode);
- setCurrentVersionCode();
- }
- }
-
- public static int getStoredVersionCode() {
- return prefs.getInt(KEY_VERSION_CODE, -1);
- }
-
- public static void setCurrentVersionCode() {
- prefs.edit().putInt(KEY_VERSION_CODE, currentVersionCode).apply();
- }
-
- private static void onUpgrade(final int oldVersionCode, final int newVersionCode) {
- if(oldVersionCode < 1030099) {
- // delete the now obsolete image cache
- // from now on, Glide will handle caching images
- new Thread() {
- public void run() {
- List<Feed> feeds = DBReader.getFeedList();
- for (Feed podcast : feeds) {
- List<FeedItem> episodes = DBReader.getFeedItemList(podcast);
- for (FeedItem episode : episodes) {
- FeedImage image = episode.getImage();
- if (image != null && image.isDownloaded() && image.getFile_url() != null) {
- File imageFile = new File(image.getFile_url());
- if (imageFile.exists()) {
- imageFile.delete();
- }
- image.setFile_url(null); // calls setDownloaded(false)
- DBWriter.setFeedImage(image);
- }
- }
- }
- }
- }.start();
- }
- if(oldVersionCode < 1050004) {
- if(MediaPlayer.isPrestoLibraryInstalled(context) && Build.VERSION.SDK_INT >= 16) {
- UserPreferences.enableSonic(true);
- }
- }
- }
-
-}
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 b4e8d4d71..e90681931 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -103,6 +103,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop()");
+ pagerAdapter.setController(null);
if(subscription != null) {
subscription.unsubscribe();
}
@@ -112,9 +113,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
@Override
public void onDestroy() {
+ Log.d(TAG, "onDestroy()");
super.onDestroy();
// don't risk creating memory leaks
+ drawerLayout = null;
navAdapter = null;
+ navList = null;
+ navDrawer = null;
drawerToggle = null;
pager = null;
pagerAdapter = null;
@@ -171,6 +176,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
media = controller.getMedia();
pagerAdapter.onMediaChanged(media);
+ pagerAdapter.setController(controller);
}
EventDistributor.getInstance().register(contentUpdate);
@@ -258,7 +264,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
});
pager = (ViewPager) findViewById(R.id.pager);
- pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
+ pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager(), media);
+ pagerAdapter.setController(controller);
pager.setAdapter(pagerAdapter);
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
@@ -537,10 +544,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
void onMediaChanged(Playable media);
}
- private class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
+ private static class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
- public AudioplayerPagerAdapter(FragmentManager fm) {
+ private static final String TAG = "AudioplayerPagerAdapter";
+
+ private Playable media;
+ private PlaybackController controller;
+
+ public AudioplayerPagerAdapter(FragmentManager fm, Playable media) {
super(fm);
+ this.media = media;
}
private CoverFragment coverFragment;
@@ -548,6 +561,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
private ChaptersFragment chaptersFragment;
public void onMediaChanged(Playable media) {
+ this.media = media;
if(coverFragment != null) {
coverFragment.onMediaChanged(media);
}
@@ -559,6 +573,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
}
}
+ public void setController(PlaybackController controller) {
+ this.controller = controller;
+ if(chaptersFragment != null) {
+ chaptersFragment.setController(controller);
+ }
+ }
+
@Nullable
public ChaptersFragment getChaptersFragment() {
return chaptersFragment;
@@ -580,7 +601,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
return itemDescriptionFragment;
case POS_CHAPTERS:
if(chaptersFragment == null) {
- chaptersFragment = ChaptersFragment.newInstance(media, controller);
+ chaptersFragment = ChaptersFragment.newInstance(media);
+ chaptersFragment.setController(controller);
}
return chaptersFragment;
default:
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 bd7da7c03..3ab6a0ab8 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -86,6 +86,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
public static final String EXTRA_NAV_INDEX = "nav_index";
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
+ public static final String EXTRA_FEED_ID = "fragment_feed_id";
public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
public static final String SAVE_TITLE = "title";
@@ -184,7 +185,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
loadFragment(lastFragment, null);
} else {
try {
- loadFeedFragmentById(Integer.valueOf(lastFragment), null);
+ loadFeedFragmentById(Integer.parseInt(lastFragment), null);
} catch (NumberFormatException e) {
// it's not a number, this happens if we removed
// a label from the NAV_DRAWER_TAGS
@@ -464,8 +465,9 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
StorageUtils.checkStorageAvailability(this);
Intent intent = getIntent();
- if (navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) &&
- (intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG))) {
+ if (intent.hasExtra(EXTRA_FEED_ID) ||
+ (navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) &&
+ (intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
handleNavIntent();
}
loadData();
@@ -709,15 +711,19 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
private void handleNavIntent() {
Log.d(TAG, "handleNavIntent()");
Intent intent = getIntent();
- if (intent.hasExtra(EXTRA_NAV_TYPE) &&
- intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)) {
+ if (intent.hasExtra(EXTRA_FEED_ID) ||
+ (intent.hasExtra(EXTRA_NAV_TYPE) &&
+ (intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
int index = intent.getIntExtra(EXTRA_NAV_INDEX, -1);
String tag = intent.getStringExtra(EXTRA_FRAGMENT_TAG);
Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
+ long feedId = intent.getLongExtra(EXTRA_FEED_ID, 0);
if (index >= 0) {
loadFragment(index, args);
} else if (tag != null) {
loadFragment(tag, args);
+ } else if(feedId > 0) {
+ loadFeedFragmentById(feedId, args);
}
}
setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
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 81ba8169f..f02f87d06 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -249,9 +249,6 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
controller.release();
}
controller = newPlaybackController();
- if(butPlay != null) {
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
- }
}
@Override
@@ -260,6 +257,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
Log.d(TAG, "onStop()");
if (controller != null) {
controller.release();
+ controller = null; // prevent leak
}
}
@@ -486,9 +484,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
- barLeftVolume.setProgress(100);
+ barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
- barRightVolume.setProgress(100);
+ barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
stereoToMono.setChecked(UserPreferences.stereoToMono());
if (controller != null && !controller.canDownmix()) {
@@ -500,14 +498,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- float leftVolume = 1.0f, rightVolume = 1.0f;
- if (progress < 100) {
- leftVolume = progress / 100.0f;
- }
- if (barRightVolume.getProgress() < 100) {
- rightVolume = barRightVolume.getProgress() / 100.0f;
- }
- controller.setVolume(leftVolume, rightVolume);
+ controller.setVolume(
+ Converter.getVolumeFromPercentage(progress),
+ Converter.getVolumeFromPercentage(barRightVolume.getProgress()));
}
@Override
@@ -521,14 +514,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- float leftVolume = 1.0f, rightVolume = 1.0f;
- if (progress < 100) {
- rightVolume = progress / 100.0f;
- }
- if (barLeftVolume.getProgress() < 100) {
- leftVolume = barLeftVolume.getProgress() / 100.0f;
- }
- controller.setVolume(leftVolume, rightVolume);
+ controller.setVolume(
+ Converter.getVolumeFromPercentage(barLeftVolume.getProgress()),
+ Converter.getVolumeFromPercentage(progress));
}
@Override
@@ -761,8 +749,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
if (butRev != null) {
butRev.setOnClickListener(v -> {
- int curr = controller.getPosition();
- controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ onRewind();
});
butRev.setOnLongClickListener(new View.OnLongClickListener() {
@@ -800,12 +787,13 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
});
}
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ onPlayPause();
+ });
if (butFF != null) {
butFF.setOnClickListener(v -> {
- int curr = controller.getPosition();
- controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ onFastForward();
});
butFF.setOnLongClickListener(new View.OnLongClickListener() {
@@ -850,6 +838,29 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
}
}
+ protected void onRewind() {
+ if (controller == null) {
+ return;
+ }
+ int curr = controller.getPosition();
+ controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ }
+
+ protected void onPlayPause() {
+ if(controller == null) {
+ return;
+ }
+ controller.playPause();
+ }
+
+ protected void onFastForward() {
+ if (controller == null) {
+ return;
+ }
+ int curr = controller.getPosition();
+ controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ }
+
protected abstract int getContentViewResourceId();
void handleError(int errorCode) {
@@ -882,7 +893,13 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
private void updateButPlaybackSpeed() {
if (controller != null && butPlaybackSpeed != null) {
- float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
+ float speed = 1.0f;
+ try {
+ speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch(NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(speed));
+ }
String speedStr = String.format("%.2fx", speed);
butPlaybackSpeed.setText(speedStr);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index c7426c006..9d8048acf 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -408,18 +408,25 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
description.setText(feed.getDescription());
subscribeButton.setOnClickListener(v -> {
- try {
+ if(feed != null && feedInFeedlist(feed)) {
+ Intent intent = new Intent(OnlineFeedViewActivity.this, MainActivity.class);
+ // feed.getId() is always 0, we have to retrieve the id from the feed list from
+ // the database
+ intent.putExtra(MainActivity.EXTRA_FEED_ID, getFeedId(feed));
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ } else {
Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
f.setPreferences(feed.getPreferences());
this.feed = f;
-
- DownloadRequester.getInstance().downloadFeed(this, f);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(OnlineFeedViewActivity.this,
- e.getMessage());
+ try {
+ DownloadRequester.getInstance().downloadFeed(this, f);
+ } catch (DownloadRequestException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, e.getMessage());
+ }
+ setSubscribeButtonState(feed);
}
- setSubscribeButtonState(feed);
});
if (alternateFeedUrls.isEmpty()) {
@@ -462,8 +469,8 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
subscribeButton.setEnabled(false);
subscribeButton.setText(R.string.downloading_label);
} else if (feedInFeedlist(feed)) {
- subscribeButton.setEnabled(false);
- subscribeButton.setText(R.string.subscribed_label);
+ subscribeButton.setEnabled(true);
+ subscribeButton.setText(R.string.open_podcast);
} else {
subscribeButton.setEnabled(true);
subscribeButton.setText(R.string.subscribe_label);
@@ -483,6 +490,18 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
return false;
}
+ private long getFeedId(Feed feed) {
+ if (feeds == null || feed == null) {
+ return 0;
+ }
+ for (Feed f : feeds) {
+ if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
+ return f.getId();
+ }
+ }
+ return 0;
+ }
+
private void showErrorDialog(String errorMsg) {
assert(Looper.myLooper() == Looper.getMainLooper()); // run on UI thread
if (!isFinishing() && !isPaused) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 8a9ec58d3..bc3e686e5 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -2,23 +2,22 @@ package de.danoeh.antennapod.activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.SparseBooleanArray;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.opml.OpmlElement;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import java.util.ArrayList;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.opml.OpmlElement;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
/**
* Displays the feeds that the OPML-Importer has read and lets the user choose
* which feeds he wants to import.
@@ -33,6 +32,9 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
private ListView feedlist;
private ArrayAdapter<String> listAdapter;
+ private MenuItem selectAll;
+ private MenuItem deselectAll;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
@@ -44,45 +46,54 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
feedlist = (ListView) findViewById(R.id.feedlist);
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- listAdapter = new ArrayAdapter<String>(this,
+ listAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_multiple_choice,
getTitleList());
feedlist.setAdapter(listAdapter);
-
- butCancel.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(RESULT_CANCELED);
- finish();
+ feedlist.setOnItemClickListener((parent, view, position, id) -> {
+ SparseBooleanArray checked = feedlist.getCheckedItemPositions();
+ int checkedCount = 0;
+ for (int i = 0; i < checked.size(); i++) {
+ if (checked.valueAt(i)) {
+ checkedCount++;
+ }
+ }
+ if(checkedCount == listAdapter.getCount()) {
+ selectAll.setVisible(false);
+ deselectAll.setVisible(true);
+ } else {
+ deselectAll.setVisible(false);
+ selectAll.setVisible(true);
}
});
- butConfirm.setOnClickListener(new OnClickListener() {
+ butCancel.setOnClickListener(v -> {
+ setResult(RESULT_CANCELED);
+ finish();
+ });
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- SparseBooleanArray checked = feedlist.getCheckedItemPositions();
+ butConfirm.setOnClickListener(v -> {
+ Intent intent = new Intent();
+ SparseBooleanArray checked = feedlist.getCheckedItemPositions();
- int checkedCount = 0;
- // Get number of checked items
- for (int i = 0; i < checked.size(); i++) {
- if (checked.valueAt(i)) {
- checkedCount++;
- }
+ int checkedCount = 0;
+ // Get number of checked items
+ for (int i = 0; i < checked.size(); i++) {
+ if (checked.valueAt(i)) {
+ checkedCount++;
}
- int[] selection = new int[checkedCount];
- for (int i = 0, collected = 0; collected < checkedCount; i++) {
- if (checked.valueAt(i)) {
- selection[collected] = checked.keyAt(i);
- collected++;
- }
+ }
+ int[] selection = new int[checkedCount];
+ for (int i = 0, collected = 0; collected < checkedCount; i++) {
+ if (checked.valueAt(i)) {
+ selection[collected] = checked.keyAt(i);
+ collected++;
}
- intent.putExtra(EXTRA_SELECTED_ITEMS, selection);
- setResult(RESULT_OK, intent);
- finish();
}
+ intent.putExtra(EXTRA_SELECTED_ITEMS, selection);
+ setResult(RESULT_OK, intent);
+ finish();
});
}
@@ -93,7 +104,6 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
for (OpmlElement element : OpmlImportHolder.getReadElements()) {
result.add(element.getText());
}
-
}
return result;
}
@@ -101,13 +111,11 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.select_all_item, Menu.NONE,
- R.string.select_all_label),
- MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
-
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.deselect_all_item, Menu.NONE,
- R.string.deselect_all_label),
- MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.opml_selection_options, menu);
+ selectAll = menu.findItem(R.id.select_all_item);
+ deselectAll = menu.findItem(R.id.deselect_all_item);
+ deselectAll.setVisible(false);
return true;
}
@@ -115,10 +123,14 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.select_all_item:
+ selectAll.setVisible(false);
selectAllItems(true);
+ deselectAll.setVisible(true);
return true;
case R.id.deselect_all_item:
+ deselectAll.setVisible(false);
selectAllItems(false);
+ selectAll.setVisible(true);
return true;
default:
return false;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index 46dabec12..fb145db1f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -4,6 +4,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
+import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
@@ -31,7 +32,7 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
private OpmlImportWorker importWorker;
private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
- private Uri uri;
+ @Nullable private Uri uri;
/**
* Handles the choices made by the user in the OpmlFeedChooserActivity and
@@ -67,7 +68,14 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
}
}
- protected void importUri(Uri uri) {
+ protected void importUri(@Nullable Uri uri) {
+ if(uri == null) {
+ new MaterialDialog.Builder(this)
+ .content(R.string.opml_import_error_no_file)
+ .positiveText(android.R.string.ok)
+ .show();
+ return;
+ }
this.uri = uri;
if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
@@ -127,8 +135,9 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
importWorker.executeAsync();
} catch (Exception e) {
Log.d(TAG, Log.getStackTraceString(e));
+ String message = getString(R.string.opml_reader_error);
new MaterialDialog.Builder(this)
- .content("Cannot open OPML file: " + e.getMessage())
+ .content(message + " " + e.getMessage())
.positiveText(android.R.string.ok)
.show();
}
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 ee459dbc6..42c9edd99 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -202,6 +202,24 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoControlsShowing = !videoControlsShowing;
}
+ @Override
+ protected void onRewind() {
+ super.onRewind();
+ setupVideoControlsToggler();
+ }
+
+ @Override
+ protected void onPlayPause() {
+ super.onPlayPause();
+ setupVideoControlsToggler();
+ }
+
+ @Override
+ protected void onFastForward() {
+ super.onFastForward();
+ setupVideoControlsToggler();
+ }
+
private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
@@ -312,7 +330,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
private static class VideoControlsHider extends Handler {
- private static final int DELAY = 5000;
+ private static final int DELAY = 2500;
private WeakReference<VideoplayerActivity> activity;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 9ff80424c..34999757f 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -13,6 +13,7 @@ import android.widget.Toast;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
+import com.joanzapata.iconify.widget.IconTextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
@@ -48,7 +49,7 @@ public class DownloadLogAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
- holder.icon = (TextView) convertView.findViewById(R.id.txtvIcon);
+ holder.icon = (IconTextView) convertView.findViewById(R.id.txtvIcon);
holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
@@ -78,14 +79,12 @@ public class DownloadLogAdapter extends BaseAdapter {
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_success_green));
holder.icon.setText("{fa-check-circle}");
- Iconify.addIcons(holder.icon);
holder.retry.setVisibility(View.GONE);
holder.reason.setVisibility(View.GONE);
} else {
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_failed_red));
holder.icon.setText("{fa-times-circle}");
- Iconify.addIcons(holder.icon);
String reasonText = status.getReason().getErrorString(context);
if (status.getReasonDetailed() != null) {
reasonText += ": " + status.getReasonDetailed();
@@ -160,7 +159,7 @@ public class DownloadLogAdapter extends BaseAdapter {
}
static class Holder {
- TextView icon;
+ IconTextView icon;
IconButton retry;
TextView title;
TextView type;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
index 47ac4c757..e9756b467 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -167,7 +167,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
for(int i=0; imageUrl == null && i < images.length(); i++) {
JSONObject image = images.getJSONObject(i);
String height = image.getJSONObject("attributes").getString("height");
- if(Integer.valueOf(height) >= 100) {
+ if(Integer.parseInt(height) >= 100) {
imageUrl = image.getString("label");
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
new file mode 100644
index 000000000..d745bb51c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -0,0 +1,323 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.content.ContextCompat;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.afollestad.materialdialogs.DialogAction;
+import com.afollestad.materialdialogs.MaterialDialog;
+import com.afollestad.materialdialogs.internal.MDButton;
+import com.squareup.okhttp.Credentials;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.util.concurrent.TimeUnit;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.core.service.download.ProxyConfig;
+import rx.Observable;
+import rx.Subscriber;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
+public class ProxyDialog {
+
+ private static final String TAG = "ProxyDialog";
+
+ private Context context;
+
+ private MaterialDialog dialog;
+
+ private Spinner spType;
+ private EditText etHost;
+ private EditText etPort;
+ private EditText etUsername;
+ private EditText etPassword;
+
+ private boolean testSuccessful = false;
+ private TextView txtvMessage;
+ private Subscription subscription;
+
+ public ProxyDialog(Context context) {
+ this.context = context;
+ }
+
+ public Dialog createDialog() {
+ dialog = new MaterialDialog.Builder(context)
+ .title(R.string.pref_proxy_title)
+ .customView(R.layout.proxy_settings, true)
+ .positiveText(R.string.proxy_test_label)
+ .negativeText(R.string.cancel_label)
+ .onPositive((dialog1, which) -> {
+ if(!testSuccessful) {
+ dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
+ test();
+ return;
+ }
+ String type = (String) ((Spinner) dialog1.findViewById(R.id.spType)).getSelectedItem();
+ ProxyConfig proxy;
+ if(Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) {
+ proxy = ProxyConfig.direct();
+ } else {
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ if(TextUtils.isEmpty(username)) {
+ username = null;
+ }
+ String password = etPassword.getText().toString();
+ if(TextUtils.isEmpty(password)) {
+ password = null;
+ }
+ int portValue = 0;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ proxy = ProxyConfig.http(host, portValue, username, password);
+ }
+ UserPreferences.setProxyConfig(proxy);
+ AntennapodHttpClient.reinit();
+ dialog.dismiss();
+ })
+ .onNegative((dialog1, which) -> {
+ dialog1.dismiss();
+ })
+ .autoDismiss(false)
+ .build();
+ View view = dialog.getCustomView();
+ spType = (Spinner) view.findViewById(R.id.spType);
+ String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() };
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
+ android.R.layout.simple_spinner_item, types);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spType.setAdapter(adapter);
+ ProxyConfig proxyConfig = UserPreferences.getProxyConfig();
+ spType.setSelection(adapter.getPosition(proxyConfig.type.name()));
+ etHost = (EditText) view.findViewById(R.id.etHost);
+ if(!TextUtils.isEmpty(proxyConfig.host)) {
+ etHost.setText(proxyConfig.host);
+ }
+ etHost.addTextChangedListener(requireTestOnChange);
+ etPort = (EditText) view.findViewById(R.id.etPort);
+ if(proxyConfig.port > 0) {
+ etPort.setText(String.valueOf(proxyConfig.port));
+ }
+ etPort.addTextChangedListener(requireTestOnChange);
+ etUsername = (EditText) view.findViewById(R.id.etUsername);
+ if(!TextUtils.isEmpty(proxyConfig.username)) {
+ etUsername.setText(proxyConfig.username);
+ }
+ etUsername.addTextChangedListener(requireTestOnChange);
+ etPassword = (EditText) view.findViewById(R.id.etPassword);
+ if(!TextUtils.isEmpty(proxyConfig.password)) {
+ etPassword.setText(proxyConfig.username);
+ }
+ etPassword.addTextChangedListener(requireTestOnChange);
+ if(proxyConfig.type == Proxy.Type.DIRECT) {
+ enableSettings(false);
+ setTestRequired(false);
+ }
+ spType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ enableSettings(position > 0);
+ setTestRequired(position > 0);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ enableSettings(false);
+ }
+ });
+ txtvMessage = (TextView) view.findViewById(R.id.txtvMessage);
+ checkValidity();
+ return dialog;
+ }
+
+ private final TextWatcher requireTestOnChange = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ setTestRequired(true);
+ }
+ };
+
+ private void enableSettings(boolean enable) {
+ etHost.setEnabled(enable);
+ etPort.setEnabled(enable);
+ etUsername.setEnabled(enable);
+ etPassword.setEnabled(enable);
+ }
+
+ private boolean checkValidity() {
+ boolean valid = true;
+ if(spType.getSelectedItemPosition() > 0) {
+ valid &= checkHost();
+ }
+ valid &= checkPort();
+ return valid;
+ }
+
+ private boolean checkHost() {
+ String host = etHost.getText().toString();
+ if(host.length() == 0) {
+ etHost.setError(context.getString(R.string.proxy_host_empty_error));
+ return false;
+ }
+ if(!"localhost".equals(host) && !Patterns.DOMAIN_NAME.matcher(host).matches()) {
+ etHost.setError(context.getString(R.string.proxy_host_invalid_error));
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkPort() {
+ int port = getPort();
+ if(port < 0 && port > 65535) {
+ etPort.setError(context.getString(R.string.proxy_port_invalid_error));
+ return false;
+ }
+ return true;
+ }
+
+ private int getPort() {
+ String port = etPort.getText().toString();
+ if(port.length() > 0) {
+ try {
+ int portValue = Integer.parseInt(port);
+ return portValue;
+ } catch(NumberFormatException e) {
+ // ignore
+ }
+ }
+ return 0;
+ }
+
+ private void setTestRequired(boolean required) {
+ if(required) {
+ testSuccessful = false;
+ MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
+ button.setText(context.getText(R.string.proxy_test_label));
+ button.setEnabled(true);
+ } else {
+ testSuccessful = true;
+ MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
+ button.setText(context.getText(android.R.string.ok));
+ button.setEnabled(true);
+ }
+ }
+
+ private void test() {
+ if(subscription != null) {
+ subscription.unsubscribe();
+ }
+ if(!checkValidity()) {
+ setTestRequired(true);
+ return;
+ }
+ TypedArray res = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary });
+ int textColorPrimary = res.getColor(0, 0);
+ res.recycle();
+ String checking = context.getString(R.string.proxy_checking);
+ txtvMessage.setTextColor(textColorPrimary);
+ txtvMessage.setText("{fa-circle-o-notch spin} " + checking);
+ txtvMessage.setVisibility(View.VISIBLE);
+ subscription = Observable.create(new Observable.OnSubscribe<Response>() {
+ @Override
+ public void call(Subscriber<? super Response> subscriber) {
+ String type = (String) spType.getSelectedItem();
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ String password = etPassword.getText().toString();
+ int portValue = 8080;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ SocketAddress address = InetSocketAddress.createUnresolved(host, portValue);
+ Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase());
+ Proxy proxy = new Proxy(proxyType, address);
+ OkHttpClient client = AntennapodHttpClient.newHttpClient();
+ client.setConnectTimeout(10, TimeUnit.SECONDS);
+ client.setProxy(proxy);
+ client.interceptors().clear();
+ if(!TextUtils.isEmpty(username)) {
+ String credentials = Credentials.basic(username, password);
+ client.interceptors().add(chain -> {
+ Request request = chain.request().newBuilder()
+ .header("Proxy-Authorization", credentials).build();
+ return chain.proceed(request);
+ });
+ }
+ Request request = new Request.Builder()
+ .url("http://www.google.com")
+ .head()
+ .build();
+ try {
+ Response response = client.newCall(request).execute();
+ subscriber.onNext(response);
+ } catch(IOException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onCompleted();
+ }
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ response -> {
+ int colorId;
+ String icon;
+ String result;
+ if(response.isSuccessful()) {
+ colorId = R.color.download_success_green;
+ icon = "{fa-check}";
+ result = context.getString(R.string.proxy_test_successful);
+ } else {
+ colorId = R.color.download_failed_red;
+ icon = "{fa-close}";
+ result = context.getString(R.string.proxy_test_failed);
+ }
+ int color = ContextCompat.getColor(context, colorId);
+ txtvMessage.setTextColor(color);
+ String message = String.format("%s %s: %s", icon, result, response.message());
+ txtvMessage.setText(message);
+ setTestRequired(!response.isSuccessful());
+ },
+ error -> {
+ String icon = "{fa-close}";
+ String result = context.getString(R.string.proxy_test_failed);
+ int color = ContextCompat.getColor(context, R.color.download_failed_red);
+ txtvMessage.setTextColor(color);
+ String message = String.format("%s %s: %s", icon, result, error.getMessage());
+ txtvMessage.setText(message);
+ setTestRequired(true);
+ }
+ );
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index 930079e40..89e24f882 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -138,7 +138,7 @@ public abstract class SleepTimerDialog {
private long readTimeMillis() {
TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()];
- long value = Long.valueOf(etxtTime.getText().toString());
+ long value = Long.parseLong(etxtTime.getText().toString());
return selectedUnit.toMillis(value);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
index 96abdd835..aea911f79 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
+import android.util.Log;
import android.view.View;
import android.widget.ListView;
@@ -15,15 +16,16 @@ import de.danoeh.antennapod.core.util.playback.PlaybackController;
public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
+ private static final String TAG = "ChaptersFragment";
+
private Playable media;
private PlaybackController controller;
private ChaptersListAdapter adapter;
- public static ChaptersFragment newInstance(Playable media, PlaybackController controller) {
+ public static ChaptersFragment newInstance(Playable media) {
ChaptersFragment f = new ChaptersFragment();
f.media = media;
- f.controller = controller;
return f;
}
@@ -37,6 +39,10 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
lv.setPadding(0, vertPadding, 0, vertPadding);
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
+ if(controller == null) {
+ Log.d(TAG, "controller is null");
+ return;
+ }
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
controller.seekToChapter(chapter);
});
@@ -58,6 +64,7 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
public void onDestroy() {
super.onDestroy();
adapter = null;
+ controller = null;
}
@Override
@@ -74,4 +81,9 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
setEmptyText(null);
}
}
+
+ public void setController(PlaybackController controller) {
+ this.controller = controller;
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index 80a9bf0b3..3fd69214d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -72,7 +72,11 @@ public class ExternalPlayerFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
controller = setupPlaybackController();
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ if(controller != null) {
+ controller.playPause();
+ }
+ });
}
private PlaybackController setupPlaybackController() {
@@ -88,7 +92,6 @@ public class ExternalPlayerFragment extends Fragment {
return butPlay;
}
-
@Override
public boolean loadMediaInfo() {
ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
@@ -145,8 +148,11 @@ public class ExternalPlayerFragment extends Fragment {
}
controller = setupPlaybackController();
if (butPlay != null) {
- butPlay.setOnClickListener(controller
- .newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ if(controller != null) {
+ controller.playPause();
+ }
+ });
}
controller.init();
}
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 c1c1aab6c..4a93bac7e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -111,7 +111,7 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "Creating view");
- webvDescription = new WebView(getActivity());
+ webvDescription = new WebView(getActivity().getApplicationContext());
if (Build.VERSION.SDK_INT >= 11) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 1382929af..0f5aa06ca 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -102,6 +102,7 @@ public class ItemFragment extends Fragment {
private ViewGroup root;
private WebView webvDescription;
+ private TextView txtvPodcast;
private TextView txtvTitle;
private TextView txtvDuration;
private TextView txtvPublished;
@@ -135,6 +136,7 @@ public class ItemFragment extends Fragment {
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
root = (ViewGroup) layout.findViewById(R.id.content_root);
+ txtvPodcast = (TextView) layout.findViewById(R.id.txtvPodcast);
txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
@@ -219,6 +221,7 @@ public class ItemFragment extends Fragment {
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().registerSticky(this);
if(itemsLoaded) {
+ progbarLoading.setVisibility(View.GONE);
updateAppearance();
}
}
@@ -295,6 +298,7 @@ public class ItemFragment extends Fragment {
return;
}
getActivity().supportInvalidateOptionsMenu();
+ txtvPodcast.setText(item.getFeed().getTitle());
txtvTitle.setText(item.getTitle());
if (item.getPubDate() != null) {
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 c563d278f..152412089 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -52,12 +52,14 @@ import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
+import de.danoeh.antennapod.dialog.ProxyDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
/**
@@ -79,9 +81,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
public static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
public static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
+ public static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
+ public static final String PREF_PROXY = "prefProxy";
private final PreferenceUI ui;
@@ -241,7 +245,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
(preference, o) -> {
if (o instanceof String) {
try {
- int value = Integer.valueOf((String) o);
+ int value = Integer.parseInt((String) o);
if (1 <= value && value <= 50) {
setParallelDownloadsText(value);
return true;
@@ -268,7 +272,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
try {
- int value = Integer.valueOf(s.toString());
+ int value = Integer.parseInt(s.toString());
if (value <= 0) {
ev.setText("1");
} else if (value > 50) {
@@ -309,6 +313,14 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
dialog.show();
return true;
});
+ ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).
+ setOnPreferenceClickListener(preference -> {
+ GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext());
+ Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ return true;
+ });
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
preference -> {
GpodnetPreferences.logout();
@@ -343,7 +355,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
- int newValue = Integer.valueOf((String) o) * 1024 * 1024;
+ int newValue = Integer.parseInt((String) o) * 1024 * 1024;
if (newValue != UserPreferences.getImageCacheSize()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
dialog.setTitle(android.R.string.dialog_alert_title);
@@ -356,6 +368,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
return false;
}
);
+ ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
+ ProxyDialog dialog = new ProxyDialog(ui.getActivity());
+ dialog.createDialog().show();
+ return true;
+ });
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
@@ -423,6 +440,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
final boolean loggedIn = GpodnetPreferences.loggedIn();
ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
+ ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).setEnabled(loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
}
@@ -781,7 +799,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
- int hours = Integer.valueOf(values[which1]);
+ int hours = Integer.parseInt(values[which1]);
UserPreferences.setUpdateInterval(hours);
dialog1.dismiss();
setUpdateIntervalText();
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
index 665ddc3b5..1075117dd 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
@@ -8,6 +8,7 @@ import android.net.NetworkInfo;
import android.text.TextUtils;
import android.util.Log;
+import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.NetworkUtils;
@@ -20,7 +21,8 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
if (TextUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.d(TAG, "Received intent");
- if (NetworkUtils.autodownloadNetworkAvailable()) {
+ ClientConfig.initialize(context);
+ if (NetworkUtils.autodownloadNetworkAvailable()) {
Log.d(TAG, "auto-dl network available, starting auto-download");
DBTasks.autodownloadUndownloadedItems(context);
} else { // if new network is Wi-Fi, finish ongoing downloads,
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
index 46946ddeb..f0d4014ed 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.receiver;
+import java.util.Arrays;
+
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
@@ -44,7 +46,7 @@ public class PlayerWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
- Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + appWidgetIds + "]");
+ Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + Arrays.toString(appWidgetIds) + "]");
startUpdate(context);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
index f050e031d..339a4f0f7 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
@@ -3,10 +3,9 @@ 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.ClientConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -25,6 +24,7 @@ public class PowerConnectionReceiver extends BroadcastReceiver {
Log.d(TAG, "charging intent: " + action);
+ ClientConfig.initialize(context);
if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
Log.d(TAG, "charging, starting auto-download");
// we're plugged in, this is a great time to auto-download if everything else is
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index 8201fe3e2..a373c5353 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -9,8 +9,8 @@ import android.widget.Toast;
import java.util.Arrays;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -27,29 +27,30 @@ public class SPAReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
- if (TextUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE");
- if (intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
- String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA);
- if (feedUrls != null) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
- for (String url : feedUrls) {
- Feed f = new Feed(url, null);
- try {
- DownloadRequester.getInstance().downloadFeed(context, f);
- } catch (DownloadRequestException e) {
- Log.e(TAG, "Error while trying to add feed " + url);
- e.printStackTrace();
- }
- }
- Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
-
- } else {
- Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null");
- }
- } else {
- Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra");
+ if (!TextUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
+ return;
+ }
+ Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE");
+ if (!intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
+ Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra");
+ return;
+ }
+ String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA);
+ if (feedUrls == null) {
+ Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null");
+ return;
+ }
+ Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
+ ClientConfig.initialize(context);
+ for (String url : feedUrls) {
+ Feed f = new Feed(url, null);
+ try {
+ DownloadRequester.getInstance().downloadFeed(context, f);
+ } catch (DownloadRequestException e) {
+ Log.e(TAG, "Error while trying to add feed " + url);
+ e.printStackTrace();
}
}
+ Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
}
}
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index 20d879933..7b4773bca 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -10,14 +10,13 @@
android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
- <TextView
+ <com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvIcon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:textSize="48sp"
- tools:text="[Icon]"
android:gravity="center" />
<com.joanzapata.iconify.widget.IconButton
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index c18e5fd6c..a6ce221db 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -31,24 +31,34 @@
android:layout_alignParentStart="true"
android:layout_width="50dp"
android:layout_height="50dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp"
android:contentDescription="@string/cover_label"
android:gravity="center_vertical"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark" />
<TextView
- android:id="@+id/txtvTitle"
+ android:id="@+id/txtvPodcast"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
android:layout_alignTop="@id/imgvCover"
android:layout_toRightOf="@id/imgvCover"
- android:includeFontPadding="false"
+ tools:text="Podcast title"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvPodcast"
+ android:layout_toRightOf="@id/imgvCover"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="end"
android:maxLines="5"
- tools:text="Podcast title"
+ tools:text="Episode title"
tools:background="@android:color/holo_green_dark" />
<TextView
@@ -58,7 +68,6 @@
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="16dp"
tools:text="00:42:23"
tools:background="@android:color/holo_green_dark"/>
@@ -70,7 +79,7 @@
android:layout_alignParentRight="true"
android:layout_below="@id/txtvTitle"
android:layout_marginLeft="8dp"
- tools:text="Jan\n23"
+ tools:text="Jan 23"
tools:background="@android:color/holo_green_dark" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/proxy_settings.xml b/app/src/main/res/layout/proxy_settings.xml
new file mode 100644
index 000000000..983325030
--- /dev/null
+++ b/app/src/main/res/layout/proxy_settings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/txtvType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/proxy_type_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <Spinner
+ android:id="@+id/spType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/txtvHost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/host_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etHost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:inputType="textUri"
+ android:hint="www.example.com" />
+
+ <TextView
+ android:id="@+id/txtvPort"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/port_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etPort"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="8080"
+ android:inputType="number" />
+
+ <TextView
+ android:id="@+id/txtvUsername"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:singleLine="true"
+ android:text="@string/username_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etUsername"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/optional_hint" />
+
+ <TextView
+ android:id="@+id/txtvPassword"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/password_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etPassword"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/optional_hint"
+ android:inputType="textPassword" />
+
+ <com.joanzapata.iconify.widget.IconTextView
+ android:id="@+id/txtvMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:visibility="invisible"
+ android:gravity="center"/>
+
+</LinearLayout>
diff --git a/app/src/main/res/menu/opml_selection_options.xml b/app/src/main/res/menu/opml_selection_options.xml
new file mode 100644
index 000000000..26d2a0519
--- /dev/null
+++ b/app/src/main/res/menu/opml_selection_options.xml
@@ -0,0 +1,19 @@
+<?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/select_all_item"
+ android:icon="?attr/ic_check_box_outline"
+ android:title="@string/select_all_label"
+ custom:showAsAction="ifRoom">
+ </item>
+
+ <item
+ android:id="@id/deselect_all_item"
+ android:icon="?attr/ic_check_box"
+ android:title="@string/deselect_all_label"
+ custom:showAsAction="ifRoom">
+ </item>
+
+</menu>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 3ecd79b1e..e0671e67b 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -200,8 +200,11 @@
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
-
</PreferenceScreen>
+ <Preference
+ android:key="prefProxy"
+ android:summary="@string/pref_proxy_sum"
+ android:title="@string/pref_proxy_title" />
</PreferenceCategory>
@@ -240,6 +243,10 @@
android:title="@string/pref_gpodnet_setlogin_information_title"
android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
<Preference
+ android:key="pref_gpodnet_sync"
+ android:title="@string/pref_gpodnet_sync_title"
+ android:summary="@string/pref_gpodnet_sync_sum"/>
+ <Preference
android:key="pref_gpodnet_logout"
android:title="@string/pref_gpodnet_logout_title"/>
<Preference