diff options
author | Tom Hennen <TomHennen@users.noreply.github.com> | 2016-01-21 16:27:04 -0500 |
---|---|---|
committer | Tom Hennen <TomHennen@users.noreply.github.com> | 2016-01-21 16:27:04 -0500 |
commit | 1e90f1822d55562a3965ac1ae9b68f6444330bf7 (patch) | |
tree | 571c7de0bc0a278fdc5aec1b1bc5cf525528db84 /app/src/main/java/de/danoeh | |
parent | 8ffe2caf3351d8000454ee6fda884e8ae001be0a (diff) | |
parent | 9f9ddad685e4291376fca35b420c07475571b789 (diff) | |
download | AntennaPod-1e90f1822d55562a3965ac1ae9b68f6444330bf7.zip |
Merge pull request #1561 from mfietz/redesign_audio_player
Audio player redesign (Part 2)
Diffstat (limited to 'app/src/main/java/de/danoeh')
11 files changed, 998 insertions, 1125 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java index 835ac29cd..50d557735 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -1,54 +1,43 @@ package de.danoeh.antennapod.activity; +import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.graphics.drawable.BitmapDrawable; -import android.os.Bundle; +import android.os.Build; +import android.support.design.widget.AppBarLayout; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.ListFragment; +import android.support.v4.view.ViewPager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; +import android.util.TypedValue; import android.view.ContextMenu; -import android.view.Gravity; -import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; -import android.view.animation.LinearInterpolator; -import android.view.animation.ScaleAnimation; import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.ImageButton; import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.SeekBar; -import android.widget.TextView; -import com.bumptech.glide.Glide; +import com.viewpagerindicator.CirclePageIndicator; -import org.apache.commons.lang3.ArrayUtils; +import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.adapter.ChapterListAdapter; +import de.danoeh.antennapod.adapter.ChaptersListAdapter; import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; -import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; -import de.danoeh.antennapod.core.feed.SimpleChapter; -import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.service.playback.PlayerStatus; @@ -57,8 +46,14 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.playback.ExternalMedia; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.fragment.AddFeedFragment; +import de.danoeh.antennapod.fragment.ChaptersFragment; import de.danoeh.antennapod.fragment.CoverFragment; +import de.danoeh.antennapod.fragment.DownloadsFragment; +import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.ItemDescriptionFragment; +import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; +import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; import de.danoeh.antennapod.preferences.PreferenceController; import rx.Observable; @@ -69,85 +64,38 @@ import rx.schedulers.Schedulers; /** * Activity for playing audio files. */ -public class AudioplayerActivity extends MediaplayerActivity implements ItemDescriptionFragment.ItemDescriptionFragmentCallback, - NavDrawerActivity { +public class AudioplayerActivity extends MediaplayerActivity implements NavDrawerActivity { private static final int POS_COVER = 0; private static final int POS_DESCR = 1; private static final int POS_CHAPTERS = 2; private static final int NUM_CONTENT_FRAGMENTS = 3; - private static final int POS_NONE = -1; final String TAG = "AudioplayerActivity"; private static final String PREFS = "AudioPlayerActivityPreferences"; private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition"; - private static final String PREF_PLAYABLE_ID = "playableId"; + + public static final String[] NAV_DRAWER_TAGS = { + QueueFragment.TAG, + EpisodesFragment.TAG, + DownloadsFragment.TAG, + PlaybackHistoryFragment.TAG, + AddFeedFragment.TAG + }; private DrawerLayout drawerLayout; private NavListAdapter navAdapter; private ListView navList; - private AdapterView.AdapterContextMenuInfo lastMenuInfo = null; private View navDrawer; private ActionBarDrawerToggle drawerToggle; + private int mPosition = -1; - private Fragment[] detachedFragments; - - private CoverFragment coverFragment; - private ItemDescriptionFragment descriptionFragment; - private ListFragment chapterFragment; - - private Fragment currentlyShownFragment; - private int currentlyShownPosition = -1; - private int lastShownPosition = POS_NONE; - /** - * Used if onResume was called without loadMediaInfo. - */ - private int savedPosition = -1; - - private TextView txtvTitle; - private Button butPlaybackSpeed; - private ImageButton butNavChaptersShownotes; - private ImageButton butShowCover; + private Playable media; + private ViewPager mPager; + private AudioplayerPagerAdapter mPagerAdapter; private Subscription subscription; - private PopupWindow popupWindow; - - private void resetFragmentView() { - FragmentTransaction fT = getSupportFragmentManager().beginTransaction(); - - if (coverFragment != null) { - Log.d(TAG, "Removing cover fragment"); - fT.remove(coverFragment); - } - if (descriptionFragment != null) { - Log.d(TAG, "Removing description fragment"); - fT.remove(descriptionFragment); - } - if (chapterFragment != null) { - Log.d(TAG, "Removing chapter fragment"); - fT.remove(chapterFragment); - } - if (currentlyShownFragment != null) { - Log.d(TAG, "Removing currently shown fragment"); - fT.remove(currentlyShownFragment); - } - for (int i = 0; i < detachedFragments.length; i++) { - Fragment f = detachedFragments[i]; - if (f != null) { - Log.d(TAG, "Removing detached fragment"); - fT.remove(f); - } - } - fT.commit(); - currentlyShownFragment = null; - coverFragment = null; - descriptionFragment = null; - chapterFragment = null; - currentlyShownPosition = -1; - detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS]; - } - @Override protected void onStop() { super.onStop(); @@ -156,6 +104,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc subscription.unsubscribe(); } EventDistributor.getInstance().unregister(contentUpdate); + saveCurrentFragment(); } @Override @@ -163,29 +112,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc setTheme(UserPreferences.getNoTitleTheme()); } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS]; - } + private void saveCurrentFragment() { + if(mPager == null) { + return; + } - private void savePreferences() { Log.d(TAG, "Saving preferences"); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - if (currentlyShownPosition >= 0 && controller != null - && controller.getMedia() != null) { - editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, - currentlyShownPosition); - editor.putString(PREF_PLAYABLE_ID, controller.getMedia() - .getIdentifier().toString()); - } else { - editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1); - editor.putString(PREF_PLAYABLE_ID, ""); - } - editor.commit(); - - savedPosition = currentlyShownPosition; + prefs.edit() + .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, mPager.getCurrentItem()) + .commit(); } @Override @@ -194,53 +130,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc drawerToggle.onConfigurationChanged(newConfig); } - @Override - protected void onSaveInstanceState(Bundle outState) { - // super.onSaveInstanceState(outState); would cause crash - Log.d(TAG, "onSaveInstanceState"); - } - - @Override - protected void onPause() { - savePreferences(); - resetFragmentView(); - super.onPause(); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - restoreFromPreferences(); - } - - /** - * Tries to restore the selected fragment position from the Activity's - * preferences. - * - * @return true if restoreFromPrefernces changed the activity's state - */ - private boolean restoreFromPreferences() { + private void loadLastFragment() { Log.d(TAG, "Restoring instance state"); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); - int savedPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, - -1); - String playableId = prefs.getString(PREF_PLAYABLE_ID, ""); - - if (savedPosition != -1 - && controller != null - && controller.getMedia() != null - && controller.getMedia().getIdentifier().toString() - .equals(playableId)) { - switchToFragment(savedPosition); - return true; - } else if (controller == null || controller.getMedia() == null) { - Log.d(TAG, "Couldn't restore from preferences: controller or media was null"); - } else { - Log.d(TAG, "Couldn't restore from preferences: savedPosition was -1 or saved identifier and playable identifier didn't match.\nsavedPosition: " - + savedPosition + ", id: " + playableId); - - } - return false; + int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1); + mPager.setCurrentItem(lastPosition); } @Override @@ -260,10 +154,12 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc true); startService(launchIntent); } - if (savedPosition != -1) { - switchToFragment(savedPosition); + if(mPagerAdapter != null && controller != null && controller.getMedia() != media) { + media = controller.getMedia(); + mPagerAdapter.notifyDataSetChanged(); } + EventDistributor.getInstance().register(contentUpdate); loadData(); } @@ -292,147 +188,25 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc @Override protected void clearStatusMsg() { // TODO Hide progress bar here - } - /** - * Changes the currently displayed fragment. - * - * @param pos Must be POS_COVER, POS_DESCR, or POS_CHAPTERS - */ - private void switchToFragment(int pos) { - Log.d(TAG, "Switching contentView to position " + pos); - if (currentlyShownPosition != pos && controller != null) { - Playable media = controller.getMedia(); - if (media != null) { - FragmentTransaction ft = getSupportFragmentManager() - .beginTransaction(); - if (currentlyShownFragment != null) { - detachedFragments[currentlyShownPosition] = currentlyShownFragment; - ft.detach(currentlyShownFragment); - } - switch (pos) { - case POS_COVER: - if (coverFragment == null) { - Log.i(TAG, "Using new coverfragment"); - coverFragment = CoverFragment.newInstance(media); - } - currentlyShownFragment = coverFragment; - break; - case POS_DESCR: - if (descriptionFragment == null) { - descriptionFragment = ItemDescriptionFragment - .newInstance(media, true, true); - } - currentlyShownFragment = descriptionFragment; - break; - case POS_CHAPTERS: - if (chapterFragment == null) { - chapterFragment = new ListFragment() { - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - // add padding - final ListView lv = getListView(); - lv.setClipToPadding(false); - final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding); - lv.setPadding(0, vertPadding, 0, vertPadding); - } - }; - chapterFragment.setListAdapter(new ChapterListAdapter( - AudioplayerActivity.this, 0, media - .getChapters(), media, position -> { - Chapter chapter = (Chapter) - chapterFragment.getListAdapter().getItem(position); - controller.seekToChapter(chapter); - } - )); - } - currentlyShownFragment = chapterFragment; - break; - } - if (currentlyShownFragment != null) { - lastShownPosition = currentlyShownPosition; - currentlyShownPosition = pos; - if (detachedFragments[pos] != null) { - Log.d(TAG, "Reattaching fragment at position " + pos); - ft.attach(detachedFragments[pos]); - } else { - ft.add(R.id.contentView, currentlyShownFragment); - } - ft.disallowAddToBackStack(); - ft.commit(); - updateNavButtonDrawable(); - } - } - } - } - - /** - * Switches to the fragment that was displayed before the current one or the description fragment - * if no fragment was previously displayed. - */ - public void switchToLastFragment() { - if (lastShownPosition != POS_NONE) { - switchToFragment(lastShownPosition); - } else { - switchToFragment(POS_DESCR); - } - } - - private void updateNavButtonDrawable() { - - final int[] buttonTexts = new int[]{R.string.show_shownotes_label, - R.string.show_chapters_label}; - - final TypedArray drawables = obtainStyledAttributes(new int[]{ - R.attr.navigation_shownotes, R.attr.navigation_chapters}); - final Playable media = controller.getMedia(); - if (butNavChaptersShownotes != null && butShowCover != null && media != null) { - - butNavChaptersShownotes.setTag(R.id.imageloader_key, null); - setNavButtonVisibility(); - switch (currentlyShownPosition) { - case POS_COVER: - butShowCover.setVisibility(View.GONE); - if (lastShownPosition == POS_CHAPTERS) { - butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1)); - butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1])); - } else { - butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0)); - butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0])); - } - break; - case POS_DESCR: - butShowCover.setVisibility(View.VISIBLE); - butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1)); - butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1])); - break; - case POS_CHAPTERS: - butShowCover.setVisibility(View.VISIBLE); - butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0)); - butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0])); - break; - } - } - drawables.recycle(); - } @Override protected void setupGUI() { super.setupGUI(); - resetFragmentView(); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle(""); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + findViewById(R.id.shadow).setVisibility(View.GONE); + AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar); + float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics()); + appBarLayout.setElevation(px); + } drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); navList = (ListView) findViewById(R.id.nav_list); navDrawer = findViewById(R.id.nav_layout); - butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed); - butNavChaptersShownotes = (ImageButton) findViewById(R.id.butNavChaptersShownotes); - butShowCover = (ImageButton) findViewById(R.id.butCover); - txtvTitle = (TextView) findViewById(R.id.txtvTitle); drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close); drawerToggle.setDrawerIndicatorEnabled(false); @@ -450,6 +224,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc } drawerLayout.closeDrawer(navDrawer); }); + navList.setOnItemLongClickListener((parent, view, position, id) -> { + if (position < navAdapter.getTags().size()) { + showDrawerPreferencesDialog(); + return true; + } else { + mPosition = position; + return false; + } + }); registerForContextMenu(navList); drawerToggle.syncState(); @@ -458,128 +241,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity())); }); - butNavChaptersShownotes.setOnClickListener(v -> { - if (currentlyShownPosition == POS_CHAPTERS) { - switchToFragment(POS_DESCR); - } else if (currentlyShownPosition == POS_DESCR) { - switchToFragment(POS_CHAPTERS); - } else if (currentlyShownPosition == POS_COVER) { - switchToLastFragment(); - } - }); - - butShowCover.setOnClickListener(v -> switchToFragment(POS_COVER)); - - butPlaybackSpeed.setOnClickListener(v -> { - if (controller != null && controller.canSetPlaybackSpeed()) { - String[] availableSpeeds = UserPreferences - .getPlaybackSpeedArray(); - String currentSpeed = UserPreferences.getPlaybackSpeed(); - - // Provide initial value in case the speed list has changed - // out from under us - // and our current speed isn't in the new list - String newSpeed; - if (availableSpeeds.length > 0) { - newSpeed = availableSpeeds[0]; - } else { - newSpeed = "1.0"; - } - - for (int i = 0; i < availableSpeeds.length; i++) { - if (availableSpeeds[i].equals(currentSpeed)) { - if (i == availableSpeeds.length - 1) { - newSpeed = availableSpeeds[0]; - } else { - newSpeed = availableSpeeds[i + 1]; - } - break; - } - } - UserPreferences.setPlaybackSpeed(newSpeed); - controller.setPlaybackSpeed(Float.parseFloat(newSpeed)); - } - }); - - butPlaybackSpeed.setOnLongClickListener(v -> { - - String[] availableSpeeds = getResources().getStringArray(R.array.playback_speed_values); - String currentSpeed = UserPreferences.getPlaybackSpeed(); - - LayoutInflater inflater = getLayoutInflater(); - View popupView = inflater.inflate(R.layout.choose_speed_dialog, null); - TextView txtvSelectedSpeed = (TextView) popupView.findViewById(R.id.txtvSelectedSpeed); - SeekBar sbSelectSpeed = (SeekBar) popupView.findViewById(R.id.sbSelectSpeed); - - txtvSelectedSpeed.setText(currentSpeed); - int progress = ArrayUtils.indexOf(availableSpeeds, currentSpeed); - int max = Math.max(progress, ArrayUtils.indexOf(availableSpeeds, "2.50")); - sbSelectSpeed.setMax(max); - sbSelectSpeed.setProgress(progress); - sbSelectSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - txtvSelectedSpeed.setText(availableSpeeds[progress]); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - String selectedSpeed = availableSpeeds[sbSelectSpeed.getProgress()]; - UserPreferences.setPlaybackSpeed(selectedSpeed); - controller.setPlaybackSpeed(Float.parseFloat(selectedSpeed)); - if (popupWindow != null && popupWindow.isShowing()) { - popupWindow.dismiss(); - } - ScaleAnimation anim = new ScaleAnimation(1.0f, 1.33f, 1.0f, 1.33f, - butPlaybackSpeed.getWidth()/2, butPlaybackSpeed.getHeight()/2); - anim.setDuration(150); - anim.setRepeatMode(ScaleAnimation.REVERSE); - anim.setRepeatCount(1); - anim.setInterpolator(new LinearInterpolator()); - butPlaybackSpeed.startAnimation(anim); - } - }); - popupWindow = new PopupWindow(popupView, - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - true); - popupWindow.setBackgroundDrawable(new BitmapDrawable()); - popupWindow.setOutsideTouchable(true); - popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0); - return true; - }); - } - - private void setNavButtonVisibility() { - if (butNavChaptersShownotes != null) { - if (controller != null) { - Playable media = controller.getMedia(); - if (media != null) { - if (media.getChapters() != null || currentlyShownPosition == POS_COVER) { - butNavChaptersShownotes.setVisibility(View.VISIBLE); - return; - } - } - } - butNavChaptersShownotes.setVisibility(View.GONE); - } - - } - - @Override - protected void onPlaybackSpeedChange() { - super.onPlaybackSpeedChange(); - updateButPlaybackSpeed(); - } - - private void updateButPlaybackSpeed() { - if (controller != null && controller.canSetPlaybackSpeed()) { - butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed()); + mPager = (ViewPager) findViewById(R.id.pager); + if(mPager.getAdapter() == null) { + mPagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager()); + mPager.setAdapter(mPagerAdapter); + CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator); + pageIndicator.setViewPager(mPager); + loadLastFragment(); } + mPager.onSaveInstanceState(); } @Override @@ -593,48 +263,17 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc if (!super.loadMediaInfo()) { return false; } - final Playable media = controller.getMedia(); - if (media == null) { - return false; + if(controller.getMedia() != media) { + media = controller.getMedia(); + mPagerAdapter.notifyDataSetChanged(); } - txtvTitle.setText(media.getEpisodeTitle()); - getSupportActionBar().setTitle(""); - Glide.with(this) - .load(media.getImageUri()) - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate() - .into(butShowCover); - - setNavButtonVisibility(); - - if (currentlyShownPosition == -1) { - if (!restoreFromPreferences()) { - switchToFragment(POS_COVER); - } - } - if (currentlyShownFragment instanceof AudioplayerContentFragment) { - ((AudioplayerContentFragment) currentlyShownFragment) - .onDataSetChanged(media); - } - - if (controller == null - || !controller.canSetPlaybackSpeed()) { - butPlaybackSpeed.setVisibility(View.GONE); - } else { - butPlaybackSpeed.setVisibility(View.VISIBLE); - } - - updateButPlaybackSpeed(); return true; } public void notifyMediaPositionChanged() { - if (chapterFragment != null) { - ArrayAdapter<SimpleChapter> adapter = (ArrayAdapter<SimpleChapter>) chapterFragment - .getListAdapter(); + ListFragment chapterFragment = (ListFragment) mPagerAdapter.getItem(POS_CHAPTERS); + ChaptersListAdapter adapter = (ChaptersListAdapter) chapterFragment.getListAdapter(); + if(adapter != null) { adapter.notifyDataSetChanged(); } } @@ -659,7 +298,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc clearStatusMsg(); } - @Override public PlaybackController getPlaybackController() { return controller; } @@ -669,10 +307,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer); } - public interface AudioplayerContentFragment { - void onDataSetChanged(Playable media); - } - @Override protected int getContentViewResourceId() { return R.layout.audioplayer_activity; @@ -704,24 +338,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc 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! - - // we may need to reference this elsewhere... - lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; } @Override public boolean onContextItemSelected(MenuItem item) { - AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); - - if(menuInfo == null) { - menuInfo = lastMenuInfo; - } - - if(menuInfo.targetView.getParent() instanceof ListView == false - || ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) { + final int position = mPosition; + mPosition = -1; // reset + if(position < 0) { return false; } - int position = menuInfo.position; Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset()); switch(item.getItemId()) { case R.id.mark_all_seen_item: @@ -772,11 +397,43 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc public void onBackPressed() { if(isDrawerOpen()) { drawerLayout.closeDrawer(navDrawer); - } else { + } else if (mPager.getCurrentItem() == 0) { + // If the user is currently looking at the first step, allow the system to handle the + // Back button. This calls finish() on this activity and pops the back stack. super.onBackPressed(); + } else { + // Otherwise, select the previous step. + mPager.setCurrentItem(mPager.getCurrentItem() - 1); } } + 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(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(); + } private DBReader.NavDrawerData navDrawerData; @@ -852,4 +509,36 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc } }; + public interface AudioplayerContentFragment { + void onDataSetChanged(Playable media); + } + + private class AudioplayerPagerAdapter extends FragmentStatePagerAdapter { + + public AudioplayerPagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + Log.d(TAG, "getItem(" + position + ")"); + switch (position) { + case POS_COVER: + return CoverFragment.newInstance(media); + case POS_DESCR: + return ItemDescriptionFragment.newInstance(media, true, true); + case POS_CHAPTERS: + return ChaptersFragment.newInstance(media, controller); + default: + return null; + } + } + + + @Override + public int getCount() { + return NUM_CONTENT_FRAGMENTS; + } + } + } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index bfbf3d86f..1778bffb1 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -1,34 +1,44 @@ package de.danoeh.antennapod.activity; import android.annotation.TargetApi; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.PixelFormat; import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; +import android.support.v4.view.ViewCompat; import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.widget.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 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; @@ -36,13 +46,17 @@ 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 ActionBarActivity - implements OnSeekBarChangeListener { +public abstract class MediaplayerActivity extends AppCompatActivity implements OnSeekBarChangeListener { private static final String TAG = "MediaplayerActivity"; private static final String PREFS = "MediaPlayerActivityPreferences"; private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; @@ -52,12 +66,17 @@ public abstract class MediaplayerActivity extends ActionBarActivity protected TextView txtvPosition; protected TextView txtvLength; protected SeekBar sbPosition; - protected ImageButton butPlay; + protected Button butPlaybackSpeed; protected ImageButton butRev; - protected boolean showTimeLeft = false; 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) { @@ -157,7 +176,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity } protected void onPlaybackSpeedChange() { - + updateButPlaybackSpeed(); } protected void onServiceQueried() { @@ -268,7 +287,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - if(controller == null) { + if (controller == null) { return false; } Playable media = controller.getMedia(); @@ -294,19 +313,35 @@ public abstract class MediaplayerActivity extends ActionBarActivity menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink); - menu.findItem(R.id.skip_episode_item).setVisible(media != null); + 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) { + if (controller == null) { return false; } Playable media = controller.getMedia(); @@ -317,84 +352,217 @@ public abstract class MediaplayerActivity extends ActionBarActivity | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return true; - } else if (media != null) { - switch (item.getItemId()) { - 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.callback(new MaterialDialog.ButtonCallback() { + } 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.callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + dialog.dismiss(); + controller.disableSleepTimer(); + } + + @Override + public void onNegative(MaterialDialog dialog) { + 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, false) + .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 -> { + barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2); + }); + final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed); + butIncSpeed.setOnClickListener(v -> { + barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2); + }); + 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) { + float playbackSpeed = (progress + 10) / 20.0f; + controller.setPlaybackSpeed(playbackSpeed); + String speed = String.format("%.2f", playbackSpeed); + UserPreferences.setPlaybackSpeed(speed); + txtvPlaybackSpeed.setText(speed + "x"); + } + @Override - public void onPositive(MaterialDialog dialog) { - dialog.dismiss(); - controller.disableSleepTimer(); + public void onStartTrackingTouch(SeekBar seekBar) { } @Override - public void onNegative(MaterialDialog dialog) { - dialog.dismiss(); + public void onStopTrackingTouch(SeekBar seekBar) { } }); - stDialog.build().show(); - } - break; - case R.id.set_sleeptimer_item: - if (controller.serviceAvailable()) { - SleepTimerDialog td = new SleepTimerDialog(this) { + barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10); + + final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left); + barLeftVolume.setProgress(100); + final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right); + barRightVolume.setProgress(100); + 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) { + float leftVolume = 1.0f, rightVolume = 1.0f; + if (progress < 100) { + leftVolume = progress / 100.0f; + } + if (barRightVolume.getProgress() < 100) { + rightVolume = barRightVolume.getProgress() / 100.0f; + } + controller.setVolume(leftVolume, rightVolume); + } + @Override - public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) { - controller.setSleepTimer(millis, shakeToReset, vibrate); + 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) { + float leftVolume = 1.0f, rightVolume = 1.0f; + if (progress < 100) { + rightVolume = progress / 100.0f; + } + if (barLeftVolume.getProgress() < 100) { + leftVolume = barLeftVolume.getProgress() / 100.0f; + } + controller.setVolume(leftVolume, rightVolume); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { } - }; - td.createNewDialog().show(); - } - 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; - case R.id.skip_episode_item: - sendBroadcast(new Intent( - PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); - break; - default: - return false; + @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; } - return true; - } else { - return false; } } @@ -427,11 +595,10 @@ public abstract class MediaplayerActivity extends ActionBarActivity && controller.getMedia() != null) { txtvPosition.setText(Converter .getDurationStringLong(currentPosition)); - if(showTimeLeft) { - txtvLength.setText("-"+Converter + if (showTimeLeft) { + txtvLength.setText("-" + Converter .getDurationStringLong(duration - currentPosition)); - } - else { + } else { txtvLength.setText(Converter .getDurationStringLong(duration)); } @@ -443,7 +610,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity } private void updateProgressbarPosition(int position, int duration) { - Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration +")"); + Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")"); float progress = ((float) position) / duration; sbPosition.setProgress((int) (progress * sbPosition.getMax())); } @@ -458,22 +625,31 @@ public abstract class MediaplayerActivity extends ActionBarActivity Log.d(TAG, "loadMediaInfo()"); Playable media = controller.getMedia(); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); - showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT,false); + showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); if (media != null) { - txtvPosition.setText(Converter.getDurationStringLong((media - .getPosition()))); + txtvPosition.setText(Converter.getDurationStringLong((media.getPosition()))); if (media.getDuration() != 0) { - txtvLength.setText(Converter.getDurationStringLong(media - .getDuration())); - float progress = ((float) media.getPosition()) - / media.getDuration(); + txtvLength.setText(Converter.getDurationStringLong(media.getDuration())); + float progress = ((float) media.getPosition()) / media.getDuration(); sbPosition.setProgress((int) (progress * sbPosition.getMax())); - if(showTimeLeft) { - txtvLength.setText("-"+Converter.getDurationStringLong((media - .getDuration()-media.getPosition()))); + if (showTimeLeft) { + int timeLeft = media.getDuration() - media.getPosition(); + txtvLength.setText("-" + Converter.getDurationStringLong(timeLeft)); + } + } + checkFavorite(); + if(controller == null) { + butPlaybackSpeed.setVisibility(View.GONE); + } else { + butPlaybackSpeed.setVisibility(View.VISIBLE); + if (controller.canSetPlaybackSpeed()) { + ViewCompat.setAlpha(butPlaybackSpeed, 1.0f); + } else { + ViewCompat.setAlpha(butPlaybackSpeed, 0.5f); } } + updateButPlaybackSpeed(); return true; } else { return false; @@ -486,43 +662,42 @@ public abstract class MediaplayerActivity extends ActionBarActivity 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"); + showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); + Log.d("timeleft", showTimeLeft ? "true" : "false"); txtvLength = (TextView) findViewById(R.id.txtvLength); - txtvLength.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showTimeLeft = !showTimeLeft; - Playable media = controller.getMedia(); - if (media == null) { - return; - } - - if (showTimeLeft) { - txtvLength.setText("-"+Converter.getDurationStringLong((media - .getDuration()-media.getPosition()))); - } else { - txtvLength.setText(Converter.getDurationStringLong((media.getDuration()))); - } + txtvLength.setOnClickListener(v -> { + showTimeLeft = !showTimeLeft; + Playable media = controller.getMedia(); + if (media == null) { + return; + } - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PREF_SHOW_TIME_LEFT,showTimeLeft); - editor.apply(); - Log.d("timeleft on click",showTimeLeft? "true":"false"); + if (showTimeLeft) { + txtvLength.setText("-" + Converter.getDurationStringLong((media + .getDuration() - media.getPosition()))); + } else { + txtvLength.setText(Converter.getDurationStringLong((media.getDuration()))); } + + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft); + editor.apply(); + Log.d("timeleft on click", showTimeLeft ? "true" : "false"); }); - butPlay = (ImageButton) findViewById(R.id.butPlay); + butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed); butRev = (ImageButton) findViewById(R.id.butRev); txtvRev = (TextView) findViewById(R.id.txtvRev); - if(txtvRev != null) { + 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) { + if (txtvFF != null) { txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs())); } + butSkip = (ImageButton) findViewById(R.id.butSkip); // SEEKBAR SETUP @@ -530,27 +705,63 @@ public abstract class MediaplayerActivity extends ActionBarActivity // BUTTON SETUP - butPlay.setOnClickListener(controller.newOnPlayButtonClickListener()); + if(butPlaybackSpeed != null) { + butPlaybackSpeed.setOnClickListener(v -> { + if (controller == null) { + return; + } + if (controller.canSetPlaybackSpeed()) { + String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray(); + String currentSpeed = UserPreferences.getPlaybackSpeed(); + + // Provide initial value in case the speed list has changed + // out from under us + // and our current speed isn't in the new list + String newSpeed; + if (availableSpeeds.length > 0) { + newSpeed = availableSpeeds[0]; + } else { + newSpeed = "1.00"; + } - if (butFF != null) { - butFF.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int curr = controller.getPosition(); - controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000); + for (int i = 0; i < availableSpeeds.length; i++) { + if (availableSpeeds[i].equals(currentSpeed)) { + if (i == availableSpeeds.length - 1) { + newSpeed = availableSpeeds[0]; + } else { + newSpeed = availableSpeeds[i + 1]; + } + break; + } + } + UserPreferences.setPlaybackSpeed(newSpeed); + controller.setPlaybackSpeed(Float.parseFloat(newSpeed)); + } else { + VariableSpeedDialog.showDialog(this); } }); - butFF.setOnLongClickListener(new View.OnLongClickListener() { + butPlaybackSpeed.setOnLongClickListener(v -> { + VariableSpeedDialog.showDialog(this); + return true; + }); + } + + if (butRev != null) { + butRev.setOnClickListener(v -> { + int curr = controller.getPosition(); + controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000); + }); + butRev.setOnLongClickListener(new View.OnLongClickListener() { int choice; @Override public boolean onLongClick(View v) { int checked = 0; - int rewindSecs = UserPreferences.getFastFowardSecs(); + 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++) { + for (int i = 0; i < values.length; i++) { if (rewindSecs == values[i]) { checked = i; } @@ -559,40 +770,40 @@ public abstract class MediaplayerActivity extends ActionBarActivity } choice = values[checked]; AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this); - builder.setTitle(R.string.pref_fast_forward); + 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.setPrefFastForwardSecs(choice); - txtvFF.setText(String.valueOf(choice)); + UserPreferences.setPrefRewindSecs(choice); + txtvRev.setText(String.valueOf(choice)); }); builder.create().show(); return true; } }); } - if (butRev != null) { - butRev.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int curr = controller.getPosition(); - controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000); - } + + butPlay.setOnClickListener(controller.newOnPlayButtonClickListener()); + + if (butFF != null) { + butFF.setOnClickListener(v -> { + int curr = controller.getPosition(); + controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000); }); - butRev.setOnLongClickListener(new View.OnLongClickListener() { + butFF.setOnLongClickListener(new View.OnLongClickListener() { int choice; @Override public boolean onLongClick(View v) { int checked = 0; - int rewindSecs = UserPreferences.getRewindSecs(); + 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++) { + for (int i = 0; i < values.length; i++) { if (rewindSecs == values[i]) { checked = i; } @@ -601,21 +812,15 @@ public abstract class MediaplayerActivity extends ActionBarActivity } choice = values[checked]; AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this); - builder.setTitle(R.string.pref_rewind); + builder.setTitle(R.string.pref_fast_forward); builder.setSingleChoiceItems(choices, checked, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - choice = values[which]; - } + (dialog, which) -> { + choice = values[which]; }); builder.setNegativeButton(R.string.cancel_label, null); - builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - UserPreferences.setPrefRewindSecs(choice); - txtvRev.setText(String.valueOf(choice)); - } + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { + UserPreferences.setPrefFastForwardSecs(choice); + txtvFF.setText(String.valueOf(choice)); }); builder.create().show(); return true; @@ -623,6 +828,11 @@ public abstract class MediaplayerActivity extends ActionBarActivity }); } + if (butSkip != null) { + butSkip.setOnClickListener(v -> { + sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + }); + } } protected abstract int getContentViewResourceId(); @@ -633,12 +843,9 @@ public abstract class MediaplayerActivity extends ActionBarActivity errorDialog .setMessage(MediaPlayerError.getErrorString(this, errorCode)); errorDialog.setNeutralButton("OK", - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - finish(); - } + (dialog, which) -> { + dialog.dismiss(); + finish(); } ); errorDialog.create().show(); @@ -652,14 +859,20 @@ public abstract class MediaplayerActivity extends ActionBarActivity if (controller != null) { prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition); - if(showTimeLeft && prog!=0) { + if (showTimeLeft && prog != 0) { int duration = controller.getDuration(); - txtvLength.setText("-"+Converter + txtvLength.setText("-" + Converter .getDurationStringLong(duration - (int) (prog * duration))); } } } + private void updateButPlaybackSpeed() { + if (controller != null) { + butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed() + "x"); + } + } + @Override public void onStartTrackingTouch(SeekBar seekBar) { if (controller != null) { @@ -674,4 +887,23 @@ public abstract class MediaplayerActivity extends ActionBarActivity } } + 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(); + } + }); + } + } + } + } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java deleted file mode 100644 index cf0532cf1..000000000 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java +++ /dev/null @@ -1,199 +0,0 @@ -package de.danoeh.antennapod.adapter; - -import android.content.Context; -import android.text.Layout; -import android.text.Selection; -import android.text.Spannable; -import android.text.Spanned; -import android.text.style.ClickableSpan; -import android.text.util.Linkify; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageButton; -import android.widget.TextView; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.feed.Chapter; -import de.danoeh.antennapod.core.util.ChapterUtils; -import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.playback.Playable; - -import java.util.List; - -public class ChapterListAdapter extends ArrayAdapter<Chapter> { - - private static final String TAG = "ChapterListAdapter"; - - private List<Chapter> chapters; - private Playable media; - - private int defaultTextColor; - private final Callback callback; - - public ChapterListAdapter(Context context, int textViewResourceId, - List<Chapter> objects, Playable media, Callback callback) { - super(context, textViewResourceId, objects); - this.chapters = objects; - this.media = media; - this.callback = callback; - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - Holder holder; - - Chapter sc = getItem(position); - - // Inflate Layout - if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - convertView = inflater.inflate(R.layout.simplechapter_item, parent, false); - holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); - defaultTextColor = holder.title.getTextColors().getDefaultColor(); - holder.start = (TextView) convertView.findViewById(R.id.txtvStart); - holder.link = (TextView) convertView.findViewById(R.id.txtvLink); - holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter); - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - - } - - holder.title.setText(sc.getTitle()); - holder.start.setText(Converter.getDurationStringLong((int) sc - .getStart())); - if (sc.getLink() != null) { - holder.link.setVisibility(View.VISIBLE); - holder.link.setText(sc.getLink()); - Linkify.addLinks(holder.link, Linkify.WEB_URLS); - } else { - holder.link.setVisibility(View.GONE); - } - holder.link.setMovementMethod(null); - holder.link.setOnTouchListener(new OnTouchListener() { - - @Override - public boolean onTouch(View v, MotionEvent event) { - // from - // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures - TextView widget = (TextView) v; - Object text = widget.getText(); - if (text instanceof Spanned) { - Spannable buffer = (Spannable) text; - - int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP - || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, - ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } else if (action == MotionEvent.ACTION_DOWN) { - Selection.setSelection(buffer, - buffer.getSpanStart(link[0]), - buffer.getSpanEnd(link[0])); - } - return true; - } - } - - } - - return false; - - } - }); - holder.butPlayChapter.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (callback != null) { - callback.onPlayChapterButtonClicked(position); - } - } - }); - Chapter current = ChapterUtils.getCurrentChapter(media); - if (current != null) { - if (current == sc) { - holder.title.setTextColor(convertView.getResources().getColor( - R.color.holo_blue_light)); - holder.start.setTextColor(convertView.getResources().getColor( - R.color.holo_blue_light)); - } else { - holder.title.setTextColor(defaultTextColor); - holder.start.setTextColor(defaultTextColor); - } - } else { - Log.w(TAG, "Could not find out what the current chapter is."); - } - - return convertView; - } - - static class Holder { - TextView title; - TextView start; - TextView link; - ImageButton butPlayChapter; - } - - @Override - public int getCount() { - // ignore invalid chapters - int counter = 0; - if (chapters != null) { - for (Chapter chapter : chapters) { - if (!ignoreChapter(chapter)) { - counter++; - } - } - } - return counter; - } - - private boolean ignoreChapter(Chapter c) { - return media.getDuration() > 0 && media.getDuration() < c.getStart(); - } - - @Override - public Chapter getItem(int position) { - int i = 0; - for (Chapter chapter : chapters) { - if (!ignoreChapter(chapter)) { - if (i == position) { - return chapter; - } else { - i++; - } - } - } - return super.getItem(position); - } - - public static interface Callback { - public void onPlayChapterButtonClicked(int position); - } - -} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java new file mode 100644 index 000000000..1c9439ee6 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java @@ -0,0 +1,198 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.text.Layout; +import android.text.Selection; +import android.text.Spannable; +import android.text.Spanned; +import android.text.style.ClickableSpan; +import android.text.util.Linkify; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageButton; +import android.widget.TextView; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.util.ChapterUtils; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.playback.Playable; + +public class ChaptersListAdapter extends ArrayAdapter<Chapter> { + + private static final String TAG = "ChapterListAdapter"; + + private Playable media; + + private int defaultTextColor; + private final Callback callback; + + public ChaptersListAdapter(Context context, int textViewResourceId, Callback callback) { + super(context, textViewResourceId); + this.callback = callback; + } + + public void setMedia(Playable media) { + this.media = media; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + Holder holder; + + Chapter sc = getItem(position); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.simplechapter_item, parent, false); + holder.view = convertView; + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + defaultTextColor = holder.title.getTextColors().getDefaultColor(); + holder.start = (TextView) convertView.findViewById(R.id.txtvStart); + holder.link = (TextView) convertView.findViewById(R.id.txtvLink); + holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + + } + + holder.title.setText(sc.getTitle()); + holder.start.setText(Converter.getDurationStringLong((int) sc + .getStart())); + if (sc.getLink() != null) { + holder.link.setVisibility(View.VISIBLE); + holder.link.setText(sc.getLink()); + Linkify.addLinks(holder.link, Linkify.WEB_URLS); + } else { + holder.link.setVisibility(View.GONE); + } + holder.link.setMovementMethod(null); + holder.link.setOnTouchListener((v, event) -> { + // from + // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures + TextView widget = (TextView) v; + Object text = widget.getText(); + if (text instanceof Spanned) { + Spannable buffer = (Spannable) text; + + int action = event.getAction(); + + if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + x += widget.getScrollX(); + y += widget.getScrollY(); + + Layout layout = widget.getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + ClickableSpan[] link = buffer.getSpans(off, off, + ClickableSpan.class); + + if (link.length != 0) { + if (action == MotionEvent.ACTION_UP) { + link[0].onClick(widget); + } else if (action == MotionEvent.ACTION_DOWN) { + Selection.setSelection(buffer, + buffer.getSpanStart(link[0]), + buffer.getSpanEnd(link[0])); + } + return true; + } + } + + } + + return false; + + }); + holder.butPlayChapter.setOnClickListener(v -> { + if (callback != null) { + callback.onPlayChapterButtonClicked(position); + } + }); + Chapter current = ChapterUtils.getCurrentChapter(media); + if (current != null) { + if (current == sc) { + int playingBackGroundColor; + if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { + playingBackGroundColor = getContext().getResources().getColor(R.color.highlight_dark); + } else { + playingBackGroundColor = getContext().getResources().getColor(R.color.highlight_light); + } + holder.view.setBackgroundColor(playingBackGroundColor); + } else { + holder.view.setBackgroundColor(getContext().getResources().getColor(android.R.color.transparent)); + holder.title.setTextColor(defaultTextColor); + holder.start.setTextColor(defaultTextColor); + } + } else { + Log.w(TAG, "Could not find out what the current chapter is."); + } + + return convertView; + } + + static class Holder { + View view; + TextView title; + TextView start; + TextView link; + ImageButton butPlayChapter; + } + + @Override + public int getCount() { + if(media == null || media.getChapters() == null) { + return 0; + } + // ignore invalid chapters + int counter = 0; + for (Chapter chapter : media.getChapters()) { + if (!ignoreChapter(chapter)) { + counter++; + } + } + return counter; + } + + private boolean ignoreChapter(Chapter c) { + return media.getDuration() > 0 && media.getDuration() < c.getStart(); + } + + @Override + public Chapter getItem(int position) { + int i = 0; + for (Chapter chapter : media.getChapters()) { + if (!ignoreChapter(chapter)) { + if (i == position) { + return chapter; + } else { + i++; + } + } + } + return super.getItem(position); + } + + public interface Callback { + void onPlayChapterButtonClicked(int position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index 4b512a48d..f2e8b6f7a 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -21,107 +21,96 @@ import de.danoeh.antennapod.core.util.IntentUtils; public class VariableSpeedDialog { - private static final String TAG = VariableSpeedDialog.class.getSimpleName(); - - private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, - Uri.parse("market://details?id=com.falconware.prestissimo")); - - private VariableSpeedDialog() { - } - - public static void showDialog(final Context context) { - if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context) - || UserPreferences.useSonic()) { - showSpeedSelectorDialog(context); - } else { - showGetPluginDialog(context); - } - } - - private static void showGetPluginDialog(final Context context) { - MaterialDialog.Builder builder = new MaterialDialog.Builder(context); - builder.title(R.string.no_playback_plugin_title); - builder.content(R.string.no_playback_plugin_or_sonic_msg); - builder.positiveText(R.string.download_plugin_label); - builder.negativeText(R.string.enable_sonic); - builder.neutralText(R.string.close_label); - builder.callback(new MaterialDialog.ButtonCallback() { - @Override - public void onPositive(MaterialDialog dialog) { - try { - context.startActivity(playStoreIntent); - } catch (ActivityNotFoundException e) { - // this is usually thrown on an emulator if the Android market is not installed - Log.e(TAG, Log.getStackTraceString(e)); - } - } - - @Override - public void onNegative(MaterialDialog dialog) { - if (Build.VERSION.SDK_INT >= 16) { // just to be safe - UserPreferences.enableSonic(true); - showSpeedSelectorDialog(context); - } - } - - @Override - public void onNeutral(MaterialDialog dialog) { - super.onNeutral(dialog); - } - }); - builder.forceStacking(true); - MaterialDialog dialog = builder.show(); - if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) { - View pos = dialog.getActionButton(DialogAction.POSITIVE); - pos.setEnabled(false); - } - if (Build.VERSION.SDK_INT < 16) { - View pos = dialog.getActionButton(DialogAction.NEGATIVE); - pos.setEnabled(false); - } - } - - private static void showSpeedSelectorDialog(final Context context) { - final String[] speedValues = context.getResources().getStringArray( - R.array.playback_speed_values); - // According to Java spec these get initialized to false on creation - final boolean[] speedChecked = new boolean[speedValues.length]; - - // Build the "isChecked" array so that multiChoice dialog is - // populated correctly - List<String> selectedSpeedList = Arrays.asList(UserPreferences - .getPlaybackSpeedArray()); - for (int i = 0; i < speedValues.length; i++) { - speedChecked[i] = selectedSpeedList.contains(speedValues[i]); - } - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.set_playback_speed_label); - builder.setMultiChoiceItems(R.array.playback_speed_values, - speedChecked, (dialog, which, isChecked) -> { - speedChecked[which] = isChecked; - }); - builder.setNegativeButton(android.R.string.cancel, null); - builder.setPositiveButton(android.R.string.ok, - (dialog, which) -> { - int choiceCount = 0; - for (int i = 0; i < speedChecked.length; i++) { - if (speedChecked[i]) { - choiceCount++; - } - } - String[] newSpeedValues = new String[choiceCount]; - int newSpeedIndex = 0; - for (int i = 0; i < speedChecked.length; i++) { - if (speedChecked[i]) { - newSpeedValues[newSpeedIndex++] = speedValues[i]; - } - } - - UserPreferences.setPlaybackSpeedArray(newSpeedValues); - - }); - builder.create().show(); - } + private static final String TAG = VariableSpeedDialog.class.getSimpleName(); + + private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, + Uri.parse("market://details?id=com.falconware.prestissimo")); + + private VariableSpeedDialog() { + } + + public static void showDialog(final Context context) { + if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context) + || UserPreferences.useSonic()) { + showSpeedSelectorDialog(context); + } else { + showGetPluginDialog(context); + } + } + + private static void showGetPluginDialog(final Context context) { + MaterialDialog.Builder builder = new MaterialDialog.Builder(context); + builder.title(R.string.no_playback_plugin_title); + builder.content(R.string.no_playback_plugin_or_sonic_msg); + builder.positiveText(R.string.download_plugin_label); + builder.negativeText(R.string.enable_sonic); + builder.neutralText(R.string.close_label); + builder.onPositive((dialog, which) -> { + try { + context.startActivity(playStoreIntent); + } catch (ActivityNotFoundException e) { + // this is usually thrown on an emulator if the Android market is not installed + Log.e(TAG, Log.getStackTraceString(e)); + } + }); + builder.onNegative((dialog, which) -> { + if (Build.VERSION.SDK_INT >= 16) { // just to be safe + UserPreferences.enableSonic(true); + showSpeedSelectorDialog(context); + } + }); + MaterialDialog dialog = builder.show(); + if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) { + View pos = dialog.getActionButton(DialogAction.POSITIVE); + pos.setEnabled(false); + } + if (Build.VERSION.SDK_INT < 16) { + View pos = dialog.getActionButton(DialogAction.NEGATIVE); + pos.setEnabled(false); + } + } + + private static void showSpeedSelectorDialog(final Context context) { + final String[] speedValues = context.getResources().getStringArray( + R.array.playback_speed_values); + // According to Java spec these get initialized to false on creation + final boolean[] speedChecked = new boolean[speedValues.length]; + + // Build the "isChecked" array so that multiChoice dialog is + // populated correctly + List<String> selectedSpeedList = Arrays.asList(UserPreferences + .getPlaybackSpeedArray()); + for (int i = 0; i < speedValues.length; i++) { + speedChecked[i] = selectedSpeedList.contains(speedValues[i]); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.set_playback_speed_label); + builder.setMultiChoiceItems(R.array.playback_speed_values, + speedChecked, (dialog, which, isChecked) -> { + speedChecked[which] = isChecked; + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.setPositiveButton(android.R.string.ok, + (dialog, which) -> { + int choiceCount = 0; + for (int i = 0; i < speedChecked.length; i++) { + if (speedChecked[i]) { + choiceCount++; + } + } + String[] newSpeedValues = new String[choiceCount]; + int newSpeedIndex = 0; + for (int i = 0; i < speedChecked.length; i++) { + if (speedChecked[i]) { + newSpeedValues[newSpeedIndex++] = speedValues[i]; + } + } + + UserPreferences.setPlaybackSpeedArray(newSpeedValues); + + }); + builder.create().show(); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java new file mode 100644 index 000000000..abc9f3d22 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java @@ -0,0 +1,68 @@ +package de.danoeh.antennapod.fragment; + +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.ListView; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; +import de.danoeh.antennapod.adapter.ChaptersListAdapter; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.util.playback.Playable; +import de.danoeh.antennapod.core.util.playback.PlaybackController; + + +public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment { + + private Playable media; + private PlaybackController controller; + + private ChaptersListAdapter adapter; + + public static ChaptersFragment newInstance(Playable media, PlaybackController controller) { + ChaptersFragment f = new ChaptersFragment(); + f.media = media; + f.controller = controller; + return f; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + // add padding + final ListView lv = getListView(); + lv.setClipToPadding(false); + final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding); + lv.setPadding(0, vertPadding, 0, vertPadding); + + adapter = new ChaptersListAdapter(getActivity(), 0, pos -> { + Chapter chapter = (Chapter) getListAdapter().getItem(pos); + controller.seekToChapter(chapter); + }); + setListAdapter(adapter); + } + + @Override + public void onResume() { + super.onResume(); + adapter.setMedia(media); + adapter.notifyDataSetChanged(); + if(media == null || media.getChapters() == null) { + setEmptyText(getString(R.string.no_chapters_label)); + } else { + setEmptyText(null); + } + } + + @Override + public void onDataSetChanged(Playable media) { + adapter.setMedia(media); + adapter.notifyDataSetChanged(); + if(media.getChapters() == null) { + setEmptyText(getString(R.string.no_items_label)); + } else { + setEmptyText(null); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index a1667cce0..60a607179 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -1,21 +1,21 @@ package de.danoeh.antennapod.fragment; -import android.app.Activity; -import android.content.Context; +import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v7.graphics.Palette; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.BitmapImageViewTarget; -import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.AudioplayerActivity; import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.util.playback.Playable; @@ -30,10 +30,11 @@ public class CoverFragment extends Fragment implements private Playable media; + private View root; + private TextView txtvPodcastTitle; + private TextView txtvEpisodeTitle; private ImageView imgvCover; - private boolean viewCreated = false; - public static CoverFragment newInstance(Playable item) { CoverFragment f = new CoverFragment(); if (item != null) { @@ -59,38 +60,45 @@ public class CoverFragment extends Fragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.cover_fragment, container, false); + root = inflater.inflate(R.layout.cover_fragment, container, false); + txtvPodcastTitle = (TextView) root.findViewById(R.id.txtvPodcastTitle); + txtvEpisodeTitle = (TextView) root.findViewById(R.id.txtvEpisodeTitle); imgvCover = (ImageView) root.findViewById(R.id.imgvCover); - imgvCover.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Activity activity = getActivity(); - if (activity != null && activity instanceof AudioplayerActivity) { - ((AudioplayerActivity)activity).switchToLastFragment(); - } - } - }); - viewCreated = true; return root; } private void loadMediaInfo() { + if(imgvCover == null) { + return; + } if (media != null) { - imgvCover.post(new Runnable() { - - @Override - public void run() { - Context c = getActivity(); - if (c != null) { - Glide.with(c) - .load(media.getImageUri()) - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .dontAnimate() - .into(imgvCover); - } - } + Log.d(TAG, "feed title: " + media.getFeedTitle()); + Log.d(TAG, "episode title: " + media.getEpisodeTitle()); + txtvPodcastTitle.setText(media.getFeedTitle()); + txtvEpisodeTitle.setText(media.getEpisodeTitle()); + imgvCover.post(() -> { + Glide.with(this) + .load(media.getImageUri()) + .asBitmap() + .placeholder(R.color.light_gray) + .error(R.color.light_gray) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .dontAnimate() + .into(new BitmapImageViewTarget(imgvCover) { + @Override + public void onResourceReady(Bitmap bitmap, GlideAnimation anim) { + super.onResourceReady(bitmap, anim); + Palette.Builder builder = new Palette.Builder(bitmap); + builder.generate(palette -> { + Palette.Swatch swatch = palette.getMutedSwatch(); + if(swatch != null) { + root.setBackgroundColor(swatch.getRgb()); + txtvPodcastTitle.setTextColor(swatch.getTitleTextColor()); + txtvEpisodeTitle.setTextColor(swatch.getBodyTextColor()); + } + }); + } + }); }); } else { Log.w(TAG, "loadMediaInfo was called while media was null"); @@ -99,12 +107,10 @@ public class CoverFragment extends Fragment implements @Override public void onStart() { - if (BuildConfig.DEBUG) - Log.d(TAG, "On Start"); + Log.d(TAG, "On Start"); super.onStart(); if (media != null) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading media info"); + Log.d(TAG, "Loading media info"); loadMediaInfo(); } else { Log.w(TAG, "Unable to load media info: media was null"); @@ -114,10 +120,7 @@ public class CoverFragment extends Fragment implements @Override public void onDataSetChanged(Playable media) { this.media = media; - if (viewCreated) { - loadMediaInfo(); - } - + loadMediaInfo(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 888684313..80a9bf0b3 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -13,7 +13,6 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.glide.ApGlideSettings; @@ -80,50 +79,15 @@ public class ExternalPlayerFragment extends Fragment { return new PlaybackController(getActivity(), true) { @Override - public void setupGUI() { - } - - @Override public void onPositionObserverUpdate() { ExternalPlayerFragment.this.onPositionObserverUpdate(); } @Override - public void onReloadNotification(int code) { - } - - @Override - public void onBufferStart() { - } - - @Override - public void onBufferEnd() { - } - - @Override - public void onBufferUpdate(float progress) { - } - - @Override - public void onSleepTimerUpdate() { - } - - @Override - public void handleError(int code) { - } - - @Override public ImageButton getPlayButton() { return butPlay; } - @Override - public void postStatusMsg(int msg) { - } - - @Override - public void clearStatusMsg() { - } @Override public boolean loadMediaInfo() { @@ -136,14 +100,6 @@ public class ExternalPlayerFragment extends Fragment { } @Override - public void onAwaitingVideoSurface() { - } - - @Override - public void onServiceQueried() { - } - - @Override public void onShutdownNotification() { playbackDone(); } @@ -152,10 +108,6 @@ public class ExternalPlayerFragment extends Fragment { public void onPlaybackEnd() { playbackDone(); } - - @Override - public void onPlaybackSpeedChange() { - } }; } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index faa4413bb..f270dc22d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -8,7 +8,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -26,6 +25,8 @@ import android.webkit.WebViewClient; import android.widget.Toast; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.AudioplayerActivity; +import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; @@ -36,11 +37,15 @@ import de.danoeh.antennapod.core.util.ShownotesProvider; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; import de.danoeh.antennapod.core.util.playback.Timeline; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Displays the description of a Playable object in a Webview. */ -public class ItemDescriptionFragment extends Fragment { +public class ItemDescriptionFragment extends Fragment implements AudioplayerContentFragment { private static final String TAG = "ItemDescriptionFragment"; @@ -55,12 +60,13 @@ public class ItemDescriptionFragment extends Fragment { private static final String ARG_HIGHLIGHT_TIMECODES = "arg.highlightTimecodes"; private WebView webvDescription; + private String webvData; private ShownotesProvider shownotesProvider; private Playable media; - private AsyncTask<Void, Void, Void> webViewLoader; + private Subscription webViewLoader; /** * URL that was selected via long-press. @@ -106,17 +112,14 @@ public class ItemDescriptionFragment extends Fragment { Bundle savedInstanceState) { Log.d(TAG, "Creating view"); webvDescription = new WebView(getActivity()); + if (Build.VERSION.SDK_INT >= 11) { + webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { - if (Build.VERSION.SDK_INT >= 11 - && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { - webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - webvDescription.setBackgroundColor(getResources().getColor( - R.color.black)); + webvDescription.setBackgroundColor(getResources().getColor(R.color.black)); } webvDescription.getSettings().setUseWideViewPort(false); - webvDescription.getSettings().setLayoutAlgorithm( - LayoutAlgorithm.NARROW_COLUMNS); + webvDescription.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); webvDescription.getSettings().setLoadWithOverviewMode(true); webvDescription.setOnLongClickListener(webViewLongClickListener); webvDescription.setWebViewClient(new WebViewClient() { @@ -142,14 +145,7 @@ public class ItemDescriptionFragment extends Fragment { super.onPageFinished(view, url); Log.d(TAG, "Page finished"); // Restoring the scroll position might not always work - view.postDelayed(new Runnable() { - - @Override - public void run() { - restoreFromPreference(); - } - - }, 50); + view.postDelayed(() -> restoreFromPreference(), 50); } }); @@ -159,26 +155,11 @@ public class ItemDescriptionFragment extends Fragment { } @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - Log.d(TAG, "Fragment attached"); - } - - @Override - public void onDetach() { - super.onDetach(); - Log.d(TAG, "Fragment detached"); - if (webViewLoader != null) { - webViewLoader.cancel(true); - } - } - - @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "Fragment destroyed"); if (webViewLoader != null) { - webViewLoader.cancel(true); + webViewLoader.unsubscribe(); } if (webvDescription != null) { webvDescription.removeAllViews(); @@ -194,7 +175,6 @@ public class ItemDescriptionFragment extends Fragment { Bundle args = getArguments(); saveState = args.getBoolean(ARG_SAVE_STATE, false); highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false); - } @Override @@ -204,46 +184,21 @@ public class ItemDescriptionFragment extends Fragment { if (args.containsKey(ARG_PLAYABLE)) { media = args.getParcelable(ARG_PLAYABLE); shownotesProvider = media; - startLoader(); + load(); } else if (args.containsKey(ARG_FEEDITEM_ID)) { - AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() { - - @Override - protected FeedItem doInBackground(Void... voids) { - return DBReader.getFeedItem(getArguments().getLong(ARG_FEEDITEM_ID)); - } - - @Override - protected void onPostExecute(FeedItem feedItem) { - super.onPostExecute(feedItem); - shownotesProvider = feedItem; - startLoader(); - } - }; - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - itemLoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - itemLoadTask.execute(); - } + long id = getArguments().getLong(ARG_FEEDITEM_ID); + Observable.defer(() -> Observable.just(DBReader.getFeedItem(id))) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(feedItem -> { + shownotesProvider = feedItem; + load(); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - - } - @Override - public void onResume() { - super.onResume(); - } - - @SuppressLint("NewApi") - private void startLoader() { - webViewLoader = createLoader(); - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - webViewLoader.execute(); - } - } private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() { @@ -338,49 +293,31 @@ public class ItemDescriptionFragment extends Fragment { } } - private AsyncTask<Void, Void, Void> createLoader() { - return new AsyncTask<Void, Void, Void>() { - @Override - protected void onCancelled() { - super.onCancelled(); - webViewLoader = null; - } - - String data; - - @Override - protected void onPostExecute(Void result) { - super.onPostExecute(result); - // /webvDescription.loadData(url, "text/html", "utf-8"); - webvDescription.loadDataWithBaseURL(null, data, "text/html", - "utf-8", "about:blank"); - Log.d(TAG, "Webview loaded"); - webViewLoader = null; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - } - - @Override - protected Void doInBackground(Void... params) { - Log.d(TAG, "Loading Webview"); - try { - Activity activity = getActivity(); - if (activity != null) { - Timeline timeline = new Timeline(activity, shownotesProvider); - data = timeline.processShownotes(highlightTimecodes); - } else { - cancel(true); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private void load() { + Log.d(TAG, "load()"); + if(webViewLoader != null) { + webViewLoader.unsubscribe(); + } + if(shownotesProvider == null) { + return; + } + webViewLoader = Observable.defer(() -> Observable.just(loadData())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(data -> { + webvData = data; + webvDescription.loadDataWithBaseURL(null, data, "text/html", + "utf-8", "about:blank"); + Log.d(TAG, "Webview loaded"); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); + } - }; + private String loadData() { + Timeline timeline = new Timeline(getActivity(), shownotesProvider); + String data = timeline.processShownotes(highlightTimecodes); + return data; } @Override @@ -410,7 +347,7 @@ public class ItemDescriptionFragment extends Fragment { } private boolean restoreFromPreference() { - if (saveState) { + if (!saveState) { Log.d(TAG, "Restoring from preferences"); Activity activity = getActivity(); if (activity != null) { @@ -433,15 +370,19 @@ public class ItemDescriptionFragment extends Fragment { private void onTimecodeLinkSelected(String link) { int time = Timeline.getTimecodeLinkTime(link); - if (getActivity() != null && getActivity() instanceof ItemDescriptionFragmentCallback) { - PlaybackController pc = ((ItemDescriptionFragmentCallback) getActivity()).getPlaybackController(); + if (getActivity() != null && getActivity() instanceof AudioplayerActivity) { + PlaybackController pc = ((AudioplayerActivity) getActivity()).getPlaybackController(); if (pc != null) { pc.seekTo(time); } } } - public interface ItemDescriptionFragmentCallback { - public PlaybackController getPlaybackController(); + @Override + public void onDataSetChanged(Playable media) { + this.media = media; + this.shownotesProvider = media; + load(); } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 885723fd9..bbffd2dea 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -310,7 +310,7 @@ public class ItemFragment extends Fragment { .dontAnimate() .into(imgvCover); - progbarDownload.setVisibility(View.INVISIBLE); + progbarDownload.setVisibility(View.GONE); if (item.hasMedia() && downloaderList != null) { for (Downloader downloader : downloaderList) { if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index 513cf2760..dbd18163c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -4,7 +4,7 @@ import android.content.Context; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; import android.util.Log; import android.view.Menu; @@ -116,7 +116,7 @@ public class SearchFragment extends ListFragment { final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding); lv.setPadding(0, vertPadding, 0, vertPadding); - ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label); + ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label); viewCreated = true; if (itemsLoaded) { onFragmentLoaded(); |