diff --git a/org.envirocar.app/res/layout/activity_base_main_bottom_bar.xml b/org.envirocar.app/res/layout/activity_base_main_bottom_bar.xml index 33cb5c623..08ceb1002 100644 --- a/org.envirocar.app/res/layout/activity_base_main_bottom_bar.xml +++ b/org.envirocar.app/res/layout/activity_base_main_bottom_bar.xml @@ -34,7 +34,7 @@ android:elevation="10dp" app:layout_constraintBottom_toBottomOf="@+id/fragmentContainer"/> - - + android:layout_weight="1"> + + + \ No newline at end of file diff --git a/org.envirocar.app/src/org/envirocar/app/views/BaseMainActivity.java b/org.envirocar.app/src/org/envirocar/app/views/BaseMainActivity.java index c4fedcd89..6f2b291f7 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/BaseMainActivity.java +++ b/org.envirocar.app/src/org/envirocar/app/views/BaseMainActivity.java @@ -29,9 +29,12 @@ import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.snackbar.Snackbar; @@ -79,7 +82,7 @@ public class BaseMainActivity extends BaseInjectorActivity { private static final String TROUBLESHOOTING_TAG = "TROUBLESHOOTING"; - private FragmentStatePagerAdapter fragmentStatePagerAdapter; + private PageSlider fragmentStatePagerAdapter; private MenuItem prevMenuItem; // Custom Callback Stack @@ -116,7 +119,7 @@ public class BaseMainActivity extends BaseInjectorActivity { protected BottomNavigationView navigationBottomBar; @BindView(R.id.fragmentContainer) - protected ViewPager viewPager; + protected ViewPager2 viewPager; private CompositeDisposable subscriptions = new CompositeDisposable(); private BroadcastReceiver errorInformationReceiver; @@ -158,7 +161,7 @@ protected void onCreate(Bundle savedInstanceState) { navigationBottomBar.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); navigationBottomBar.setSelectedItemId(R.id.navigation_dashboard); - fragmentStatePagerAdapter = new PageSlider(getSupportFragmentManager(), FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + fragmentStatePagerAdapter = new PageSlider(this); viewPager.setAdapter(fragmentStatePagerAdapter); // Custom Back Navigation for fragments in BaseMainActivity @@ -175,14 +178,10 @@ public void handleOnBackPressed() { }; this.getOnBackPressedDispatcher().addCallback(this, callback); - viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - - } - + viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { + super.onPageSelected(position); if (prevMenuItem != null) { prevMenuItem.setChecked(false); } else { @@ -195,14 +194,9 @@ public void onPageSelected(int position) { } navigationBottomBar.getMenu().getItem(position).setChecked(true); prevMenuItem = navigationBottomBar.getMenu().getItem(position); - fragmentStatePagerAdapter.notifyDataSetChanged(); - } - - @Override - public void onPageScrollStateChanged(int state) { - } }); + // Subscribe for preference subscriptions. In this case, subscribe for changes to the // active screen settings. // TODO @@ -355,12 +349,13 @@ private void showSnackbar(String info) { Snackbar.make(navigationBottomBar, info, Snackbar.LENGTH_LONG).show(); } - private class PageSlider extends FragmentStatePagerAdapter { + + private class PageSlider extends FragmentStateAdapter { private Fragment[] fragments; - public PageSlider(@NonNull FragmentManager fm, int behavior) { - super(fm, behavior); + public PageSlider(@NonNull FragmentActivity fragmentActivity) { + super(fragmentActivity); fragments = new Fragment[]{ dashboardFragment, trackListPagerFragment, @@ -370,12 +365,12 @@ public PageSlider(@NonNull FragmentManager fm, int behavior) { @NonNull @Override - public Fragment getItem(int position) { + public Fragment createFragment(int position) { return fragments[position]; } @Override - public int getCount() { + public int getItemCount() { return 3; } } diff --git a/org.envirocar.app/src/org/envirocar/app/views/tracklist/TrackListPagerFragment.java b/org.envirocar.app/src/org/envirocar/app/views/tracklist/TrackListPagerFragment.java index f4c51ec55..fc8aee2a9 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/tracklist/TrackListPagerFragment.java +++ b/org.envirocar.app/src/org/envirocar/app/views/tracklist/TrackListPagerFragment.java @@ -23,11 +23,14 @@ import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; import org.envirocar.app.BaseApplication; import org.envirocar.app.BaseApplicationComponent; @@ -49,7 +52,7 @@ public class TrackListPagerFragment extends BaseInjectorFragment { @BindView(R.id.trackListSegmentedGroup) protected SegmentedGroup trackListSegmentedGroup; @BindView(R.id.fragment_tracklist_layout_viewpager) - protected ViewPager mViewPager; + protected ViewPager2 mViewPager; private TrackListPagerAdapter trackListPageAdapter; @@ -68,18 +71,15 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa View content = inflater.inflate(R.layout.fragment_tracklist_layout, container, false); ButterKnife.bind(this, content); - trackListPageAdapter = new TrackListPagerAdapter(getChildFragmentManager()); + trackListPageAdapter = new TrackListPagerAdapter(this); mViewPager.setAdapter(trackListPageAdapter); mViewPager.setSaveFromParentEnabled(false); - mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - - } + mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { + super.onPageSelected(position); if (position == 0) { trackListSegmentedGroup.check(R.id.localSegmentedButton); } else { @@ -87,11 +87,8 @@ public void onPageSelected(int position) { } } - @Override - public void onPageScrollStateChanged(int state) { - - } }); + trackListSegmentedGroup.check(R.id.localSegmentedButton); trackListSegmentedGroup.setOnCheckedChangeListener((radioGroup, i) -> { @@ -126,7 +123,7 @@ public void onDestroyView() { /** * @author dewall */ - class TrackListPagerAdapter extends FragmentStatePagerAdapter { + class TrackListPagerAdapter extends FragmentStateAdapter { private static final int NUM_PAGES = 2; private TrackListLocalCardFragment localCardFragment; @@ -137,7 +134,7 @@ class TrackListPagerAdapter extends FragmentStatePagerAdapter { * * @param fm the fragment manager of the application's current scope. */ - public TrackListPagerAdapter(FragmentManager fm) { + public TrackListPagerAdapter(@NonNull Fragment fm) { super(fm); remoteCardFragment = new TrackListRemoteCardFragment(); @@ -145,8 +142,9 @@ public TrackListPagerAdapter(FragmentManager fm) { localCardFragment.setOnTrackUploadedListener(remoteCardFragment); } + @NonNull @Override - public Fragment getItem(int position) { + public Fragment createFragment(int position) { if (position == 0) { return localCardFragment; } else { @@ -155,9 +153,8 @@ public Fragment getItem(int position) { } @Override - public int getCount() { + public int getItemCount() { return NUM_PAGES; } - } } diff --git a/org.envirocar.app/src/org/envirocar/app/views/utils/NestedScrollableHost.java b/org.envirocar.app/src/org/envirocar/app/views/utils/NestedScrollableHost.java new file mode 100644 index 000000000..464f4b590 --- /dev/null +++ b/org.envirocar.app/src/org/envirocar/app/views/utils/NestedScrollableHost.java @@ -0,0 +1,104 @@ +package org.envirocar.app.views.utils; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager2.widget.ViewPager2; + +public class NestedScrollableHost extends FrameLayout { + + private int touchSlop = 0; + private float initialX = 0; + private float initialY = 0; + private ViewPager2 parentPager; + private ViewPager2 childPager; + + 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(); + } + + public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + } + + public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + View parentView = (View) getParent(); + while (parentView!=null && !(parentView instanceof ViewPager2)) + { + parentView = (View) parentView.getParent(); + } + parentPager = (ViewPager2) parentView; + + if(getChildCount()>0) childPager = (ViewPager2) getChildAt(0); + } + + private boolean canChildScroll(int orientation, float delta) { + int direction = (int) -Math.signum(delta); + switch (orientation) + { + case 0: + return childPager.canScrollHorizontally(direction); + case 1: + return childPager.canScrollVertically(direction); + } + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if(parentPager!=null && childPager!=null) + { + int orientation = parentPager.getOrientation(); + boolean isHorizontal = orientation==ViewPager2.ORIENTATION_HORIZONTAL; + if(canChildScroll(orientation,-1f) || canChildScroll(orientation,1f)) + { + if(ev.getAction()==MotionEvent.ACTION_DOWN) + { + initialX = ev.getX(); + initialY = ev.getY(); + getParent().requestDisallowInterceptTouchEvent(true); + } + else if(ev.getAction()==MotionEvent.ACTION_MOVE) + { + float dx = ev.getX() - initialX; + float dy = ev.getY() - initialY; + float scaleDx = Math.abs(dx) * ( isHorizontal ? 0.5f : 1f); + float scaleDy = Math.abs(dy) * ( isHorizontal ? 1f : 0.5f); + if(scaleDx>touchSlop || scaleDy>touchSlop) + { + if( isHorizontal == (scaleDy>scaleDx) ) + { + getParent().requestDisallowInterceptTouchEvent(false); + } + else + { + getParent().requestDisallowInterceptTouchEvent(canChildScroll(orientation,isHorizontal ? dx : dy)); + } + } + } + } + } + return super.onInterceptTouchEvent(ev); + } +}