adapt ui to different flavors

This commit is contained in:
Domingos Lopes 2016-06-04 14:20:28 -04:00
parent f84f40d350
commit bcdcfe0d58
14 changed files with 84 additions and 3229 deletions

View File

@ -106,10 +106,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity {
// *
// * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)}
// */
// public final void requestCastButton(int showAsAction) {
// castButtonVisibilityManager.requestCastButton(showAsAction);
// }
//
public final void requestCastButton(int showAsAction) {
// no-op
}
// private class CastButtonVisibilityManager {
// private volatile boolean prefEnabled = false;
// private volatile boolean viewRequested = false;

View File

@ -1,773 +0,0 @@
package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
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 com.bumptech.glide.Glide;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import java.util.List;
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.ProgressEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
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.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
import de.danoeh.antennapod.fragment.ItemlistFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
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;
import rx.schedulers.Schedulers;
/**
* The activity that is shown when the user launches the app.
*/
public class MainActivity extends CastEnabledActivity implements NavDrawerActivity {
private static final String TAG = "MainActivity";
private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
| EventDistributor.UNREAD_ITEMS_UPDATE;
public static final String PREF_NAME = "MainActivityPrefs";
public static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
public static final String PREF_LAST_FRAGMENT_TAG = "prefMainActivityLastFragmentTag";
public static final String EXTRA_NAV_TYPE = "nav_type";
public static final String EXTRA_NAV_INDEX = "nav_index";
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
public static final String EXTRA_FEED_ID = "fragment_feed_id";
public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
public static final String SAVE_TITLE = "title";
public static final String[] NAV_DRAWER_TAGS = {
QueueFragment.TAG,
EpisodesFragment.TAG,
SubscriptionFragment.TAG,
DownloadsFragment.TAG,
PlaybackHistoryFragment.TAG,
AddFeedFragment.TAG,
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
private Toolbar toolbar;
private ExternalPlayerFragment externalPlayerFragment;
private DrawerLayout drawerLayout;
private View navDrawer;
private ListView navList;
private NavListAdapter navAdapter;
private int mPosition = -1;
private ActionBarDrawerToggle drawerToggle;
private CharSequence currentTitle;
private ProgressDialog pd;
private Subscription subscription;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getNoTitleTheme());
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
findViewById(R.id.shadow).setVisibility(View.GONE);
int elevation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
getResources().getDisplayMetrics());
getSupportActionBar().setElevation(elevation);
}
currentTitle = getTitle();
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.nav_list);
navDrawer = findViewById(R.id.nav_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
if (savedInstanceState != null) {
int backstackCount = savedInstanceState.getInt(SAVE_BACKSTACK_COUNT, 0);
drawerToggle.setDrawerIndicatorEnabled(backstackCount == 0);
}
drawerLayout.setDrawerListener(drawerToggle);
final FragmentManager fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(() -> {
drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0);
});
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
navAdapter = new NavListAdapter(itemAccess, this);
navList.setAdapter(navAdapter);
navList.setOnItemClickListener(navListClickListener);
navList.setOnItemLongClickListener(newListLongClickListener);
registerForContextMenu(navList);
navAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
selectedNavListIndex = getSelectedNavListIndex();
}
});
findViewById(R.id.nav_settings).setOnClickListener(v -> {
drawerLayout.closeDrawer(navDrawer);
startActivity(new Intent(MainActivity.this, PreferenceController.getPreferenceActivity()));
});
FragmentTransaction transaction = fm.beginTransaction();
Fragment mainFragment = fm.findFragmentByTag("main");
if (mainFragment != null) {
transaction.replace(R.id.main_view, mainFragment);
} else {
String lastFragment = getLastNavFragment();
if (ArrayUtils.contains(NAV_DRAWER_TAGS, lastFragment)) {
loadFragment(lastFragment, null);
} else {
try {
loadFeedFragmentById(Integer.parseInt(lastFragment), null);
} catch (NumberFormatException e) {
// it's not a number, this happens if we removed
// a label from the NAV_DRAWER_TAGS
// give them a nice default...
loadFragment(QueueFragment.TAG, null);
}
}
}
externalPlayerFragment = new ExternalPlayerFragment();
transaction.replace(R.id.playerFragment, externalPlayerFragment, ExternalPlayerFragment.TAG);
transaction.commit();
checkFirstLaunch();
}
private void saveLastNavFragment(String tag) {
Log.d(TAG, "saveLastNavFragment(tag: " + tag +")");
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
if(tag != null) {
edit.putString(PREF_LAST_FRAGMENT_TAG, tag);
} else {
edit.remove(PREF_LAST_FRAGMENT_TAG);
}
edit.commit();
}
private String getLastNavFragment() {
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
String lastFragment = prefs.getString(PREF_LAST_FRAGMENT_TAG, QueueFragment.TAG);
Log.d(TAG, "getLastNavFragment() -> " + lastFragment);
return lastFragment;
}
private void checkFirstLaunch() {
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) {
new Handler().postDelayed(() -> drawerLayout.openDrawer(navDrawer), 1500);
// for backward compatibility, we only change defaults for fresh installs
UserPreferences.setUpdateInterval(12);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
edit.commit();
}
}
public void showDrawerPreferencesDialog() {
final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
String[] navLabels = new String[NAV_DRAWER_TAGS.length];
final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) {
String tag = NAV_DRAWER_TAGS[i];
navLabels[i] = navAdapter.getLabel(tag);
if (!hiddenDrawerItems.contains(tag)) {
checked[i] = true;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.drawer_preferences);
builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> {
if (isChecked) {
hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
} else {
hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
}
});
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
}
public boolean isDrawerOpen() {
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
public List<Feed> getFeeds() {
return (navDrawerData != null) ? navDrawerData.feeds : null;
}
public void loadFragment(int index, Bundle args) {
Log.d(TAG, "loadFragment(index: " + index + ", args: " + args + ")");
if (index < navAdapter.getSubscriptionOffset()) {
String tag = navAdapter.getTags().get(index);
loadFragment(tag, args);
} else {
int pos = index - navAdapter.getSubscriptionOffset();
loadFeedFragmentByPosition(pos, args);
}
}
public void loadFragment(String tag, Bundle args) {
Log.d(TAG, "loadFragment(tag: " + tag + ", args: " + args + ")");
Fragment fragment = null;
switch (tag) {
case QueueFragment.TAG:
fragment = new QueueFragment();
break;
case EpisodesFragment.TAG:
fragment = new EpisodesFragment();
break;
case DownloadsFragment.TAG:
fragment = new DownloadsFragment();
break;
case PlaybackHistoryFragment.TAG:
fragment = new PlaybackHistoryFragment();
break;
case AddFeedFragment.TAG:
fragment = new AddFeedFragment();
break;
case SubscriptionFragment.TAG:
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
fragment = subscriptionFragment;
break;
default:
// default to the queue
tag = QueueFragment.TAG;
fragment = new QueueFragment();
args = null;
break;
}
currentTitle = navAdapter.getLabel(tag);
getSupportActionBar().setTitle(currentTitle);
saveLastNavFragment(tag);
if (args != null) {
fragment.setArguments(args);
}
loadFragment(fragment);
}
private void loadFeedFragmentByPosition(int relPos, Bundle args) {
if(relPos < 0) {
return;
}
Feed feed = itemAccess.getItem(relPos);
loadFeedFragmentById(feed.getId(), args);
}
public void loadFeedFragmentById(long feedId, Bundle args) {
Fragment fragment = ItemlistFragment.newInstance(feedId);
if(args != null) {
fragment.setArguments(args);
}
saveLastNavFragment(String.valueOf(feedId));
currentTitle = "";
getSupportActionBar().setTitle(currentTitle);
loadFragment(fragment);
}
private void loadFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
// clear back stack
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
fragmentManager.popBackStack();
}
FragmentTransaction t = fragmentManager.beginTransaction();
t.replace(R.id.main_view, fragment, "main");
fragmentManager.popBackStack();
// TODO: we have to allow state loss here
// since this function can get called from an AsyncTask which
// could be finishing after our app has already committed state
// and is about to get shutdown. What we *should* do is
// not commit anything in an AsyncTask, but that's a bigger
// change than we want now.
t.commitAllowingStateLoss();
if (navAdapter != null) {
navAdapter.notifyDataSetChanged();
}
}
public void loadChildFragment(Fragment fragment) {
Validate.notNull(fragment);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.replace(R.id.main_view, fragment, "main")
.addToBackStack(null)
.commit();
}
public void dismissChildFragment() {
getSupportFragmentManager().popBackStack();
}
private int getSelectedNavListIndex() {
String currentFragment = getLastNavFragment();
if(currentFragment == null) {
// should not happen, but better safe than sorry
return -1;
}
int tagIndex = navAdapter.getTags().indexOf(currentFragment);
if(tagIndex >= 0) {
return tagIndex;
} else if(ArrayUtils.contains(NAV_DRAWER_TAGS, currentFragment)) {
// the fragment was just hidden
return -1;
} else { // last fragment was not a list, but a feed
long feedId = Long.parseLong(currentFragment);
if (navDrawerData != null) {
List<Feed> feeds = navDrawerData.feeds;
for (int i = 0; i < feeds.size(); i++) {
if (feeds.get(i).getId() == feedId) {
return i + navAdapter.getSubscriptionOffset();
}
}
}
return -1;
}
}
private AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int viewType = parent.getAdapter().getItemViewType(position);
if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER && position != selectedNavListIndex) {
loadFragment(position, null);
}
drawerLayout.closeDrawer(navDrawer);
}
};
private AdapterView.OnItemLongClickListener newListLongClickListener = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if(position < navAdapter.getTags().size()) {
showDrawerPreferencesDialog();
return true;
} else {
mPosition = position;
return false;
}
}
};
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
if (savedInstanceState != null) {
currentTitle = savedInstanceState.getString(SAVE_TITLE);
if (!drawerLayout.isDrawerOpen(navDrawer)) {
getSupportActionBar().setTitle(currentTitle);
}
selectedNavListIndex = getSelectedNavListIndex();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVE_TITLE, getSupportActionBar().getTitle().toString());
outState.putInt(SAVE_BACKSTACK_COUNT, getSupportFragmentManager().getBackStackEntryCount());
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
RatingDialog.init(this);
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_FEED_ID) ||
(navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) &&
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
handleNavIntent();
}
loadData();
RatingDialog.check();
}
@Override
protected void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(subscription != null) {
subscription.unsubscribe();
}
if(pd != null) {
pd.dismiss();
}
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Glide.get(this).trimMemory(level);
}
@Override
public void onLowMemory() {
super.onLowMemory();
Glide.get(this).clearMemory();
}
@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;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
} else if (item.getItemId() == android.R.id.home) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
dismissChildFragment();
}
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if(v.getId() != R.id.nav_list) {
return;
}
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
int position = adapterInfo.position;
if(position < navAdapter.getSubscriptionOffset()) {
return;
}
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.nav_feed_context, menu);
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
menu.setHeaderTitle(feed.getTitle());
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
}
@Override
public boolean onContextItemSelected(MenuItem item) {
final int position = mPosition;
mPosition = -1; // reset
if(position < 0) {
return false;
}
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
case R.id.mark_all_seen_item:
DBWriter.markFeedSeen(feed.getId());
return true;
case R.id.mark_all_read_item:
DBWriter.markFeedRead(feed.getId());
return true;
case R.id.remove_item:
final FeedRemover remover = new FeedRemover(this, feed) {
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if(getSelectedNavListIndex() == position) {
loadFragment(EpisodesFragment.TAG, null);
}
}
};
ConfirmationDialog conDialog = new ConfirmationDialog(this,
R.string.remove_feed_label,
R.string.feed_delete_confirmation_msg) {
@Override
public void onConfirmButtonPressed(
DialogInterface dialog) {
dialog.dismiss();
long mediaId = PlaybackPreferences.getCurrentlyPlayingFeedMediaId();
if (mediaId > 0 &&
FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId) >= 0) {
Log.d(TAG, "Currently playing episode is about to be deleted, skipping");
remover.skipOnCompletion = true;
int playerStatus = PlaybackPreferences.getCurrentPlayerStatus();
if(playerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) {
sendBroadcast(new Intent(
PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
}
}
remover.executeAsync();
}
};
conDialog.createNewDialog().show();
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
public void onBackPressed() {
if(isDrawerOpen()) {
drawerLayout.closeDrawer(navDrawer);
} else {
super.onBackPressed();
}
}
private DBReader.NavDrawerData navDrawerData;
private int selectedNavListIndex = 0;
private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
if (navDrawerData != null) {
return navDrawerData.feeds.size();
} else {
return 0;
}
}
@Override
public Feed getItem(int position) {
if (navDrawerData != null && 0 <= position && position < navDrawerData.feeds.size()) {
return navDrawerData.feeds.get(position);
} else {
return null;
}
}
@Override
public int getSelectedItemIndex() {
return selectedNavListIndex;
}
@Override
public int getQueueSize() {
return (navDrawerData != null) ? navDrawerData.queueSize : 0;
}
@Override
public int getNumberOfNewItems() {
return (navDrawerData != null) ? navDrawerData.numNewItems : 0;
}
@Override
public int getNumberOfDownloadedItems() {
return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0;
}
@Override
public int getReclaimableItems() {
return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0;
}
@Override
public int getFeedCounter(long feedId) {
return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
}
@Override
public int getFeedCounterSum() {
if(navDrawerData == null) {
return 0;
}
int sum = 0;
for(int counter : navDrawerData.feedCounters.values()) {
sum += counter;
}
return sum;
}
};
private void loadData() {
subscription = Observable.fromCallable(DBReader::getNavDrawerData)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
boolean handleIntent = (navDrawerData == null);
navDrawerData = result;
navAdapter.notifyDataSetChanged();
if (handleIntent) {
handleNavIntent();
}
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
});
}
public void onEvent(QueueEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
// we are only interested in the number of queue items, not download status or position
if(event.action == QueueEvent.Action.DELETED_MEDIA ||
event.action == QueueEvent.Action.SORTED ||
event.action == QueueEvent.Action.MOVED) {
return;
}
loadData();
}
public void onEventMainThread(ProgressEvent event) {
Log.d(TAG, "onEvent(" + event + ")");
switch(event.action) {
case START:
pd = new ProgressDialog(this);
pd.setMessage(event.message);
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
break;
case END:
if(pd != null) {
pd.dismiss();
}
break;
}
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((EVENTS & arg) != 0) {
Log.d(TAG, "Received contentUpdate Intent.");
loadData();
}
}
};
private void handleNavIntent() {
Log.d(TAG, "handleNavIntent()");
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_FEED_ID) ||
(intent.hasExtra(EXTRA_NAV_TYPE) &&
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
int index = intent.getIntExtra(EXTRA_NAV_INDEX, -1);
String tag = intent.getStringExtra(EXTRA_FRAGMENT_TAG);
Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
long feedId = intent.getLongExtra(EXTRA_FEED_ID, 0);
if (index >= 0) {
loadFragment(index, args);
} else if (tag != null) {
loadFragment(tag, args);
} else if(feedId > 0) {
loadFeedFragmentById(feedId, args);
}
}
setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
}

View File

@ -1,592 +0,0 @@
package de.danoeh.antennapod.fragment;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GestureDetectorCompat;
import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
import org.apache.commons.lang3.ArrayUtils;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
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;
import de.danoeh.antennapod.view.OnSwipeGesture;
import de.danoeh.antennapod.view.SwipeGestureDetector;
import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Displays information about a FeedItem and actions.
*/
public class ItemFragment extends Fragment implements OnSwipeGesture {
private static final String TAG = "ItemFragment";
private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE;
private static final String ARG_FEEDITEMS = "feeditems";
private static final String ARG_FEEDITEM_POS = "feeditem_pos";
private GestureDetectorCompat headerGestureDetector;
private GestureDetectorCompat webviewGestureDetector;
/**
* Creates a new instance of an ItemFragment
*
* @param feeditem The ID of the FeedItem that should be displayed.
* @return The ItemFragment instance
*/
public static ItemFragment newInstance(long feeditem) {
return newInstance(new long[] { feeditem }, 0);
}
/**
* Creates a new instance of an ItemFragment
*
* @param feeditems The IDs of the FeedItems that belong to the same list
* @param feedItemPos The position of the FeedItem that is currently shown
* @return The ItemFragment instance
*/
public static ItemFragment newInstance(long[] feeditems, int feedItemPos) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putLongArray(ARG_FEEDITEMS, feeditems);
args.putInt(ARG_FEEDITEM_POS, feedItemPos);
fragment.setArguments(args);
return fragment;
}
private boolean itemsLoaded = false;
private long[] feedItems;
private int feedItemPos;
private FeedItem item;
private String webviewData;
private List<Downloader> downloaderList;
private ViewGroup root;
private WebView webvDescription;
private TextView txtvPodcast;
private TextView txtvTitle;
private TextView txtvDuration;
private TextView txtvPublished;
private ImageView imgvCover;
private ProgressBar progbarDownload;
private ProgressBar progbarLoading;
private IconButton butAction1;
private IconButton butAction2;
private Menu popupMenu;
private Subscription subscription;
/**
* URL that was selected via long-press.
*/
private String selectedURL;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
headerGestureDetector = new GestureDetectorCompat(getActivity(), new SwipeGestureDetector(this));
webviewGestureDetector = new GestureDetectorCompat(getActivity(), new SwipeGestureDetector(this) {
// necessary for the longclick context menu to work properly
@Override
public boolean onDown(MotionEvent e) {
return false;
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
root = (ViewGroup) layout.findViewById(R.id.content_root);
LinearLayout header = (LinearLayout) root.findViewById(R.id.header);
if(feedItems.length > 0) {
header.setOnTouchListener((v, event) -> headerGestureDetector.onTouchEvent(event));
}
txtvPodcast = (TextView) layout.findViewById(R.id.txtvPodcast);
txtvPodcast.setOnClickListener(v -> openPodcast());
txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
txtvTitle.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
}
webvDescription = (WebView) layout.findViewById(R.id.webvDescription);
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
if (Build.VERSION.SDK_INT >= 11
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webvDescription.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.black));
}
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(
WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webvDescription.getSettings().setLoadWithOverviewMode(true);
if(feedItems.length > 0) {
webvDescription.setOnLongClickListener(webViewLongClickListener);
}
webvDescription.setOnTouchListener((v, event) -> webviewGestureDetector.onTouchEvent(event));
webvDescription.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if(IntentUtils.isCallable(getActivity(), intent)) {
startActivity(intent);
}
return true;
}
});
registerForContextMenu(webvDescription);
imgvCover = (ImageView) layout.findViewById(R.id.imgvCover);
imgvCover.setOnClickListener(v -> openPodcast());
progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload);
progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
butAction1 = (IconButton) layout.findViewById(R.id.butAction1);
butAction2 = (IconButton) layout.findViewById(R.id.butAction2);
butAction1.setOnClickListener(v -> {
if (item == null) {
return;
}
DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
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
((MainActivity) getActivity()).dismissChildFragment();
}
});
butAction2.setOnClickListener(v -> {
if (item == null) {
return;
}
if (item.hasMedia()) {
FeedMedia media = item.getMedia();
if (!media.isDownloaded()) {
DBTasks.playMedia(getActivity(), media, true, true, true);
((MainActivity) getActivity()).dismissChildFragment();
} else {
DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId());
}
} else if (item.getLink() != null) {
Uri uri = Uri.parse(item.getLink());
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
});
return layout;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
load();
}
@Override
public void onResume() {
super.onResume();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().registerSticky(this);
if(itemsLoaded) {
progbarLoading.setVisibility(View.GONE);
updateAppearance();
}
}
@Override
public void onPause() {
super.onPause();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(subscription != null) {
subscription.unsubscribe();
}
if (webvDescription != null && root != null) {
root.removeView(webvDescription);
webvDescription.destroy();
}
}
@Override
public boolean onSwipeLeftToRight() {
Log.d(TAG, "onSwipeLeftToRight()");
feedItemPos = feedItemPos - 1;
if(feedItemPos < 0) {
feedItemPos = feedItems.length - 1;
}
load();
return true;
}
@Override
public boolean onSwipeRightToLeft() {
Log.d(TAG, "onSwipeRightToLeft()");
feedItemPos = (feedItemPos + 1) % feedItems.length;
load();
return true;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if(!isAdded() || item == null) {
return;
}
// ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
inflater.inflate(R.menu.feeditem_options, menu);
popupMenu = menu;
if (item.hasMedia()) {
FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null);
} else {
// these are already available via button1 and button2
FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, null,
R.id.mark_read_item, R.id.visit_website_item);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch(menuItem.getItemId()) {
case R.id.open_podcast:
openPodcast();
return true;
default:
try {
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
} catch (DownloadRequestException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
return true;
}
}
}
private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
@Override
public void setItemVisibility(int id, boolean visible) {
MenuItem item = popupMenu.findItem(id);
if (item != null) {
item.setVisible(visible);
}
}
};
private void onFragmentLoaded() {
if (webviewData != null) {
webvDescription.loadDataWithBaseURL(null, webviewData, "text/html", "utf-8", "about:blank");
}
updateAppearance();
}
private void updateAppearance() {
if (item == null) {
Log.d(TAG, "updateAppearance item is null");
return;
}
getActivity().supportInvalidateOptionsMenu();
txtvPodcast.setText(item.getFeed().getTitle());
txtvTitle.setText(item.getTitle());
if (item.getPubDate() != null) {
String pubDateStr = DateUtils.formatAbbrev(getActivity(), item.getPubDate());
txtvPublished.setText(pubDateStr);
}
Glide.with(getActivity())
.load(item.getImageLocation())
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.fitCenter()
.dontAnimate()
.into(imgvCover);
progbarDownload.setVisibility(View.GONE);
if (item.hasMedia() && downloaderList != null) {
for (Downloader downloader : downloaderList) {
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
&& downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
progbarDownload.setVisibility(View.VISIBLE);
progbarDownload.setProgress(downloader.getDownloadRequest().getProgressPercent());
}
}
}
FeedMedia media = item.getMedia();
String butAction1Icon = null;
int butAction1Text = 0;
String butAction2Icon = null;
int butAction2Text = 0;
if (media == null) {
if (!item.isPlayed()) {
butAction1Icon = "{fa-check 24sp}";
butAction1Text = R.string.mark_read_label;
}
if (item.getLink() != null) {
butAction2Icon = "{md-web 24sp}";
butAction2Text = R.string.visit_website_label;
}
} else {
if(media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
}
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
if (!media.isDownloaded()) {
butAction2Icon = "{md-settings-input-antenna 24sp}";
butAction2Text = R.string.stream_label;
} else {
butAction2Icon = "{md-delete 24sp}";
butAction2Text = R.string.remove_label;
}
if (isDownloading) {
butAction1Icon = "{md-cancel 24sp}";
butAction1Text = R.string.cancel_label;
} else if (media.isDownloaded()) {
butAction1Icon = "{md-play-arrow 24sp}";
butAction1Text = R.string.play_label;
} else {
butAction1Icon = "{md-file-download 24sp}";
butAction1Text = R.string.download_label;
}
}
if(butAction1Icon != null && butAction1Text != 0) {
butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
Iconify.addIcons(butAction1);
butAction1.setVisibility(View.VISIBLE);
} else {
butAction1.setVisibility(View.INVISIBLE);
}
if(butAction2Icon != null && butAction2Text != 0) {
butAction2.setText(butAction2Icon +"\u0020\u0020" + getActivity().getString(butAction2Text));
Iconify.addIcons(butAction2);
butAction2.setVisibility(View.VISIBLE);
} else {
butAction2.setVisibility(View.INVISIBLE);
}
}
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
WebView.HitTestResult r = webvDescription.getHitTestResult();
if (r != null
&& r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
selectedURL = r.getExtra();
webvDescription.showContextMenu();
return true;
}
selectedURL = null;
return false;
}
};
@Override
public boolean onContextItemSelected(MenuItem item) {
boolean handled = selectedURL != null;
if (selectedURL != null) {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
Uri uri = Uri.parse(selectedURL);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if(IntentUtils.isCallable(getActivity(), intent)) {
getActivity().startActivity(intent);
}
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
break;
case R.id.copy_url_item:
if (android.os.Build.VERSION.SDK_INT >= 11) {
ClipData clipData = ClipData.newPlainText(selectedURL,
selectedURL);
android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(clipData);
} else {
android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(selectedURL);
}
Toast t = Toast.makeText(getActivity(),
R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
break;
default:
handled = false;
break;
}
selectedURL = null;
}
return handled;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
if (selectedURL != null) {
super.onCreateContextMenu(menu, v, menuInfo);
Uri uri = Uri.parse(selectedURL);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if(IntentUtils.isCallable(getActivity(), intent)) {
menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
R.string.open_in_browser_label);
}
menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
R.string.copy_url_label);
menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
R.string.share_url_label);
menu.setHeaderTitle(selectedURL);
}
}
private void openPodcast() {
Fragment fragment = ItemlistFragment.newInstance(item.getFeedId());
((MainActivity)getActivity()).loadChildFragment(fragment);
}
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
for(FeedItem item : event.items) {
if(feedItems[feedItemPos] == item.getId()) {
load();
return;
}
}
}
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
if(item == null || item.getMedia() == null) {
return;
}
long mediaId = item.getMedia().getId();
if(ArrayUtils.contains(update.mediaIds, mediaId)) {
if (itemsLoaded && getActivity() != null) {
updateAppearance();
}
}
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
load();
}
}
};
private void load() {
if(subscription != null) {
subscription.unsubscribe();
}
progbarLoading.setVisibility(View.VISIBLE);
subscription = Observable.fromCallable(this::loadInBackground)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
progbarLoading.setVisibility(View.GONE);
item = result;
itemsLoaded = true;
onFragmentLoaded();
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
});
}
private FeedItem loadInBackground() {
FeedItem feedItem = DBReader.getFeedItem(feedItems[feedItemPos]);
if (feedItem != null) {
Timeline t = new Timeline(getActivity(), feedItem);
webviewData = t.processShownotes(false);
}
return feedItem;
}
}

View File

@ -0,0 +1,13 @@
package de.danoeh.antennapod.preferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
/**
* Implements functions from PreferenceController that are flavor dependent.
*/
public class PreferenceControllerHelper {
static void setupFlavoredUI(PreferenceController.PreferenceUI ui) {
ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setEnabled(false);
}
}

View File

@ -48,6 +48,7 @@ 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.core.util.Flavors;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.AddFeedFragment;
@ -507,21 +508,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:
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:
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;
return retVal;
}
} else {
return retVal;
}
}
@Override

View File

@ -39,6 +39,7 @@ 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.playback.MediaPlayerError;
@ -281,7 +282,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;

View File

@ -58,6 +58,7 @@ 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;
@ -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()) {

View File

@ -410,22 +410,7 @@ 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;
// });
PreferenceControllerHelper.setupFlavoredUI(ui);
buildEpisodeCleanupPreference();
buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference();

View File

@ -1,876 +0,0 @@
package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.bumptech.glide.Glide;
import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.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.Converter;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Provides general features which are both needed for playing audio and video
* files.
*/
public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener {
private static final String TAG = "MediaplayerActivity";
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
protected PlaybackController controller;
protected TextView txtvPosition;
protected TextView txtvLength;
protected SeekBar sbPosition;
protected ImageButton butRev;
protected TextView txtvRev;
protected ImageButton butPlay;
protected ImageButton butFF;
protected TextView txtvFF;
protected ImageButton butSkip;
protected boolean showTimeLeft = false;
private boolean isFavorite = false;
private PlaybackController newPlaybackController() {
return new PlaybackController(this, false) {
@Override
public void setupGUI() {
MediaplayerActivity.this.setupGUI();
}
@Override
public void onPositionObserverUpdate() {
MediaplayerActivity.this.onPositionObserverUpdate();
}
@Override
public void onBufferStart() {
MediaplayerActivity.this.onBufferStart();
}
@Override
public void onBufferEnd() {
MediaplayerActivity.this.onBufferEnd();
}
@Override
public void onBufferUpdate(float progress) {
MediaplayerActivity.this.onBufferUpdate(progress);
}
@Override
public void handleError(int code) {
MediaplayerActivity.this.handleError(code);
}
@Override
public void onReloadNotification(int code) {
MediaplayerActivity.this.onReloadNotification(code);
}
@Override
public void onSleepTimerUpdate() {
supportInvalidateOptionsMenu();
}
@Override
public ImageButton getPlayButton() {
return butPlay;
}
@Override
public void postStatusMsg(int msg, boolean showToast) {
MediaplayerActivity.this.postStatusMsg(msg, showToast);
}
@Override
public void clearStatusMsg() {
MediaplayerActivity.this.clearStatusMsg();
}
@Override
public boolean loadMediaInfo() {
return MediaplayerActivity.this.loadMediaInfo();
}
@Override
public void onAwaitingVideoSurface() {
MediaplayerActivity.this.onAwaitingVideoSurface();
}
@Override
public void onServiceQueried() {
MediaplayerActivity.this.onServiceQueried();
}
@Override
public void onShutdownNotification() {
finish();
}
@Override
public void onPlaybackEnd() {
finish();
}
@Override
public void onPlaybackSpeedChange() {
MediaplayerActivity.this.onPlaybackSpeedChange();
}
@Override
protected void setScreenOn(boolean enable) {
super.setScreenOn(enable);
MediaplayerActivity.this.setScreenOn(enable);
}
@Override
public void onSetSpeedAbilityChanged() {
MediaplayerActivity.this.onSetSpeedAbilityChanged();
}
};
}
protected void onSetSpeedAbilityChanged() {
Log.d(TAG, "onSetSpeedAbilityChanged()");
updatePlaybackSpeedButton();
}
protected void onPlaybackSpeedChange() {
updatePlaybackSpeedButtonText();
}
protected void onServiceQueried() {
supportInvalidateOptionsMenu();
}
protected void chooseTheme() {
setTheme(UserPreferences.getTheme());
}
protected void setScreenOn(boolean enable) {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
chooseTheme();
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
StorageUtils.checkStorageAvailability(this);
orientation = getResources().getConfiguration().orientation;
getWindow().setFormat(PixelFormat.TRANSPARENT);
}
@Override
protected void onPause() {
if(controller != null) {
controller.reinitServiceIfPaused();
controller.pause();
}
super.onPause();
}
/**
* Should be used to switch to another player activity if the mime type is
* not the correct one for the current activity.
*/
protected abstract void onReloadNotification(int notificationCode);
/**
* Should be used to inform the user that the PlaybackService is currently
* buffering.
*/
protected abstract void onBufferStart();
/**
* Should be used to hide the view that was showing the 'buffering'-message.
*/
protected abstract void onBufferEnd();
protected void onBufferUpdate(float progress) {
if (sbPosition != null) {
sbPosition.setSecondaryProgress((int) progress * sbPosition.getMax());
}
}
/**
* Current screen orientation.
*/
protected int orientation;
@Override
protected void onStart() {
super.onStart();
if (controller != null) {
controller.release();
}
controller = newPlaybackController();
}
@Override
protected void onStop() {
Log.d(TAG, "onStop()");
if (controller != null) {
controller.release();
controller = null; // prevent leak
}
super.onStop();
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Glide.get(this).trimMemory(level);
}
@Override
public void onLowMemory() {
super.onLowMemory();
Glide.get(this).clearMemory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mediaplayer, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if (controller == null) {
return false;
}
Playable media = controller.getMedia();
menu.findItem(R.id.support_item).setVisible(
media != null && media.getPaymentLink() != null &&
(media instanceof FeedMedia) &&
((FeedMedia) media).getItem() != null &&
((FeedMedia) media).getItem().getFlattrStatus().flattrable()
);
boolean hasWebsiteLink = media != null && media.getWebsiteLink() != null;
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
boolean isItemAndHasLink = media != null && (media instanceof FeedMedia) &&
((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;
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_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) {
menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
}
boolean sleepTimerSet = controller.sleepTimerActive();
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
if (this instanceof AudioplayerActivity) {
int[] attrs = {R.attr.action_bar_icon_color};
TypedArray ta = obtainStyledAttributes(UserPreferences.getTheme(), attrs);
int textColor = ta.getColor(0, Color.GRAY);
ta.recycle();
menu.findItem(R.id.audio_controls).setIcon(new IconDrawable(this,
FontAwesomeIcons.fa_sliders).color(textColor).actionBarSize());
} else {
menu.findItem(R.id.audio_controls).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (controller == null) {
return false;
}
Playable media = controller.getMedia();
if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(MediaplayerActivity.this,
MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
} else {
if (media != null) {
switch (item.getItemId()) {
case R.id.add_to_favorites_item:
if(media instanceof FeedMedia) {
FeedItem feedItem = ((FeedMedia)media).getItem();
if(feedItem != null) {
DBWriter.addFavoriteItem(feedItem);
isFavorite = true;
invalidateOptionsMenu();
Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
.show();
}
}
break;
case R.id.remove_from_favorites_item:
if(media instanceof FeedMedia) {
FeedItem feedItem = ((FeedMedia)media).getItem();
if(feedItem != null) {
DBWriter.removeFavoriteItem(feedItem);
isFavorite = false;
invalidateOptionsMenu();
Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
.show();
}
}
break;
case R.id.disable_sleeptimer_item:
if (controller.serviceAvailable()) {
MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
stDialog.title(R.string.sleep_timer_label);
stDialog.content(getString(R.string.time_left_label)
+ Converter.getDurationStringLong((int) controller
.getSleepTimerTimeLeft()));
stDialog.positiveText(R.string.disable_sleeptimer_label);
stDialog.negativeText(R.string.cancel_label);
stDialog.onPositive((dialog, which) -> {
dialog.dismiss();
controller.disableSleepTimer();
});
stDialog.onNegative((dialog, which) -> dialog.dismiss());
stDialog.build().show();
}
break;
case R.id.set_sleeptimer_item:
if (controller.serviceAvailable()) {
SleepTimerDialog td = new SleepTimerDialog(this) {
@Override
public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
controller.setSleepTimer(millis, shakeToReset, vibrate);
}
};
td.createNewDialog().show();
}
break;
case R.id.audio_controls:
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title(R.string.audio_controls)
.customView(R.layout.audio_controls, true)
.neutralText(R.string.close_label)
.onNeutral((dialog1, which) -> {
final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
UserPreferences.setVolume(left.getProgress(), right.getProgress());
})
.show();
final SeekBar barPlaybackSpeed = (SeekBar) dialog.findViewById(R.id.playback_speed);
final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
butDecSpeed.setOnClickListener(v -> {
if(controller != null && controller.canSetPlaybackSpeed()) {
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
} else {
VariableSpeedDialog.showGetPluginDialog(this);
}
});
final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
butIncSpeed.setOnClickListener(v -> {
if(controller != null && controller.canSetPlaybackSpeed()) {
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
} else {
VariableSpeedDialog.showGetPluginDialog(this);
}
});
final TextView txtvPlaybackSpeed = (TextView) dialog.findViewById(R.id.txtvPlaybackSpeed);
float currentSpeed = 1.0f;
try {
currentSpeed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
} catch (NumberFormatException e) {
Log.e(TAG, Log.getStackTraceString(e));
UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
}
txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(controller != null && controller.canSetPlaybackSpeed()) {
float playbackSpeed = (progress + 10) / 20.0f;
controller.setPlaybackSpeed(playbackSpeed);
String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
UserPreferences.setPlaybackSpeed(speedPref);
String speedStr = String.format("%.2fx", playbackSpeed);
txtvPlaybackSpeed.setText(speedStr);
} else if(fromUser) {
float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress((int) (20 * speed) - 10));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if(controller != null && !controller.canSetPlaybackSpeed()) {
VariableSpeedDialog.showGetPluginDialog(MediaplayerActivity.this);
}
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
stereoToMono.setChecked(UserPreferences.stereoToMono());
if (controller != null && !controller.canDownmix()) {
stereoToMono.setEnabled(false);
String sonicOnly = getString(R.string.sonic_only);
stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
}
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
controller.setVolume(
Converter.getVolumeFromPercentage(progress),
Converter.getVolumeFromPercentage(barRightVolume.getProgress()));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
controller.setVolume(
Converter.getVolumeFromPercentage(barLeftVolume.getProgress()),
Converter.getVolumeFromPercentage(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
stereoToMono.setOnCheckedChangeListener((buttonView, isChecked) -> {
UserPreferences.stereoToMono(isChecked);
if (controller != null) {
controller.setDownmix(isChecked);
}
});
break;
case R.id.visit_website_item:
Uri uri = Uri.parse(media.getWebsiteLink());
startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
case R.id.support_item:
if (media instanceof FeedMedia) {
DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
}
break;
case R.id.share_link_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
}
break;
case R.id.share_download_url_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
}
break;
case R.id.share_link_with_position_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
}
break;
case R.id.share_download_url_with_position_item:
if (media instanceof FeedMedia) {
ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
}
break;
default:
return false;
}
return true;
} else {
return false;
}
}
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume()");
StorageUtils.checkStorageAvailability(this);
if(controller != null) {
controller.init();
}
}
/**
* Called by 'handleStatus()' when the PlaybackService is waiting for
* a video surface.
*/
protected abstract void onAwaitingVideoSurface();
protected abstract void postStatusMsg(int resId, boolean showToast);
protected abstract void clearStatusMsg();
protected void onPositionObserverUpdate() {
if (controller == null || txtvPosition == null || txtvLength == null) {
return;
}
int currentPosition = controller.getPosition();
int duration = controller.getDuration();
Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
if (currentPosition == PlaybackService.INVALID_TIME ||
duration == PlaybackService.INVALID_TIME) {
Log.w(TAG, "Could not react to position observer update because of invalid time");
return;
}
txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
if (showTimeLeft) {
txtvLength.setText("-" + Converter.getDurationStringLong(duration - currentPosition));
} else {
txtvLength.setText(Converter.getDurationStringLong(duration));
}
updateProgressbarPosition(currentPosition, duration);
}
private void updateProgressbarPosition(int position, int duration) {
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
if(sbPosition == null) {
return;
}
float progress = ((float) position) / duration;
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
/**
* Load information about the media that is going to be played or currently
* being played. This method will be called when the activity is connected
* to the PlaybackService to ensure that the activity has the right
* FeedMedia object.
*/
protected boolean loadMediaInfo() {
Log.d(TAG, "loadMediaInfo()");
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;
}
}
protected void updatePlaybackSpeedButton() {
// Only meaningful on AudioplayerActivity, where it is overridden.
}
protected void updatePlaybackSpeedButtonText() {
// Only meaningful on AudioplayerActivity, where it is overridden.
}
protected void setupGUI() {
setContentView(getContentViewResourceId());
sbPosition = (SeekBar) findViewById(R.id.sbPosition);
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
Log.d("timeleft", showTimeLeft ? "true" : "false");
txtvLength = (TextView) findViewById(R.id.txtvLength);
if (txtvLength != null) {
txtvLength.setOnClickListener(v -> {
showTimeLeft = !showTimeLeft;
Playable media = controller.getMedia();
if (media == null) {
return;
}
String length;
if (showTimeLeft) {
length = "-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition());
} else {
length = Converter.getDurationStringLong(media.getDuration());
}
txtvLength.setText(length);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft);
editor.apply();
Log.d("timeleft on click", showTimeLeft ? "true" : "false");
});
}
butRev = (ImageButton) findViewById(R.id.butRev);
txtvRev = (TextView) findViewById(R.id.txtvRev);
if (txtvRev != null) {
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
}
butPlay = (ImageButton) findViewById(R.id.butPlay);
butFF = (ImageButton) findViewById(R.id.butFF);
txtvFF = (TextView) findViewById(R.id.txtvFF);
if (txtvFF != null) {
txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs()));
}
butSkip = (ImageButton) findViewById(R.id.butSkip);
// SEEKBAR SETUP
sbPosition.setOnSeekBarChangeListener(this);
// BUTTON SETUP
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;
}
});
}
butPlay.setOnClickListener(v -> onPlayPause());
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;
}
});
}
if (butSkip != null) {
butSkip.setOnClickListener(v -> sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE)));
}
}
protected void onRewind() {
if (controller == null) {
return;
}
int curr = controller.getPosition();
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
}
protected void onPlayPause() {
if(controller == null) {
return;
}
controller.playPause();
}
protected void onFastForward() {
if (controller == null) {
return;
}
int curr = controller.getPosition();
controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
}
protected abstract int getContentViewResourceId();
void handleError(int errorCode) {
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
errorDialog.setTitle(R.string.error_label);
errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
errorDialog.setNeutralButton("OK",
(dialog, which) -> {
dialog.dismiss();
finish();
}
);
errorDialog.create().show();
}
float prog;
@Override
public void onProgressChanged (SeekBar seekBar,int progress, boolean fromUser) {
if (controller == null || txtvLength == null) {
return;
}
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
if (showTimeLeft && prog != 0) {
int duration = controller.getDuration();
String length = "-" + Converter.getDurationStringLong(duration - (int) (prog * duration));
txtvLength.setText(length);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (controller != null) {
controller.onSeekBarStartTrackingTouch(seekBar);
}
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (controller != null) {
controller.onSeekBarStopTrackingTouch(seekBar, prog);
}
}
private void checkFavorite() {
Playable playable = controller.getMedia();
if (playable != null && playable instanceof FeedMedia) {
FeedItem feedItem = ((FeedMedia) playable).getItem();
if (feedItem != null) {
Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
item -> {
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
if (isFavorite != isFav) {
isFavorite = isFav;
invalidateOptionsMenu();
}
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
}
);
}
}
}
}

View File

@ -1,953 +0,0 @@
package de.danoeh.antennapod.preferences;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.TimePickerDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import android.widget.ListView;
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;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AboutActivity;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
import de.danoeh.antennapod.activity.StatisticsActivity;
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.GpodnetSyncService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
import de.danoeh.antennapod.dialog.ProxyDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
/**
* Sets up a preference UI that lets the user change user preferences.
*/
public class PreferenceController implements SharedPreferences.OnSharedPreferenceChangeListener {
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[] EXTERNAL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
public PreferenceController(PreferenceUI ui) {
this.ui = ui;
PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext())
.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<? extends Activity> getPreferenceActivity() {
if (Build.VERSION.SDK_INT > 10) {
return PreferenceActivity.class;
} else {
return PreferenceActivityGingerbread.class;
}
}
public void onCreate() {
final Activity activity = ui.getActivity();
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// disable expanded notification option on unsupported android versions
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setEnabled(false);
ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener(
preference -> {
Toast toast = Toast.makeText(activity,
R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT);
toast.show();
return true;
}
);
}
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
preference -> {
FlattrUtils.revokeAccessToken(activity);
checkItemVisibility();
return true;
}
);
ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
preference -> {
activity.startActivity(new Intent(activity, AboutActivity.class));
return true;
}
);
ui.findPreference(PreferenceController.STATISTICS).setOnPreferenceClickListener(
preference -> {
activity.startActivity(new Intent(activity, StatisticsActivity.class));
return true;
}
);
ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener(
preference -> {
new OpmlExportWorker(activity).executeAsync();
return true;
}
);
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
preference -> {
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
showChooseDataFolderDialog();
} else {
int readPermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (readPermission == PackageManager.PERMISSION_GRANTED &&
writePermission == PackageManager.PERMISSION_GRANTED) {
openDirectoryChooser();
} else {
requestPermission();
}
}
return true;
}
);
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
.setOnPreferenceClickListener(
preference -> {
if (Build.VERSION.SDK_INT >= 19) {
showChooseDataFolderDialog();
} else {
Intent intent = new Intent(activity, DirectoryChooserActivity.class);
activity.startActivityForResult(intent,
DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
return true;
}
);
ui.findPreference(UserPreferences.PREF_THEME)
.setOnPreferenceChangeListener(
(preference, newValue) -> {
Intent i = new Intent(activity, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
activity.finish();
activity.startActivity(i);
return true;
}
);
ui.findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)
.setOnPreferenceClickListener(preference -> {
showDrawerPreferencesDialog();
return true;
});
ui.findPreference(UserPreferences.PREF_COMPACT_NOTIFICATION_BUTTONS)
.setOnPreferenceClickListener(preference -> {
showNotificationButtonsDialog();
return true;
});
ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
.setOnPreferenceClickListener(preference -> {
showUpdateIntervalTimePreferencesDialog();
return true;
});
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener(
(preference, newValue) -> {
if (newValue instanceof Boolean) {
boolean enabled = (Boolean) newValue;
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(enabled);
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(enabled);
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(enabled);
setSelectedNetworksEnabled(enabled && UserPreferences.isEnableAutodownloadWifiFilter());
}
return true;
});
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
.setOnPreferenceChangeListener(
(preference, newValue) -> {
if (newValue instanceof Boolean) {
setSelectedNetworksEnabled((Boolean) newValue);
return true;
} else {
return false;
}
}
);
ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
.setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
try {
int value = Integer.parseInt((String) o);
if (1 <= value && value <= 50) {
setParallelDownloadsText(value);
return true;
}
} catch (NumberFormatException e) {
return false;
}
}
return false;
}
);
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
final EditText ev = ((EditTextPreference) ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
ev.addTextChangedListener(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) {
if (s.length() > 0) {
try {
int value = Integer.parseInt(s.toString());
if (value <= 0) {
ev.setText("1");
} else if (value > 50) {
ev.setText("50");
}
} catch (NumberFormatException e) {
ev.setText("6");
}
ev.setSelection(ev.getText().length());
}
}
});
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
.setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o));
}
return true;
}
);
ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER)
.setOnPreferenceClickListener(preference -> {
VariableSpeedDialog.showDialog(activity);
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION)
.setOnPreferenceClickListener(preference -> {
AuthenticationDialog dialog = new AuthenticationDialog(activity,
R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(),
null) {
@Override
protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
GpodnetPreferences.setPassword(password);
}
};
dialog.show();
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).
setOnPreferenceClickListener(preference -> {
GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext());
Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started,
Toast.LENGTH_SHORT);
toast.show();
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
preference -> {
GpodnetPreferences.logout();
Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT);
toast.show();
updateGpodnetPreferenceScreen();
return true;
});
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(
preference -> {
GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
return true;
});
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
.setOnPreferenceClickListener(preference -> {
AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
@Override
public void onCancelled() {
}
@Override
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
checkItemVisibility();
}
});
return true;
});
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
int newValue = Integer.parseInt((String) o) * 1024 * 1024;
if (newValue != UserPreferences.getImageCacheSize()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
dialog.setTitle(android.R.string.dialog_alert_title);
dialog.setMessage(R.string.pref_restart_required);
dialog.setPositiveButton(android.R.string.ok, null);
dialog.show();
}
return true;
}
return false;
}
);
ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
ProxyDialog dialog = new ProxyDialog(ui.getActivity());
dialog.createDialog().show();
return true;
});
ui.findPreference(PREF_KNOWN_ISSUES).setOnPreferenceClickListener(preference -> {
openInBrowser("https://github.com/AntennaPod/AntennaPod/labels/bug");
return true;
});
ui.findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> {
openInBrowser("http://antennapod.org/faq.html");
return true;
});
ui.findPreference(PREF_SEND_CRASH_REPORT).setOnPreferenceClickListener(preference -> {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"Martin.Fietz@gmail.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe what you were doing when the app crashed");
// the attachment
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(CrashReportWriter.getFile()));
String intentTitle = ui.getActivity().getString(R.string.send_email);
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;
});
buildEpisodeCleanupPreference();
buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference();
setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
}
private void openInBrowser(String url) {
try {
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
ui.getActivity().startActivity(myIntent);
} catch (ActivityNotFoundException e) {
Toast.makeText(ui.getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}
public void onResume() {
checkItemVisibility();
setUpdateIntervalText();
setParallelDownloadsText(UserPreferences.getParallelDownloads());
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
setDataFolderText();
updateGpodnetPreferenceScreen();
}
@SuppressLint("NewApi")
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK &&
requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
if(dir != null) {
path = new File(dir);
} else {
path = ui.getActivity().getExternalFilesDir(null);
}
String message = null;
final Context context= ui.getActivity().getApplicationContext();
if(!path.exists()) {
message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
} else if(!path.canRead()) {
message = String.format(context.getString(R.string.folder_not_readable_error), dir);
} else if(!path.canWrite()) {
message = String.format(context.getString(R.string.folder_not_writable_error), dir);
}
if(message == null) {
Log.d(TAG, "Setting data folder: " + dir);
UserPreferences.setDataFolder(dir);
setDataFolderText();
} else {
AlertDialog.Builder ab = new AlertDialog.Builder(ui.getActivity());
ab.setMessage(message);
ab.setPositiveButton(android.R.string.ok, null);
ab.show();
}
}
}
private void updateGpodnetPreferenceScreen() {
final boolean loggedIn = GpodnetPreferences.loggedIn();
ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).setEnabled(loggedIn);
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
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));
} else {
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setSummary(null);
}
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
}
private String[] getUpdateIntervalEntries(final String[] values) {
final Resources res = ui.getActivity().getResources();
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
Integer v = Integer.parseInt(values[x]);
switch (v) {
case 0:
entries[x] = res.getString(R.string.pref_update_interval_hours_manual);
break;
case 1:
entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_singular);
break;
default:
entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_plural);
break;
}
}
return entries;
}
private void buildEpisodeCleanupPreference() {
final Resources res = ui.getActivity().getResources();
ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_EPISODE_CLEANUP);
String[] values = res.getStringArray(
R.array.episode_cleanup_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
int v = Integer.parseInt(values[x]);
if (v == UserPreferences.EPISODE_CLEANUP_QUEUE) {
entries[x] = res.getString(R.string.episode_cleanup_queue_removal);
} else if (v == UserPreferences.EPISODE_CLEANUP_NULL){
entries[x] = res.getString(R.string.episode_cleanup_never);
} else if (v == 0) {
entries[x] = res.getString(R.string.episode_cleanup_after_listening);
} else {
entries[x] = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, v, v);
}
}
pref.setEntries(entries);
}
private void buildSmartMarkAsPlayedPreference() {
final Resources res = ui.getActivity().getResources();
ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS);
String[] values = res.getStringArray(R.array.smart_mark_as_played_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
if(x == 0) {
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
} else {
Integer v = Integer.parseInt(values[x]);
if(v < 60) {
entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v);
} else {
v /= 60;
entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v);
}
}
}
pref.setEntries(entries);
}
private void setSelectedNetworksEnabled(boolean b) {
if (selectedNetworks != null) {
for (Preference p : selectedNetworks) {
p.setEnabled(b);
}
}
}
@SuppressWarnings("deprecation")
private void checkItemVisibility() {
boolean hasFlattrToken = FlattrUtils.hasToken();
ui.findPreference(PreferenceController.PREF_FLATTR_SETTINGS).setEnabled(FlattrUtils.hasAPICredentials());
ui.findPreference(PreferenceController.PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setEnabled(hasFlattrToken);
boolean autoDownload = UserPreferences.isEnableAutodownload();
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(autoDownload);
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(autoDownload);
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(autoDownload);
setSelectedNetworksEnabled(autoDownload && UserPreferences.isEnableAutodownloadWifiFilter());
ui.findPreference(PREF_SEND_CRASH_REPORT).setEnabled(CrashReportWriter.getFile().exists());
if (Build.VERSION.SDK_INT >= 16) {
ui.findPreference(UserPreferences.PREF_SONIC).setEnabled(true);
} else {
Preference prefSonic = ui.findPreference(UserPreferences.PREF_SONIC);
prefSonic.setSummary("[Android 4.1+]\n" + prefSonic.getSummary());
}
}
private void setUpdateIntervalText() {
Context context = ui.getActivity().getApplicationContext();
String val;
long interval = UserPreferences.getUpdateInterval();
if(interval > 0) {
int hours = (int) TimeUnit.MILLISECONDS.toHours(interval);
String hoursStr = context.getResources().getQuantityString(R.plurals.time_hours_quantified, hours, hours);
val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_every), hoursStr);
} else {
int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
if(timeOfDay.length == 2) {
Calendar cal = new GregorianCalendar();
cal.set(Calendar.HOUR_OF_DAY, timeOfDay[0]);
cal.set(Calendar.MINUTE, timeOfDay[1]);
String timeOfDayStr = DateFormat.getTimeFormat(context).format(cal.getTime());
val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_at),
timeOfDayStr);
} else {
val = context.getString(R.string.pref_smart_mark_as_played_disabled);
}
}
String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n"
+ String.format(context.getString(R.string.pref_current_value), val);
ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary);
}
private void setParallelDownloadsText(int downloads) {
final Resources res = ui.getActivity().getResources();
String s = Integer.toString(downloads)
+ res.getString(R.string.parallel_downloads_suffix);
ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s);
}
private void setEpisodeCacheSizeText(int cacheSize) {
final Resources res = ui.getActivity().getResources();
String s;
if (cacheSize == res.getInteger(
R.integer.episode_cache_size_unlimited)) {
s = res.getString(R.string.pref_episode_cache_unlimited);
} else {
s = Integer.toString(cacheSize)
+ res.getString(R.string.episodes_suffix);
}
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(s);
}
private void setDataFolderText() {
File f = UserPreferences.getDataFolder(null);
if (f != null) {
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
.setSummary(f.getAbsolutePath());
}
}
private void buildAutodownloadSelectedNetworsPreference() {
final Activity activity = ui.getActivity();
if (selectedNetworks != null) {
clearAutodownloadSelectedNetworsPreference();
}
// get configured networks
WifiManager wifiservice = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
if (networks != null) {
selectedNetworks = new CheckBoxPreference[networks.size()];
List<String> prefValues = Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks());
PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
Preference.OnPreferenceClickListener clickListener = preference -> {
if (preference instanceof CheckBoxPreference) {
String key = preference.getKey();
List<String> prefValuesList = new ArrayList<>(
Arrays.asList(UserPreferences
.getAutodownloadSelectedNetworks())
);
boolean newValue = ((CheckBoxPreference) preference)
.isChecked();
Log.d(TAG, "Selected network " + key + ". New state: " + newValue);
int index = prefValuesList.indexOf(key);
if (index >= 0 && !newValue) {
// remove network
prefValuesList.remove(index);
} else if (index < 0 && newValue) {
prefValuesList.add(key);
}
UserPreferences.setAutodownloadSelectedNetworks(
prefValuesList.toArray(new String[prefValuesList.size()])
);
return true;
} else {
return false;
}
};
// create preference for each known network. attach listener and set
// value
for (int i = 0; i < networks.size(); i++) {
WifiConfiguration config = networks.get(i);
CheckBoxPreference pref = new CheckBoxPreference(activity);
String key = Integer.toString(config.networkId);
pref.setTitle(config.SSID);
pref.setKey(key);
pref.setOnPreferenceClickListener(clickListener);
pref.setPersistent(false);
pref.setChecked(prefValues.contains(key));
selectedNetworks[i] = pref;
prefScreen.addPreference(pref);
}
} else {
Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
}
}
private void clearAutodownloadSelectedNetworsPreference() {
if (selectedNetworks != null) {
PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN);
for (CheckBoxPreference network : selectedNetworks) {
if (network != null) {
prefScreen.removePreference(network);
}
}
}
}
private void showDrawerPreferencesDialog() {
final Context context = ui.getActivity();
final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
final String[] navTitles = context.getResources().getStringArray(R.array.nav_drawer_titles);
final String[] NAV_DRAWER_TAGS = MainActivity.NAV_DRAWER_TAGS;
boolean[] checked = new boolean[MainActivity.NAV_DRAWER_TAGS.length];
for(int i=0; i < NAV_DRAWER_TAGS.length; i++) {
String tag = NAV_DRAWER_TAGS[i];
if(!hiddenDrawerItems.contains(tag)) {
checked[i] = true;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.drawer_preferences);
builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> {
if (isChecked) {
hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
} else {
hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
}
});
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
}
private void showNotificationButtonsDialog() {
final Context context = ui.getActivity();
final List<Integer> preferredButtons = UserPreferences.getCompactNotificationButtons();
final String[] allButtonNames = context.getResources().getStringArray(
R.array.compact_notification_buttons_options);
boolean[] checked = new boolean[allButtonNames.length]; // booleans default to false in java
for(int i=0; i < checked.length; i++) {
if(preferredButtons.contains(i)) {
checked[i] = true;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(String.format(context.getResources().getString(
R.string.pref_compact_notification_buttons_dialog_title), 2));
builder.setMultiChoiceItems(allButtonNames, checked, (dialog, which, isChecked) -> {
checked[which] = isChecked;
if (isChecked) {
if (preferredButtons.size() < 2) {
preferredButtons.add(which);
} else {
// Only allow a maximum of two selections. This is because the notification
// on the lock screen can only display 3 buttons, and the play/pause button
// is always included.
checked[which] = false;
ListView selectionView = ((AlertDialog) dialog).getListView();
selectionView.setItemChecked(which, false);
Snackbar.make(
selectionView,
String.format(context.getResources().getString(
R.string.pref_compact_notification_buttons_dialog_error), 2),
Snackbar.LENGTH_SHORT).show();
}
} else {
preferredButtons.remove((Integer) which);
}
});
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
UserPreferences.setCompactNotificationButtons(preferredButtons);
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.create().show();
}
// CHOOSE DATA FOLDER
private void requestPermission() {
ActivityCompat.requestPermissions(ui.getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
PERMISSION_REQUEST_EXTERNAL_STORAGE);
}
private void openDirectoryChooser() {
Activity activity = ui.getActivity();
Intent intent = new Intent(activity, DirectoryChooserActivity.class);
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
private void showChooseDataFolderDialog() {
Context context = ui.getActivity();
File dataFolder = UserPreferences.getDataFolder(null);
if(dataFolder == null) {
new MaterialDialog.Builder(ui.getActivity())
.title(R.string.error_label)
.content(R.string.external_storage_error_msg)
.neutralText(android.R.string.ok)
.show();
return;
}
String dataFolderPath = dataFolder.getAbsolutePath();
int selectedIndex = -1;
File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
List<String> folders = new ArrayList<>(mediaDirs.length);
List<CharSequence> choices = new ArrayList<>(mediaDirs.length);
for(int i=0; i < mediaDirs.length; i++) {
File dir = mediaDirs[i];
if(dir == null || !dir.exists() || !dir.canRead() || !dir.canWrite()) {
continue;
}
String path = mediaDirs[i].getAbsolutePath();
folders.add(path);
if(dataFolderPath.equals(path)) {
selectedIndex = i;
}
int index = path.indexOf("Android");
String choice;
if(index >= 0) {
choice = path.substring(0, index);
} else {
choice = path;
}
long bytes = StorageUtils.getFreeSpaceAvailable(path);
String freeSpace = String.format(context.getString(R.string.free_space_label),
Converter.byteToString(bytes));
choices.add(Html.fromHtml("<html><small>" + choice
+ " [" + freeSpace + "]" + "</small></html>"));
}
if(choices.size() == 0) {
new MaterialDialog.Builder(ui.getActivity())
.title(R.string.error_label)
.content(R.string.external_storage_error_msg)
.neutralText(android.R.string.ok)
.show();
return;
}
MaterialDialog dialog = new MaterialDialog.Builder(ui.getActivity())
.title(R.string.choose_data_directory)
.content(R.string.choose_data_directory_message)
.items(choices.toArray(new CharSequence[choices.size()]))
.itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> {
String folder = folders.get(which);
Log.d(TAG, "data folder: " + folder);
UserPreferences.setDataFolder(folder);
setDataFolderText();
return true;
})
.negativeText(R.string.cancel_label)
.cancelable(true)
.build();
dialog.show();
}
// UPDATE TIME/INTERVAL DIALOG
private void showUpdateIntervalTimePreferencesDialog() {
final Context context = ui.getActivity();
MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
builder.title(R.string.pref_autoUpdateIntervallOrTime_title);
builder.content(R.string.pref_autoUpdateIntervallOrTime_message);
builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval);
builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay);
builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable);
builder.onPositive((dialog, which) -> {
AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
final String[] entries = getUpdateIntervalEntries(values);
long currInterval = UserPreferences.getUpdateInterval();
int checkedItem = -1;
if(currInterval > 0) {
String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval));
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
int hours = Integer.parseInt(values[which1]);
UserPreferences.setUpdateInterval(hours);
dialog1.dismiss();
setUpdateIntervalText();
});
builder1.setNegativeButton(context.getString(R.string.cancel_label), null);
builder1.show();
});
builder.onNegative((dialog, which) -> {
int hourOfDay = 7, minute = 0;
int[] updateTime = UserPreferences.getUpdateTimeOfDay();
if (updateTime.length == 2) {
hourOfDay = updateTime[0];
minute = updateTime[1];
}
TimePickerDialog timePickerDialog = new TimePickerDialog(context,
(view, selectedHourOfDay, selectedMinute) -> {
if (view.getTag() == null) { // onTimeSet() may get called twice!
view.setTag("TAGGED");
UserPreferences.setUpdateTimeOfDay(selectedHourOfDay, selectedMinute);
setUpdateIntervalText();
}
}, hourOfDay, minute, DateFormat.is24HourFormat(context));
timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
timePickerDialog.show();
});
builder.onNeutral((dialog, which) -> {
UserPreferences.setUpdateInterval(0);
setUpdateIntervalText();
});
builder.show();
}
public interface PreferenceUI {
/**
* Finds a preference based on its key.
*/
Preference findPreference(CharSequence key);
Activity getActivity();
}
}

View File

@ -0,0 +1,31 @@
package de.danoeh.antennapod.preferences;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import de.danoeh.antennapod.core.preferences.UserPreferences;
/**
* Implements functions from PreferenceController that are flavor dependent.
*/
public class PreferenceControllerHelper {
static void setupFlavoredUI(PreferenceController.PreferenceUI ui) {
//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;
});
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pref_cast_message">@string/pref_cast_message_free_flavor</string>
</resources>

View File

@ -402,7 +402,8 @@
<string name="pref_known_issues">Known issues</string>
<string name="pref_no_browser_found">No web browser found.</string>
<string name="pref_cast_title">Chromecast support</string>
<string name="pref_cast_message">Enable support for remote media playback on Cast devices (such as Chromecast, Audio Speakers or Android TV)</string>
<string name="pref_cast_message_play_flavor">Enable support for remote media playback on Cast devices (such as Chromecast, Audio Speakers or Android TV)</string>
<string name="pref_cast_message_free_flavor">Chromecast requires third party proprietary libraries that are disabled in this version of AntennaPod</string>
<!-- Auto-Flattr dialog -->
<string name="auto_flattr_enable">Enable automatic flattring</string>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pref_cast_message">@string/pref_cast_message_play_flavor</string>
</resources>