diff options
Diffstat (limited to 'app/src/main/java/de')
69 files changed, 1427 insertions, 1004 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index f6a8db5fb..caa82d725 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod; import android.app.Application; import android.os.Build; import android.os.StrictMode; +import android.support.multidex.MultiDexApplication; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.fonts.FontAwesomeModule; @@ -13,7 +14,7 @@ import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.spa.SPAUtil; /** Main application class. */ -public class PodcastApp extends Application { +public class PodcastApp extends MultiDexApplication { // make sure that ClientConfigurator executes its static code static { diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java index eef2fa4da..1b42b274c 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java @@ -124,12 +124,11 @@ public class AboutActivity extends AppCompatActivity { }) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(webviewData -> { - webview.loadDataWithBaseURL("file:///android_asset/", webviewData, "text/html", - "utf-8", "about:blank"); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + .subscribe( + webviewData -> + webview.loadDataWithBaseURL("file:///android_asset/", webviewData, "text/html", "utf-8", "about:blank"), + error -> Log.e(TAG, Log.getStackTraceString(error)) + ); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java deleted file mode 100644 index b8856c295..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java +++ /dev/null @@ -1,237 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.annotation.CallSuper; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; - -import com.google.android.gms.cast.ApplicationMetadata; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.cast.CastConsumer; -import de.danoeh.antennapod.core.cast.CastManager; -import de.danoeh.antennapod.core.cast.DefaultCastConsumer; -import de.danoeh.antennapod.core.cast.SwitchableMediaRouteActionProvider; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.service.playback.PlaybackService; - -/** - * Activity that allows for showing the MediaRouter button whenever there's a cast device in the - * network. - */ -public abstract class CastEnabledActivity extends AppCompatActivity - implements SharedPreferences.OnSharedPreferenceChangeListener { - public static final String TAG = "CastEnabledActivity"; - - protected CastManager castManager; - protected SwitchableMediaRouteActionProvider mediaRouteActionProvider; - private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - PreferenceManager.getDefaultSharedPreferences(getApplicationContext()). - registerOnSharedPreferenceChangeListener(this); - - castManager = CastManager.getInstance(); - castManager.addCastConsumer(castConsumer); - castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled()); - onCastConnectionChanged(castManager.isConnected()); - } - - @Override - protected void onDestroy() { - PreferenceManager.getDefaultSharedPreferences(getApplicationContext()) - .unregisterOnSharedPreferenceChangeListener(this); - castManager.removeCastConsumer(castConsumer); - super.onDestroy(); - } - - @Override - @CallSuper - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.cast_enabled, menu); - castButtonVisibilityManager.setMenu(menu); - return true; - } - - @Override - @CallSuper - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - mediaRouteActionProvider = castManager - .addMediaRouterButton(menu.findItem(R.id.media_route_menu_item)); - mediaRouteActionProvider.setEnabled(castButtonVisibilityManager.shouldEnable()); - return true; - } - - @Override - protected void onResume() { - super.onResume(); - castButtonVisibilityManager.setResumed(true); - } - - @Override - protected void onPause() { - super.onPause(); - castButtonVisibilityManager.setResumed(false); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { - boolean newValue = UserPreferences.isCastEnabled(); - Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + newValue); - castButtonVisibilityManager.setPrefEnabled(newValue); - // PlaybackService has its own listener, so if it's active we don't have to take action here. - if (!newValue && !PlaybackService.isRunning) { - CastManager.getInstance().disconnect(); - } - } - } - - CastConsumer castConsumer = new DefaultCastConsumer() { - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { - onCastConnectionChanged(true); - } - - @Override - public void onDisconnected() { - onCastConnectionChanged(false); - } - }; - - private void onCastConnectionChanged(boolean connected) { - if (connected) { - castButtonVisibilityManager.onConnected(); - setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE); - } else { - castButtonVisibilityManager.onDisconnected(); - setVolumeControlStream(AudioManager.STREAM_MUSIC); - } - } - - /** - * Should be called by any activity or fragment for which the cast button should be shown. - * - * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)} - */ - public final void requestCastButton(int showAsAction) { - castButtonVisibilityManager.requestCastButton(showAsAction); - } - - private class CastButtonVisibilityManager { - private volatile boolean prefEnabled = false; - private volatile boolean viewRequested = false; - private volatile boolean resumed = false; - private volatile boolean connected = false; - private volatile int showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM; - private Menu menu; - - public synchronized void setPrefEnabled(boolean newValue) { - if (prefEnabled != newValue && resumed && (viewRequested || connected)) { - if (newValue) { - castManager.incrementUiCounter(); - } else { - castManager.decrementUiCounter(); - } - } - prefEnabled = newValue; - if (mediaRouteActionProvider != null) { - mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); - } - } - - public synchronized void setResumed(boolean newValue) { - if (resumed == newValue) { - Log.e(TAG, "resumed should never change to the same value"); - return; - } - resumed = newValue; - if (prefEnabled && (viewRequested || connected)) { - if (resumed) { - castManager.incrementUiCounter(); - } else { - castManager.decrementUiCounter(); - } - } - } - - public synchronized void setViewRequested(boolean newValue) { - if (viewRequested != newValue && resumed && prefEnabled && !connected) { - if (newValue) { - castManager.incrementUiCounter(); - } else { - castManager.decrementUiCounter(); - } - } - viewRequested = newValue; - if (mediaRouteActionProvider != null) { - mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); - } - } - - public synchronized void setConnected(boolean newValue) { - if (connected != newValue && resumed && prefEnabled && !prefEnabled) { - if (newValue) { - castManager.incrementUiCounter(); - } else { - castManager.decrementUiCounter(); - } - } - connected = newValue; - if (mediaRouteActionProvider != null) { - mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); - } - } - - public synchronized boolean shouldEnable() { - return prefEnabled && viewRequested; - } - - public void setMenu(Menu menu) { - setViewRequested(false); - showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM; - this.menu = menu; - setShowAsAction(); - } - - public void requestCastButton(int showAsAction) { - setViewRequested(true); - this.showAsAction = showAsAction; - setShowAsAction(); - } - - public void onConnected() { - setConnected(true); - setShowAsAction(); - } - - public void onDisconnected() { - setConnected(false); - setShowAsAction(); - } - - private void setShowAsAction() { - if (menu == null) { - Log.d(TAG, "setShowAsAction() without a menu"); - return; - } - MenuItem item = menu.findItem(R.id.media_route_menu_item); - if (item == null) { - Log.e(TAG, "setShowAsAction(), but cast button not inflated"); - return; - } - MenuItemCompat.setShowAsAction(item, connected? MenuItem.SHOW_AS_ACTION_ALWAYS : showAsAction); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java index 1ca4d095f..a7e9b1e70 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/CastplayerActivity.java @@ -50,10 +50,10 @@ public class CastplayerActivity extends MediaplayerInfoActivity { if (butPlaybackSpeed != null) { butPlaybackSpeed.setVisibility(View.GONE); } - if (butCastDisconnect != null) { - butCastDisconnect.setOnClickListener(v -> castManager.disconnect()); - butCastDisconnect.setVisibility(View.VISIBLE); - } +// if (butCastDisconnect != null) { +// butCastDisconnect.setOnClickListener(v -> castManager.disconnect()); +// butCastDisconnect.setVisibility(View.VISIBLE); +// } } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java index 5fd69ef6a..390d4cef8 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java @@ -89,9 +89,7 @@ public class DirectoryChooserActivity extends AppCompatActivity { adb.setTitle(R.string.folder_not_empty_dialog_title); adb.setMessage(R.string.folder_not_empty_dialog_msg); adb.setNegativeButton(R.string.cancel_label, - (dialog, which) -> { - dialog.dismiss(); - }); + (dialog, which) -> dialog.dismiss()); adb.setPositiveButton(R.string.confirm_label, (dialog, which) -> { dialog.dismiss(); @@ -291,9 +289,7 @@ public class DirectoryChooserActivity extends AppCompatActivity { builder.setMessage(String.format(getString(R.string.create_folder_msg), CREATE_DIRECTORY_NAME)); builder.setNegativeButton(R.string.cancel_label, - (dialog, which) -> { - dialog.dismiss(); - }); + (dialog, which) -> dialog.dismiss()); builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { dialog.dismiss(); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java index d4356719e..2a58d5104 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java @@ -5,10 +5,10 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.Menu; @@ -28,6 +28,10 @@ import android.widget.Toast; import com.bumptech.glide.Glide; import com.joanzapata.iconify.Iconify; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; @@ -41,23 +45,29 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.util.IntentUtils; import de.danoeh.antennapod.core.util.LangUtils; +import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; import de.danoeh.antennapod.menuhandler.FeedMenuHandler; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Displays information about a feed. */ -public class FeedInfoActivity extends ActionBarActivity { - private static final String TAG = "FeedInfoActivity"; - private boolean autoDeleteChanged = false; +public class FeedInfoActivity extends AppCompatActivity { public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; - + private static final String TAG = "FeedInfoActivity"; + private boolean autoDeleteChanged = false; private Feed feed; private ImageView imgvCover; private TextView txtvTitle; private TextView txtvDescription; + private TextView lblLanguage; private TextView txtvLanguage; + private TextView lblAuthor; private TextView txtvAuthor; private TextView txtvUrl; private EditText etxtUsername; @@ -70,6 +80,9 @@ public class FeedInfoActivity extends ActionBarActivity { private Spinner spnAutoDelete; private boolean filterInclude = true; + private Subscription subscription; + + private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() { @Override public void onClick(View v) { @@ -91,6 +104,40 @@ public class FeedInfoActivity extends ActionBarActivity { } }; + private boolean authInfoChanged = false; + + private TextWatcher authTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + authInfoChanged = true; + } + }; + + private boolean filterTextChanged = false; + + private TextWatcher filterTextWatcher = 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) { + filterTextChanged = true; + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); @@ -102,7 +149,9 @@ public class FeedInfoActivity extends ActionBarActivity { imgvCover = (ImageView) findViewById(R.id.imgvCover); txtvTitle = (TextView) findViewById(R.id.txtvTitle); txtvDescription = (TextView) findViewById(R.id.txtvDescription); + lblLanguage = (TextView) findViewById(R.id.lblLanguage); txtvLanguage = (TextView) findViewById(R.id.txtvLanguage); + lblAuthor = (TextView) findViewById(R.id.lblAuthor); txtvAuthor = (TextView) findViewById(R.id.txtvAuthor); txtvUrl = (TextView) findViewById(R.id.txtvUrl); cbxAutoDownload = (CheckBox) findViewById(R.id.cbxAutoDownload); @@ -124,48 +173,62 @@ public class FeedInfoActivity extends ActionBarActivity { txtvUrl.setOnClickListener(copyUrlToClipboard); - AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>() { - - @Override - protected Feed doInBackground(Long... params) { - return DBReader.getFeed(params[0]); - } - - @Override - protected void onPostExecute(Feed result) { - if (result != null) { + subscription = Observable.fromCallable(()-> DBReader.getFeed(feedId)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result == null) { + Log.e(TAG, "Activity was started with invalid arguments"); + finish(); + } feed = result; Log.d(TAG, "Language is " + feed.getLanguage()); Log.d(TAG, "Author is " + feed.getAuthor()); Log.d(TAG, "URL is " + feed.getDownload_url()); FeedPreferences prefs = feed.getPreferences(); - imgvCover.post(() -> Glide.with(FeedInfoActivity.this) - .load(feed.getImageUri()) + Glide.with(FeedInfoActivity.this) + .load(feed.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .fitCenter() .dontAnimate() - .into(imgvCover)); + .into(imgvCover); txtvTitle.setText(feed.getTitle()); + String description = feed.getDescription(); - txtvDescription.setText((description != null) ? description.trim() : ""); - if (feed.getAuthor() != null) { + if(description != null) { + if(Feed.TYPE_ATOM1.equals(feed.getType())) { + HtmlToPlainText formatter = new HtmlToPlainText(); + Document feedDescription = Jsoup.parse(feed.getDescription()); + description = StringUtils.trim(formatter.getPlainText(feedDescription)); + } + } else { + description = ""; + } + txtvDescription.setText(description); + + if (!TextUtils.isEmpty(feed.getAuthor())) { txtvAuthor.setText(feed.getAuthor()); + } else { + lblAuthor.setVisibility(View.GONE); + txtvAuthor.setVisibility(View.GONE); } - if (feed.getLanguage() != null) { - txtvLanguage.setText(LangUtils - .getLanguageString(feed.getLanguage())); + if (!TextUtils.isEmpty(feed.getLanguage())) { + txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage())); + } else { + lblLanguage.setVisibility(View.GONE); + txtvLanguage.setVisibility(View.GONE); } txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); - Iconify.addIcons(txtvUrl); + Iconify.addIcons(txtvUrl); cbxAutoDownload.setEnabled(UserPreferences.isEnableAutodownload()); cbxAutoDownload.setChecked(prefs.getAutoDownload()); cbxAutoDownload.setOnCheckedChangeListener((compoundButton, checked) -> { feed.getPreferences().setAutoDownload(checked); - feed.savePreferences(FeedInfoActivity.this); + feed.savePreferences(); updateAutoDownloadSettings(); ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(FeedInfoActivity.this, feed, checked); @@ -174,7 +237,7 @@ public class FeedInfoActivity extends ActionBarActivity { cbxKeepUpdated.setChecked(prefs.getKeepUpdated()); cbxKeepUpdated.setOnCheckedChangeListener((compoundButton, checked) -> { feed.getPreferences().setKeepUpdated(checked); - feed.savePreferences(FeedInfoActivity.this); + feed.savePreferences(); }); spnAutoDelete.setOnItemSelectedListener(new OnItemSelectedListener() { @Override @@ -184,15 +247,12 @@ public class FeedInfoActivity extends ActionBarActivity { case 0: auto_delete_action = FeedPreferences.AutoDeleteAction.GLOBAL; break; - case 1: auto_delete_action = FeedPreferences.AutoDeleteAction.YES; break; - case 2: auto_delete_action = FeedPreferences.AutoDeleteAction.NO; break; - default: // TODO - add exceptions here return; } @@ -234,57 +294,12 @@ public class FeedInfoActivity extends ActionBarActivity { supportInvalidateOptionsMenu(); updateAutoDownloadSettings(); - } else { - Log.e(TAG, "Activity was started with invalid arguments"); - } - } - }; - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - loadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, feedId); - } else { - loadTask.execute(feedId); - } + }, error -> { + Log.d(TAG, Log.getStackTraceString(error)); + finish(); + }); } - - private boolean authInfoChanged = false; - - private TextWatcher authTextWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - authInfoChanged = true; - } - }; - - private boolean filterTextChanged = false; - - private TextWatcher filterTextWatcher = 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) { - filterTextChanged = true; - } - }; - @Override protected void onPause() { super.onPause(); @@ -317,6 +332,14 @@ public class FeedInfoActivity extends ActionBarActivity { } @Override + public void onDestroy() { + super.onDestroy(); + if(subscription != null) { + subscription.unsubscribe(); + } + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); @@ -367,7 +390,7 @@ public class FeedInfoActivity extends ActionBarActivity { private final Feed feed; private final boolean autoDownload; - public ApplyToEpisodesDialog(Context context, Feed feed, boolean autoDownload) { + ApplyToEpisodesDialog(Context context, Feed feed, boolean autoDownload) { super(context, R.string.auto_download_apply_to_items_title, R.string.auto_download_apply_to_items_message); this.feed = feed; 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 b7c7d86c7..f0fcdca90 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -10,6 +10,7 @@ import android.database.DataSetObserver; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; @@ -38,6 +39,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; +import de.danoeh.antennapod.core.event.MessageEvent; import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; @@ -46,10 +48,13 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; 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.util.FeedItemUtil; +import de.danoeh.antennapod.core.util.Flavors; import de.danoeh.antennapod.core.util.StorageUtils; import de.danoeh.antennapod.dialog.RatingDialog; +import de.danoeh.antennapod.dialog.RenameFeedDialog; import de.danoeh.antennapod.fragment.AddFeedFragment; import de.danoeh.antennapod.fragment.DownloadsFragment; import de.danoeh.antennapod.fragment.EpisodesFragment; @@ -148,9 +153,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi final FragmentManager fm = getSupportFragmentManager(); - fm.addOnBackStackChangedListener(() -> { - drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0); - }); + fm.addOnBackStackChangedListener(() -> drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); @@ -209,7 +212,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi } else { edit.remove(PREF_LAST_FRAGMENT_TAG); } - edit.commit(); + edit.apply(); } private String getLastNavFragment() { @@ -254,9 +257,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> UserPreferences.setHiddenDrawerItems(hiddenDrawerItems)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } @@ -466,6 +467,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi protected void onResume() { super.onResume(); StorageUtils.checkStorageAvailability(this); + DBTasks.checkShouldRefreshFeeds(getApplicationContext()); Intent intent = getIntent(); if (intent.hasExtra(EXTRA_FEED_ID) || @@ -507,21 +509,24 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi @Override public boolean onCreateOptionsMenu(Menu menu) { boolean retVal = super.onCreateOptionsMenu(menu); - switch (getLastNavFragment()) { - case QueueFragment.TAG: - case EpisodesFragment.TAG: - requestCastButton(MenuItem.SHOW_AS_ACTION_IF_ROOM); - return retVal; - case DownloadsFragment.TAG: - case PlaybackHistoryFragment.TAG: - case AddFeedFragment.TAG: - case SubscriptionFragment.TAG: - return retVal; - default: - requestCastButton(MenuItem.SHOW_AS_ACTION_NEVER); - return retVal; + if (Flavors.FLAVOR == Flavors.PLAY) { + switch (getLastNavFragment()) { + case QueueFragment.TAG: + case EpisodesFragment.TAG: + requestCastButton(MenuItem.SHOW_AS_ACTION_IF_ROOM); + return retVal; + case DownloadsFragment.TAG: + case PlaybackHistoryFragment.TAG: + case AddFeedFragment.TAG: + case SubscriptionFragment.TAG: + return retVal; + default: + requestCastButton(MenuItem.SHOW_AS_ACTION_NEVER); + return retVal; + } + } else { + return retVal; } - } @Override @@ -573,6 +578,9 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi case R.id.mark_all_read_item: DBWriter.markFeedRead(feed.getId()); return true; + case R.id.rename_item: + new RenameFeedDialog(this, feed).show(); + return true; case R.id.remove_item: final FeedRemover remover = new FeedRemover(this, feed) { @Override @@ -585,7 +593,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi }; ConfirmationDialog conDialog = new ConfirmationDialog(this, R.string.remove_feed_label, - R.string.feed_delete_confirmation_msg) { + getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) { @Override public void onConfirmButtonPressed( DialogInterface dialog) { @@ -699,9 +707,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi if (handleIntent) { handleNavIntent(); } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } public void onEvent(QueueEvent event) { @@ -733,6 +739,18 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi } } + public void onEventMainThread(MessageEvent event) { + Log.d(TAG, "onEvent(" + event + ")"); + View parentLayout = findViewById(R.id.drawer_layout); + Snackbar snackbar = Snackbar.make(parentLayout, event.message, Snackbar.LENGTH_SHORT); + if(event.action != null) { + snackbar.setAction(getString(R.string.undo), v -> { + event.action.run(); + }); + } + snackbar.show(); + } + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { @Override 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 71d288725..21a0fa66f 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.activity; import android.annotation.TargetApi; +import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; @@ -9,6 +10,7 @@ import android.graphics.PixelFormat; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.Menu; @@ -39,8 +41,10 @@ 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.util.Converter; +import de.danoeh.antennapod.core.util.Flavors; import de.danoeh.antennapod.core.util.ShareUtils; import de.danoeh.antennapod.core.util.StorageUtils; +import de.danoeh.antennapod.core.util.Supplier; import de.danoeh.antennapod.core.util.playback.MediaPlayerError; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; @@ -48,6 +52,8 @@ import de.danoeh.antennapod.dialog.SleepTimerDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.functions.Func1; import rx.schedulers.Schedulers; @@ -177,6 +183,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements }; } + protected static TextView getTxtvFFFromActivity(MediaplayerActivity activity) { + return activity.txtvFF; + } + protected static TextView getTxtvRevFromActivity(MediaplayerActivity activity) { + return activity.txtvRev; + } + protected void onSetSpeedAbilityChanged() { Log.d(TAG, "onSetSpeedAbilityChanged()"); updatePlaybackSpeedButton(); @@ -281,7 +294,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS); + if (Flavors.FLAVOR == Flavors.PLAY) { + requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS); + } MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mediaplayer, menu); return true; @@ -294,10 +309,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements return false; } Playable media = controller.getMedia(); + boolean isFeedMedia = media != null && (media instanceof FeedMedia); - menu.findItem(R.id.support_item).setVisible( - media != null && media.getPaymentLink() != null && - (media instanceof FeedMedia) && + menu.findItem(R.id.support_item).setVisible(isFeedMedia && media.getPaymentLink() != null && ((FeedMedia) media).getItem() != null && ((FeedMedia) media).getItem().getFlattrStatus().flattrable() ); @@ -305,20 +319,21 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements boolean hasWebsiteLink = media != null && media.getWebsiteLink() != null; menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink); - boolean isItemAndHasLink = media != null && (media instanceof FeedMedia) && + boolean isItemAndHasLink = isFeedMedia && ((FeedMedia) media).getItem() != null && ((FeedMedia) media).getItem().getLink() != null; menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink); menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink); - boolean isItemHasDownloadLink = media != null && (media instanceof FeedMedia) && ((FeedMedia) media).getDownload_url() != null; + boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null; menu.findItem(R.id.share_download_url_item).setVisible(isItemHasDownloadLink); menu.findItem(R.id.share_download_url_with_position_item).setVisible(isItemHasDownloadLink); + menu.findItem(R.id.share_file).setVisible(isFeedMedia && ((FeedMedia) media).fileExists()); menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink); menu.findItem(R.id.add_to_favorites_item).setVisible(false); menu.findItem(R.id.remove_from_favorites_item).setVisible(false); - if(media != null && media instanceof FeedMedia) { + if (isFeedMedia) { menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite); menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite); } @@ -559,6 +574,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true); } break; + case R.id.share_file: + if (media instanceof FeedMedia) { + ShareUtils.shareFeedItemFile(this, ((FeedMedia) media)); + } + break; default: return false; } @@ -627,17 +647,16 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements */ protected boolean loadMediaInfo() { Log.d(TAG, "loadMediaInfo()"); + if(controller == null || controller.getMedia() == null) { + return false; + } Playable media = controller.getMedia(); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); - if (media != null) { - onPositionObserverUpdate(); - checkFavorite(); - updatePlaybackSpeedButton(); - return true; - } else { - return false; - } + onPositionObserverUpdate(); + checkFavorite(); + updatePlaybackSpeedButton(); + return true; } protected void updatePlaybackSpeedButton() { @@ -648,6 +667,91 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements // Only meaningful on AudioplayerActivity, where it is overridden. } + /** + * Abstract directions to skip forward or back (rewind) and encapsulates behavior to get or set preference (including update of UI on the skip buttons). + */ + static public enum SkipDirection { + SKIP_FORWARD( + UserPreferences::getFastForwardSecs, + MediaplayerActivity::getTxtvFFFromActivity, + UserPreferences::setFastForwardSecs, + R.string.pref_fast_forward), + SKIP_REWIND(UserPreferences::getRewindSecs, + MediaplayerActivity::getTxtvRevFromActivity, + UserPreferences::setRewindSecs, + R.string.pref_rewind); + + private final Supplier<Integer> getPrefSecsFn; + private final Func1<MediaplayerActivity, TextView> getTextViewFn; + private final Action1<Integer> setPrefSecsFn; + private final int titleResourceID; + + /** + * Constructor for skip direction enum. Stores references to utility functions and resource + * id's that vary dependending on the direction. + * + * @param getPrefSecsFn Handle to function that retrieves current seconds of the skip delta + * @param getTextViewFn Handle to function that gets the TextView which displays the current skip delta value + * @param setPrefSecsFn Handle to function that sets the preference (setting) for the skip delta value (and optionally updates the button label with the current values) + * @param titleResourceID ID of the resource string with the title for a view + */ + SkipDirection(Supplier<Integer> getPrefSecsFn, Func1<MediaplayerActivity, TextView> getTextViewFn, Action1<Integer> setPrefSecsFn, int titleResourceID) { + this.getPrefSecsFn = getPrefSecsFn; + this.getTextViewFn = getTextViewFn; + this.setPrefSecsFn = setPrefSecsFn; + this.titleResourceID = titleResourceID; + } + + + public int getPrefSkipSeconds() { + return(getPrefSecsFn.get()); + } + + /** + * Updates preferences for a forward or backward skip depending on the direction of the instance, optionally updating the UI. + * + * @param seconds Number of seconds to set the preference associated with the direction of the instance. + * @param activity MediaplyerActivity that contains textview to update the display of the skip delta setting (or null if nothing to update) + */ + public void setPrefSkipSeconds(int seconds, @Nullable Activity activity) { + setPrefSecsFn.call(seconds); + + if (activity != null && activity instanceof MediaplayerActivity) { + TextView tv = getTextViewFn.call((MediaplayerActivity)activity); + if (tv != null) tv.setText(String.valueOf(seconds)); + } + } + public int getTitleResourceID() { + return titleResourceID; + } + } + + static public void showSkipPreference(Activity activity, SkipDirection direction) { + int checked = 0; + int skipSecs = direction.getPrefSkipSeconds(); + final int[] values = activity.getResources().getIntArray(R.array.seek_delta_values); + final String[] choices = new String[values.length]; + for (int i = 0; i < values.length; i++) { + if (skipSecs == values[i]) { + checked = i; + } + choices[i] = String.valueOf(values[i]) + " " + activity.getString(R.string.time_seconds); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(direction.getTitleResourceID()); + builder.setSingleChoiceItems(choices, checked, null); + builder.setNegativeButton(R.string.cancel_label, null); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { + int choice = ((AlertDialog)dialog).getListView().getCheckedItemPosition(); + if (choice < 0 || choice >= values.length) { + System.err.printf("Choice in showSkipPreference is out of bounds %d", choice); + } else { + direction.setPrefSkipSeconds(values[choice], activity); + } + }); + builder.create().show(); + } protected void setupGUI() { setContentView(getContentViewResourceId()); @@ -690,7 +794,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements butFF = (ImageButton) findViewById(R.id.butFF); txtvFF = (TextView) findViewById(R.id.txtvFF); if (txtvFF != null) { - txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs())); + txtvFF.setText(String.valueOf(UserPreferences.getFastForwardSecs())); } butSkip = (ImageButton) findViewById(R.id.butSkip); @@ -702,39 +806,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if (butRev != null) { butRev.setOnClickListener(v -> onRewind()); - butRev.setOnLongClickListener(new View.OnLongClickListener() { - - int choice; - - @Override - public boolean onLongClick(View v) { - int checked = 0; - int rewindSecs = UserPreferences.getRewindSecs(); - final int[] values = getResources().getIntArray(R.array.seek_delta_values); - final String[] choices = new String[values.length]; - for (int i = 0; i < values.length; i++) { - if (rewindSecs == values[i]) { - checked = i; - } - choices[i] = String.valueOf(values[i]) + " " + getString(R.string.time_seconds); - } - choice = values[checked]; - AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this); - builder.setTitle(R.string.pref_rewind); - builder.setSingleChoiceItems(choices, checked, - (dialog, which) -> { - choice = values[which]; - }); - builder.setNegativeButton(R.string.cancel_label, null); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setPrefRewindSecs(choice); - if(txtvRev != null){ - txtvRev.setText(String.valueOf(choice)); - } - }); - builder.create().show(); - return true; - } + butRev.setOnLongClickListener(v -> { + showSkipPreference(MediaplayerActivity.this, SkipDirection.SKIP_REWIND); + return true; }); } @@ -742,39 +816,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if (butFF != null) { butFF.setOnClickListener(v -> onFastForward()); - butFF.setOnLongClickListener(new View.OnLongClickListener() { - - int choice; - - @Override - public boolean onLongClick(View v) { - int checked = 0; - int rewindSecs = UserPreferences.getFastFowardSecs(); - final int[] values = getResources().getIntArray(R.array.seek_delta_values); - final String[] choices = new String[values.length]; - for (int i = 0; i < values.length; i++) { - if (rewindSecs == values[i]) { - checked = i; - } - choices[i] = String.valueOf(values[i]) + " " + getString(R.string.time_seconds); - } - choice = values[checked]; - AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this); - builder.setTitle(R.string.pref_fast_forward); - builder.setSingleChoiceItems(choices, checked, - (dialog, which) -> { - choice = values[which]; - }); - builder.setNegativeButton(R.string.cancel_label, null); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setPrefFastForwardSecs(choice); - if(txtvFF != null) { - txtvFF.setText(String.valueOf(choice)); - } - }); - builder.create().show(); - return true; - } + butFF.setOnLongClickListener(v -> { + showSkipPreference(MediaplayerActivity.this, SkipDirection.SKIP_FORWARD); + return false; }); } @@ -803,7 +847,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements return; } int curr = controller.getPosition(); - controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000); + controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000); } protected abstract int getContentViewResourceId(); @@ -865,10 +909,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements isFavorite = isFav; invalidateOptionsMenu(); } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - } - ); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java index 647745e39..b3cda69d3 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java @@ -8,6 +8,7 @@ import android.content.res.Configuration; import android.os.Build; import android.support.annotation.Nullable; import android.support.design.widget.AppBarLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; @@ -36,6 +37,7 @@ import de.danoeh.antennapod.adapter.ChaptersListAdapter; import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; +import de.danoeh.antennapod.core.event.MessageEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -43,9 +45,11 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.service.playback.PlayerStatus; 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.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.dialog.RenameFeedDialog; import de.danoeh.antennapod.fragment.AddFeedFragment; import de.danoeh.antennapod.fragment.ChaptersFragment; import de.danoeh.antennapod.fragment.CoverFragment; @@ -57,6 +61,7 @@ import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.fragment.SubscriptionFragment; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; import de.danoeh.antennapod.preferences.PreferenceController; +import de.greenrobot.event.EventBus; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; @@ -102,6 +107,12 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem private Subscription subscription; @Override + protected void onPause() { + super.onPause(); + EventBus.getDefault().unregister(this); + } + + @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop()"); @@ -168,8 +179,10 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem pagerAdapter.onMediaChanged(media); pagerAdapter.setController(controller); } + DBTasks.checkShouldRefreshFeeds(getApplicationContext()); EventDistributor.getInstance().register(contentUpdate); + EventBus.getDefault().register(this); loadData(); } @@ -277,7 +290,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem if (!super.loadMediaInfo()) { return false; } - if(controller.getMedia() != media) { + if(controller != null && controller.getMedia() != media) { media = controller.getMedia(); pagerAdapter.onMediaChanged(media); } @@ -370,6 +383,9 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem case R.id.mark_all_read_item: DBWriter.markFeedRead(feed.getId()); return true; + case R.id.rename_item: + new RenameFeedDialog(this, feed).show(); + return true; case R.id.remove_item: final FeedRemover remover = new FeedRemover(this, feed) { @Override @@ -379,7 +395,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem }; ConfirmationDialog conDialog = new ConfirmationDialog(this, R.string.remove_feed_label, - R.string.feed_delete_confirmation_msg) { + getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) { @Override public void onConfirmButtonPressed( DialogInterface dialog) { @@ -443,9 +459,7 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> UserPreferences.setHiddenDrawerItems(hiddenDrawerItems)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } @@ -461,12 +475,20 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem if (navAdapter != null) { navAdapter.notifyDataSetChanged(); } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } - + public void onEventMainThread(MessageEvent event) { + Log.d(TAG, "onEvent(" + event + ")"); + View parentLayout = findViewById(R.id.drawer_layout); + Snackbar snackbar = Snackbar.make(parentLayout, event.message, Snackbar.LENGTH_SHORT); + if (event.action != null) { + snackbar.setAction(getString(R.string.undo), v -> { + event.action.run(); + }); + } + snackbar.show(); + } private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { 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 a53f9bdb8..f6bf11e66 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -29,7 +29,6 @@ import com.bumptech.glide.Glide; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; -import org.jsoup.examples.HtmlToPlainText; import org.jsoup.nodes.Document; import java.io.File; @@ -63,6 +62,7 @@ import de.danoeh.antennapod.core.util.FileNameGenerator; import de.danoeh.antennapod.core.util.StorageUtils; import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer; +import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.greenrobot.event.EventBus; import rx.Observable; @@ -81,17 +81,12 @@ import rx.schedulers.Schedulers; */ public class OnlineFeedViewActivity extends AppCompatActivity { - private static final String TAG = "OnlineFeedViewActivity"; - public static final String ARG_FEEDURL = "arg.feedurl"; - // Optional argument: specify a title for the actionbar. public static final String ARG_TITLE = "title"; - - private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE; - public static final int RESULT_ERROR = 2; - + private static final String TAG = "OnlineFeedViewActivity"; + private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE; private volatile List<Feed> feeds; private Feed feed; private String selectedDownloadUrl; @@ -106,22 +101,19 @@ public class OnlineFeedViewActivity extends AppCompatActivity { private Subscription download; private Subscription parser; private Subscription updater; - - public void onEventMainThread(DownloadEvent event) { - Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - setSubscribeButtonState(feed); - } - private EventDistributor.EventListener listener = new EventDistributor.EventListener() { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) { - updater = Observable.fromCallable(() -> DBReader.getFeedList()) + updater = Observable.fromCallable(DBReader::getFeedList) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(feeds -> { + .subscribe( + feeds -> { OnlineFeedViewActivity.this.feeds = feeds; setSubscribeButtonState(feed); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); } ); } else if ((arg & EVENTS) != 0) { @@ -130,6 +122,11 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } }; + public void onEventMainThread(DownloadEvent event) { + Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); + setSubscribeButtonState(feed); + } + @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); @@ -149,7 +146,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { || TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) { feedUrl = (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)) ? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString(); - getSupportActionBar().setTitle(R.string.add_new_feed_label); + getSupportActionBar().setTitle(R.string.add_feed_label); } else { throw new IllegalArgumentException("Activity must be started with feedurl argument!"); } @@ -281,30 +278,33 @@ public class OnlineFeedViewActivity extends AppCompatActivity { }) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(status -> { - if (status != null) { - if (!status.isCancelled()) { - if (status.isSuccessful()) { - parseFeed(); - } else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { - if (!isFinishing() && !isPaused) { - dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this, - R.string.authentication_notification_title, downloader.getDownloadRequest().getSource()); - dialog.show(); - } - } else { - String errorMsg = status.getReason().getErrorString(OnlineFeedViewActivity.this); - if (errorMsg != null && status.getReasonDetailed() != null) { - errorMsg += " (" + status.getReasonDetailed() + ")"; - } - showErrorDialog(errorMsg); - } - } - } else { - Log.wtf(TAG, "DownloadStatus returned by Downloader was null"); - finish(); - } - }); + .subscribe(this::checkDownloadResult, + error -> Log.e(TAG, Log.getStackTraceString(error))); + } + + private void checkDownloadResult(DownloadStatus status) { + if (status == null) { + Log.wtf(TAG, "DownloadStatus returned by Downloader was null"); + finish(); + } + if (status.isCancelled()) { + return; + } + if (status.isSuccessful()) { + parseFeed(); + } else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { + if (!isFinishing() && !isPaused) { + dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this, + R.string.authentication_notification_title, downloader.getDownloadRequest().getSource()); + dialog.show(); + } + } else { + String errorMsg = status.getReason().getErrorString(OnlineFeedViewActivity.this); + if (errorMsg != null && status.getReasonDetailed() != null) { + errorMsg += " (" + status.getReasonDetailed() + ")"; + } + showErrorDialog(errorMsg); + } } private void parseFeed() { @@ -354,14 +354,19 @@ public class OnlineFeedViewActivity extends AppCompatActivity { * This method is executed on a background thread */ private void beforeShowFeedInformation(Feed feed) { - // remove HTML tags from descriptions + final HtmlToPlainText formatter = new HtmlToPlainText(); + if(Feed.TYPE_ATOM1.equals(feed.getType()) && feed.getDescription() != null) { + // remove HTML tags from descriptions + Log.d(TAG, "Removing HTML from feed description"); + Document feedDescription = Jsoup.parse(feed.getDescription()); + feed.setDescription(StringUtils.trim(formatter.getPlainText(feedDescription))); + } Log.d(TAG, "Removing HTML from shownotes"); if (feed.getItems() != null) { - HtmlToPlainText formatter = new HtmlToPlainText(); for (FeedItem item : feed.getItems()) { if (item.getDescription() != null) { - Document description = Jsoup.parse(item.getDescription()); - item.setDescription(StringUtils.trim(formatter.getPlainText(description))); + Document itemDescription = Jsoup.parse(item.getDescription()); + item.setDescription(StringUtils.trim(formatter.getPlainText(itemDescription))); } } } @@ -514,9 +519,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { builder.setMessage(R.string.error_msg_prefix); } builder.setNeutralButton(android.R.string.ok, - (dialog, which) -> { - dialog.cancel(); - } + (dialog, which) -> dialog.cancel() ); builder.setOnCancelListener(dialog -> { setResult(RESULT_ERROR); @@ -585,7 +588,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { private String feedUrl; - public FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) { + FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) { super(context, titleRes, true, false, null, null); this.feedUrl = feedUrl; } 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 fce50bd1c..cd375a65a 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java @@ -15,7 +15,7 @@ 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.export.opml.OpmlElement; import de.danoeh.antennapod.core.preferences.UserPreferences; /** @@ -23,10 +23,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; * which feeds he wants to import. */ public class OpmlFeedChooserActivity extends AppCompatActivity { - private static final String TAG = "OpmlFeedChooserActivity"; - public static final String EXTRA_SELECTED_ITEMS = "de.danoeh.antennapod.selectedItems"; - + private static final String TAG = "OpmlFeedChooserActivity"; private Button butConfirm; private Button butCancel; private ListView feedlist; 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 8726af281..07b0b3cdb 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.activity; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; @@ -20,7 +21,7 @@ import java.util.ArrayList; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; import de.danoeh.antennapod.asynctask.OpmlImportWorker; -import de.danoeh.antennapod.core.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlElement; import de.danoeh.antennapod.core.util.LangUtils; /** @@ -29,9 +30,8 @@ import de.danoeh.antennapod.core.util.LangUtils; public class OpmlImportBaseActivity extends AppCompatActivity { private static final String TAG = "OpmlImportBaseActivity"; - private OpmlImportWorker importWorker; - private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5; + private OpmlImportWorker importWorker; @Nullable private Uri uri; /** @@ -77,7 +77,8 @@ public class OpmlImportBaseActivity extends AppCompatActivity { return; } this.uri = uri; - if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + uri.toString().contains(Environment.getExternalStorageDirectory().toString())) { int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { requestPermission(); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java index 02e16a7b5..4c94e2b76 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java @@ -1,25 +1,30 @@ package de.danoeh.antennapod.activity; +import android.content.Intent; import android.net.Uri; import android.os.Bundle; import de.danoeh.antennapod.core.preferences.UserPreferences; -/** Lets the user start the OPML-import process. */ +/** + * Lets the user start the OPML-import process. + */ public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity { private static final String TAG = "OpmlImportFromIntentAct"; @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); + protected void onCreate(Bundle savedInstanceState) { + setTheme(UserPreferences.getTheme()); + super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); Uri uri = getIntent().getData(); - if(uri.toString().startsWith("/")) { + if (uri != null && uri.toString().startsWith("/")) { uri = Uri.parse("file://" + uri.toString()); + } else { + uri = Uri.parse(getIntent().getStringExtra(Intent.EXTRA_TEXT)); } importUri(uri); } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java index b2dab7f68..eb6b473d2 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java @@ -135,7 +135,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) { Uri uri = data.getData(); - if(uri.toString().startsWith("/")) { + if(uri != null && uri.toString().startsWith("/")) { uri = Uri.parse("file://" + uri.toString()); } importUri(uri); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java index 3a1a7be05..dc5570dc0 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportHolder.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.activity; -import de.danoeh.antennapod.core.opml.OpmlElement; - import java.util.ArrayList; +import de.danoeh.antennapod.core.export.opml.OpmlElement; + /** * Hold infos gathered by Ompl-Import * <p/> 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 ba22a42b4..dd932814f 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -26,11 +26,9 @@ import de.danoeh.antennapod.preferences.PreferenceController; */ public class PreferenceActivity extends AppCompatActivity { + private static WeakReference<PreferenceActivity> instance; private PreferenceController preferenceController; private MainFragment prefFragment; - private static WeakReference<PreferenceActivity> instance; - - private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() { @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override @@ -103,6 +101,7 @@ public class PreferenceActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setRetainInstance(true); addPreferencesFromResource(R.xml.preferences); PreferenceActivity activity = instance.get(); if(activity != null && activity.preferenceController != null) { @@ -118,5 +117,23 @@ public class PreferenceActivity extends AppCompatActivity { activity.preferenceController.onResume(); } } + + @Override + public void onPause() { + PreferenceActivity activity = instance.get(); + if(activity != null && activity.preferenceController != null) { + activity.preferenceController.onPause(); + } + super.onPause(); + } + + @Override + public void onStop() { + PreferenceActivity activity = instance.get(); + if(activity != null && activity.preferenceController != null) { + activity.preferenceController.onStop(); + } + super.onStop(); + } } } 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 633f8d66d..390bec15c 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivityGingerbread.java @@ -18,9 +18,6 @@ import de.danoeh.antennapod.preferences.PreferenceController; */ public class PreferenceActivityGingerbread extends android.preference.PreferenceActivity { private static final String TAG = "PreferenceActivity"; - - private PreferenceController preferenceController; - private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() { @SuppressWarnings("deprecation") @@ -34,6 +31,7 @@ public class PreferenceActivityGingerbread extends android.preference.Preference return PreferenceActivityGingerbread.this; } }; + private PreferenceController preferenceController; @SuppressLint("NewApi") @SuppressWarnings("deprecation") @@ -55,6 +53,18 @@ public class PreferenceActivityGingerbread extends android.preference.Preference } @Override + protected void onPause() { + preferenceController.onPause(); + super.onPause(); + } + + @Override + protected void onStop() { + preferenceController.onStop(); + super.onStop(); + } + + @Override protected void onApplyThemeResource(Theme theme, int resid, boolean first) { theme.applyStyle(UserPreferences.getTheme(), true); } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java new file mode 100644 index 000000000..b92ac8577 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java @@ -0,0 +1,23 @@ +package de.danoeh.antennapod.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; + +/** + * Creator: vbarad + * Date: 2016-12-03 + * Project: AntennaPod + */ + +public class SplashActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = new Intent(this, MainActivity.class); + startActivity(intent); + finish(); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java index 0254617e4..b2ff43c43 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java @@ -1,14 +1,18 @@ package de.danoeh.antennapod.activity; +import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.ProgressBar; +import android.widget.RadioButton; import android.widget.TextView; import de.danoeh.antennapod.R; @@ -28,12 +32,16 @@ public class StatisticsActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private static final String TAG = StatisticsActivity.class.getSimpleName(); + private static final String PREF_NAME = "StatisticsActivityPrefs"; + private static final String PREF_COUNT_ALL = "countAll"; private Subscription subscription; private TextView totalTimeTextView; private ListView feedStatisticsList; private ProgressBar progressBar; private StatisticsListAdapter listAdapter; + private boolean countAll = false; + private SharedPreferences prefs; @Override protected void onCreate(Bundle savedInstanceState) { @@ -42,10 +50,14 @@ public class StatisticsActivity extends AppCompatActivity getSupportActionBar().setDisplayShowHomeEnabled(true); setContentView(R.layout.statistics_activity); + prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); + countAll = prefs.getBoolean(PREF_COUNT_ALL, false); + totalTimeTextView = (TextView) findViewById(R.id.total_time); feedStatisticsList = (ListView) findViewById(R.id.statistics_list); progressBar = (ProgressBar) findViewById(R.id.progressBar); listAdapter = new StatisticsListAdapter(this); + listAdapter.setCountAll(countAll); feedStatisticsList.setAdapter(listAdapter); feedStatisticsList.setOnItemClickListener(this); } @@ -53,10 +65,15 @@ public class StatisticsActivity extends AppCompatActivity @Override public void onResume() { super.onResume(); - progressBar.setVisibility(View.VISIBLE); - totalTimeTextView.setVisibility(View.GONE); - feedStatisticsList.setVisibility(View.GONE); - loadStats(); + refreshStatistics(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.statistics, menu); + return true; } @Override @@ -64,30 +81,60 @@ public class StatisticsActivity extends AppCompatActivity if (item.getItemId() == android.R.id.home) { finish(); return true; + } else if (item.getItemId() == R.id.statistics_mode) { + selectStatisticsMode(); + return true; } else { return super.onOptionsItemSelected(item); } } - private void loadStats() { - if(subscription != null) { + private void selectStatisticsMode() { + View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setView(contentView); + builder.setTitle(R.string.statistics_mode); + + if (countAll) { + ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true); + } else { + ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true); + } + + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { + countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked(); + listAdapter.setCountAll(countAll); + prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply(); + refreshStatistics(); + }); + + builder.show(); + } + + private void refreshStatistics() { + progressBar.setVisibility(View.VISIBLE); + totalTimeTextView.setVisibility(View.GONE); + feedStatisticsList.setVisibility(View.GONE); + loadStatistics(); + } + + private void loadStatistics() { + if (subscription != null) { subscription.unsubscribe(); } - subscription = Observable.fromCallable(() -> DBReader.getStatistics()) + subscription = Observable.fromCallable(() -> DBReader.getStatistics(countAll)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { if (result != null) { totalTimeTextView.setText(Converter - .shortLocalizedDuration(this, result.totalTime)); + .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime)); listAdapter.update(result.feedTime); progressBar.setVisibility(View.GONE); totalTimeTextView.setVisibility(View.VISIBLE); feedStatisticsList.setVisibility(View.VISIBLE); } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } @Override @@ -97,9 +144,10 @@ public class StatisticsActivity extends AppCompatActivity AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle(stats.feed.getTitle()); dialog.setMessage(getString(R.string.statistics_details_dialog, - stats.episodesStarted, + countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted, stats.episodes, - Converter.shortLocalizedDuration(this, stats.timePlayed), + Converter.shortLocalizedDuration(this, countAll ? + stats.timePlayedCountAll : stats.timePlayed), Converter.shortLocalizedDuration(this, stats.time))); dialog.setPositiveButton(android.R.string.ok, null); dialog.show(); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java index 81d727283..62bff0891 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java @@ -55,7 +55,7 @@ public class StorageErrorActivity extends AppCompatActivity { openDirectoryChooser(); } }); - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int readPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); int writePermission = ActivityCompat.checkSelfPermission(this, diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java index d46a3d6c2..8ede947c5 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java @@ -6,11 +6,13 @@ import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; @@ -40,7 +42,7 @@ import de.danoeh.antennapod.core.service.GpodnetSyncService; * Step 2: Choose device from a list of available devices or create a new one * Step 3: Choose from a list of actions */ -public class GpodnetAuthenticationActivity extends ActionBarActivity { +public class GpodnetAuthenticationActivity extends AppCompatActivity { private static final String TAG = "GpodnetAuthActivity"; private static final String CURRENT_STEP = "current_step"; @@ -113,6 +115,9 @@ public class GpodnetAuthenticationActivity extends ActionBarActivity { final TextView txtvError = (TextView) view.findViewById(R.id.txtvError); final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progBarLogin); + password.setOnEditorActionListener((v, actionID, event) -> + actionID == EditorInfo.IME_ACTION_GO && login.performClick()); + login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -131,6 +136,11 @@ public class GpodnetAuthenticationActivity extends ActionBarActivity { login.setEnabled(false); progressBar.setVisibility(View.VISIBLE); txtvError.setVisibility(View.GONE); + // hide the keyboard + InputMethodManager inputManager = (InputMethodManager) + getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.hideSoftInputFromWindow(login.getWindowToken(), + InputMethodManager.HIDE_NOT_ALWAYS); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java index 66e6f9a00..c18564351 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java @@ -1,8 +1,9 @@ package de.danoeh.antennapod.adapter; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.util.LongList; public interface ActionButtonCallback { /** Is called when the action button of a list item has been pressed. */ - void onActionButtonPressed(FeedItem item); + void onActionButtonPressed(FeedItem item, LongList queueIds); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java index 1a8f0a67a..f0210f983 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java @@ -47,6 +47,7 @@ public class ActionButtonUtils { * Sets the displayed bitmap and content description of the given * action button so that it matches the state of the FeedItem. */ + @SuppressWarnings("ResourceType") public void configureActionButton(ImageButton butSecondary, FeedItem item, boolean isInQueue) { Validate.isTrue(butSecondary != null && item != null, "butSecondary or item was null"); @@ -57,8 +58,7 @@ public class ActionButtonUtils { if (isDownloadingMedia) { // item is being downloaded butSecondary.setVisibility(View.VISIBLE); - butSecondary.setImageDrawable(drawables - .getDrawable(1)); + butSecondary.setImageDrawable(drawables.getDrawable(1)); butSecondary.setContentDescription(context.getString(labels[1])); } else { // item is not downloaded and not being downloaded diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java index 8aaf0055a..5c58d00f2 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java @@ -15,7 +15,7 @@ import de.danoeh.antennapod.core.util.NetworkUtils; /** * Utility methods for adapters */ -public class AdapterUtils { +class AdapterUtils { private static final String TAG = AdapterUtils.class.getSimpleName(); @@ -26,7 +26,7 @@ public class AdapterUtils { /** * Updates the contents of the TextView that shows the current playback position and the ProgressBar. */ - public static void updateEpisodePlaybackProgress(FeedItem item, TextView txtvPos, ProgressBar episodeProgress) { + static void updateEpisodePlaybackProgress(FeedItem item, TextView txtvPos, ProgressBar episodeProgress) { FeedMedia media = item.getMedia(); episodeProgress.setVisibility(View.GONE); if (media == null) { @@ -47,7 +47,6 @@ public class AdapterUtils { - media.getPosition())); } } else if (!media.isDownloaded()) { - Log.d(TAG, "size: " + media.getSize()); if (media.getSize() > 0) { txtvPos.setText(Converter.byteToString(media.getSize())); } else if(NetworkUtils.isDownloadAllowed() && !media.checkedOnSizeButUnknown()) { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java index 43a00f7c5..3e8bbc488 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -200,11 +200,11 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR holder.butSecondary.setOnClickListener(secondaryActionListener); Glide.with(mainActivityRef.get()) - .load(item.getImageUri()) + .load(item.getImageLocation()) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .fitCenter() .dontAnimate() - .into(new CoverTarget(item.getFeed().getImageUri(), holder.placeholder, holder.cover, mainActivityRef.get())); + .into(new CoverTarget(item.getFeed().getImageLocation(), holder.placeholder, holder.cover, mainActivityRef.get())); } @Override @@ -232,7 +232,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR @Override public void onClick(View v) { FeedItem item = (FeedItem) v.getTag(); - actionButtonCallback.onActionButtonPressed(item); + actionButtonCallback.onActionButtonPressed(item, itemAccess.getQueueIds()); } }; @@ -319,6 +319,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR boolean isInQueue(FeedItem item); + LongList getQueueIds(); + } /** diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java index 37e00ab74..d7bebb672 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java @@ -60,6 +60,7 @@ public class ChaptersListAdapter 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.duration = (TextView) convertView.findViewById(R.id.txtvDuration); holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter); convertView.setTag(holder); } else { @@ -70,6 +71,16 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> { holder.title.setText(sc.getTitle()); holder.start.setText(Converter.getDurationStringLong((int) sc .getStart())); + + long duration; + if (position + 1 < media.getChapters().size()) { + duration = media.getChapters().get(position + 1).getStart() - sc.getStart(); + } else { + duration = media.getDuration() - sc.getStart(); + } + holder.duration.setText(getContext().getString(R.string.chapter_duration, + Converter.getDurationStringLong((int) duration))); + if (sc.getLink() != null) { holder.link.setVisibility(View.VISIBLE); holder.link.setText(sc.getLink()); @@ -155,6 +166,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> { TextView title; TextView start; TextView link; + TextView duration; ImageButton butPlayChapter; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java index ed0c08086..538af8c79 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverTarget.java @@ -18,12 +18,12 @@ import de.danoeh.antennapod.core.glide.ApGlideSettings; class CoverTarget extends GlideDrawableImageViewTarget { - private final WeakReference<Uri> fallback; + private final WeakReference<String> fallback; private final WeakReference<TextView> placeholder; private final WeakReference<ImageView> cover; private final WeakReference<MainActivity> mainActivity; - public CoverTarget(Uri fallbackUri, TextView txtvPlaceholder, ImageView imgvCover, MainActivity activity) { + public CoverTarget(String fallbackUri, TextView txtvPlaceholder, ImageView imgvCover, MainActivity activity) { super(imgvCover); fallback = new WeakReference<>(fallbackUri); placeholder = new WeakReference<>(txtvPlaceholder); @@ -33,7 +33,7 @@ class CoverTarget extends GlideDrawableImageViewTarget { @Override public void onLoadFailed(Exception e, Drawable errorDrawable) { - Uri fallbackUri = fallback.get(); + String fallbackUri = fallback.get(); TextView txtvPlaceholder = placeholder.get(); ImageView imgvCover = cover.get(); if (fallbackUri != null && txtvPlaceholder != null && imgvCover != null) { @@ -48,7 +48,7 @@ class CoverTarget extends GlideDrawableImageViewTarget { } @Override - public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) { + public void onResourceReady(GlideDrawable drawable, GlideAnimation<? super GlideDrawable> anim) { super.onResourceReady(drawable, anim); TextView txtvPlaceholder = placeholder.get(); if (txtvPlaceholder != null) { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java index 00ab96f6c..4a53be9dc 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java @@ -51,13 +51,12 @@ public class DefaultActionButtonCallback implements ActionButtonCallback { } @Override - public void onActionButtonPressed(final FeedItem item) { + public void onActionButtonPressed(final FeedItem item, final LongList queueIds) { if (item.hasMedia()) { final FeedMedia media = item.getMedia(); boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media); if (!isDownloading && !media.isDownloaded()) { - LongList queueIds = DBReader.getQueueIDList(); if (NetworkUtils.isDownloadAllowed() || userAllowedMobileDownloads()) { try { DBTasks.downloadFeedItems(context, item); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java index 6d0beff9e..6907e467b 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -12,6 +12,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; +import com.nineoldandroids.view.ViewHelper; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; @@ -77,7 +78,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { } Glide.with(context) - .load(item.getImageUri()) + .load(item.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) @@ -85,6 +86,12 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { .dontAnimate() .into(holder.imageView); + if(item.isPlayed()) { + ViewHelper.setAlpha(convertView, 0.5f); + } else { + ViewHelper.setAlpha(convertView, 1.0f); + } + holder.title.setText(item.getTitle()); holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize())); holder.queueStatus.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index 4e9c5d71b..35c42725c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -26,6 +26,7 @@ import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.ThemeUtils; /** @@ -86,6 +87,7 @@ public class FeedItemlistAdapter extends BaseAdapter { } @Override + @SuppressWarnings("ResourceType") public View getView(final int position, View convertView, ViewGroup parent) { Holder holder; final FeedItem item = getItem(position); @@ -219,7 +221,7 @@ public class FeedItemlistAdapter extends BaseAdapter { @Override public void onClick(View v) { FeedItem item = (FeedItem) v.getTag(); - callback.onActionButtonPressed(item); + callback.onActionButtonPressed(item, itemAccess.getQueueIds()); } }; @@ -243,6 +245,8 @@ public class FeedItemlistAdapter extends BaseAdapter { FeedItem getItem(int position); + LongList getQueueIds(); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index 75c858ec6..465497b55 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.adapter; +import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.res.TypedArray; @@ -21,6 +22,7 @@ import com.joanzapata.iconify.widget.IconTextView; import org.apache.commons.lang3.ArrayUtils; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -45,6 +47,7 @@ import de.danoeh.antennapod.fragment.SubscriptionFragment; */ public class NavListAdapter extends BaseAdapter implements SharedPreferences.OnSharedPreferenceChangeListener { + public static final int VIEW_TYPE_COUNT = 3; public static final int VIEW_TYPE_NAV = 0; public static final int VIEW_TYPE_SECTION_DIVIDER = 1; @@ -60,12 +63,12 @@ public class NavListAdapter extends BaseAdapter private static String[] titles; private ItemAccess itemAccess; - private Context context; + private WeakReference<Activity> activity; private boolean showSubscriptionList = true; - public NavListAdapter(ItemAccess itemAccess, Context context) { + public NavListAdapter(ItemAccess itemAccess, Activity context) { this.itemAccess = itemAccess; - this.context = context; + this.activity = new WeakReference<>(context); titles = context.getResources().getStringArray(R.array.nav_drawer_titles); loadItems(); @@ -108,6 +111,10 @@ public class NavListAdapter extends BaseAdapter } private Drawable getDrawable(String tag) { + Activity context = activity.get(); + if(context == null) { + return null; + } int icon; switch (tag) { case QueueFragment.TAG: @@ -218,6 +225,10 @@ public class NavListAdapter extends BaseAdapter } private View getNavView(String title, int position, View convertView, ViewGroup parent) { + Activity context = activity.get(); + if(context == null) { + return null; + } NavHolder holder; if (convertView == null) { holder = new NavHolder(); @@ -236,30 +247,28 @@ public class NavListAdapter extends BaseAdapter holder.title.setText(title); + // reset for re-use + holder.count.setVisibility(View.GONE); + holder.count.setOnClickListener(null); + String tag = tags.get(position); if (tag.equals(QueueFragment.TAG)) { int queueSize = itemAccess.getQueueSize(); if (queueSize > 0) { - holder.count.setVisibility(View.VISIBLE); holder.count.setText(String.valueOf(queueSize)); - } else { - holder.count.setVisibility(View.GONE); + holder.count.setVisibility(View.VISIBLE); } } else if (tag.equals(EpisodesFragment.TAG)) { int unreadItems = itemAccess.getNumberOfNewItems(); if (unreadItems > 0) { - holder.count.setVisibility(View.VISIBLE); holder.count.setText(String.valueOf(unreadItems)); - } else { - holder.count.setVisibility(View.GONE); + holder.count.setVisibility(View.VISIBLE); } } else if (tag.equals(SubscriptionFragment.TAG)) { int sum = itemAccess.getFeedCounterSum(); if (sum > 0) { - holder.count.setVisibility(View.VISIBLE); holder.count.setText(String.valueOf(sum)); - } else { - holder.count.setVisibility(View.GONE); + holder.count.setVisibility(View.VISIBLE); } } else if(tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) { int epCacheSize = UserPreferences.getEpisodeCacheSize(); @@ -278,11 +287,7 @@ public class NavListAdapter extends BaseAdapter .setPositiveButton(android.R.string.ok, (dialog, which) -> {}) .show() ); - } else { - holder.count.setVisibility(View.GONE); } - } else { - holder.count.setVisibility(View.GONE); } holder.image.setImageDrawable(getDrawable(tags.get(position))); @@ -291,6 +296,10 @@ public class NavListAdapter extends BaseAdapter } private View getSectionDividerView(View convertView, ViewGroup parent) { + Activity context = activity.get(); + if(context == null) { + return null; + } LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -303,6 +312,10 @@ public class NavListAdapter extends BaseAdapter } private View getFeedView(int position, View convertView, ViewGroup parent) { + Activity context = activity.get(); + if(context == null) { + return null; + } int feedPos = position - getSubscriptionOffset(); Feed feed = itemAccess.getItem(feedPos); @@ -324,7 +337,7 @@ public class NavListAdapter extends BaseAdapter } Glide.with(context) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java index 796ac4184..c6ddc6c86 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -296,11 +296,11 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap butSecondary.setOnClickListener(secondaryActionListener); Glide.with(mainActivity.get()) - .load(item.getImageUri()) + .load(item.getImageLocation()) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .fitCenter() .dontAnimate() - .into(new CoverTarget(item.getFeed().getImageUri(), placeholder, cover, mainActivity.get())); + .into(new CoverTarget(item.getFeed().getImageLocation(), placeholder, cover, mainActivity.get())); } } @@ -309,7 +309,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap @Override public void onClick(View v) { FeedItem item = (FeedItem) v.getTag(); - actionButtonCallback.onActionButtonPressed(item); + actionButtonCallback.onActionButtonPressed(item, itemAccess.getQueueIds()); } }; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java index a68ef01d9..8e1aa24e0 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -11,6 +11,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; +import com.nineoldandroids.view.ViewHelper; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.Feed; @@ -80,7 +81,7 @@ public class SearchlistAdapter extends BaseAdapter { holder.subtitle.setVisibility(View.GONE); Glide.with(context) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) @@ -96,8 +97,10 @@ public class SearchlistAdapter extends BaseAdapter { holder.subtitle.setText(result.getSubtitle()); } + ViewHelper.setAlpha(convertView, item.isPlayed() ? 0.5f : 1.0f); + Glide.with(context) - .load(item.getFeed().getImageUri()) + .load(item.getFeed().getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java index 7fb1472ad..c060083a6 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java @@ -9,11 +9,9 @@ import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.joanzapata.iconify.widget.IconTextView; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.Feed; @@ -27,11 +25,15 @@ import de.danoeh.antennapod.core.util.Converter; public class StatisticsListAdapter extends BaseAdapter { private Context context; List<DBReader.StatisticsItem> feedTime = new ArrayList<>(); + private boolean countAll = true; public StatisticsListAdapter(Context context) { this.context = context; } + public void setCountAll(boolean countAll) { + this.countAll = countAll; + } @Override public int getCount() { @@ -69,7 +71,7 @@ public class StatisticsListAdapter extends BaseAdapter { } Glide.with(context) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) @@ -79,7 +81,8 @@ public class StatisticsListAdapter extends BaseAdapter { holder.title.setText(feed.getTitle()); holder.time.setText(Converter.shortLocalizedDuration(context, - feedTime.get(position).timePlayed)); + countAll ? feedTime.get(position).timePlayedCountAll + : feedTime.get(position).timePlayed)); return convertView; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java index e2561804e..6d19bfa6c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java @@ -1,9 +1,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; -import android.net.Uri; import android.support.v4.app.Fragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -32,8 +30,8 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI /** placeholder object that indicates item should be added */ public static final Object ADD_ITEM_OBJ = new Object(); - /** the position in the view that holds the add item */ - private static final int ADD_POSITION = 0; + /** the position in the view that holds the add item; 0 is the first, -1 is the last position */ + private static final int ADD_POSITION = -1; private static final String TAG = "SubscriptionsAdapter"; private final WeakReference<MainActivity> mainActivityRef; @@ -44,8 +42,16 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI this.itemAccess = itemAccess; } + private int getAddTilePosition() { + if(ADD_POSITION < 0) { + return ADD_POSITION + getCount(); + } + return ADD_POSITION; + } + private int getAdjustedPosition(int origPosition) { - return origPosition - 1; + assert(origPosition != getAddTilePosition()); + return origPosition < getAddTilePosition() ? origPosition : origPosition - 1; } @Override @@ -55,15 +61,20 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI @Override public Object getItem(int position) { - if (position == ADD_POSITION) { + if (position == getAddTilePosition()) { return ADD_ITEM_OBJ; } return itemAccess.getItem(getAdjustedPosition(position)); } @Override + public boolean hasStableIds() { + return true; + } + + @Override public long getItemId(int position) { - if (position == ADD_POSITION) { + if (position == getAddTilePosition()) { return 0; } return itemAccess.getItem(getAdjustedPosition(position)).getId(); @@ -89,13 +100,17 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI holder = (Holder) convertView.getTag(); } - if (position == ADD_POSITION) { + if (position == getAddTilePosition()) { holder.feedTitle.setText("{md-add 500%}\n\n" + mainActivityRef.get().getString(R.string.add_feed_label)); holder.feedTitle.setVisibility(View.VISIBLE); // prevent any accidental re-use of old values (not sure how that would happen...) holder.count.setPrimaryText(""); // make it go away, we don't need it for add feed holder.count.setVisibility(View.INVISIBLE); + + // when this holder is reused, we could else end up with a cover image + Glide.clear(holder.imageView); + return convertView; } @@ -104,10 +119,15 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI holder.feedTitle.setText(feed.getTitle()); holder.feedTitle.setVisibility(View.VISIBLE); - holder.count.setPrimaryText(String.valueOf(itemAccess.getFeedCounter(feed.getId()))); - holder.count.setVisibility(View.VISIBLE); + int count = itemAccess.getFeedCounter(feed.getId()); + if(count > 0) { + holder.count.setPrimaryText(String.valueOf(itemAccess.getFeedCounter(feed.getId()))); + holder.count.setVisibility(View.VISIBLE); + } else { + holder.count.setVisibility(View.GONE); + } Glide.with(mainActivityRef.get()) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .fitCenter() @@ -119,7 +139,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (position == ADD_POSITION) { + if (position == getAddTilePosition()) { mainActivityRef.get().loadChildFragment(new AddFeedFragment()); } else { Fragment fragment = ItemlistFragment.newInstance(getItemId(position)); 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 e9756b467..f1f8be559 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 @@ -1,6 +1,8 @@ package de.danoeh.antennapod.adapter.itunes; import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -18,6 +20,7 @@ import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; +import de.mfietz.fyydlin.SearchHit; public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { /** @@ -42,8 +45,9 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { this.context = context; } + @NonNull @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(int position, View convertView, @NonNull ViewGroup parent) { //Current podcast Podcast podcast = data.get(position); @@ -66,7 +70,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { //Set the title viewHolder.titleView.setText(podcast.title); - if(!podcast.feedUrl.contains("itunes.apple.com")) { + if(podcast.feedUrl != null && !podcast.feedUrl.contains("itunes.apple.com")) { viewHolder.urlView.setText(podcast.feedUrl); viewHolder.urlView.setVisibility(View.VISIBLE); } else { @@ -87,35 +91,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { } /** - * View holder object for the GridView - */ - class PodcastViewHolder { - - /** - * ImageView holding the Podcast image - */ - public final ImageView coverView; - - /** - * TextView holding the Podcast title - */ - public final TextView titleView; - - public final TextView urlView; - - - /** - * Constructor - * @param view GridView cell - */ - PodcastViewHolder(View view){ - coverView = (ImageView) view.findViewById(R.id.imgvCover); - titleView = (TextView) view.findViewById(R.id.txtvTitle); - urlView = (TextView) view.findViewById(R.id.txtvUrl); - } - } - - /** * Represents an individual podcast on the iTunes Store. */ public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model @@ -128,14 +103,16 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { /** * URL of the podcast image */ + @Nullable public final String imageUrl; /** * URL of the podcast feed */ + @Nullable public final String feedUrl; - private Podcast(String title, String imageUrl, String feedUrl) { + private Podcast(String title, @Nullable String imageUrl, @Nullable String feedUrl) { this.title = title; this.imageUrl = imageUrl; this.feedUrl = feedUrl; @@ -148,12 +125,16 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { * @throws JSONException */ public static Podcast fromSearch(JSONObject json) throws JSONException { - String title = json.getString("collectionName"); - String imageUrl = json.getString("artworkUrl100"); - String feedUrl = json.getString("feedUrl"); + String title = json.optString("collectionName", ""); + String imageUrl = json.optString("artworkUrl100", null); + String feedUrl = json.optString("feedUrl", null); return new Podcast(title, imageUrl, feedUrl); } + public static Podcast fromSearch(SearchHit searchHit) { + return new Podcast(searchHit.getTitle(), searchHit.getImageUrl(), searchHit.getXmlUrl()); + } + /** * Constructs a Podcast instance from iTunes toplist entry * @@ -177,4 +158,33 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> { } } + + /** + * View holder object for the GridView + */ + class PodcastViewHolder { + + /** + * ImageView holding the Podcast image + */ + final ImageView coverView; + + /** + * TextView holding the Podcast title + */ + final TextView titleView; + + final TextView urlView; + + + /** + * Constructor + * @param view GridView cell + */ + PodcastViewHolder(View view){ + coverView = (ImageView) view.findViewById(R.id.imgvCover); + titleView = (TextView) view.findViewById(R.id.txtvTitle); + urlView = (TextView) view.findViewById(R.id.txtvUrl); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java new file mode 100644 index 000000000..192df8ca5 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java @@ -0,0 +1,65 @@ +package de.danoeh.antennapod.asynctask; + +import android.support.annotation.NonNull; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; + +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.util.LangUtils; +import rx.Observable; + +/** + * Writes an OPML file into the export directory in the background. + */ +public class ExportWorker { + + private static final String EXPORT_DIR = "export/"; + private static final String TAG = "ExportWorker"; + private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds"; + + private ExportWriter exportWriter; + private File output; + + public ExportWorker(ExportWriter exportWriter) { + this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR), + DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension())); + } + + public ExportWorker(ExportWriter exportWriter, @NonNull File output) { + this.exportWriter = exportWriter; + this.output = output; + } + + public Observable<File> exportObservable() { + if (output.exists()) { + Log.w(TAG, "Overwriting previously exported file."); + output.delete(); + } + return Observable.create(subscriber -> { + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8); + exportWriter.writeDocument(DBReader.getFeedList(), writer); + subscriber.onNext(output); + } catch (IOException e) { + subscriber.onError(e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + subscriber.onError(e); + } + } + subscriber.onCompleted(); + } + }); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java deleted file mode 100644 index 13abb26ea..000000000 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java +++ /dev/null @@ -1,122 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.annotation.SuppressLint; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.AsyncTask; -import android.support.v7.app.AlertDialog; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.opml.OpmlWriter; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.util.LangUtils; - -/** - * Writes an OPML file into the export directory in the background. - */ -public class OpmlExportWorker extends AsyncTask<Void, Void, Void> { - private static final String TAG = "OpmlExportWorker"; - private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds.opml"; - public static final String EXPORT_DIR = "export/"; - - private Context context; - private File output; - - private ProgressDialog progDialog; - private Exception exception; - - public OpmlExportWorker(Context context, File output) { - this.context = context; - this.output = output; - } - - public OpmlExportWorker(Context context) { - this.context = context; - } - - @Override - protected Void doInBackground(Void... params) { - OpmlWriter opmlWriter = new OpmlWriter(); - if (output == null) { - output = new File( - UserPreferences.getDataFolder(EXPORT_DIR), - DEFAULT_OUTPUT_NAME); - if (output.exists()) { - Log.w(TAG, "Overwriting previously exported file."); - output.delete(); - } - } - OutputStreamWriter writer = null; - try { - writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8); - opmlWriter.writeDocument(DBReader.getFeedList(), writer); - } catch (IOException e) { - e.printStackTrace(); - exception = e; - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException ioe) { - exception = ioe; - } - } - } - return null; - } - - @Override - protected void onPostExecute(Void result) { - progDialog.dismiss(); - AlertDialog.Builder alert = new AlertDialog.Builder(context) - .setNeutralButton(android.R.string.ok, - (dialog, which) -> dialog.dismiss()); - if (exception != null) { - alert.setTitle(R.string.export_error_label); - alert.setMessage(exception.getMessage()); - } else { - alert.setTitle(R.string.opml_export_success_title); - alert.setMessage(context - .getString(R.string.opml_export_success_sum) - + output.toString()) - .setPositiveButton(R.string.send_label, (dialog, which) -> { - Uri outputUri = Uri.fromFile(output); - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, - context.getResources().getText(R.string.opml_export_label)); - sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri); - sendIntent.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent, - context.getResources().getText(R.string.send_label))); - }); - } - alert.create().show(); - } - - @Override - protected void onPreExecute() { - progDialog = new ProgressDialog(context); - progDialog.setMessage(context.getString(R.string.exporting_label)); - progDialog.setIndeterminate(true); - progDialog.show(); - } - - @SuppressLint("NewApi") - public void executeAsync() { - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - executeOnExecutor(THREAD_POOL_EXECUTOR); - } else { - execute(); - } - } - -} diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java index 1cb653f01..4449d82c2 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java @@ -9,8 +9,8 @@ import java.util.Arrays; import de.danoeh.antennapod.activity.OpmlImportHolder; import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.export.opml.OpmlElement; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.opml.OpmlElement; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java index 45ec6c5fa..62ea85811 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java @@ -14,8 +14,8 @@ import java.io.Reader; import java.util.ArrayList; import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.opml.OpmlElement; -import de.danoeh.antennapod.core.opml.OpmlReader; +import de.danoeh.antennapod.core.export.opml.OpmlElement; +import de.danoeh.antennapod.core.export.opml.OpmlReader; public class OpmlImportWorker extends AsyncTask<Void, Void, ArrayList<OpmlElement>> { @@ -75,9 +75,7 @@ public class OpmlImportWorker extends alert.setTitle(R.string.error_label); alert.setMessage(context.getString(R.string.opml_reader_error) + exception.getMessage()); - alert.setNeutralButton(android.R.string.ok, (dialog, which) -> { - dialog.dismiss(); - }); + alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); alert.create().show(); } } 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 691eccdd9..538abd4c7 100644 --- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java +++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java @@ -18,5 +18,6 @@ public class ClientConfigurator { ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl(); ClientConfig.flattrCallbacks = new FlattrCallbacksImpl(); ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl(); + ClientConfig.castCallbacks = new CastCallbackImpl(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 577a3ecbe..ac073141d 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -225,6 +225,10 @@ public class EpisodesApplyActionFragment extends Fragment { checkQueued(false); resId = R.string.selected_not_queued_label; break; + case R.id.check_has_media: + checkWithMedia(); + resId = R.string.selected_has_media_label; + break; case R.id.sort_title_a_z: sortByTitle(false); return true; @@ -357,6 +361,17 @@ public class EpisodesApplyActionFragment extends Fragment { refreshCheckboxes(); } + private void checkWithMedia() { + for (FeedItem episode : episodes) { + if(episode.hasMedia()) { + checkedIds.add(episode.getId()); + } else { + checkedIds.remove(episode.getId()); + } + } + refreshCheckboxes(); + } + private void refreshTitles() { titles.clear(); for(FeedItem episode : episodes) { diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java index b875eaf62..a4e71c249 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java @@ -35,9 +35,7 @@ public class GpodnetSetHostnameDialog { } dialog1.dismiss(); }) - .setNegativeButton(R.string.cancel_label, (dialog1, which) -> { - dialog1.cancel(); - }) + .setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel()) .setNeutralButton(R.string.pref_gpodnet_sethostname_use_default_host, (dialog1, which) -> { GpodnetPreferences.setHostname(GpodnetService.DEFAULT_BASE_HOST); dialog1.dismiss(); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java index 98a4b5356..0bd75b5b0 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java @@ -18,10 +18,6 @@ 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; @@ -33,6 +29,10 @@ 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 okhttp3.Credentials; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import rx.Observable; import rx.Subscriber; import rx.Subscription; @@ -258,10 +258,11 @@ public class ProxyDialog { 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(); + OkHttpClient.Builder builder = AntennapodHttpClient.newBuilder() + .connectTimeout(10, TimeUnit.SECONDS) + .proxy(proxy); + builder.interceptors().clear(); + OkHttpClient client = builder.build(); if(!TextUtils.isEmpty(username)) { String credentials = Credentials.basic(username, password); client.interceptors().add(chain -> { diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java new file mode 100644 index 000000000..31a544582 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/dialog/RenameFeedDialog.java @@ -0,0 +1,44 @@ +package de.danoeh.antennapod.dialog; + +import android.app.Activity; +import android.text.InputType; + +import com.afollestad.materialdialogs.MaterialDialog; + +import java.lang.ref.WeakReference; + +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.storage.DBWriter; + +public class RenameFeedDialog { + + private final WeakReference<Activity> activityRef; + private final Feed feed; + + public RenameFeedDialog(Activity activity, Feed feed) { + this.activityRef = new WeakReference<>(activity); + this.feed = feed; + } + + public void show() { + Activity activity = activityRef.get(); + if(activity == null) { + return; + } + new MaterialDialog.Builder(activity) + .title(de.danoeh.antennapod.core.R.string.rename_feed_label) + .inputType(InputType.TYPE_CLASS_TEXT) + .input(feed.getTitle(), feed.getTitle(), true, (dialog, input) -> { + feed.setCustomTitle(input.toString()); + DBWriter.setFeedCustomTitle(feed); + dialog.dismiss(); + }) + .neutralText(de.danoeh.antennapod.core.R.string.reset) + .onNeutral((dialog, which) -> dialog.getInputEditText().setText(feed.getFeedTitle())) + .negativeText(de.danoeh.antennapod.core.R.string.cancel_label) + .onNegative((dialog, which) -> dialog.dismiss()) + .autoDismiss(false) + .show(); + } + +} 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 8a13a75d9..7d6a66a54 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.dialog; import android.content.Context; -import android.content.SharedPreferences; +import android.support.design.widget.Snackbar; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; @@ -9,6 +9,7 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; @@ -16,36 +17,27 @@ import android.widget.Toast; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; -import java.util.concurrent.TimeUnit; - import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.event.MessageEvent; +import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; +import de.greenrobot.event.EventBus; public abstract class SleepTimerDialog { private static final String TAG = SleepTimerDialog.class.getSimpleName(); - private static final int DEFAULT_SPINNER_POSITION = 1; - private Context context; - private String PREF_NAME = "SleepTimerDialog"; - private String PREF_VALUE = "LastValue"; - private String PREF_TIME_UNIT = "LastTimeUnit"; - private String PREF_VIBRATE = "Vibrate"; - private String PREF_SHAKE_TO_RESET = "ShakeToReset"; - private SharedPreferences prefs; private MaterialDialog dialog; private EditText etxtTime; private Spinner spTimeUnit; private CheckBox cbShakeToReset; private CheckBox cbVibrate; + private CheckBox chAutoEnable; - private TimeUnit[] units = { TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS }; - - public SleepTimerDialog(Context context) { + protected SleepTimerDialog(Context context) { this.context = context; - prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } public MaterialDialog createNewDialog() { @@ -58,7 +50,7 @@ public abstract class SleepTimerDialog { builder.onPositive((dialog, which) -> { try { savePreferences(); - long input = readTimeMillis(); + long input = SleepTimerPreferences.timerMillis(); onTimerSet(input, cbShakeToReset.isChecked(), cbVibrate.isChecked()); dialog.dismiss(); } catch (NumberFormatException e) { @@ -75,8 +67,9 @@ public abstract class SleepTimerDialog { spTimeUnit = (Spinner) view.findViewById(R.id.spTimeUnit); cbShakeToReset = (CheckBox) view.findViewById(R.id.cbShakeToReset); cbVibrate = (CheckBox) view.findViewById(R.id.cbVibrate); + chAutoEnable = (CheckBox) view.findViewById(R.id.chAutoEnable); - etxtTime.setText(prefs.getString(PREF_VALUE, "15")); + etxtTime.setText(SleepTimerPreferences.lastTimerValue()); etxtTime.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) { @@ -104,12 +97,17 @@ public abstract class SleepTimerDialog { android.R.layout.simple_spinner_item, spinnerContent); spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spTimeUnit.setAdapter(spinnerAdapter); - int selection = prefs.getInt(PREF_TIME_UNIT, DEFAULT_SPINNER_POSITION); - spTimeUnit.setSelection(selection); + spTimeUnit.setSelection(SleepTimerPreferences.lastTimerTimeUnit()); - cbShakeToReset.setChecked(prefs.getBoolean(PREF_SHAKE_TO_RESET, true)); - cbVibrate.setChecked(prefs.getBoolean(PREF_VIBRATE, true)); + cbShakeToReset.setChecked(SleepTimerPreferences.shakeToReset()); + cbVibrate.setChecked(SleepTimerPreferences.vibrate()); + chAutoEnable.setChecked(SleepTimerPreferences.autoEnable()); + chAutoEnable.setOnCheckedChangeListener((compoundButton, isChecked) -> { + SleepTimerPreferences.setAutoEnable(isChecked); + int messageString = isChecked ? R.string.sleep_timer_enabled_label : R.string.sleep_timer_disabled_label; + EventBus.getDefault().post(new MessageEvent(context.getString(messageString))); + }); return dialog; } @@ -125,19 +123,12 @@ public abstract class SleepTimerDialog { public abstract void onTimerSet(long millis, boolean shakeToReset, boolean vibrate); - private long readTimeMillis() { - TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()]; - long value = Long.parseLong(etxtTime.getText().toString()); - return selectedUnit.toMillis(value); - } - private void savePreferences() { - prefs.edit() - .putString(PREF_VALUE, etxtTime.getText().toString()) - .putInt(PREF_TIME_UNIT, spTimeUnit.getSelectedItemPosition()) - .putBoolean(PREF_SHAKE_TO_RESET, cbShakeToReset.isChecked()) - .putBoolean(PREF_VIBRATE, cbVibrate.isChecked()) - .apply(); + SleepTimerPreferences.setLastTimer(etxtTime.getText().toString(), + spTimeUnit.getSelectedItemPosition()); + SleepTimerPreferences.setShakeToReset(cbShakeToReset.isChecked()); + SleepTimerPreferences.setVibrate(cbVibrate.isChecked()); + SleepTimerPreferences.setAutoEnable(chAutoEnable.isChecked()); } } diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index 2bf9c4e7a..6a975fe49 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -95,9 +95,7 @@ public class VariableSpeedDialog { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.set_playback_speed_label); builder.setMultiChoiceItems(R.array.playback_speed_values, - speedChecked, (dialog, which, isChecked) -> { - speedChecked[which] = isChecked; - }); + speedChecked, (dialog, which, isChecked) -> speedChecked[which] = isChecked); builder.setNegativeButton(android.R.string.cancel, null); builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java index 45364ca07..f14ebbdaf 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -39,10 +39,11 @@ public class AddFeedFragment extends Fragment { etxtFeedurl.setText(args.getString(ARG_FEED_URL)); } + Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet); + Button butSearchFyyd = (Button) root.findViewById(R.id.butSearchFyyd); Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport); Button butConfirm = (Button) root.findViewById(R.id.butConfirm); - Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); final MainActivity activity = (MainActivity) getActivity(); activity.getSupportActionBar().setTitle(R.string.add_feed_label); @@ -51,6 +52,8 @@ public class AddFeedFragment extends Fragment { butBrowserGpoddernet.setOnClickListener(v -> activity.loadChildFragment(new GpodnetMainFragment())); + butSearchFyyd.setOnClickListener(v -> activity.loadChildFragment(new FyydSearchFragment())); + butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(), OpmlImportFromPathActivity.class))); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 8ae7f1cf9..bbfd1688d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -80,6 +80,7 @@ public class AllEpisodesFragment extends Fragment { private boolean viewsCreated = false; private boolean isUpdatingFeeds; + protected boolean isMenuInvalidationAllowed = false; protected Subscription subscription; private LinearLayoutManager layoutManager; @@ -180,7 +181,7 @@ public class AllEpisodesFragment extends Fragment { } super.onCreateOptionsMenu(menu, inflater); if (itemsLoaded) { - inflater.inflate(R.menu.new_episodes, menu); + inflater.inflate(R.menu.episodes, menu); MenuItem searchItem = menu.findItem(R.id.action_search); final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem); @@ -206,11 +207,13 @@ public class AllEpisodesFragment extends Fragment { @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - if (itemsLoaded) { - MenuItem menuItem = menu.findItem(R.id.mark_all_read_item); - if (menuItem != null) { - menuItem.setVisible(episodes != null && !episodes.isEmpty()); - } + MenuItem markAllRead = menu.findItem(R.id.mark_all_read_item); + if (markAllRead != null) { + markAllRead.setVisible(!showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty()); + } + MenuItem markAllSeen = menu.findItem(R.id.mark_all_seen_item); + if(markAllSeen != null) { + markAllSeen.setVisible(showOnlyNewEpisodes() && episodes != null && !episodes.isEmpty()); } } @@ -225,19 +228,32 @@ public class AllEpisodesFragment extends Fragment { } return true; case R.id.mark_all_read_item: - ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), + ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(), R.string.mark_all_read_label, R.string.mark_all_read_confirmation_msg) { @Override - public void onConfirmButtonPressed( - DialogInterface dialog) { + public void onConfirmButtonPressed(DialogInterface dialog) { dialog.dismiss(); DBWriter.markAllItemsRead(); Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show(); } }; - conDialog.createNewDialog().show(); + markAllReadConfirmationDialog.createNewDialog().show(); + return true; + case R.id.mark_all_seen_item: + ConfirmationDialog markAllSeenConfirmationDialog = new ConfirmationDialog(getActivity(), + R.string.mark_all_seen_label, + R.string.mark_all_seen_confirmation_msg) { + + @Override + public void onConfirmButtonPressed(DialogInterface dialog) { + dialog.dismiss(); + DBWriter.markNewItemsSeen(); + Toast.makeText(getActivity(), R.string.mark_all_seen_msg, Toast.LENGTH_SHORT).show(); + } + }; + markAllSeenConfirmationDialog.createNewDialog().show(); return true; default: return false; @@ -378,6 +394,20 @@ public class AllEpisodesFragment extends Fragment { return item != null && item.isTagged(FeedItem.TAG_QUEUE); } + @Override + public LongList getQueueIds() { + LongList queueIds = new LongList(); + if(episodes == null) { + return queueIds; + } + for(FeedItem item : episodes) { + if(item.isTagged(FeedItem.TAG_QUEUE)) { + queueIds.add(item.getId()); + } + } + return queueIds; + } + }; public void onEventMainThread(FeedItemEvent event) { @@ -401,7 +431,7 @@ public class AllEpisodesFragment extends Fragment { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; downloaderList = update.downloaders; - if (isUpdatingFeeds != update.feedIds.length > 0) { + if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) { getActivity().supportInvalidateOptionsMenu(); } if(listAdapter != null && update.mediaIds.length > 0) { @@ -450,9 +480,7 @@ public class AllEpisodesFragment extends Fragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } protected List<FeedItem> loadData() { 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 77e66f3b0..4d34d076d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java @@ -69,16 +69,18 @@ public class ChaptersFragment extends ListFragment implements MediaplayerInfoCon @Override public void onMediaChanged(Playable media) { - if(this.media == media || adapter == null) { + if(this.media == media) { return; } this.media = media; - adapter.setMedia(media); - adapter.notifyDataSetChanged(); - if(media == null || media.getChapters() == null || media.getChapters().size() == 0) { - setEmptyText(getString(R.string.no_items_label)); - } else { - setEmptyText(null); + if (adapter != null) { + adapter.setMedia(media); + adapter.notifyDataSetChanged(); + if(media == null || media.getChapters() == null || media.getChapters().size() == 0) { + setEmptyText(getString(R.string.no_items_label)); + } else { + setEmptyText(null); + } } } 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 d14265f70..1ba7ed557 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -215,9 +215,7 @@ public class CompletedDownloadsFragment extends ListFragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } } 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 943ddeec7..1d3fcefba 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -33,22 +33,15 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra public static CoverFragment newInstance(Playable item) { CoverFragment f = new CoverFragment(); - if (item != null) { - Bundle args = new Bundle(); - args.putParcelable(ARG_PLAYABLE, item); - f.setArguments(args); - } + f.media = item; return f; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - media = args.getParcelable(ARG_PLAYABLE); - } else { - Log.e(TAG, TAG + " was called with invalid arguments"); + if (media == null) { + Log.e(TAG, TAG + " was called without media"); } } @@ -67,7 +60,7 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra txtvPodcastTitle.setText(media.getFeedTitle()); txtvEpisodeTitle.setText(media.getEpisodeTitle()); Glide.with(this) - .load(media.getImageUri()) + .load(media.getImageLocation()) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .dontAnimate() .fitCenter() @@ -98,11 +91,13 @@ public class CoverFragment extends Fragment implements MediaplayerInfoContentFra @Override public void onMediaChanged(Playable media) { - if(!isAdded() || this.media == media) { + if(this.media == media) { return; } this.media = media; - loadMediaInfo(); + if (isAdded()) { + loadMediaInfo(); + } } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java index 93527b149..0a710196a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java @@ -165,9 +165,7 @@ public class DownloadLogFragment extends ListFragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java index f23981935..e2fbd91f3 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java @@ -79,6 +79,11 @@ public class EpisodesFragment extends Fragment { public static class EpisodesPagerAdapter extends FragmentPagerAdapter { private final Resources resources; + private AllEpisodesFragment[] fragments = { + new NewEpisodesFragment(), + new AllEpisodesFragment(), + new FavoriteEpisodesFragment() + }; public EpisodesPagerAdapter(FragmentManager fm, Resources resources) { super(fm); @@ -87,15 +92,7 @@ public class EpisodesFragment extends Fragment { @Override public Fragment getItem(int position) { - switch (position) { - case POS_ALL_EPISODES: - return new AllEpisodesFragment(); - case POS_NEW_EPISODES: - return new NewEpisodesFragment(); - case POS_FAV_EPISODES: - return new FavoriteEpisodesFragment(); - } - return null; + return fragments[position]; } @Override @@ -116,5 +113,14 @@ public class EpisodesFragment extends Fragment { return super.getPageTitle(position); } } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + for (int i = 0; i < TOTAL_COUNT; i++) { + // Invalidating the OptionsMenu is only allowed for the currently active fragment + fragments[i].isMenuInvalidationAllowed = (i == position); + } + } } } 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 758f8095d..1e385728a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -163,7 +163,7 @@ public class ExternalPlayerFragment extends Fragment { ((double) controller.getPosition() / controller.getDuration() * 100)); Glide.with(getActivity()) - .load(media.getImageUri()) + .load(media.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java index 65305df3d..234c8377d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -71,9 +71,7 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment { Snackbar snackbar = Snackbar.make(root, getString(R.string.removed_item), Snackbar.LENGTH_LONG); - snackbar.setAction(getString(R.string.undo), v -> { - DBWriter.addFavoriteItem(item); - }); + snackbar.setAction(getString(R.string.undo), v -> DBWriter.addFavoriteItem(item)); snackbar.show(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java new file mode 100644 index 000000000..7c1ec5ec1 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java @@ -0,0 +1,192 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.widget.SearchView; +import android.util.Log; +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.Button; +import android.widget.GridView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.OnlineFeedViewActivity; +import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; +import de.danoeh.antennapod.menuhandler.MenuItemUtils; +import de.mfietz.fyydlin.FyydClient; +import de.mfietz.fyydlin.FyydResponse; +import de.mfietz.fyydlin.SearchHit; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; + +import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast; +import static java.util.Collections.emptyList; + +public class FyydSearchFragment extends Fragment { + + private static final String TAG = "FyydSearchFragment"; + + /** + * Adapter responsible with the search results + */ + private ItunesAdapter adapter; + private GridView gridView; + private ProgressBar progressBar; + private TextView txtvError; + private Button butRetry; + private TextView txtvEmpty; + + private FyydClient client = new FyydClient(AntennapodHttpClient.getHttpClient()); + + /** + * List of podcasts retreived from the search + */ + private List<Podcast> searchResults; + private Subscription subscription; + + /** + * Constructor + */ + public FyydSearchFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_itunes_search, container, false); + gridView = (GridView) root.findViewById(R.id.gridView); + adapter = new ItunesAdapter(getActivity(), new ArrayList<>()); + gridView.setAdapter(adapter); + + //Show information about the podcast when the list item is clicked + gridView.setOnItemClickListener((parent, view1, position, id) -> { + Podcast podcast = searchResults.get(position); + Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, podcast.feedUrl); + intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, podcast.title); + startActivity(intent); + }); + progressBar = (ProgressBar) root.findViewById(R.id.progressBar); + txtvError = (TextView) root.findViewById(R.id.txtvError); + butRetry = (Button) root.findViewById(R.id.butRetry); + txtvEmpty = (TextView) root.findViewById(android.R.id.empty); + + return root; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (subscription != null) { + subscription.unsubscribe(); + } + adapter = null; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.itunes_search, menu); + MenuItem searchItem = menu.findItem(R.id.action_search); + final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem); + MenuItemUtils.adjustTextColor(getActivity(), sv); + sv.setQueryHint(getString(R.string.search_fyyd_label)); + sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + sv.clearFocus(); + search(s); + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return false; + } + }); + MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + getActivity().getSupportFragmentManager().popBackStack(); + return true; + } + }); + MenuItemCompat.expandActionView(searchItem); + } + + private void search(String query) { + if (subscription != null) { + subscription.unsubscribe(); + } + showOnlyProgressBar(); + subscription = client.searchPodcasts(query) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + progressBar.setVisibility(View.GONE); + processSearchResult(result); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + progressBar.setVisibility(View.GONE); + txtvError.setText(error.toString()); + txtvError.setVisibility(View.VISIBLE); + butRetry.setOnClickListener(v -> search(query)); + butRetry.setVisibility(View.VISIBLE); + }); + } + + private void showOnlyProgressBar() { + gridView.setVisibility(View.GONE); + txtvError.setVisibility(View.GONE); + butRetry.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + } + + void processSearchResult(FyydResponse response) { + adapter.clear(); + if (!response.getData().isEmpty()) { + adapter.clear(); + searchResults = new ArrayList<>(); + for (SearchHit searchHit : response.getData().values()) { + Podcast podcast = Podcast.fromSearch(searchHit); + searchResults.add(podcast); + } + } else { + searchResults = emptyList(); + } + for(Podcast podcast : searchResults) { + adapter.add(podcast); + } + adapter.notifyDataSetInvalidated(); + gridView.setVisibility(!searchResults.isEmpty() ? View.VISIBLE : View.GONE); + txtvEmpty.setVisibility(searchResults.isEmpty() ? View.VISIBLE : View.GONE); + } + +} 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 55d28cadb..a0586fe16 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -185,8 +185,10 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo super.onViewCreated(view, savedInstanceState); Bundle args = getArguments(); if (args.containsKey(ARG_PLAYABLE)) { - media = args.getParcelable(ARG_PLAYABLE); - shownotesProvider = media; + if (media == null) { + media = args.getParcelable(ARG_PLAYABLE); + shownotesProvider = media; + } load(); } else if (args.containsKey(ARG_FEEDITEM_ID)) { long id = getArguments().getLong(ARG_FEEDITEM_ID); @@ -196,9 +198,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo .subscribe(feedItem -> { shownotesProvider = feedItem; load(); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } } @@ -311,9 +311,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo webvDescription.loadDataWithBaseURL(null, data, "text/html", "utf-8", "about:blank"); Log.d(TAG, "Webview loaded"); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } private String loadData() { @@ -348,7 +346,7 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo } private boolean restoreFromPreference() { - if (!saveState) { + if (saveState) { Log.d(TAG, "Restoring from preferences"); Activity activity = getActivity(); if (activity != null) { @@ -381,12 +379,14 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo @Override public void onMediaChanged(Playable media) { - if(this.media == media || webvDescription == null) { + if(this.media == media) { return; } this.media = media; this.shownotesProvider = media; - load(); + if (webvDescription != null) { + load(); + } } } 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 e721af47d..7939dcb23 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -44,9 +44,7 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.event.DownloaderUpdate; -import de.danoeh.antennapod.core.event.FavoritesEvent; import de.danoeh.antennapod.core.event.FeedItemEvent; -import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -60,7 +58,9 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.Flavors; import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.ShareUtils; import de.danoeh.antennapod.core.util.playback.Timeline; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; @@ -222,7 +222,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { return; } DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity()); - actionButtonCallback.onActionButtonPressed(item); + actionButtonCallback.onActionButtonPressed(item, item.isTagged(FeedItem.TAG_QUEUE) ? + LongList.of(item.getId()) : new LongList(0)); FeedMedia media = item.getMedia(); if (media != null && media.isDownloaded()) { // playback was started, dialog should close itself @@ -312,7 +313,10 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { if(!isAdded() || item == null) { return; } - ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS); + super.onCreateOptionsMenu(menu, inflater); + if (Flavors.FLAVOR == Flavors.PLAY) { + ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS); + } inflater.inflate(R.menu.feeditem_options, menu); popupMenu = menu; if (item.hasMedia()) { @@ -374,7 +378,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { } Glide.with(getActivity()) - .load(item.getImageUri()) + .load(item.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) @@ -417,7 +421,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { butAction2Text = R.string.stream_label; } else { butAction2Icon = "{md-delete 24sp}"; - butAction2Text = R.string.remove_label; + butAction2Text = R.string.delete_label; } if (isDownloading) { butAction1Icon = "{md-cancel 24sp}"; @@ -576,9 +580,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { item = result; itemsLoaded = true; onFragmentLoaded(); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } private FeedItem loadInBackground() { 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 3194d7cab..a118673a6 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -64,8 +64,10 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.FeedItemUtil; +import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil; import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment; +import de.danoeh.antennapod.dialog.RenameFeedDialog; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.FeedMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; @@ -98,6 +100,7 @@ public class ItemlistFragment extends ListFragment { private boolean itemsLoaded = false; private boolean viewsCreated = false; + private boolean headerCreated = false; private List<Downloader> downloaderList; @@ -105,7 +108,10 @@ public class ItemlistFragment extends ListFragment { private boolean isUpdatingFeed; + private TextView txtvTitle; private IconTextView txtvFailure; + private ImageView imgvBackground; + private ImageView imgvCover; private TextView txtvInformation; @@ -247,6 +253,9 @@ public class ItemlistFragment extends ListFragment { .newInstance(feed.getItems()); ((MainActivity)getActivity()).loadChildFragment(fragment); return true; + case R.id.rename_item: + new RenameFeedDialog(getActivity(), feed).show(); + return true; case R.id.remove_item: final FeedRemover remover = new FeedRemover( getActivity(), feed) { @@ -258,7 +267,7 @@ public class ItemlistFragment extends ListFragment { }; ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(), R.string.remove_feed_label, - R.string.feed_delete_confirmation_msg) { + getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) { @Override public void onConfirmButtonPressed( @@ -414,6 +423,7 @@ public class ItemlistFragment extends ListFragment { public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { Log.d(TAG, "Received contentUpdate Intent. arg " + arg); + refreshHeaderView(); loadItems(); updateProgressBarVisibility(); } @@ -459,15 +469,17 @@ public class ItemlistFragment extends ListFragment { } private void refreshHeaderView() { - if (getListView() == null || feed == null) { - Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null"); + if (getListView() == null || feed == null || !headerCreated) { + Log.e(TAG, "Unable to refresh header view"); return; } + loadFeedImage(); if(feed.hasLastUpdateFailed()) { txtvFailure.setVisibility(View.VISIBLE); } else { txtvFailure.setVisibility(View.GONE); } + txtvTitle.setText(feed.getTitle()); if(feed.getItemFilter() != null) { FeedItemFilter filter = feed.getItemFilter(); if(filter.getValues().length > 0) { @@ -497,10 +509,10 @@ public class ItemlistFragment extends ListFragment { View header = inflater.inflate(R.layout.feeditemlist_header, lv, false); lv.addHeaderView(header); - TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); + 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); + imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground); + imgvCover = (ImageView) header.findViewById(R.id.imgvCover); ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo); txtvInformation = (TextView) header.findViewById(R.id.txtvInformation); txtvFailure = (IconTextView) header.findViewById(R.id.txtvFailure); @@ -512,8 +524,22 @@ public class ItemlistFragment extends ListFragment { // https://github.com/bumptech/glide/issues/529 imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); + loadFeedImage(); + + butShowInfo.setOnClickListener(v -> { + if (viewsCreated && itemsLoaded) { + Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); + startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, + feed.getId()); + startActivity(startIntent); + } + }); + headerCreated = true; + } + + private void loadFeedImage() { Glide.with(getActivity()) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .placeholder(R.color.image_readability_tint) .error(R.color.image_readability_tint) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) @@ -522,22 +548,13 @@ public class ItemlistFragment extends ListFragment { .into(imgvBackground); Glide.with(getActivity()) - .load(feed.getImageUri()) + .load(feed.getImageLocation()) .placeholder(R.color.light_gray) .error(R.color.light_gray) .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .fitCenter() .dontAnimate() .into(imgvCover); - - butShowInfo.setOnClickListener(v -> { - if (viewsCreated && itemsLoaded) { - Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); - startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); - } - }); } @@ -578,6 +595,20 @@ public class ItemlistFragment extends ListFragment { } @Override + public LongList getQueueIds() { + LongList queueIds = new LongList(); + if(feed == null) { + return queueIds; + } + for(FeedItem item : feed.getItems()) { + if(item.isTagged(FeedItem.TAG_QUEUE)) { + queueIds.add(item.getId()); + } + } + return queueIds; + } + + @Override public int getCount() { return (feed != null) ? feed.getNumOfItems() : 0; } @@ -612,9 +643,7 @@ public class ItemlistFragment extends ListFragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } private Feed loadData() { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java index b736688b9..db88c070d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java @@ -18,9 +18,6 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Request; -import com.squareup.okhttp.Response; import org.json.JSONArray; import org.json.JSONException; @@ -39,6 +36,9 @@ import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.menuhandler.MenuItemUtils; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; 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 7ef070f21..183c10f3d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -7,6 +7,8 @@ import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -92,7 +94,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment { } }; - Snackbar snackbar = Snackbar.make(root, getString(R.string.marked_as_read_label), + Snackbar snackbar = Snackbar.make(root, getString(R.string.marked_as_seen_label), Snackbar.LENGTH_LONG); snackbar.setAction(getString(R.string.undo), v -> { DBWriter.markItemPlayed(FeedItem.NEW, item.getId()); 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 49c68c732..441f0096c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -28,6 +28,7 @@ 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.FeedItemUtil; +import de.danoeh.antennapod.core.util.LongList; import de.greenrobot.event.EventBus; import rx.Observable; import rx.Subscription; @@ -251,6 +252,20 @@ public class PlaybackHistoryFragment extends ListFragment { return null; } } + + @Override + public LongList getQueueIds() { + LongList queueIds = new LongList(); + if(playbackHistory == null) { + return queueIds; + } + for (FeedItem item : playbackHistory) { + if (item.isTagged(FeedItem.TAG_QUEUE)) { + queueIds.add(item.getId()); + } + } + return queueIds; + } }; private void loadItems() { @@ -268,9 +283,7 @@ public class PlaybackHistoryFragment extends ListFragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } private List<FeedItem> loadData() { 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 08e681c99..d7f25c134 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -304,11 +304,11 @@ public class QueueFragment extends Fragment { }; conDialog.createNewDialog().show(); return true; - case R.id.queue_sort_alpha_asc: - QueueSorter.sort(getActivity(), QueueSorter.Rule.ALPHA_ASC, true); + case R.id.queue_sort_episode_title_asc: + QueueSorter.sort(getActivity(), QueueSorter.Rule.EPISODE_TITLE_ASC, true); return true; - case R.id.queue_sort_alpha_desc: - QueueSorter.sort(getActivity(), QueueSorter.Rule.ALPHA_DESC, true); + case R.id.queue_sort_episode_title_desc: + QueueSorter.sort(getActivity(), QueueSorter.Rule.EPISODE_TITLE_DESC, true); return true; case R.id.queue_sort_date_asc: QueueSorter.sort(getActivity(), QueueSorter.Rule.DATE_ASC, true); @@ -322,6 +322,12 @@ public class QueueFragment extends Fragment { case R.id.queue_sort_duration_desc: QueueSorter.sort(getActivity(), QueueSorter.Rule.DURATION_DESC, true); return true; + case R.id.queue_sort_feed_title_asc: + QueueSorter.sort(getActivity(), QueueSorter.Rule.FEED_TITLE_ASC, true); + return true; + case R.id.queue_sort_feed_title_desc: + QueueSorter.sort(getActivity(), QueueSorter.Rule.FEED_TITLE_DESC, true); + return true; default: return false; } @@ -605,9 +611,7 @@ public class QueueFragment extends Fragment { recyclerAdapter.notifyDataSetChanged(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } } 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 510909379..f64b4c20a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -182,6 +182,9 @@ public class SearchFragment extends ListFragment { } searchAdapter.notifyDataSetChanged(); setListShown(true); + + String query = getArguments().getString(ARG_QUERY); + setEmptyText(getString(R.string.no_results_for_query, query)); } private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() { @@ -219,9 +222,7 @@ public class SearchFragment extends ListFragment { onFragmentLoaded(); } } - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } private List<SearchResult> performSearch() { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index a314419ac..9626e6c2e 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -26,7 +26,9 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.FeedItemUtil; +import de.danoeh.antennapod.dialog.RenameFeedDialog; import rx.Observable; +import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; @@ -46,6 +48,7 @@ public class SubscriptionFragment extends Fragment { private int mPosition = -1; + private Subscription subscription; public SubscriptionFragment() { } @@ -88,16 +91,25 @@ public class SubscriptionFragment extends Fragment { EventDistributor.getInstance().register(contentUpdate); } + @Override + public void onDestroy() { + super.onDestroy(); + if(subscription != null) { + subscription.unsubscribe(); + } + } + private void loadSubscriptions() { - Observable.fromCallable(() -> DBReader.getNavDrawerData()) + if(subscription != null) { + subscription.unsubscribe(); + } + subscription = Observable.fromCallable(DBReader::getNavDrawerData) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { navDrawerData = result; subscriptionAdapter.notifyDataSetChanged(); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); } @Override @@ -143,21 +155,18 @@ public class SubscriptionFragment extends Fragment { Observable.fromCallable(() -> DBWriter.markFeedSeen(feed.getId())) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - loadSubscriptions(); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + .subscribe(result -> loadSubscriptions(), + error -> Log.e(TAG, Log.getStackTraceString(error))); return true; case R.id.mark_all_read_item: Observable.fromCallable(() -> DBWriter.markFeedRead(feed.getId())) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - loadSubscriptions(); - }, error -> { - Log.e(TAG, Log.getStackTraceString(error)); - }); + .subscribe(result -> loadSubscriptions(), + error -> Log.e(TAG, Log.getStackTraceString(error))); + return true; + case R.id.rename_item: + new RenameFeedDialog(getActivity(), feed).show(); return true; case R.id.remove_item: final FeedRemover remover = new FeedRemover(getContext(), feed) { @@ -169,7 +178,7 @@ public class SubscriptionFragment extends Fragment { }; ConfirmationDialog conDialog = new ConfirmationDialog(getContext(), R.string.remove_feed_label, - R.string.feed_delete_confirmation_msg) { + getString(R.string.feed_delete_confirmation_msg, feed.getTitle())) { @Override public void onConfirmButtonPressed( DialogInterface dialog) { diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java index b80213459..57b7c359c 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java @@ -80,7 +80,7 @@ public class FeedItemMenuHandler { if(queueAccess == null || queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == selectedItem.getId()) { mi.setItemVisibility(R.id.move_to_bottom_item, false); } - if (!isInQueue || isPlaying) { + if (!isInQueue) { mi.setItemVisibility(R.id.remove_from_queue_item, false); } if (!(!isInQueue && selectedItem.getMedia() != null)) { @@ -101,6 +101,8 @@ public class FeedItemMenuHandler { mi.setItemVisibility(R.id.share_download_url_with_position_item, false); } + mi.setItemVisibility(R.id.share_file, hasMedia && selectedItem.getMedia().fileExists()); + if (selectedItem.isPlayed()) { mi.setItemVisibility(R.id.mark_read_item, false); } else { @@ -239,6 +241,9 @@ public class FeedItemMenuHandler { case R.id.share_download_url_with_position_item: ShareUtils.shareFeedItemDownloadLink(context, selectedItem, true); break; + case R.id.share_file: + ShareUtils.shareFeedItemFile(context, selectedItem.getMedia()); + break; default: Log.d(TAG, "Unknown menuItemId: " + menuItemId); return false; 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 4c28b197d..ac703e13e 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java @@ -28,6 +28,7 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte } } + @SuppressWarnings("ResourceType") public static void refreshLockItem(Context context, Menu menu) { final MenuItem queueLock = menu.findItem(de.danoeh.antennapod.R.id.queue_lock); int[] lockIcons = new int[] { de.danoeh.antennapod.R.attr.ic_lock_open, de.danoeh.antennapod.R.attr.ic_lock_closed }; 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 6c03dc7ae..2ca7dd029 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.preferences; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.ProgressDialog; import android.app.TimePickerDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -28,14 +29,13 @@ import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.text.format.DateFormat; +import android.text.format.DateUtils; import android.util.Log; import android.widget.EditText; -import android.widget.Toast; import android.widget.ListView; +import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GoogleApiAvailability; import org.apache.commons.lang3.ArrayUtils; @@ -43,6 +43,8 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; import java.util.GregorianCalendar; import java.util.List; import java.util.concurrent.TimeUnit; @@ -52,10 +54,14 @@ 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.MediaplayerActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.activity.PreferenceActivityGingerbread; import de.danoeh.antennapod.activity.StatisticsActivity; -import de.danoeh.antennapod.asynctask.OpmlExportWorker; +import de.danoeh.antennapod.asynctask.ExportWorker; +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.export.html.HtmlWriter; +import de.danoeh.antennapod.core.export.opml.OpmlWriter; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.GpodnetSyncService; @@ -67,6 +73,10 @@ import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog; import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog; import de.danoeh.antennapod.dialog.ProxyDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Sets up a preference UI that lets the user change user preferences. @@ -76,35 +86,45 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc private static final String TAG = "PreferenceController"; - public static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings"; - public static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate"; - public static final String PREF_FLATTR_REVOKE = "prefRevokeAccess"; - public static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs"; - public static final String PREF_OPML_EXPORT = "prefOpmlExport"; - public static final String STATISTICS = "statistics"; - public static final String PREF_ABOUT = "prefAbout"; - public static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir"; - public static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings"; - 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"; - public static final String PREF_KNOWN_ISSUES = "prefKnownIssues"; - public static final String PREF_FAQ = "prefFaq"; - public static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport"; - - private final PreferenceUI ui; - - private CheckBoxPreference[] selectedNetworks; - + private static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings"; + private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate"; + private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess"; + private static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs"; + private static final String PREF_OPML_EXPORT = "prefOpmlExport"; + private static final String PREF_HTML_EXPORT = "prefHtmlExport"; + private static final String STATISTICS = "statistics"; + private static final String PREF_ABOUT = "prefAbout"; + private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir"; + private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings"; + private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher"; + public static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher"; + public static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher"; + private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate"; + private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information"; + private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync"; + private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync"; + private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; + private static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname"; + private static final String PREF_GPODNET_NOTIFICATIONS = "pref_gpodnet_notifications"; + private static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; + private static final String PREF_PROXY = "prefProxy"; + private static final String PREF_KNOWN_ISSUES = "prefKnownIssues"; + private static final String PREF_FAQ = "prefFaq"; + private static final String PREF_SEND_CRASH_REPORT = "prefSendCrashReport"; private static final String[] EXTERNAL_STORAGE_PERMISSIONS = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41; + private final PreferenceUI ui; + private final SharedPreferences.OnSharedPreferenceChangeListener gpoddernetListener = + (sharedPreferences, key) -> { + if (GpodnetPreferences.PREF_LAST_SYNC_ATTEMPT_TIMESTAMP.equals(key)) { + updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(), + GpodnetPreferences.getLastSyncAttemptTimestamp()); + } + }; + private CheckBoxPreference[] selectedNetworks; + private Subscription subscription; public PreferenceController(PreferenceUI ui) { this.ui = ui; @@ -112,22 +132,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc .registerOnSharedPreferenceChangeListener(this); } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(key.equals(UserPreferences.PREF_SONIC)) { - CheckBoxPreference prefSonic = (CheckBoxPreference) ui.findPreference(UserPreferences.PREF_SONIC); - if(prefSonic != null) { - prefSonic.setChecked(sharedPreferences.getBoolean(UserPreferences.PREF_SONIC, false)); - } - } - } - /** * Returns the preference activity that should be used on this device. * * @return PreferenceActivity if the API level is greater than 10, PreferenceActivityGingerbread otherwise. */ - public static Class getPreferenceActivity() { + public static Class<? extends Activity> getPreferenceActivity() { if (Build.VERSION.SDK_INT > 10) { return PreferenceActivity.class; } else { @@ -135,6 +145,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } } + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if(key.equals(UserPreferences.PREF_SONIC)) { + CheckBoxPreference prefSonic = (CheckBoxPreference) ui.findPreference(UserPreferences.PREF_SONIC); + if(prefSonic != null) { + prefSonic.setChecked(sharedPreferences.getBoolean(UserPreferences.PREF_SONIC, false)); + } + } + } + public void onCreate() { final Activity activity = ui.getActivity(); @@ -170,11 +190,9 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } ); ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener( - preference -> { - new OpmlExportWorker(activity).executeAsync(); - return true; - } - ); + preference -> export(new OpmlWriter())); + ui.findPreference(PreferenceController.PREF_HTML_EXPORT).setOnPreferenceClickListener( + preference -> export(new HtmlWriter())); ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener( preference -> { if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT && @@ -318,6 +336,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc VariableSpeedDialog.showDialog(activity); return true; }); + ui.findPreference(PreferenceController.PREF_PLAYBACK_REWIND_DELTA_LAUNCHER) + .setOnPreferenceClickListener(preference -> { + MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND); + return true; + }); + ui.findPreference(PreferenceController.PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER) + .setOnPreferenceClickListener(preference -> { + MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD); + return true; + }); ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION) .setOnPreferenceClickListener(preference -> { AuthenticationDialog dialog = new AuthenticationDialog(activity, @@ -340,6 +368,18 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc toast.show(); return true; }); + ui.findPreference(PreferenceController.PREF_GPODNET_FORCE_FULL_SYNC). + setOnPreferenceClickListener(preference -> { + GpodnetPreferences.setLastSubscriptionSyncTimestamp(0L); + GpodnetPreferences.setLastEpisodeActionsSyncTimestamp(0L); + GpodnetPreferences.setLastSyncAttempt(false, 0); + updateLastGpodnetSyncReport(false, 0); + 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(); @@ -412,28 +452,47 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle)); return true; }); - //checks whether Google Play Services is installed on the device (condition necessary for Cast support) - ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setOnPreferenceChangeListener((preference, o) -> { - if (o instanceof Boolean && ((Boolean) o)) { - final int googlePlayServicesCheck = GoogleApiAvailability.getInstance() - .isGooglePlayServicesAvailable(ui.getActivity()); - if (googlePlayServicesCheck == ConnectionResult.SUCCESS) { - return true; - } else { - GoogleApiAvailability.getInstance() - .getErrorDialog(ui.getActivity(), googlePlayServicesCheck, 0) - .show(); - return false; - } - } - return true; - }); + PreferenceControllerFlavorHelper.setupFlavoredUI(ui); buildEpisodeCleanupPreference(); buildSmartMarkAsPlayedPreference(); buildAutodownloadSelectedNetworsPreference(); setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter()); } + private boolean export(ExportWriter exportWriter) { + Context context = ui.getActivity(); + final ProgressDialog progressDialog = new ProgressDialog(context); + progressDialog.setMessage(context.getString(R.string.exporting_label)); + progressDialog.setIndeterminate(true); + progressDialog.show(); + final AlertDialog.Builder alert = new AlertDialog.Builder(context) + .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); + Observable<File> observable = new ExportWorker(exportWriter).exportObservable(); + subscription = observable.subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(output -> { + alert.setTitle(R.string.opml_export_success_title); + String message = context.getString(R.string.opml_export_success_sum) + output.toString(); + alert.setMessage(message); + alert.setPositiveButton(R.string.send_label, (dialog, which) -> { + Uri outputUri = Uri.fromFile(output); + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, + context.getResources().getText(R.string.opml_export_label)); + sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri); + sendIntent.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent, + context.getResources().getText(R.string.send_label))); + }); + alert.create().show(); + }, error -> { + alert.setTitle(R.string.export_error_label); + alert.setMessage(error.getMessage()); + alert.show(); + }, () -> progressDialog.dismiss()); + return true; + } + private void openInBrowser(String url) { try { Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); @@ -450,9 +509,20 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc setParallelDownloadsText(UserPreferences.getParallelDownloads()); setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize()); setDataFolderText(); + GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener); updateGpodnetPreferenceScreen(); } + public void onPause() { + GpodnetPreferences.unregisterOnSharedPreferenceChangeListener(gpoddernetListener); + } + + public void onStop() { + if(subscription != null) { + subscription.unsubscribe(); + } + } + @SuppressLint("NewApi") public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && @@ -494,18 +564,41 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc 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_FORCE_FULL_SYNC).setEnabled(loggedIn); ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn); + ui.findPreference(PREF_GPODNET_NOTIFICATIONS).setEnabled(loggedIn); if(loggedIn) { String format = ui.getActivity().getString(R.string.pref_gpodnet_login_status); String summary = String.format(format, GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID()); ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setSummary(Html.fromHtml(summary)); + updateLastGpodnetSyncReport(GpodnetPreferences.getLastSyncAttemptResult(), + GpodnetPreferences.getLastSyncAttemptTimestamp()); } else { ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setSummary(null); + updateLastGpodnetSyncReport(false, 0); } ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname()); } + private void updateLastGpodnetSyncReport(boolean successful, long lastTime) { + Preference sync = ui.findPreference(PREF_GPODNET_SYNC); + if (lastTime != 0) { + sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum) + "\n" + + ui.getActivity().getString(R.string.pref_gpodnet_sync_sum_last_sync_line, + ui.getActivity().getString(successful ? + R.string.gpodnetsync_pref_report_successful : + R.string.gpodnetsync_pref_report_failed), + DateUtils.getRelativeDateTimeString(ui.getActivity(), + lastTime, + DateUtils.MINUTE_IN_MILLIS, + DateUtils.WEEK_IN_MILLIS, + DateUtils.FORMAT_SHOW_TIME))); + } else { + sync.setSummary(ui.getActivity().getString(R.string.pref_gpodnet_sync_changes_sum)); + } + } + private String[] getUpdateIntervalEntries(final String[] values) { final Resources res = ui.getActivity().getResources(); String[] entries = new String[values.length]; @@ -621,7 +714,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_at), timeOfDayStr); } else { - val = context.getString(R.string.pref_smart_mark_as_played_disabled); + val = context.getString(R.string.pref_smart_mark_as_played_disabled); // TODO: Is this a bug? Otherwise document why is this related to smart mark??? } } String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n" @@ -666,10 +759,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc clearAutodownloadSelectedNetworsPreference(); } // get configured networks - WifiManager wifiservice = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE); + WifiManager wifiservice = (WifiManager) activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE); List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks(); if (networks != null) { + Collections.sort(networks, new Comparator<WifiConfiguration>() { + @Override + public int compare(WifiConfiguration x, WifiConfiguration y) { + return x.SSID.compareTo(y.SSID); + } + }); selectedNetworks = new CheckBoxPreference[networks.size()]; List<String> prefValues = Arrays.asList(UserPreferences .getAutodownloadSelectedNetworks()); @@ -754,9 +853,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> + UserPreferences.setHiddenDrawerItems(hiddenDrawerItems)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } @@ -800,9 +898,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc preferredButtons.remove((Integer) which); } }); - builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { - UserPreferences.setCompactNotificationButtons(preferredButtons); - }); + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> + UserPreferences.setCompactNotificationButtons(preferredButtons)); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } |