Intervals refactoring: avoid duplication code: IntervalsRecordingFragment is a version of IntervalsFragment.

This commit is contained in:
Román
2020-09-12 14:53:00 +02:00
committed by Román Martínez
parent 684762db58
commit ffedc04777
6 changed files with 80 additions and 184 deletions
@@ -37,7 +37,7 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.fragments.ChartFragment; import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment; import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.IntervalsRecordedFragment; import de.dennisguse.opentracks.fragments.IntervalsFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment; import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.SettingsActivity; import de.dennisguse.opentracks.settings.SettingsActivity;
@@ -253,7 +253,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Choos
case 0: case 0:
return StatisticsRecordedFragment.newInstance(track.getId()); return StatisticsRecordedFragment.newInstance(track.getId());
case 1: case 1:
return IntervalsRecordedFragment.newInstance(track.getId()); return IntervalsFragment.newInstance(track.getId());
case 2: case 2:
return ChartFragment.newInstance(false); return ChartFragment.newInstance(false);
case 3: case 3:
@@ -25,7 +25,7 @@ import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.fragments.ChartFragment; import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.fragments.IntervalsRecordingFragment; import de.dennisguse.opentracks.fragments.IntervalsFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment; import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface; import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
@@ -390,7 +390,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
case 0: case 0:
return StatisticsRecordingFragment.newInstance(); return StatisticsRecordingFragment.newInstance();
case 1: case 1:
return IntervalsRecordingFragment.newInstance(trackId); return IntervalsFragment.IntervalsRecordingFragment.newInstance(trackId);
case 2: case 2:
return ChartFragment.newInstance(false); return ChartFragment.newInstance(false);
case 3: case 3:
@@ -423,5 +423,8 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
public void setTrackIdListener(OnTrackIdListener listener) { public void setTrackIdListener(OnTrackIdListener listener) {
this.intervalsListener = listener; this.intervalsListener = listener;
if (trackId != null) {
listener.onTrackId(trackId);
}
} }
} }
@@ -1,7 +1,6 @@
package de.dennisguse.opentracks.adapters; package de.dennisguse.opentracks.adapters;
import android.content.Context; import android.content.Context;
import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -49,7 +48,7 @@ public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.I
viewHolder = (ViewHolder) intervalView.getTag(); viewHolder = (ViewHolder) intervalView.getTag();
} }
sumDistance_m = position + 1 == getCount() ? interval.getDistance_m() : (position + 1) * interval.getDistance_m(); sumDistance_m = position + 1 == getCount() && position > 0 ? (position * getItem(position - 1).getDistance_m()) + interval.getDistance_m() : (position + 1) * interval.getDistance_m();
viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits)); viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits));
Pair<String, String> speedParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, true); Pair<String, String> speedParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, true);
@@ -30,17 +30,14 @@ import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel; import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
/** /**
* A fragment to display the intervals from recording track. * A fragment to display the intervals from recorded track.
*/ */
public class IntervalsRecordingFragment extends Fragment implements TrackRecordingActivity.OnTrackIdListener { public class IntervalsFragment extends Fragment {
private static final String TAG = IntervalsRecordingFragment.class.getSimpleName(); private static final String TAG = IntervalsFragment.class.getSimpleName();
private static final String TRACK_ID_KEY = "trackId"; 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 IntervalStatisticsModel viewModel;
private ListView intervalListView; private ListView intervalListView;
private IntervalStatisticsModel.IntervalOption selectedInterval; private IntervalStatisticsModel.IntervalOption selectedInterval;
@@ -64,23 +61,11 @@ public class IntervalsRecordingFragment extends Fragment implements TrackRecordi
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable(TRACK_ID_KEY, trackId); bundle.putParcelable(TRACK_ID_KEY, trackId);
Fragment fragment = new IntervalsRecordingFragment(); Fragment fragment = new IntervalsFragment();
fragment.setArguments(bundle); fragment.setArguments(bundle);
return fragment; return fragment;
} }
private final Runnable intervalRunner = new Runnable() {
@Override
public void run() {
if (isResumed()) {
updateIntervals();
intervalHandler.postDelayed(intervalRunner, UI_UPDATE_INTERVAL);
}
}
};
private Handler intervalHandler;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.interval_list_view, container, false); return inflater.inflate(R.layout.interval_list_view, container, false);
@@ -92,10 +77,11 @@ public class IntervalsRecordingFragment extends Fragment implements TrackRecordi
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener); PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
trackId = getArguments().getParcelable(TRACK_ID_KEY); if (savedInstanceState != null) {
((TrackRecordingActivity) getActivity()).setTrackIdListener(this); trackId = savedInstanceState.getParcelable(TRACK_ID_KEY);
} else {
intervalHandler = new Handler(); trackId = getArguments().getParcelable(TRACK_ID_KEY);
}
intervalListView = view.findViewById(R.id.interval_list); intervalListView = view.findViewById(R.id.interval_list);
intervalListView.setEmptyView(view.findViewById(R.id.interval_list_empty_view)); intervalListView.setEmptyView(view.findViewById(R.id.interval_list_empty_view));
@@ -122,18 +108,8 @@ public class IntervalsRecordingFragment extends Fragment implements TrackRecordi
} }
}); });
}
@Override intervalChanged();
public void onResume() {
super.onResume();
intervalHandler.post(intervalRunner);
}
@Override
public void onPause() {
super.onPause();
intervalHandler.removeCallbacks(intervalRunner);
} }
@Override @Override
@@ -149,6 +125,12 @@ public class IntervalsRecordingFragment extends Fragment implements TrackRecordi
viewModel = null; viewModel = null;
} }
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(TRACK_ID_KEY, trackId);
}
/** /**
* Update intervals through {@link IntervalStatisticsModel} view model. * Update intervals through {@link IntervalStatisticsModel} view model.
*/ */
@@ -166,12 +148,62 @@ public class IntervalsRecordingFragment extends Fragment implements TrackRecordi
}); });
} }
private void updateIntervals() { public void setTrackId(Track.Id trackId) {
intervalChanged();
}
@Override
public void onTrackId(Track.Id trackId) {
this.trackId = trackId; this.trackId = trackId;
} }
public static class IntervalsRecordingFragment extends IntervalsFragment implements TrackRecordingActivity.OnTrackIdListener {
// 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 Handler intervalHandler;
private final Runnable intervalRunner = new Runnable() {
@Override
public void run() {
if (isResumed()) {
updateIntervals();
intervalHandler.postDelayed(intervalRunner, UI_UPDATE_INTERVAL);
}
}
};
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;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
((TrackRecordingActivity) getActivity()).setTrackIdListener(this);
intervalHandler = new Handler();
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
intervalHandler.post(intervalRunner);
}
@Override
public void onPause() {
super.onPause();
intervalHandler.removeCallbacks(intervalRunner);
}
private void updateIntervals() {
intervalChanged();
}
@Override
public void onTrackId(Track.Id trackId) {
setTrackId(trackId);
}
}
} }
@@ -1,137 +0,0 @@
package de.dennisguse.opentracks.fragments;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import java.util.Arrays;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.adapters.IntervalStatisticsAdapter;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
import de.dennisguse.opentracks.viewmodels.IntervalStatisticsModel;
/**
* A fragment to display the intervals from recorded track.
*/
public class IntervalsRecordedFragment extends Fragment {
private static final String TAG = IntervalsRecordedFragment.class.getSimpleName();
private static final String TRACK_ID_KEY = "trackId";
private IntervalStatisticsModel viewModel;
private ListView intervalListView;
private IntervalStatisticsModel.IntervalOption selectedInterval;
private IntervalStatisticsAdapter adapter;
protected Spinner spinnerIntervals;
protected TextView spinnerIntervalsUnit;
private Track.Id trackId;
protected 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 (spinnerIntervalsUnit != null) {
spinnerIntervalsUnit.setText(PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile));
intervalChanged();
}
}
};
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.interval_list_view, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
trackId = getArguments().getParcelable(TRACK_ID_KEY);
intervalListView = view.findViewById(R.id.interval_list);
intervalListView.setEmptyView(view.findViewById(R.id.interval_list_empty_view));
viewModel = new ViewModelProvider(this).get(IntervalStatisticsModel.class);
spinnerIntervals = view.findViewById(R.id.spinner_intervals);
int[] intValues = Arrays.stream(IntervalStatisticsModel.IntervalOption.values()).mapToInt(i -> i.getValue()).toArray();
spinnerIntervals.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, Arrays.stream(intValues).mapToObj(String::valueOf).toArray(String[]::new)));
spinnerIntervalsUnit = view.findViewById(R.id.spinner_intervals_unit);
spinnerIntervalsUnit.setText(PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile));
spinnerIntervals.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
selectedInterval = IntervalStatisticsModel.IntervalOption.values()[i];
intervalChanged();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
intervalChanged();
}
@Override
public void onDestroy() {
super.onDestroy();
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
intervalListView = null;
adapter = null;
spinnerIntervals = null;
spinnerIntervalsUnit = null;
viewModel = null;
}
/**
* Update intervals through {@link IntervalStatisticsModel} view model.
*/
public void intervalChanged() {
if (viewModel == null || intervalListView == null) {
return;
}
LiveData<IntervalStatistics> liveData = viewModel.getIntervalStats(trackId, selectedInterval);
liveData.observe(getActivity(), intervalStatistics -> {
if (intervalStatistics != null) {
adapter = new IntervalStatisticsAdapter(getContext(), intervalStatistics.getIntervalList());
intervalListView.setAdapter(adapter);
}
});
}
}
@@ -24,7 +24,6 @@ import de.dennisguse.opentracks.util.UnitConversions;
public class IntervalStatisticsModel extends AndroidViewModel { public class IntervalStatisticsModel extends AndroidViewModel {
private MutableLiveData<IntervalStatistics> intervalStats = new MutableLiveData<>(); private MutableLiveData<IntervalStatistics> intervalStats = new MutableLiveData<>();
private IntervalOption interval = IntervalOption.OPTION_1;
public IntervalStatisticsModel(@NonNull Application application) { public IntervalStatisticsModel(@NonNull Application application) {
super(application); super(application);