Merge pull request #4020 from ebraminio/rtl

Adopt the project with ViewPager2
This commit is contained in:
H. Lehmann 2020-05-01 12:40:03 +02:00 committed by GitHub
commit b870c233ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 371 additions and 233 deletions

View File

@ -142,6 +142,7 @@ dependencies {
implementation "androidx.preference:preference:1.1.0"
implementation "androidx.gridlayout:gridlayout:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "androidx.media:media:1.1.0"
implementation "androidx.work:work-runtime:$workManagerVersion"

View File

@ -4,8 +4,10 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.view.ViewCompat;
import androidx.viewpager.widget.ViewPager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.lang.ref.WeakReference;
@ -31,9 +33,10 @@ public class ViewPagerBottomSheetBehavior<V extends View> extends BottomSheetBeh
return view;
}
if (view instanceof ViewPager) {
ViewPager viewPager = (ViewPager) view;
View currentViewPagerChild = viewPager.getChildAt(viewPager.getCurrentItem());
if (view instanceof ViewPager2) {
ViewPager2 viewPager = (ViewPager2) view;
RecyclerView recycler = (RecyclerView) viewPager.getChildAt(0);
View currentViewPagerChild = recycler.getChildAt(viewPager.getCurrentItem());
if (currentViewPagerChild != null) {
return findScrollingChild(currentViewPagerChild);
}

View File

@ -13,20 +13,28 @@ import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
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 androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.text.DecimalFormat;
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;
@ -50,12 +58,6 @@ import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
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.
@ -73,7 +75,7 @@ public class AudioPlayerFragment extends Fragment implements
PlaybackSpeedIndicatorView butPlaybackSpeed;
TextView txtvPlaybackSpeed;
private ViewPager pager;
private ViewPager2 pager;
private PagerIndicatorView pageIndicator;
private TextView txtvPosition;
private TextView txtvLength;
@ -127,11 +129,10 @@ public class AudioPlayerFragment extends Fragment implements
sbPosition.setOnSeekBarChangeListener(this);
pager = root.findViewById(R.id.pager);
AudioPlayerPagerAdapter pagerAdapter = new AudioPlayerPagerAdapter(getChildFragmentManager());
pager.setAdapter(pagerAdapter);
pager.setAdapter(new AudioPlayerPagerAdapter(this));
// Required for getChildAt(int) in ViewPagerBottomSheetBehavior to return the correct page
pager.setOffscreenPageLimit(NUM_CONTENT_FRAGMENTS);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
pager.setOffscreenPageLimit((int) NUM_CONTENT_FRAGMENTS);
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
pager.post(() -> ((MainActivity) getActivity()).getBottomSheet().updateScrollingChild());
@ -502,30 +503,30 @@ public class AudioPlayerFragment extends Fragment implements
return false;
}
private static class AudioPlayerPagerAdapter extends FragmentPagerAdapter {
private static class AudioPlayerPagerAdapter extends FragmentStateAdapter {
private static final String TAG = "AudioPlayerPagerAdapter";
public AudioPlayerPagerAdapter(FragmentManager fm) {
super(fm);
public AudioPlayerPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment getItem(int position) {
public Fragment createFragment(int position) {
Log.d(TAG, "getItem(" + position + ")");
switch (position) {
case POS_COVER:
return new CoverFragment();
case POS_DESCR:
return new ItemDescriptionFragment();
default:
case POS_CHAPTERS:
return new ChaptersFragment();
default:
return null;
}
}
@Override
public int getCount() {
public int getItemCount() {
return NUM_CONTENT_FRAGMENTS;
}
}

View File

@ -86,10 +86,15 @@ public class CompletedDownloadsFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
setHasOptionsMenu(true);
loadItems();
}
@Override
public void onResume() {
super.onResume();
setHasOptionsMenu(true);
}
@Override
public void onStop() {
super.onStop();

View File

@ -50,6 +50,12 @@ public class DownloadLogFragment extends ListFragment {
loadItems();
}
@Override
public void onResume() {
super.onResume();
setHasOptionsMenu(true);
}
@Override
public void onStop() {
super.onStop();
@ -61,8 +67,6 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
// add padding
final ListView lv = getListView();
lv.setClipToPadding(false);

View File

@ -2,19 +2,21 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
/**
@ -29,10 +31,11 @@ public class DownloadsFragment extends Fragment {
public static final int POS_RUNNING = 0;
private static final int POS_COMPLETED = 1;
public static final int POS_LOG = 2;
private static final int TOTAL_COUNT = 3;
private static final String PREF_LAST_TAB_POSITION = "tab_position";
private ViewPager viewPager;
private ViewPager2 viewPager;
private TabLayout tabLayout;
@Override
@ -44,12 +47,30 @@ public class DownloadsFragment extends Fragment {
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
viewPager = root.findViewById(R.id.viewpager);
DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
viewPager.setAdapter(new DownloadsPagerAdapter(this));
// Give the TabLayout the ViewPager
tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
case POS_RUNNING:
tab.setText(R.string.downloads_running_label);
break;
case POS_COMPLETED:
tab.setText(R.string.downloads_completed_label);
break;
case POS_LOG:
tab.setText(R.string.downloads_log_label);
break;
default:
break;
}
}).attach();
// restore our last position
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
viewPager.setCurrentItem(lastPosition, false);
return root;
}
@ -73,56 +94,29 @@ public class DownloadsFragment extends Fragment {
editor.apply();
}
@Override
public void onStart() {
super.onStart();
public static class DownloadsPagerAdapter extends FragmentStateAdapter {
// restore our last position
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
viewPager.setCurrentItem(lastPosition);
}
public static class DownloadsPagerAdapter extends FragmentPagerAdapter {
final Resources resources;
public DownloadsPagerAdapter(FragmentManager fm, Resources resources) {
super(fm);
this.resources = resources;
DownloadsPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment getItem(int position) {
public Fragment createFragment(int position) {
switch (position) {
case POS_RUNNING:
return new RunningDownloadsFragment();
case POS_COMPLETED:
return new CompletedDownloadsFragment();
default:
case POS_LOG:
return new DownloadLogFragment();
default:
return null;
}
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case POS_RUNNING:
return resources.getString(R.string.downloads_running_label);
case POS_COMPLETED:
return resources.getString(R.string.downloads_completed_label);
case POS_LOG:
return resources.getString(R.string.downloads_log_label);
default:
return super.getPageTitle(position);
}
public int getItemCount() {
return TOTAL_COUNT;
}
}
}

View File

@ -6,13 +6,17 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
public class EpisodesFragment extends Fragment {
@ -27,7 +31,7 @@ public class EpisodesFragment extends Fragment {
private TabLayout tabLayout;
private ViewPager viewPager;
private ViewPager2 viewPager;
//Mandatory Constructor
public EpisodesFragment() {
@ -46,11 +50,32 @@ public class EpisodesFragment extends Fragment {
toolbar.setTitle(R.string.episodes_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
viewPager = rootView.findViewById(R.id.viewpager);
viewPager.setAdapter(new EpisodesPagerAdapter());
viewPager.setAdapter(new EpisodesPagerAdapter(this));
// Give the TabLayout the ViewPager
tabLayout = rootView.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
case POS_NEW_EPISODES:
tab.setText(R.string.new_episodes_label);
break;
case POS_ALL_EPISODES:
tab.setText(R.string.all_episodes_short_label);
break;
case POS_FAV_EPISODES:
tab.setText(R.string.favorite_episodes_label);
break;
default:
break;
}
}).attach();
// restore our last position
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
viewPager.setCurrentItem(lastPosition, false);
return rootView;
}
@ -64,52 +89,29 @@ public class EpisodesFragment extends Fragment {
editor.apply();
}
@Override
public void onStart() {
super.onStart();
static class EpisodesPagerAdapter extends FragmentStateAdapter {
// restore our last position
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
viewPager.setCurrentItem(lastPosition);
}
public class EpisodesPagerAdapter extends FragmentPagerAdapter {
public EpisodesPagerAdapter() {
super(getChildFragmentManager());
EpisodesPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@Override
@NonNull
public Fragment getItem(int position) {
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
case POS_NEW_EPISODES:
return new NewEpisodesFragment();
case 1:
case POS_ALL_EPISODES:
return new AllEpisodesFragment();
default:
case POS_FAV_EPISODES:
return new FavoriteEpisodesFragment();
}
}
@Override
public int getCount() {
public int getItemCount() {
return TOTAL_COUNT;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case POS_ALL_EPISODES:
return getString(R.string.all_episodes_short_label);
case POS_NEW_EPISODES:
return getString(R.string.new_episodes_label);
case POS_FAV_EPISODES:
return getString(R.string.favorite_episodes_label);
default:
return super.getPageTitle(position);
}
}
}
}

View File

@ -83,7 +83,6 @@ public abstract class EpisodesListFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
setHasOptionsMenu(true);
EventBus.getDefault().register(this);
loadItems();
}
@ -91,6 +90,7 @@ public abstract class EpisodesListFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
setHasOptionsMenu(true);
registerForContextMenu(recyclerView);
}

View File

@ -7,29 +7,30 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Flavors;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
* Displays information about a list of FeedItems.
@ -41,7 +42,7 @@ public class ItemPagerFragment extends Fragment {
/**
* Creates a new instance of an ItemPagerFragment.
*
* @param feeditems The IDs of the FeedItems that belong to the same list
* @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
*/
@ -76,31 +77,21 @@ public class ItemPagerFragment extends Fragment {
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
int feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
ViewPager pager = layout.findViewById(R.id.pager);
ViewPager2 pager = layout.findViewById(R.id.pager);
// FragmentStatePagerAdapter documentation:
// > When using FragmentStatePagerAdapter the host ViewPager must have a valid ID set.
// When opening multiple ItemPagerFragments by clicking "item" -> "visit podcast" -> "item" -> etc,
// the ID is no longer unique and FragmentStatePagerAdapter does not display any pages.
int newId = ViewCompat.generateViewId();
pager.setId(newId);
pager.setAdapter(new ItemPagerAdapter());
pager.setCurrentItem(feedItemPos);
pager.setAdapter(new ItemPagerAdapter(this));
pager.setCurrentItem(feedItemPos, false);
loadItem(feedItems[feedItemPos]);
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
loadItem(feedItems[position]);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
EventBus.getDefault().register(this);
@ -173,20 +164,20 @@ public class ItemPagerFragment extends Fragment {
((MainActivity) getActivity()).loadChildFragment(fragment);
}
private class ItemPagerAdapter extends FragmentStatePagerAdapter {
private class ItemPagerAdapter extends FragmentStateAdapter {
ItemPagerAdapter() {
super(getFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
ItemPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment getItem(int position) {
public Fragment createFragment(int position) {
return ItemFragment.newInstance(feedItems[position]);
}
@Override
public int getCount() {
public int getItemCount() {
return feedItems.length;
}
}

View File

@ -4,13 +4,17 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
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 androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
/**
@ -18,6 +22,11 @@ import de.danoeh.antennapod.R;
*/
public class GpodnetMainFragment extends Fragment {
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;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
@ -26,63 +35,59 @@ public class GpodnetMainFragment extends Fragment {
toolbar.setTitle(R.string.gpodnet_main_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
ViewPager viewPager = root.findViewById(R.id.viewpager);
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager());
ViewPager2 viewPager = root.findViewById(R.id.viewpager);
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(this);
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
TabLayout tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
case POS_TAGS:
tab.setText(R.string.gpodnet_taglist_header);
break;
case POS_TOPLIST:
tab.setText(R.string.gpodnet_toplist_header);
break;
default:
case POS_SUGGESTIONS:
tab.setText(R.string.gpodnet_suggestions_header);
break;
}
}).attach();
return root;
}
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;
public static class GpodnetPagerAdapter extends FragmentStateAdapter {
public GpodnetPagerAdapter(FragmentManager fm) {
super(fm);
GpodnetPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment getItem(int i) {
public Fragment createFragment(int position) {
Bundle arguments = new Bundle();
arguments.putBoolean(PodcastListFragment.ARGUMENT_HIDE_TOOLBAR, true);
switch (i) {
switch (position) {
case POS_TAGS:
return new TagListFragment();
case POS_TOPLIST:
PodcastListFragment topListFragment = new PodcastTopListFragment();
topListFragment.setArguments(arguments);
return topListFragment;
default:
case POS_SUGGESTIONS:
PodcastListFragment suggestionsFragment = new SuggestionListFragment();
suggestionsFragment.setArguments(arguments);
return suggestionsFragment;
default:
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case POS_TAGS:
return getString(R.string.gpodnet_taglist_header);
case POS_TOPLIST:
return getString(R.string.gpodnet_toplist_header);
case POS_SUGGESTIONS:
return getString(R.string.gpodnet_suggestions_header);
default:
return super.getPageTitle(position);
}
}
@Override
public int getCount() {
public int getItemCount() {
return NUM_PAGES;
}
}

View File

@ -1,17 +1,17 @@
package de.danoeh.antennapod.fragment.preferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
@ -29,25 +29,35 @@ public class StatisticsFragment extends Fragment {
private TabLayout tabLayout;
private ViewPager viewPager;
private ViewPager2 viewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(true);
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
viewPager = rootView.findViewById(R.id.viewpager);
viewPager.setAdapter(new StatisticsPagerAdapter(getChildFragmentManager(), getResources()));
viewPager.setAdapter(new StatisticsPagerAdapter(this));
// Give the TabLayout the ViewPager
tabLayout = rootView.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
case POS_LISTENED_HOURS:
tab.setText(R.string.playback_statistics_label);
break;
case POS_SPACE_TAKEN:
tab.setText(R.string.download_statistics_label);
break;
default:
break;
}
}).attach();
rootView.findViewById(R.id.toolbar).setVisibility(View.GONE);
@ -60,39 +70,27 @@ public class StatisticsFragment extends Fragment {
((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
}
public static class StatisticsPagerAdapter extends FragmentPagerAdapter {
public static class StatisticsPagerAdapter extends FragmentStateAdapter {
private final Resources resources;
public StatisticsPagerAdapter(FragmentManager fm, Resources resources) {
super(fm);
this.resources = resources;
StatisticsPagerAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment getItem(int position) {
if (position == 0) {
return new PlaybackStatisticsFragment();
} else {
return new DownloadStatisticsFragment();
}
}
@Override
public int getCount() {
return TOTAL_COUNT;
}
@Override
public CharSequence getPageTitle(int position) {
public Fragment createFragment(int position) {
switch (position) {
case POS_LISTENED_HOURS:
return resources.getString(R.string.playback_statistics_label);
case POS_SPACE_TAKEN:
return resources.getString(R.string.download_statistics_label);
return new PlaybackStatisticsFragment();
default:
return super.getPageTitle(position);
case POS_SPACE_TAKEN:
return new DownloadStatisticsFragment();
}
}
@Override
public int getItemCount() {
return TOTAL_COUNT;
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Source: https://github.com/android/views-widgets-samples/blob/87e58d1/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/NestedScrollableHost.kt
* And modified for our need
*/
package de.danoeh.antennapod.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager2.widget.ViewPager2;
import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL;
import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL;
/**
* Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem
* where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as
* ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.
*
* <p>This solution has limitations when using multiple levels of nested scrollable elements
* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).
*/
class NestedScrollableHost extends FrameLayout {
public NestedScrollableHost(@NonNull Context context) {
super(context);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
private int touchSlop = 0;
private float initialX = 0f;
private float initialY = 0f;
private ViewPager2 getParentViewPager() {
View v = (View) getParent();
while (v != null && !(v instanceof ViewPager2)) {
v = (View) v.getParent();
}
return v == null ? null : (ViewPager2) v;
}
public boolean onInterceptTouchEvent(MotionEvent e) {
ViewPager2 parentViewPager = getParentViewPager();
if (parentViewPager == null) {
return super.onInterceptTouchEvent(e);
}
ViewParent parent = getParent();
int orientation = parentViewPager.getOrientation();
if (e.getAction() == MotionEvent.ACTION_DOWN) {
initialX = e.getX();
initialY = e.getY();
parent.requestDisallowInterceptTouchEvent(true);
} else if (e.getAction() == MotionEvent.ACTION_MOVE) {
int dx = (int) (e.getX() - initialX);
int dy = (int) (e.getY() - initialY);
boolean isVpHorizontal = orientation == ORIENTATION_HORIZONTAL;
// assuming ViewPager2 touch-slop is 2x touch-slop of child
float scaledDx = Math.abs(dx) * (isVpHorizontal ? .5f : 1f);
float scaledDy = Math.abs(dy) * (isVpHorizontal ? 1f : .5f);
if (scaledDx > touchSlop || scaledDy > touchSlop) {
int value = isVpHorizontal ? dy : dx;
if (isVpHorizontal == (scaledDy > scaledDx)) {
// Gesture is perpendicular
orientation = orientation == ORIENTATION_VERTICAL
? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
value = isVpHorizontal ? dy : dx;
}
int direction = (int) -Math.copySign(1, value);
View child = getChildAt(0);
if (orientation == ORIENTATION_HORIZONTAL) {
parent.requestDisallowInterceptTouchEvent(child.canScrollHorizontally(direction));
} else {
parent.requestDisallowInterceptTouchEvent(child.canScrollVertically(direction));
}
}
}
return super.onInterceptTouchEvent(e);
}
}

View File

@ -1,15 +1,20 @@
package de.danoeh.antennapod.view;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.vectordrawable.graphics.drawable.ArgbEvaluator;
import androidx.viewpager.widget.ViewPager;
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.util.Locale;
public class PagerIndicatorView extends View {
private final Paint paint = new Paint();
@ -38,26 +43,31 @@ public class PagerIndicatorView extends View {
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
int[] colorAttrs = new int[] { android.R.attr.textColorSecondary };
int[] colorAttrs = new int[]{android.R.attr.textColorSecondary};
TypedArray a = getContext().obtainStyledAttributes(colorAttrs);
circleColorHighlight = a.getColor(0, 0xffffffff);
circleColor = (Integer) new ArgbEvaluator().evaluate(0.8f, 0x00ffffff, circleColorHighlight);
a.recycle();
}
public void setViewPager(ViewPager pager) {
numPages = pager.getAdapter().getCount();
pager.getAdapter().registerDataSetObserver(new DataSetObserver() {
public void setViewPager(ViewPager2 pager) {
numPages = pager.getAdapter().getItemCount();
pager.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
numPages = pager.getAdapter().getCount();
numPages = pager.getAdapter().getItemCount();
invalidate();
}
});
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
boolean isLocaleRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
== ViewCompat.LAYOUT_DIRECTION_RTL;
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
PagerIndicatorView.this.position = position + positionOffset;
if (isLocaleRtl) {
PagerIndicatorView.this.position = numPages - 1 - PagerIndicatorView.this.position;
}
invalidate();
}
});

View File

@ -34,7 +34,7 @@
tools:background="@android:color/holo_green_light"
android:elevation="8dp"/>
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"

View File

@ -171,12 +171,18 @@
</LinearLayout>
<de.danoeh.antennapod.view.ShownotesWebView
android:id="@+id/webvDescription"
android:layout_width="match_parent"
<de.danoeh.antennapod.view.NestedScrollableHost
android:layout_below="@id/header"
android:layout_height="match_parent"
android:foreground="?android:windowContentOverlay" />
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.danoeh.antennapod.view.ShownotesWebView
android:id="@+id/webvDescription"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:windowContentOverlay" />
</de.danoeh.antennapod.view.NestedScrollableHost>
<FrameLayout
android:layout_width="match_parent"

View File

@ -14,7 +14,7 @@
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@ -1,11 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">
<de.danoeh.antennapod.view.ShownotesWebView
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">
<de.danoeh.antennapod.view.NestedScrollableHost
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.danoeh.antennapod.view.ShownotesWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content" />
</de.danoeh.antennapod.view.NestedScrollableHost>
</androidx.core.widget.NestedScrollView>

View File

@ -21,9 +21,9 @@
app:tabMode="fixed"
app:tabGravity="fill"/>
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -14,7 +14,7 @@
app:tabGravity="fill"
app:tabMode="fixed" />
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"