diff --git a/build.gradle b/build.gradle index ecafae418..ee59d9229 100644 --- a/build.gradle +++ b/build.gradle @@ -100,4 +100,5 @@ dependencies { testImplementation 'androidx.test:core:1.2.0' testImplementation 'org.mockito:mockito-core:3.0.0' + implementation 'com.google.android.material:material:1.0.0' } diff --git a/src/main/java/de/dennisguse/opentracks/TabsAdapter.java b/src/main/java/de/dennisguse/opentracks/TabsAdapter.java deleted file mode 100644 index 2e0aa2cf3..000000000 --- a/src/main/java/de/dennisguse/opentracks/TabsAdapter.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2013q Google Inc. - * - * 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. - */ - -package de.dennisguse.opentracks; - -import android.content.Context; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TabHost; -import android.widget.TabHost.TabContentFactory; -import android.widget.TabWidget; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentPagerAdapter; -import androidx.viewpager.widget.ViewPager; - -import java.util.ArrayList; - -/** - * This is a helper class that implements the management of tabs and all details - * of connecting a ViewPager with associated TabHost. It relies on a trick. - * Normally a tab host has a simple API for supplying a View or Intent that each - * tab will show. This is not sufficient for switching between pages. So instead - * we make the content part of the tab host 0dp high (it is not shown) and the - * TabsAdapter supplies its own dummy view to show as the tab content. It - * listens to changes in tabs, and takes care of switch to the correct paged in - * the ViewPager whenever the selected tab changes. - *

- * Copied from the FragmentTabsPager sample in the support library. - * - * @author Jimmy Shih - */ -//TODO Rework or better remove. -public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { - - private final Context context; - private final TabHost tabHost; - private final ViewPager viewPager; - private final ArrayList tabInfos = new ArrayList<>(); - - public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager viewPager) { - super(activity.getSupportFragmentManager()); - this.context = activity; - this.tabHost = tabHost; - this.viewPager = viewPager; - this.tabHost.setOnTabChangedListener(this); - this.viewPager.setAdapter(this); - this.viewPager.setOnPageChangeListener(this); - } - - public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle bundle) { - tabSpec.setContent(new DummyTabFactory(context)); - - TabInfo info = new TabInfo(clss, bundle); - - tabInfos.add(info); - tabHost.addTab(tabSpec); - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return tabInfos.size(); - } - - @Override - @NonNull - public Fragment getItem(int position) { - TabInfo info = tabInfos.get(position); - return Fragment.instantiate(context, info.clss.getName(), info.bundle); - } - - @Override - public void onTabChanged(String tabId) { - int position = tabHost.getCurrentTab(); - viewPager.setCurrentItem(position); - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - /* - * Unfortunately when TabHost changes the current tab, it kindly also takes care of putting focus on it when not in touch mode. - * The jerk. This hack tries to prevent this from pulling focus out of our ViewPager. - */ - TabWidget tabWidget = tabHost.getTabWidget(); - int oldFocusability = tabWidget.getDescendantFocusability(); - tabWidget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - tabHost.setCurrentTab(position); - tabWidget.setDescendantFocusability(oldFocusability); - } - - @Override - public void onPageScrollStateChanged(int state) { - } - - /** - * An object to hold a tab's info. - * - * @author Jimmy Shih - */ - private static final class TabInfo { - - private final Class clss; - private final Bundle bundle; - - TabInfo(Class clss, Bundle bundle) { - this.clss = clss; - this.bundle = bundle; - } - } - - /** - * A dummy {@link TabContentFactory} that creates an empty view to satisfy the {@link TabHost} API. - * - * @author Jimmy Shih - */ - private static class DummyTabFactory implements TabHost.TabContentFactory { - - private final Context context; - - DummyTabFactory(Context context) { - this.context = context; - } - - @Override - public View createTabContent(String tag) { - View view = new View(context); - view.setMinimumWidth(0); - view.setMinimumHeight(0); - return view; - } - } -} diff --git a/src/main/java/de/dennisguse/opentracks/TrackDetailActivity.java b/src/main/java/de/dennisguse/opentracks/TrackDetailActivity.java index d3920fbff..78bef7925 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackDetailActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackDetailActivity.java @@ -31,14 +31,17 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; -import android.widget.TabHost; -import android.widget.TabHost.TabSpec; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.google.android.material.tabs.TabLayout; + import de.dennisguse.opentracks.content.ContentProviderUtils; import de.dennisguse.opentracks.content.Track; import de.dennisguse.opentracks.content.TrackDataHub; @@ -86,7 +89,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA private SharedPreferences sharedPreferences; private TrackRecordingServiceConnection trackRecordingServiceConnection; private TrackDataHub trackDataHub; - private TabHost tabHost; + private ViewPager pager; private TrackController trackController; // From intent @@ -202,28 +205,46 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback); trackDataHub = TrackDataHub.newInstance(this); - tabHost = findViewById(R.id.tackdetail_tabhost); - tabHost.setup(); + FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) { + @Override + public int getCount() { + return 3; + } - ViewPager viewPager = findViewById(R.id.pager); - TabsAdapter tabsAdapter = new TabsAdapter(this, tabHost, viewPager); - - TabSpec statsTabSpec = tabHost.newTabSpec(StatsFragment.STATS_FRAGMENT_TAG).setIndicator(getString(R.string.track_detail_stats_tab)); - tabsAdapter.addTab(statsTabSpec, StatsFragment.class, null); - - TabSpec chartTimeTabSpec = tabHost.newTabSpec(ChartTimeFragment.CHART_FRAGMENT_TAG).setIndicator(getString(R.string.settings_chart_by_time)); - tabsAdapter.addTab(chartTimeTabSpec, ChartTimeFragment.class, null); - - TabSpec chartDistanceTabSpec = tabHost.newTabSpec(ChartDistanceFragment.CHART_FRAGMENT_TAG).setIndicator(getString(R.string.settings_chart_by_distance)); - tabsAdapter.addTab(chartDistanceTabSpec, ChartDistanceFragment.class, null); + @NonNull + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: + return new StatsFragment(); + case 1: + return new ChartTimeFragment(); + case 2: + return new ChartDistanceFragment(); + } + return null; + } + @Nullable + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case 0: + return getString(R.string.track_detail_stats_tab); + case 1: + return getString(R.string.settings_chart_by_time); + case 2: + return getString(R.string.settings_chart_by_distance); + } + return "Unknown Tab"; + } + }; + pager = findViewById(R.id.track_detail_activity_view_pager); + pager.setAdapter(adapter); + TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout); + tabs.setupWithViewPager(pager); if (savedInstanceState != null) { - tabHost.setCurrentTabByTag(savedInstanceState.getString(CURRENT_TAB_TAG_KEY)); - } - - // Set the background after all three tabs are added - for (int i = 0; i < tabHost.getTabWidget().getChildCount(); i++) { - tabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.tab_indicator); + pager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY)); } trackController = new TrackController(this, trackRecordingServiceConnection, false, recordListener, stopListener); @@ -298,7 +319,8 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); - outState.putString(CURRENT_TAB_TAG_KEY, tabHost.getCurrentTabTag()); + outState.putInt(CURRENT_TAB_TAG_KEY, pager.getCurrentItem()); + if (photoUri != null) { outState.putParcelable(PHOTO_URI_KEY, photoUri); } diff --git a/src/main/res/layout/track_detail.xml b/src/main/res/layout/track_detail.xml index 16f24f20b..da16e02b7 100644 --- a/src/main/res/layout/track_detail.xml +++ b/src/main/res/layout/track_detail.xml @@ -14,20 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - + + - - - + android:layout_weight="1" /> \ No newline at end of file diff --git a/src/main/res/layout/track_details_tab.xml b/src/main/res/layout/track_details_tab.xml deleted file mode 100644 index 98fe4c675..000000000 --- a/src/main/res/layout/track_details_tab.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/res/values/do_not_translate.xml b/src/main/res/values/do_not_translate.xml index 0afe48518..9fec1daee 100644 --- a/src/main/res/values/do_not_translate.xml +++ b/src/main/res/values/do_not_translate.xml @@ -17,7 +17,10 @@ limitations under the License. https://github.com/dennisguse/opentracks - Google\'s androidX support (Apache License, Version 2.0) + + Google\'s androidX support (Apache License, Version 2.0) \n + Material Components for Android (Apache License, Version 2.0) + http://maps.google.com/mapfiles/ms/micons/ylw-pushpin.png http://maps.google.com/mapfiles/ms/micons/blue-pushpin.png