From 25ef0ecad1afd242e94d9943490584b39db737d9 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 1 Sep 2020 21:55:39 +0200 Subject: [PATCH] Interval Stats: use a tab for recorded tracks as well. --- .../opentracks/TrackRecordedActivity.java | 83 ++++++++------ .../opentracks/TrackRecordingActivity.java | 4 +- .../fragments/IntervalsRecordedFragment.java | 103 ++++++++++++++++++ .../fragments/IntervalsRecordingFragment.java | 18 ++- .../fragments/StatisticsRecordedFragment.java | 49 +-------- .../StatisticsRecordingFragment.java | 2 + src/main/res/layout/interval_list_view.xml | 7 -- 7 files changed, 170 insertions(+), 96 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordedFragment.java diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java index 3ac6ee2eb..f2b412241 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java @@ -24,6 +24,7 @@ import android.view.MenuItem; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; @@ -36,6 +37,7 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.fragments.ChartFragment; import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment; +import de.dennisguse.opentracks.fragments.IntervalsRecordedFragment; import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.settings.SettingsActivity; @@ -76,42 +78,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos trackDataHub = new TrackDataHub(this); - FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) { - @Override - public int getCount() { - return 3; - } - - @NonNull - @Override - public Fragment getItem(int position) { - switch (position) { - case 0: - return StatisticsRecordedFragment.newInstance(track.getId()); - case 1: - return ChartFragment.newInstance(false); - case 2: - return ChartFragment.newInstance(true); - default: - throw new RuntimeException("There isn't Fragment associated with the position: " + position); - } - } - - @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); + pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)); TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout); tabs.setupWithViewPager(pager); if (savedInstanceState != null) { @@ -266,4 +234,49 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos String category = getString(TrackIconUtils.getIconActivityType(iconValue)); TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils); } + + private class CustomFragmentPagerAdapter extends FragmentPagerAdapter { + + public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) { + super(fm, behavior); + } + + @Override + public int getCount() { + return 4; + } + + @NonNull + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: + return StatisticsRecordedFragment.newInstance(track.getId()); + case 1: + return IntervalsRecordedFragment.newInstance(track.getId()); + case 2: + return ChartFragment.newInstance(false); + case 3: + return ChartFragment.newInstance(true); + default: + throw new RuntimeException("There isn't Fragment associated with the position: " + position); + } + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case 0: + return getString(R.string.track_detail_stats_tab); + case 1: + return getString(R.string.track_detail_intervals_tab); + case 2: + return getString(R.string.settings_chart_by_time); + case 3: + return getString(R.string.settings_chart_by_distance); + default: + throw new RuntimeException("There isn't Fragment associated with the position: " + position); + } + } + } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java index cd5dbf28b..eb8f90008 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java @@ -181,7 +181,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc trackDataHub = new TrackDataHub(this); pager = findViewById(R.id.track_detail_activity_view_pager); - pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), 1)); + pager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)); TabLayout tabs = findViewById(R.id.track_detail_activity_tablayout); tabs.setupWithViewPager(pager); if (savedInstanceState != null) { @@ -383,7 +383,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc case 0: return StatisticsRecordingFragment.newInstance(); case 1: - return IntervalsRecordingFragment.newInstance(); + return IntervalsRecordingFragment.newInstance(trackId); case 2: return ChartFragment.newInstance(false); case 3: diff --git a/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordedFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordedFragment.java new file mode 100644 index 000000000..449270de0 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordedFragment.java @@ -0,0 +1,103 @@ +package de.dennisguse.opentracks.fragments; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.ViewModelProvider; + +import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.content.data.Track; +import de.dennisguse.opentracks.viewmodels.IntervalStatistics; +import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel; +import de.dennisguse.opentracks.views.IntervalListView; + +/** + * A fragment to display the intervals from recorded track. + */ +public class IntervalsRecordedFragment extends Fragment implements IntervalListView.IntervalListListener { + + private static final String TAG = IntervalsRecordedFragment.class.getSimpleName(); + + private static final String TRACK_ID_KEY = "trackId"; + + private IntervalStatisticsModel viewModel; + private IntervalListView.IntervalReverseListView intervalListView; + + private Track.Id trackId; + + public static Fragment newInstance(Track.Id trackId) { + Bundle bundle = new Bundle(); + bundle.putParcelable(TRACK_ID_KEY, trackId); + + Fragment fragment = new IntervalsRecordedFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.intervals_recording, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + trackId = getArguments().getParcelable(TRACK_ID_KEY); + + intervalListView = new IntervalListView.IntervalReverseListView(getActivity(), this); + intervalListView.setId(View.generateViewId()); + LinearLayout linearLayout = view.findViewById(R.id.root_view); + linearLayout.removeAllViews(); + linearLayout.addView(intervalListView); + + viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class); + + updateIntervals(null); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + intervalListView.destroy(); + intervalListView = null; + viewModel = null; + } + + /** + * Update intervals through {@link IntervalStatisticsModel} view model. + * + * @param interval intervals will split in this interval if not null. If it's null then view model will use the default one. + */ + private void updateIntervals(@Nullable IntervalStatisticsModel.IntervalOption interval) { + if (viewModel == null || intervalListView == null) { + return; + } + + viewModel.invalidate(); + LiveData liveData; + if (interval == null) { + liveData = viewModel.getIntervalStats(trackId); + } else { + liveData = viewModel.getIntervalStats(trackId, interval); + } + liveData.observe(getActivity(), intervalStatistics -> { + if (intervalStatistics != null) { + intervalListView.display(intervalStatistics.getIntervalList()); + } + }); + } + + @Override + public void intervalChanged(IntervalStatisticsModel.IntervalOption interval) { + updateIntervals(interval); + } +} \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordingFragment.java index a52806630..05a7379aa 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsRecordingFragment.java @@ -15,7 +15,6 @@ import androidx.lifecycle.ViewModelProvider; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.data.Track; -import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.UnitConversions; import de.dennisguse.opentracks.viewmodels.IntervalStatistics; import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel; @@ -28,14 +27,23 @@ public class IntervalsRecordingFragment extends Fragment implements IntervalList private static final String TAG = IntervalsRecordingFragment.class.getSimpleName(); + private static final String TRACK_ID_KEY = "trackId"; + // Refreshing intervals stats it's not so demanding so 5 seconds is enough to balance performance and user experience. private static final long UI_UPDATE_INTERVAL = 5 * UnitConversions.ONE_SECOND_MS; private IntervalStatisticsModel viewModel; private IntervalListView.IntervalReverseListView intervalListView; - public static Fragment newInstance() { - return new IntervalsRecordingFragment(); + private Track.Id trackId; + + public static Fragment newInstance(Track.Id trackId) { + Bundle bundle = new Bundle(); + bundle.putParcelable(TRACK_ID_KEY, trackId); + + Fragment fragment = new IntervalsRecordingFragment(); + fragment.setArguments(bundle); + return fragment; } private final Runnable intervalRunner = new Runnable() { @@ -59,11 +67,12 @@ public class IntervalsRecordingFragment extends Fragment implements IntervalList public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + trackId = getArguments().getParcelable(TRACK_ID_KEY); + intervalHandler = new Handler(); intervalListView = new IntervalListView.IntervalReverseListView(getActivity(), this); intervalListView.setId(View.generateViewId()); - intervalListView.findViewById(R.id.interval_title_label).setVisibility(View.GONE); LinearLayout linearLayout = view.findViewById(R.id.root_view); linearLayout.removeAllViews(); linearLayout.addView(intervalListView); @@ -102,7 +111,6 @@ public class IntervalsRecordingFragment extends Fragment implements IntervalList return; } - Track.Id trackId = PreferencesUtils.getRecordingTrackId(getContext()); viewModel.invalidate(); LiveData liveData; if (interval == null) { diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java index bdc3a8077..619b78352 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java @@ -24,14 +24,12 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.TrackRecordedActivity; @@ -41,8 +39,6 @@ import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.TrackIconUtils; -import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel; -import de.dennisguse.opentracks.views.IntervalListView; /** * A fragment to display track statistics to the user. @@ -50,7 +46,7 @@ import de.dennisguse.opentracks.views.IntervalListView; * @author Sandor Dornbush * @author Rodrigo Damazio */ -public class StatisticsRecordedFragment extends Fragment implements IntervalListView.IntervalListListener { +public class StatisticsRecordedFragment extends Fragment { private static final String TRACK_ID_KEY = "trackId"; @@ -58,14 +54,8 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList private String category = ""; private Track track; - private IntervalStatisticsModel viewModel; - private IntervalListView intervalListView; - private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> { if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) { - if (viewModel != null) { - viewModel.invalidate(); - } if (isResumed()) { getActivity().runOnUiThread(() -> { if (isResumed()) { @@ -81,8 +71,6 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList return inflater.inflate(R.layout.statistics_recorded, container, false); } - /* Views */ - private ViewGroup rootView; private TextView totalTimeValueView; private TextView distanceValue; private TextView distanceUnit; @@ -121,7 +109,7 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - rootView = view.findViewById(R.id.root_view); + ViewGroup rootView = view.findViewById(R.id.root_view); totalTimeValueView = view.findViewById(R.id.stats_total_time_value); @@ -144,14 +132,6 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList speedMovingLabel = view.findViewById(R.id.stats_moving_speed_label); speedMovingValue = view.findViewById(R.id.stats_moving_speed_value); speedMovingUnit = view.findViewById(R.id.stats_moving_speed_unit); - - intervalListView = new IntervalListView(getActivity(), this); - intervalListView.setId(View.generateViewId()); - LinearLayout linearLayoutExtra = rootView.findViewById(R.id.linear_layout_extra); - linearLayoutExtra.removeAllViews(); - linearLayoutExtra.addView(intervalListView); - - viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class); } @Override @@ -174,14 +154,6 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList }); } - private void addIntervals() { - viewModel.getIntervalStats(track.getId()).observe(getActivity(), intervalStatistics -> { - if (intervalStatistics != null) { - intervalListView.display(intervalStatistics.getIntervalList()); - } - }); - } - @Override public void onResume() { super.onResume(); @@ -217,10 +189,6 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList speedMovingLabel = null; speedMovingValue = null; speedMovingUnit = null; - - intervalListView.destroy(); - intervalListView = null; - viewModel = null; } public void loadStatistics() { @@ -298,18 +266,5 @@ public class StatisticsRecordedFragment extends Fragment implements IntervalList speedMovingValue.setText(parts.first); speedMovingUnit.setText(parts.second); } - - addIntervals(); - } - - @Override - public void intervalChanged(IntervalStatisticsModel.IntervalOption interval) { - if (viewModel != null && intervalListView != null) { - viewModel.getIntervalStats(track.getId(), interval).observe(getActivity(), intervalStatistics -> { - if (intervalStatistics != null) { - intervalListView.display(intervalStatistics.getIntervalList()); - } - }); - } } } diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index c9b4e4cbd..c5a8a68b6 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -48,6 +48,8 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi private static final String TAG = StatisticsRecordingFragment.class.getSimpleName(); + private static final String TRACK_ID_KEY = "trackId"; + private static final long UI_UPDATE_INTERVAL = UnitConversions.ONE_SECOND_MS; private TrackDataHub trackDataHub; diff --git a/src/main/res/layout/interval_list_view.xml b/src/main/res/layout/interval_list_view.xml index c97745e82..57937abc8 100644 --- a/src/main/res/layout/interval_list_view.xml +++ b/src/main/res/layout/interval_list_view.xml @@ -5,13 +5,6 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical"> - -