diff options
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/fragment')
14 files changed, 609 insertions, 109 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 216c8cc57..05f38000c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -25,7 +25,6 @@ import java.util.Set; * supports swiping to mark as read. */ public class AllEpisodesFragment extends EpisodesListFragment { - public static final String TAG = "AllEpisodesFragment"; private static final String PREF_NAME = "PrefAllEpisodesFragment"; private static final String PREF_FILTER = "filter"; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java new file mode 100644 index 000000000..ed136af3c --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java @@ -0,0 +1,505 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ProgressBar; +import android.widget.SeekBar; +import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.CastEnabledActivity; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.core.event.FavoritesEvent; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils; +import de.danoeh.antennapod.core.preferences.PlaybackPreferences; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.playback.PlaybackService; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.TimeSpeedConverter; +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.PlaybackControlsDialog; +import de.danoeh.antennapod.dialog.SkipPreferenceDialog; +import de.danoeh.antennapod.dialog.SleepTimerDialog; +import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; +import de.danoeh.antennapod.view.PagerIndicatorView; +import de.danoeh.antennapod.view.PlaybackSpeedIndicatorView; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.text.DecimalFormat; +import java.util.List; + +/** + * Shows the audio player. + */ +public class AudioPlayerFragment extends Fragment implements + SeekBar.OnSeekBarChangeListener, Toolbar.OnMenuItemClickListener { + public static final String TAG = "AudioPlayerFragment"; + 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 String PREFS = "AudioPlayerFragmentPreferences"; + private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; + private static final float EPSILON = 0.001f; + + PlaybackSpeedIndicatorView butPlaybackSpeed; + TextView txtvPlaybackSpeed; + private ViewPager pager; + private PagerIndicatorView pageIndicator; + private TextView txtvPosition; + private TextView txtvLength; + private SeekBar sbPosition; + private ImageButton butRev; + private TextView txtvRev; + private ImageButton butPlay; + private ImageButton butFF; + private TextView txtvFF; + private ImageButton butSkip; + private Toolbar toolbar; + private ProgressBar progressIndicator; + + private PlaybackController controller; + private boolean showTimeLeft; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View root = inflater.inflate(R.layout.audioplayer_fragment, container, false); + toolbar = root.findViewById(R.id.toolbar); + toolbar.setTitle(""); + toolbar.setNavigationOnClickListener(v -> + ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED)); + toolbar.setOnMenuItemClickListener(this); + setupOptionsMenu(); + + ExternalPlayerFragment externalPlayerFragment = new ExternalPlayerFragment(); + getFragmentManager().beginTransaction() + .replace(R.id.playerFragment, externalPlayerFragment, ExternalPlayerFragment.TAG) + .commit(); + + butPlaybackSpeed = root.findViewById(R.id.butPlaybackSpeed); + txtvPlaybackSpeed = root.findViewById(R.id.txtvPlaybackSpeed); + sbPosition = root.findViewById(R.id.sbPosition); + txtvPosition = root.findViewById(R.id.txtvPosition); + txtvLength = root.findViewById(R.id.txtvLength); + butRev = root.findViewById(R.id.butRev); + txtvRev = root.findViewById(R.id.txtvRev); + butPlay = root.findViewById(R.id.butPlay); + butFF = root.findViewById(R.id.butFF); + txtvFF = root.findViewById(R.id.txtvFF); + butSkip = root.findViewById(R.id.butSkip); + progressIndicator = root.findViewById(R.id.progLoading); + + setupLengthTextView(); + setupControlButtons(); + setupPlaybackSpeedButton(); + txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs())); + txtvFF.setText(String.valueOf(UserPreferences.getFastForwardSecs())); + sbPosition.setOnSeekBarChangeListener(this); + + pager = root.findViewById(R.id.pager); + AudioPlayerPagerAdapter pagerAdapter = new AudioPlayerPagerAdapter(getFragmentManager()); + pager.setAdapter(pagerAdapter); + // Required for getChildAt(int) in ViewPagerBottomSheetBehavior to return the correct page + pager.setOffscreenPageLimit(NUM_CONTENT_FRAGMENTS); + pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + pager.post(() -> ((MainActivity) getActivity()).getBottomSheet().updateScrollingChild()); + } + }); + pageIndicator = root.findViewById(R.id.page_indicator); + pageIndicator.setViewPager(pager); + pageIndicator.setOnClickListener(v -> + pager.setCurrentItem((pager.getCurrentItem() + 1) % pager.getChildCount())); + return root; + } + + public View getExternalPlayerHolder() { + return getView().findViewById(R.id.playerFragment); + } + + private void setupControlButtons() { + butRev.setOnClickListener(v -> { + if (controller != null) { + int curr = controller.getPosition(); + controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000); + } + }); + butRev.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(getContext(), + SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev); + return true; + }); + butPlay.setOnClickListener(v -> { + if (controller != null) { + controller.init(); + controller.playPause(); + } + }); + butFF.setOnClickListener(v -> { + if (controller != null) { + int curr = controller.getPosition(); + controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000); + } + }); + butFF.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(getContext(), + SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF); + return false; + }); + butSkip.setOnClickListener(v -> + IntentUtils.sendLocalBroadcast(getActivity(), PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + } + + private void setupLengthTextView() { + SharedPreferences prefs = getContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE); + showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); + txtvLength.setOnClickListener(v -> { + if (controller == null) { + return; + } + showTimeLeft = !showTimeLeft; + prefs.edit().putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft).apply(); + updatePosition(new PlaybackPositionEvent(controller.getPosition(), controller.getDuration())); + }); + } + + private void setupPlaybackSpeedButton() { + butPlaybackSpeed.setOnClickListener(v -> { + if (controller == null) { + return; + } + if (!controller.canSetPlaybackSpeed()) { + VariableSpeedDialog.showGetPluginDialog(getContext()); + return; + } + float[] availableSpeeds = UserPreferences.getPlaybackSpeedArray(); + float currentSpeed = controller.getCurrentPlaybackSpeedMultiplier(); + + int newSpeedIndex = 0; + while (newSpeedIndex < availableSpeeds.length && availableSpeeds[newSpeedIndex] < currentSpeed + EPSILON) { + newSpeedIndex++; + } + + float newSpeed; + if (availableSpeeds.length == 0) { + newSpeed = 1.0f; + } else if (newSpeedIndex == availableSpeeds.length) { + newSpeed = availableSpeeds[0]; + } else { + newSpeed = availableSpeeds[newSpeedIndex]; + } + + PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(newSpeed); + UserPreferences.setPlaybackSpeed(newSpeed); + controller.setPlaybackSpeed(newSpeed); + updateUi(); + }); + butPlaybackSpeed.setOnLongClickListener(v -> { + VariableSpeedDialog.showDialog(getContext()); + return true; + }); + butPlaybackSpeed.setVisibility(View.VISIBLE); + txtvPlaybackSpeed.setVisibility(View.VISIBLE); + } + + protected void updatePlaybackSpeedButton() { + if (butPlaybackSpeed == null || controller == null) { + return; + } + float speed = 1.0f; + if (controller.canSetPlaybackSpeed()) { + speed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(controller.getMedia()); + } + String speedStr = new DecimalFormat("0.00").format(speed); + txtvPlaybackSpeed.setText(speedStr); + butPlaybackSpeed.setSpeed(speed); + butPlaybackSpeed.setAlpha(controller.canSetPlaybackSpeed() ? 1.0f : 0.5f); + butPlaybackSpeed.setVisibility(View.VISIBLE); + txtvPlaybackSpeed.setVisibility(View.VISIBLE); + } + + private PlaybackController newPlaybackController() { + return new PlaybackController(getActivity(), false) { + + @Override + public void setupGUI() { + updateUi(); + } + + @Override + public void onBufferStart() { + progressIndicator.setVisibility(View.VISIBLE); + } + + @Override + public void onBufferEnd() { + progressIndicator.setVisibility(View.GONE); + } + + @Override + public void onBufferUpdate(float progress) { + sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax())); + } + + @Override + public void handleError(int code) { + final AlertDialog.Builder errorDialog = new AlertDialog.Builder(getContext()); + errorDialog.setTitle(R.string.error_label); + errorDialog.setMessage(MediaPlayerError.getErrorString(getContext(), code)); + errorDialog.setNeutralButton(android.R.string.ok, + (dialog, which) -> { + dialog.dismiss(); + ((MainActivity) getActivity()).getBottomSheet() + .setState(BottomSheetBehavior.STATE_COLLAPSED); + } + ); + errorDialog.create().show(); + } + + @Override + public void onSleepTimerUpdate() { + setupOptionsMenu(); + } + + @Override + public ImageButton getPlayButton() { + return butPlay; + } + + @Override + public boolean loadMediaInfo() { + updateUi(); + return true; + } + + @Override + public void onShutdownNotification() { + ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED); + } + + @Override + public void onPlaybackEnd() { + ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED); + } + + @Override + public void onPlaybackSpeedChange() { + updatePlaybackSpeedButton(); + } + + @Override + public void onSetSpeedAbilityChanged() { + updatePlaybackSpeedButton(); + } + }; + } + + private void updateUi() { + if (controller == null) { + return; + } + updatePosition(new PlaybackPositionEvent(controller.getPosition(), controller.getDuration())); + updatePlaybackSpeedButton(); + setupOptionsMenu(); + + if (controller.getMedia() != null) { + List<Chapter> chapters = controller.getMedia().getChapters(); + boolean hasChapters = chapters != null && !chapters.isEmpty(); + pageIndicator.setDisabledPage(hasChapters ? -1 : 2); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + } + + @Override + public void onStart() { + super.onStart(); + controller = newPlaybackController(); + controller.init(); + updateUi(); + EventBus.getDefault().register(this); + } + + @Override + public void onStop() { + super.onStop(); + controller.release(); + controller = null; + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void updatePosition(PlaybackPositionEvent event) { + if (controller == null || txtvPosition == null || txtvLength == null || sbPosition == null) { + return; + } + + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + int currentPosition = converter.convert(event.getPosition()); + int duration = converter.convert(event.getDuration()); + int remainingTime = converter.convert(event.getDuration() - event.getPosition()); + Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition)); + if (currentPosition == PlaybackService.INVALID_TIME || duration == PlaybackService.INVALID_TIME) { + Log.w(TAG, "Could not react to position observer update because of invalid time"); + return; + } + txtvPosition.setText(Converter.getDurationStringLong(currentPosition)); + if (showTimeLeft) { + txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime)); + } else { + txtvLength.setText(Converter.getDurationStringLong(duration)); + } + float progress = ((float) event.getPosition()) / event.getDuration(); + sbPosition.setProgress((int) (progress * sbPosition.getMax())); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void favoritesChanged(FavoritesEvent event) { + setupOptionsMenu(); + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (controller == null || txtvLength == null) { + return; + } + if (fromUser) { + float prog = progress / ((float) seekBar.getMax()); + int duration = controller.getDuration(); + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + int position = converter.convert((int) (prog * duration)); + txtvPosition.setText(Converter.getDurationStringLong(position)); + + if (showTimeLeft && prog != 0) { + int timeLeft = converter.convert(duration - (int) (prog * duration)); + String length = "-" + Converter.getDurationStringLong(timeLeft); + txtvLength.setText(length); + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // interrupt position Observer, restart later + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (controller != null) { + float prog = seekBar.getProgress() / ((float) seekBar.getMax()); + controller.seekTo((int) (prog * controller.getDuration())); + } + } + + public void setupOptionsMenu() { + if (toolbar.getMenu().size() == 0) { + toolbar.inflateMenu(R.menu.mediaplayer); + } + if (controller == null) { + return; + } + Playable media = controller.getMedia(); + boolean isFeedMedia = media instanceof FeedMedia; + toolbar.getMenu().findItem(R.id.open_feed_item).setVisible(isFeedMedia); + if (isFeedMedia) { + FeedItemMenuHandler.onPrepareMenu(toolbar.getMenu(), ((FeedMedia) media).getItem()); + } + + toolbar.getMenu().findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive()); + toolbar.getMenu().findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive()); + + ((CastEnabledActivity) getActivity()).requestCastButton(toolbar.getMenu()); + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + if (controller == null) { + return false; + } + Playable media = controller.getMedia(); + if (media == null) { + return false; + } + + final @Nullable FeedItem feedItem = (media instanceof FeedMedia) ? ((FeedMedia) media).getItem() : null; + if (feedItem != null && FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), feedItem)) { + return true; + } + switch (item.getItemId()) { + case R.id.disable_sleeptimer_item: // Fall-through + case R.id.set_sleeptimer_item: + new SleepTimerDialog().show(getFragmentManager(), "SleepTimerDialog"); + return true; + case R.id.audio_controls: + PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(false); + dialog.show(getFragmentManager(), "playback_controls"); + return true; + case R.id.open_feed_item: + if (feedItem != null) { + Intent intent = MainActivity.getIntentToOpenFeed(getContext(), feedItem.getFeedId()); + startActivity(intent); + } + return true; + } + return false; + } + + private static class AudioPlayerPagerAdapter extends FragmentPagerAdapter { + private static final String TAG = "AudioPlayerPagerAdapter"; + + public AudioPlayerPagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + Log.d(TAG, "getItem(" + position + ")"); + switch (position) { + case POS_COVER: + return new CoverFragment(); + case POS_DESCR: + return new ItemDescriptionFragment(); + case POS_CHAPTERS: + return new ChaptersFragment(); + default: + return null; + } + } + + @Override + public int getCount() { + return NUM_CONTENT_FRAGMENTS; + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java index 9940ccbdd..0aba568d1 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java @@ -1,24 +1,24 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import androidx.fragment.app.ListFragment; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; -import android.widget.ListView; - -import de.danoeh.antennapod.core.util.ChapterUtils; -import java.util.List; -import java.util.ListIterator; - +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.ChaptersListAdapter; -import de.danoeh.antennapod.adapter.QueueRecyclerAdapter; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.service.playback.PlayerStatus; +import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; - import de.danoeh.antennapod.view.EmptyViewHandler; import io.reactivex.Maybe; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -28,38 +28,43 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -public class ChaptersFragment extends ListFragment { +public class ChaptersFragment extends Fragment { private static final String TAG = "ChaptersFragment"; private ChaptersListAdapter adapter; private PlaybackController controller; private Disposable disposable; private int focusedChapter = -1; private Playable media; + private LinearLayoutManager layoutManager; + @Nullable @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); - - EmptyViewHandler emptyView = new EmptyViewHandler(getContext()); - emptyView.attachToListView(lv); - emptyView.setIcon(R.attr.ic_bookmark); - emptyView.setTitle(R.string.no_chapters_head_label); - emptyView.setMessage(R.string.no_chapters_label); - - adapter = new ChaptersListAdapter(getActivity(), 0, pos -> { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.simple_list_fragment, container, false); + root.findViewById(R.id.toolbar).setVisibility(View.GONE); + RecyclerView recyclerView = root.findViewById(R.id.recyclerView); + layoutManager = new LinearLayoutManager(getActivity()); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setHasFixedSize(true); + recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); + + adapter = new ChaptersListAdapter(getActivity(), pos -> { if (controller.getStatus() != PlayerStatus.PLAYING) { controller.playPause(); } - Chapter chapter = (Chapter) getListAdapter().getItem(pos); + Chapter chapter = adapter.getItem(pos); controller.seekToChapter(chapter); updateChapterSelection(pos); }); - setListAdapter(adapter); + recyclerView.setAdapter(adapter); + + EmptyViewHandler emptyView = new EmptyViewHandler(getContext()); + emptyView.attachToRecyclerView(recyclerView); + emptyView.setIcon(R.attr.ic_bookmark); + emptyView.setTitle(R.string.no_chapters_head_label); + emptyView.setMessage(R.string.no_chapters_label); + + return root; } @Override @@ -136,7 +141,6 @@ public class ChaptersFragment extends ListFragment { return; } adapter.setMedia(media); - adapter.notifyDataSetChanged(); int positionOfCurrentChapter = getCurrentChapter(media); updateChapterSelection(positionOfCurrentChapter); } @@ -149,9 +153,9 @@ public class ChaptersFragment extends ListFragment { if (position != -1 && focusedChapter != position) { focusedChapter = position; adapter.notifyChapterChanged(focusedChapter); - if (getListView().getFirstVisiblePosition() >= position - || getListView().getLastVisiblePosition() <= position) { - getListView().setSelectionFromTop(position, 100); + if (layoutManager.findFirstCompletelyVisibleItemPosition() >= position + || layoutManager.findLastCompletelyVisibleItemPosition() <= position) { + layoutManager.scrollToPositionWithOffset(position, 100); } } } 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 ce2232a55..03b1d6f8f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -1,9 +1,7 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; -import android.os.Build; import android.os.Bundle; -import androidx.core.app.ActivityOptionsCompat; import androidx.fragment.app.Fragment; import android.util.Log; import android.view.LayoutInflater; @@ -17,7 +15,9 @@ import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import com.google.android.material.bottomsheet.BottomSheetBehavior; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.glide.ApGlideSettings; @@ -40,7 +40,6 @@ import org.greenrobot.eventbus.ThreadMode; public class ExternalPlayerFragment extends Fragment { public static final String TAG = "ExternalPlayerFragment"; - private ViewGroup fragmentLayout; private ImageView imgvCover; private TextView txtvTitle; private ImageButton butPlay; @@ -56,26 +55,21 @@ public class ExternalPlayerFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.external_player_fragment, - container, false); - fragmentLayout = root.findViewById(R.id.fragmentLayout); + View root = inflater.inflate(R.layout.external_player_fragment, container, false); imgvCover = root.findViewById(R.id.imgvCover); txtvTitle = root.findViewById(R.id.txtvTitle); butPlay = root.findViewById(R.id.butPlay); mFeedName = root.findViewById(R.id.txtvAuthor); mProgressBar = root.findViewById(R.id.episodeProgress); - fragmentLayout.setOnClickListener(v -> { + root.findViewById(R.id.fragmentLayout).setOnClickListener(v -> { Log.d(TAG, "layoutInfo was clicked"); if (controller != null && controller.getMedia() != null) { - Intent intent = PlaybackService.getPlayerActivityIntent(getActivity(), controller.getMedia()); - if (controller.getMedia().getMediaType() == MediaType.AUDIO) { - ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation(getActivity(), imgvCover, "coverTransition"); - startActivity(intent, options.toBundle()); + ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_EXPANDED); } else { + Intent intent = PlaybackService.getPlayerActivityIntent(getActivity(), controller.getMedia()); startActivity(intent); } } @@ -178,9 +172,7 @@ public class ExternalPlayerFragment extends Fragment { } private void playbackDone() { - if (fragmentLayout != null) { - fragmentLayout.setVisibility(View.GONE); - } + clearUi(); if (controller != null) { controller.release(); } @@ -217,10 +209,22 @@ public class ExternalPlayerFragment extends Fragment { .observeOn(AndroidSchedulers.mainThread()) .subscribe(media -> updateUi((Playable) media), error -> Log.e(TAG, Log.getStackTraceString(error)), - () -> fragmentLayout.setVisibility(View.GONE)); + this::clearUi); return true; } + private void clearUi() { + if (txtvTitle == null || mFeedName == null || mProgressBar == null || butPlay == null) { + return; + } + txtvTitle.setText(R.string.no_media_playing_label); + mFeedName.setText(""); + butPlay.setVisibility(View.GONE); + mProgressBar.setProgress(0); + Glide.with(getActivity()).clear(imgvCover); + ((MainActivity) getActivity()).getBottomSheet().setLocked(true); + } + private void updateUi(Playable media) { if (media != null) { txtvTitle.setText(media.getEpisodeTitle()); @@ -236,12 +240,13 @@ public class ExternalPlayerFragment extends Fragment { .fitCenter() .dontAnimate()) .into(imgvCover); - - fragmentLayout.setVisibility(View.VISIBLE); if (controller != null && controller.isPlayingVideoLocally()) { butPlay.setVisibility(View.GONE); + ((MainActivity) getActivity()).getBottomSheet().setLocked(true); + ((MainActivity) getActivity()).getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED); } else { butPlay.setVisibility(View.VISIBLE); + ((MainActivity) getActivity()).getBottomSheet().setLocked(false); } } else { Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!"); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index 2cddc10cb..23b8b7f19 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -200,10 +200,10 @@ public class FeedSettingsFragment extends Fragment { private void setupAuthentificationPreference() { findPreference("authentication").setOnPreferenceClickListener(preference -> { new AuthenticationDialog(getContext(), - R.string.authentication_label, true, false, + R.string.authentication_label, true, feedPreferences.getUsername(), feedPreferences.getPassword()) { @Override - protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { + protected void onConfirmed(String username, String password) { feedPreferences.setUsername(username); feedPreferences.setPassword(password); feed.savePreferences(); 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 256615199..58cc9290c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -10,6 +10,7 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.util.playback.PlaybackController; import de.danoeh.antennapod.core.util.playback.Timeline; import de.danoeh.antennapod.view.ShownotesWebView; @@ -35,7 +36,8 @@ public class ItemDescriptionFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "Creating view"); - webvDescription = new ShownotesWebView(getActivity().getApplicationContext()); + View root = inflater.inflate(R.layout.item_description_fragment, container, false); + webvDescription = root.findViewById(R.id.webview); webvDescription.setTimecodeSelectedListener(time -> { if (controller != null) { controller.seekTo(time); @@ -46,7 +48,7 @@ public class ItemDescriptionFragment extends Fragment { webvDescription.postDelayed(ItemDescriptionFragment.this::restoreFromPreference, 50); }); registerForContextMenu(webvDescription); - return webvDescription; + return root; } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java index f251de5ec..aac89a65f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemPagerFragment.java @@ -41,16 +41,6 @@ public class ItemPagerFragment extends Fragment { /** * Creates a new instance of an ItemPagerFragment. * - * @param feeditem The ID of the FeedItem that should be displayed. - * @return The ItemFragment instance - */ - public static ItemPagerFragment newInstance(long feeditem) { - return newInstance(new long[] { feeditem }, 0); - } - - /** - * Creates a new instance of an ItemPagerFragment. - * * @param feeditems The IDs of the FeedItems that belong to the same list * @param feedItemPos The position of the FeedItem that is currently shown * @return The ItemFragment instance @@ -146,9 +136,6 @@ public class ItemPagerFragment extends Fragment { return; } super.onCreateOptionsMenu(menu, inflater); - if (Flavors.FLAVOR == Flavors.PLAY) { - ((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS); - } inflater.inflate(R.menu.feeditem_options, menu); if (item.hasMedia()) { FeedItemMenuHandler.onPrepareMenu(menu, item); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java index 63969345c..0dff8f24b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NavDrawerFragment.java @@ -48,7 +48,7 @@ import org.greenrobot.eventbus.Subscribe; import java.util.List; public class NavDrawerFragment extends Fragment implements AdapterView.OnItemClickListener, - AdapterView.OnItemLongClickListener { + AdapterView.OnItemLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener { @VisibleForTesting public static final String PREF_LAST_FRAGMENT_TAG = "prefLastFragmentTag"; @VisibleForTesting @@ -88,6 +88,8 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli root.findViewById(R.id.nav_settings).setOnClickListener(v -> { startActivity(new Intent(getActivity(), PreferenceActivity.class)); }); + getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .registerOnSharedPreferenceChangeListener(this); return root; } @@ -124,6 +126,8 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli if (disposable != null) { disposable.dispose(); } + getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + .unregisterOnSharedPreferenceChangeListener(this); } @Override @@ -192,7 +196,6 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli } else { showMainActivity(EpisodesFragment.TAG); } - saveLastNavFragment(getContext(), EpisodesFragment.TAG); } } }; @@ -371,7 +374,6 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli } else { showMainActivity(tag); } - saveLastNavFragment(getContext(), tag); } else { int pos = position - navAdapter.getSubscriptionOffset(); long feedId = navDrawerData.feeds.get(pos).getId(); @@ -382,10 +384,7 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli intent.putExtra(MainActivity.EXTRA_FEED_ID, feedId); startActivity(intent); } - saveLastNavFragment(getContext(), String.valueOf(feedId)); } - selectedNavListIndex = position; - navAdapter.notifyDataSetChanged(); } } @@ -418,4 +417,12 @@ public class NavDrawerFragment extends Fragment implements AdapterView.OnItemCli Log.d(TAG, "getLastNavFragment() -> " + lastFragment); return lastFragment; } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (PREF_LAST_FRAGMENT_TAG.equals(key)) { + updateSelection(); + navAdapter.notifyDataSetChanged(); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 0a752b855..0411fd01b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -416,11 +416,11 @@ public class QueueFragment extends Fragment { recyclerAdapter.setLocked(locked); } if (locked) { - Snackbar.make(getActivity().findViewById(R.id.content), R.string - .queue_locked, Snackbar.LENGTH_SHORT).show(); + Snackbar.make(getActivity().findViewById(android.R.id.content), + R.string.queue_locked, Snackbar.LENGTH_SHORT).show(); } else { - Snackbar.make(getActivity().findViewById(R.id.content), R.string - .queue_unlocked, Snackbar.LENGTH_SHORT).show(); + Snackbar.make(getActivity().findViewById(android.R.id.content), + R.string.queue_unlocked, Snackbar.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java index e34f1ea1c..3ebdd80d8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java @@ -1,6 +1,5 @@ package de.danoeh.antennapod.fragment.gpodnet; -import android.content.res.Resources; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -28,7 +27,7 @@ public class GpodnetMainFragment extends Fragment { ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar); ViewPager viewPager = root.findViewById(R.id.viewpager); - GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources()); + GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager()); viewPager.setAdapter(pagerAdapter); // Give the TabLayout the ViewPager @@ -39,18 +38,13 @@ public class GpodnetMainFragment extends Fragment { } public class GpodnetPagerAdapter extends FragmentPagerAdapter { - - private static final int NUM_PAGES = 2; private static final int POS_TOPLIST = 0; private static final int POS_TAGS = 1; private static final int POS_SUGGESTIONS = 2; - final Resources resources; - - public GpodnetPagerAdapter(FragmentManager fm, Resources resources) { + public GpodnetPagerAdapter(FragmentManager fm) { super(fm); - this.resources = resources; } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java index 1e51380ca..271b31fad 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java @@ -63,11 +63,11 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat { findPreference(PREF_GPODNET_SETLOGIN_INFORMATION) .setOnPreferenceClickListener(preference -> { AuthenticationDialog dialog = new AuthenticationDialog(activity, - R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(), + R.string.pref_gpodnet_setlogin_information_title, false, GpodnetPreferences.getUsername(), null) { @Override - protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { + protected void onConfirmed(String username, String password) { GpodnetPreferences.setPassword(password); } }; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java index 1ca8f63aa..f9015c006 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java @@ -96,8 +96,7 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat { private void setParallelDownloadsText(int downloads) { final Resources res = getActivity().getResources(); - String s = Integer.toString(downloads) - + res.getString(R.string.parallel_downloads_suffix); + String s = downloads + res.getString(R.string.parallel_downloads_suffix); findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java index 34684ac49..6b2255b52 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java @@ -9,11 +9,11 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.MediaplayerActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; +import de.danoeh.antennapod.dialog.SkipPreferenceDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; import de.danoeh.antennapod.preferences.PreferenceControllerFlavorHelper; import java.util.Map; @@ -48,11 +48,11 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat { return true; }); findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER).setOnPreferenceClickListener(preference -> { - MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND); + SkipPreferenceDialog.showSkipPreference(activity, SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null); return true; }); findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER).setOnPreferenceClickListener(preference -> { - MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD); + SkipPreferenceDialog.showSkipPreference(activity, SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null); return true; }); if (!PictureInPictureUtil.supportsPictureInPicture(activity)) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index c3611d683..0ea8d5b93 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -8,7 +8,6 @@ import com.google.android.material.snackbar.Snackbar; import androidx.appcompat.app.AlertDialog; import androidx.preference.PreferenceFragmentCompat; import android.widget.ListView; -import android.widget.Toast; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.PreferenceActivity; @@ -19,7 +18,6 @@ import org.apache.commons.lang3.ArrayUtils; import java.util.List; public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { - private static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -59,26 +57,26 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { findPreference(UserPreferences.PREF_BACK_BUTTON_BEHAVIOR) .setOnPreferenceChangeListener((preference, newValue) -> { - if (newValue.equals("page")) { - final Context context = getActivity(); - final String[] navTitles = context.getResources().getStringArray(R.array.back_button_go_to_pages); - final String[] navTags = context.getResources().getStringArray(R.array.back_button_go_to_pages_tags); - final String[] choice = { UserPreferences.getBackButtonGoToPage() }; + if (!newValue.equals("page")) { + return true; + } + final Context context = getActivity(); + final String[] navTitles = context.getResources().getStringArray(R.array.back_button_go_to_pages); + final String[] navTags = context.getResources().getStringArray(R.array.back_button_go_to_pages_tags); + final String[] choice = { UserPreferences.getBackButtonGoToPage() }; - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.back_button_go_to_page_title); - builder.setSingleChoiceItems(navTitles, ArrayUtils.indexOf(navTags, UserPreferences.getBackButtonGoToPage()), (dialogInterface, i) -> { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.back_button_go_to_page_title); + builder.setSingleChoiceItems(navTitles, ArrayUtils.indexOf(navTags, + UserPreferences.getBackButtonGoToPage()), (dialogInterface, i) -> { if (i >= 0) { choice[0] = navTags[i]; } }); - builder.setPositiveButton(R.string.confirm_label, (dialogInterface, i) -> UserPreferences.setBackButtonGoToPage(choice[0])); - builder.setNegativeButton(R.string.cancel_label, null); - builder.create().show(); - return true; - } else { - return true; - } + builder.setPositiveButton(R.string.confirm_label, (dialogInterface, i) -> UserPreferences.setBackButtonGoToPage(choice[0])); + builder.setNegativeButton(R.string.cancel_label, null); + builder.create().show(); + return true; }); if (Build.VERSION.SDK_INT >= 26) { |