Skip to content

Commit

Permalink
Do not crash on empty track
Browse files Browse the repository at this point in the history
  • Loading branch information
andreynovikov committed Feb 4, 2024
1 parent bbcad95 commit 4d68df1
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 42 deletions.
125 changes: 85 additions & 40 deletions app/src/main/java/mobi/maptrek/fragments/TrackInformation.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,31 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
if (!selectedTrack.equals(viewModel.track.getValue())) {
initializeTrackInformation(selectedTrack);
viewModel.track.setValue(selectedTrack);
viewModel.doInBackground(() -> initializeTrackStatistics(selectedTrack));
if (!viewModel.isEmpty) {
viewBinding.progressBar.setVisibility(View.VISIBLE);
viewModel.doInBackground(() -> initializeTrackStatistics(selectedTrack));
}
}
});
trackViewModel.currentTrack.observe(getViewLifecycleOwner(), currentTrack -> { // new points were added to current track
viewModel.doInBackground(() -> updateTrackStatistics(currentTrack));
Track track = trackViewModel.selectedTrack.getValue();
if (track == null || track != currentTrack)
return;
if (viewModel.isEmpty) {
initializeTrackInformation(track);
if (!viewModel.isEmpty)
viewModel.doInBackground(() -> {
viewBinding.progressBar.setVisibility(View.VISIBLE);
initializeTrackStatistics(track);
updateTrackStatistics(currentTrack);
});
} else {
viewModel.doInBackground(() -> updateTrackStatistics(currentTrack));
}
});

viewModel.track.observe(getViewLifecycleOwner(), trackObserver);
viewModel.firstPoint.observe(getViewLifecycleOwner(), firstPointObserver);
viewModel.lastPoint.observe(getViewLifecycleOwner(), lastPointObserver);
viewModel.statisticsState.observe(getViewLifecycleOwner(), statisticsObserver);
viewModel.chartState.observe(getViewLifecycleOwner(), chartObserver);
Expand Down Expand Up @@ -187,6 +204,7 @@ public void onStart() {
mListener.onTrackShare(trackViewModel.selectedTrack.getValue());
mFragmentHolder.popCurrent();
});
mFloatingButton.setVisibility(View.INVISIBLE);
viewBinding.getRoot().setOnScrollChangeListener(scrollChangeListener);
}

Expand Down Expand Up @@ -223,16 +241,20 @@ public boolean onMenuItemClick(MenuItem item) {

private void initializeTrackInformation(Track track) {
viewModel.reset();
Track.TrackPoint ftp = track.points.get(0);
Track.TrackPoint ltp = track.getLastPoint();
viewModel.hasTime = ftp.time > 0 && ltp.time > 0;
viewModel.startTime = ftp.time;
viewModel.lastPoint.setValue(ltp);
viewModel.isEmpty = track.points.isEmpty();
if (!viewModel.isEmpty) {
Track.TrackPoint ftp = track.points.get(0);
Track.TrackPoint ltp = track.getLastPoint();
viewModel.hasTime = ftp.time > 0 && ltp.time > 0;
viewModel.startTime = ftp.time;
viewModel.firstPoint.setValue(ftp);
viewModel.lastPoint.setValue(ltp);
viewModel.segmentCount = 1;
}
}

private void initializeTrackStatistics(Track track) {
logger.debug("initializeTrackStatistics");
viewModel.segmentCount = 1;
for (Track.TrackPoint point : track.points) {
if (Thread.currentThread().isInterrupted())
return;
Expand All @@ -247,9 +269,6 @@ private void initializeTrackStatistics(Track track) {
}

private void updateTrackStatistics(Track currentTrack) {
Track track = trackViewModel.selectedTrack.getValue();
if (track == null || track != currentTrack)
return;
if (viewModel.lastKnownSize >= currentTrack.points.size())
return;

Expand All @@ -265,13 +284,12 @@ private void updateTrackStatistics(Track currentTrack) {
}

private void processTrackPoint(Track.TrackPoint point) {
if (!point.continuous)
viewModel.segmentCount++;

double distance = Double.NaN;
if (viewModel.prevPoint != null) {
distance = point.vincentyDistance(viewModel.prevPoint);
viewModel.distance += distance;
if (!viewModel.prevPoint.continuous)
viewModel.segmentCount++;
}

if (!Float.isNaN(point.elevation) && point.elevation != 0) {
Expand Down Expand Up @@ -334,48 +352,68 @@ private void processTrackPoint(Track.TrackPoint point) {
private final Observer<Track> trackObserver = new Observer<Track>() {
@Override
public void onChanged(Track track) {
Activity activity = requireActivity();
viewBinding.name.setText(track.name);
if (track.source == null || track.source.isNativeTrack()) {
viewBinding.sourceRow.setVisibility(View.GONE);
} else {
viewBinding.source.setText(track.source.name);
viewBinding.sourceRow.setVisibility(View.VISIBLE);
}
Track.TrackPoint ftp = track.points.get(0);
viewBinding.startCoordinates.setText(StringFormatter.coordinates(ftp));
if (viewModel.hasTime) {
Date startDate = new Date(ftp.time);
viewBinding.startDate.setText(String.format("%s %s", DateFormat.getDateFormat(activity).format(startDate), DateFormat.getTimeFormat(activity).format(startDate)));
viewBinding.startDateRow.setVisibility(View.VISIBLE);
viewBinding.finishDateRow.setVisibility(View.VISIBLE);
viewBinding.timeRow.setVisibility(View.VISIBLE);
}
};

private final Observer<Track.TrackPoint> firstPointObserver = new Observer<Track.TrackPoint>() {
@Override
public void onChanged(Track.TrackPoint firstPoint) {
if (firstPoint == null) {
viewBinding.moreButton.setVisibility(View.GONE);
viewBinding.statisticsTable.setVisibility(View.GONE);
viewBinding.charts.setVisibility(View.GONE);
viewBinding.empty.setVisibility(View.VISIBLE);
} else {
viewBinding.startDateRow.setVisibility(View.GONE);
viewBinding.finishDateRow.setVisibility(View.GONE);
viewBinding.timeRow.setVisibility(View.GONE);
logger.error("firstPoint changed");
Activity activity = requireActivity();
viewBinding.startCoordinates.setText(StringFormatter.coordinates(firstPoint));
if (viewModel.hasTime) {
Date startDate = new Date(firstPoint.time);
viewBinding.startDate.setText(String.format("%s %s", DateFormat.getDateFormat(activity).format(startDate), DateFormat.getTimeFormat(activity).format(startDate)));
viewBinding.startDateRow.setVisibility(View.VISIBLE);
viewBinding.finishDateRow.setVisibility(View.VISIBLE);
viewBinding.timeRow.setVisibility(View.VISIBLE);
} else {
viewBinding.startDateRow.setVisibility(View.GONE);
viewBinding.finishDateRow.setVisibility(View.GONE);
viewBinding.timeRow.setVisibility(View.GONE);
}
viewBinding.moreButton.setVisibility(View.VISIBLE);
viewBinding.statisticsTable.setVisibility(View.VISIBLE);
viewBinding.charts.setVisibility(View.VISIBLE);
viewBinding.empty.setVisibility(View.GONE);
mFloatingButton.show();
}
}
};

private final Observer<Track.TrackPoint> lastPointObserver = new Observer<Track.TrackPoint>() {
@Override
public void onChanged(Track.TrackPoint lastPoint) {
if (lastPoint == null)
return;
logger.error("lastPoint changed");
Activity activity = requireActivity();

viewBinding.finishCoordinates.setText(StringFormatter.coordinates(lastPoint));

Date finishDate = new Date(lastPoint.time);
viewBinding.finishDate.setText(String.format("%s %s", DateFormat.getDateFormat(activity).format(finishDate), DateFormat.getTimeFormat(activity).format(finishDate)));

long elapsed = (lastPoint.time - viewModel.startTime) / 1000;
String timeSpan;
if (elapsed < 24 * 3600 * 3) { // 3 days
timeSpan = DateUtils.formatElapsedTime(elapsed);
} else {
timeSpan = DateUtils.formatDateRange(activity, viewModel.startTime, lastPoint.time, DateUtils.FORMAT_ABBREV_MONTH);
if (viewModel.hasTime) {
Date finishDate = new Date(lastPoint.time);
viewBinding.finishDate.setText(String.format("%s %s", DateFormat.getDateFormat(activity).format(finishDate), DateFormat.getTimeFormat(activity).format(finishDate)));
long elapsed = (lastPoint.time - viewModel.startTime) / 1000;
String timeSpan;
if (elapsed < 24 * 3600 * 3) { // 3 days
timeSpan = DateUtils.formatElapsedTime(elapsed);
} else {
timeSpan = DateUtils.formatDateRange(activity, viewModel.startTime, lastPoint.time, DateUtils.FORMAT_ABBREV_MONTH);
}
viewBinding.timeSpan.setText(timeSpan);
}
viewBinding.timeSpan.setText(timeSpan);
}
};

Expand All @@ -385,15 +423,14 @@ public void onChanged(Integer lastSize) {
Resources resources = getResources();
if (lastSize > 0) {
viewBinding.progressBar.setVisibility(View.GONE);
viewBinding.pointCount.setText(resources.getQuantityString(R.plurals.numberOfPoints, lastSize - 1, lastSize - 1));
viewBinding.pointCount.setText(resources.getQuantityString(R.plurals.numberOfPoints, lastSize, lastSize));
viewBinding.segmentCount.setText(resources.getQuantityString(R.plurals.numberOfSegments, viewModel.segmentCount, viewModel.segmentCount));
String distance = StringFormatter.distanceHP(viewModel.distance);
viewBinding.distance.setText(distance);
TransitionManager.beginDelayedTransition(viewBinding.getRoot(), new Fade()); // otherwise skeleton sometimes does not show original views
viewBinding.pointCountSkeleton.showOriginal();
viewBinding.distanceSkeleton.showOriginal();
} else {
viewBinding.progressBar.setVisibility(View.VISIBLE);
viewBinding.pointCountSkeleton.showSkeleton();
viewBinding.distanceSkeleton.showSkeleton();
}
Expand Down Expand Up @@ -511,6 +548,8 @@ public void onChanged(Boolean enabled) {
View.OnScrollChangeListener scrollChangeListener = new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (viewModel.isEmpty)
return;
int dy = scrollY - oldScrollY;
if (scrollY < 10 || dy < -15 && !mFloatingButton.isShown())
mFloatingButton.show();
Expand All @@ -527,6 +566,7 @@ public void handleOnBackPressed() {
};

private static class TrackInformationViewModel extends ViewModel {
private boolean isEmpty = true;
private boolean hasTime;
private boolean hasElevation;
private boolean hasSpeed;
Expand All @@ -547,6 +587,7 @@ private static class TrackInformationViewModel extends ViewModel {
private final LineData speedData;

private final MutableLiveData<Track> track = new MutableLiveData<>(null);
private final MutableLiveData<Track.TrackPoint> firstPoint = new MutableLiveData<>(null);
private final MutableLiveData<Track.TrackPoint> lastPoint = new MutableLiveData<>(null);
private final MutableLiveData<Integer> statisticsState = new MutableLiveData<>(0);
private final MutableLiveData<Integer> chartState = new MutableLiveData<>(0);
Expand All @@ -571,6 +612,7 @@ public TrackInformationViewModel(int color) {
}

public void reset() {
isEmpty = true;
hasTime = false;
hasElevation = false;
hasSpeed = false;
Expand All @@ -591,6 +633,9 @@ public void reset() {
elevationData.setXVals(new ArrayList<>());
speedData.getDataSetByIndex(0).clear();
speedData.setXVals(new ArrayList<>());

firstPoint.setValue(null);
lastPoint.setValue(null);
}

static final ViewModelInitializer<TrackInformationViewModel> initializer = new ViewModelInitializer<>(
Expand Down
20 changes: 18 additions & 2 deletions app/src/main/res/layout/fragment_track_information.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
style="@style/Scrollbar"
android:layout_width="@dimen/fragment_width"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="@color/panelSolidBackground"
tools:context=".fragments.TrackInformation">
Expand Down Expand Up @@ -72,11 +72,26 @@

</FrameLayout>

<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name_placeholder"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/fragment_padding"
android:layout_marginTop="16dp"
android:layout_marginEnd="@dimen/fragment_padding"
android:text="@string/msgEmptyTrack"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:textColorPrimary"
android:visibility="gone" />

<TableLayout
android:id="@+id/statistics_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name_placeholder"
android:layout_below="@android:id/empty"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/fragment_padding"
Expand Down Expand Up @@ -477,6 +492,7 @@
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:indeterminate="true"
android:visibility="gone"
android:padding="@dimen/fragment_padding" />

<View
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
<string name="msgTrackNotSavedPeriod">Track was not saved: too short period of time</string>
<string name="msgTrackNotSavedDistance">Track was not saved: too small distance passed</string>
<string name="msgEmptyTrackList">Your recorded tracks will appear here.</string>
<string name="msgEmptyTrack">Track has no points</string>
<string name="msgNoFileDataSources">You can also import GPX and KML files.</string>
<string name="msgDataImported">File is saved in application folder.</string>
<string name="msgSaveFailed">Failed to save: %s</string>
Expand Down

0 comments on commit 4d68df1

Please sign in to comment.