diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java index 9a2ea1e9..f0e477c9 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java @@ -57,7 +57,7 @@ import de.stephanlindauer.criticalmaps.events.NewLocationEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; import de.stephanlindauer.criticalmaps.handler.GetLocationHandler; -// import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; +import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.model.OtherUsersLocationModel; import de.stephanlindauer.criticalmaps.model.OwnLocationModel; @@ -90,10 +90,8 @@ public class MapFragment extends Fragment { @Inject LocationUpdateManager locationUpdateManager; - /* @Inject ShowGpxHandler showGpxHandler; - */ @Inject SharedPreferences sharedPreferences; @@ -216,6 +214,8 @@ public void getOutline(View view, Outline outline) { mapStyle = style; MapViewUtils.setupSourcesAndLayers(getActivity(), mapStyle); + showGpxHandler.showGpx(mapStyle); + // trigger fake location update in case fix was acquired already during map init handleNewLocation(NEW_LOCATION_EVENT); }); @@ -234,8 +234,6 @@ public void getOutline(View view, Outline outline) { isInitialLocationSet = savedState.getBoolean(KEY_INITIAL_LOCATION_SET, false); } - // showGpxHandler.showGpx(mapView); - if (!LocationUpdateManager.checkPermission()) { zoomToLocation(defaultGeoPoint, NO_GPS_PERMISSION_ZOOM_LEVEL); } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java index 413048e6..1b0333e5 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java @@ -1,13 +1,13 @@ package de.stephanlindauer.criticalmaps.fragments; -// import android.annotation.SuppressLint; -// import android.app.Activity; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -// import android.database.Cursor; -// import android.net.Uri; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; -// import android.provider.OpenableColumns; +import android.provider.OpenableColumns; import android.text.format.Formatter; import android.view.LayoutInflater; import android.view.View; @@ -22,15 +22,15 @@ import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.R; import de.stephanlindauer.criticalmaps.databinding.FragmentSettingsBinding; -// import de.stephanlindauer.criticalmaps.handler.ChooseGpxFileHandler; +import de.stephanlindauer.criticalmaps.handler.ChooseGpxFileHandler; import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; import de.stephanlindauer.criticalmaps.model.StorageLocation; -// import de.stephanlindauer.criticalmaps.vo.RequestCodes; +import de.stephanlindauer.criticalmaps.vo.RequestCodes; import info.metadude.android.typedpreferences.BooleanPreference; -// import info.metadude.android.typedpreferences.StringPreference; +import info.metadude.android.typedpreferences.StringPreference; import timber.log.Timber; -// import static de.stephanlindauer.criticalmaps.utils.GpxUtils.persistPermissionOnFile; +import static de.stephanlindauer.criticalmaps.utils.GpxUtils.persistPermissionOnFile; import org.maplibre.android.offline.OfflineManager; @@ -70,7 +70,7 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { updateClearCachePref(); updateStorageGraph(); - // updateGpxFileName(); + updateGpxFileName(); binding.settingsShowOnLockscreenCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.SHOW_ON_LOCKSCREEN).get()); @@ -78,10 +78,8 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { binding.settingsKeepScreenOnCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.KEEP_SCREEN_ON).get()); - /* binding.settingsShowGpxCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.SHOW_GPX).get()); - */ binding.settingsClearCacheButton.setOnClickListener(v -> handleClearCacheClicked()); @@ -89,18 +87,16 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { (buttonView, isChecked) -> handleShowOnLockscreenChecked(isChecked)); binding.settingsKeepScreenOnCheckbox.setOnCheckedChangeListener( (buttonView, isChecked) -> handleKeepScreenOnChecked(isChecked)); - /* + binding.settingsShowGpxCheckbox.setOnCheckedChangeListener( (buttonView, isChecked) -> handleShowTrack(isChecked)); binding.settingsChooseGpxContainer.setOnClickListener(v -> handleChooseTrackClicked()); - */ } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - /* if (requestCode == RequestCodes.CHOOSE_GPX_RESULT_CODE && resultCode == Activity.RESULT_OK) { Uri fileUri = data.getData(); if (fileUri == null) { @@ -112,7 +108,6 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { persistPermissionOnFile(data, app.getContentResolver()); updateGpxFileName(); } - */ } private void updateStorageGraph() { @@ -141,7 +136,6 @@ private void updateClearCachePref() { Formatter.formatShortFileSize(getActivity(), currentSize))); } - /* @SuppressLint("Range") private void updateGpxFileName() { String gpxFile = new StringPreference( @@ -157,7 +151,6 @@ private void updateGpxFileName() { binding.settingsChooseGpxSummaryText.setText(filename); } - */ void handleClearCacheClicked() { OfflineManager.getInstance(getActivity()).clearAmbientCache(new OfflineManager.FileSourceCallback() { @@ -185,7 +178,6 @@ void handleKeepScreenOnChecked(boolean isChecked) { sharedPreferences, SharedPrefsKeys.KEEP_SCREEN_ON).set(isChecked); } - /* void handleShowTrack(boolean isChecked) { new BooleanPreference( sharedPreferences, SharedPrefsKeys.SHOW_GPX).set(isChecked); @@ -194,7 +186,6 @@ void handleShowTrack(boolean isChecked) { void handleChooseTrackClicked() { new ChooseGpxFileHandler(this).openChooser(); } - */ @Override public void onDestroyView() { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java index 7dd83e4b..cf883255 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java @@ -1,18 +1,24 @@ -/* package de.stephanlindauer.criticalmaps.handler; import android.content.SharedPreferences; -import android.graphics.Color; import android.net.Uri; import android.widget.Toast; -import org.osmdroid.views.MapView; -import org.osmdroid.views.overlay.Marker; -import org.osmdroid.views.overlay.Polyline; +import com.google.gson.JsonObject; + +import org.maplibre.android.geometry.LatLng; +import org.maplibre.android.maps.Style; +import org.maplibre.android.style.sources.GeoJsonSource; + +import org.maplibre.geojson.Feature; +import org.maplibre.geojson.FeatureCollection; +import org.maplibre.geojson.LineString; +import org.maplibre.geojson.Point; import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import javax.inject.Inject; import javax.xml.parsers.ParserConfigurationException; @@ -20,7 +26,6 @@ import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.R; import de.stephanlindauer.criticalmaps.model.gpx.GpxModel; -import de.stephanlindauer.criticalmaps.model.gpx.GpxPoi; import de.stephanlindauer.criticalmaps.model.gpx.GpxTrack; import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; import de.stephanlindauer.criticalmaps.utils.GpxReader; @@ -43,7 +48,7 @@ public ShowGpxHandler(SharedPreferences sharedPreferences, GpxModel gpxModel, Ap this.gpxReader = gpxReader; } - public void showGpx(MapView mapView) { + public void showGpx(Style mapStyle) { boolean showTrack = new BooleanPreference(sharedPreferences, SharedPrefsKeys.SHOW_GPX).get(); if (!showTrack) { return; @@ -54,7 +59,7 @@ public void showGpx(MapView mapView) { readFile(gpxUri); } - showModelOnMap(mapView); + showModelOnMap(mapStyle); } private void readFile(String gpxUri) { @@ -66,29 +71,44 @@ private void readFile(String gpxUri) { } } - private void showModelOnMap(MapView mapView) { + private void showModelOnMap(Style mapStyle) { + addTracksToMap(mapStyle); + addPoisToMap(mapStyle); + } + + private void addTracksToMap(Style mapStyle) { + ArrayList features = new ArrayList<>(); + for (GpxTrack track : gpxModel.getTracks()) { - addTrackToMap(mapView, track); - } + ArrayList points = new ArrayList<>(); + + for (LatLng location : track.getWaypoints()) { + points.add(Point.fromLngLat(location.getLongitude(), location.getLatitude())); + } - for (GpxPoi poi : gpxModel.getPoiList()) { - addPoiToMap(mapView, poi); + JsonObject properties = new JsonObject(); + properties.addProperty("label", track.getName()); + features.add(Feature.fromGeometry(LineString.fromLngLats(points), properties)); } - } - private void addTrackToMap(MapView mapView, GpxTrack track) { - Polyline trackLine = new Polyline(mapView); - trackLine.setPoints(track.getWaypoints()); - trackLine.setTitle(track.getName()); - trackLine.getOutlinePaint().setColor(Color.RED); - mapView.getOverlayManager().add(trackLine); + GeoJsonSource gpxTrackSource = + (GeoJsonSource) mapStyle.getSource("gpxTrackSource"); + gpxTrackSource.setGeoJson(FeatureCollection.fromFeatures(features)); } - private void addPoiToMap(MapView mapView, GpxPoi poi) { - Marker marker = new Marker(mapView); - marker.setPosition(poi.getPosition()); - marker.setTitle(poi.getName()); - mapView.getOverlayManager().add(marker); + private void addPoisToMap(Style mapStyle) { + ArrayList features = new ArrayList<>(); + + gpxModel.getPoiList().forEach((gpxPoi) -> { + LatLng location = gpxPoi.getPosition(); + JsonObject properties = new JsonObject(); + properties.addProperty("label", gpxPoi.getName()); + features.add(Feature.fromGeometry( + Point.fromLngLat(location.getLongitude(), location.getLatitude()), properties)); + }); + + GeoJsonSource gpxPoiSource = + (GeoJsonSource) mapStyle.getSource("gpxPoiSource"); + gpxPoiSource.setGeoJson(FeatureCollection.fromFeatures(features)); } } - */ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java index 336fa5ac..ce5493a2 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java @@ -1,4 +1,3 @@ -/* package de.stephanlindauer.criticalmaps.model.gpx; import java.util.ArrayList; @@ -48,4 +47,3 @@ public void clear() { uri = null; } } -*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java index 84410d4b..dcf62f3c 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java @@ -1,14 +1,13 @@ -/* package de.stephanlindauer.criticalmaps.model.gpx; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; public class GpxPoi { private final String name; - private final GeoPoint position; + private final LatLng position; - public GpxPoi(String name, GeoPoint position) { + public GpxPoi(String name, LatLng position) { this.name = name; this.position = position; } @@ -17,8 +16,7 @@ public String getName() { return name; } - public GeoPoint getPosition() { + public LatLng getPosition() { return position; } } -*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java index 30527e5d..8655c283 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java @@ -1,16 +1,15 @@ -/* package de.stephanlindauer.criticalmaps.model.gpx; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; import java.util.List; public class GpxTrack { private final String name; - private final List waypoints; + private final List waypoints; - public GpxTrack(String name, List waypoints) { + public GpxTrack(String name, List waypoints) { this.name = name; this.waypoints = waypoints; } @@ -19,8 +18,7 @@ public String getName() { return name; } - public List getWaypoints() { + public List getWaypoints() { return waypoints; } } -*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java b/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java index 6d0c8e3b..c2011b36 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java @@ -11,10 +11,8 @@ public interface SharedPrefsKeys { BuildConfig.APPLICATION_ID + ".SHOW_ON_LOCKSCREEN"; String KEEP_SCREEN_ON = BuildConfig.APPLICATION_ID + ".KEEP_SCREEN_ON"; - /* String SHOW_GPX = BuildConfig.APPLICATION_ID + ".SHOW_GPX"; String GPX_FILE = BuildConfig.APPLICATION_ID + ".GPX_FILE"; - */ } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java index ee020444..975bbad8 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java @@ -1,8 +1,7 @@ -/* package de.stephanlindauer.criticalmaps.utils; import org.jetbrains.annotations.NotNull; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -59,7 +58,7 @@ private void readWaypoints(Element gpxElement) { NodeList wptList = gpxElement.getElementsByTagName(ELEMENT_WPT); for (int i = 0; i < wptList.getLength(); i++) { Element wpt = (Element) wptList.item(i); - GeoPoint location = parsePoint(wpt); + LatLng location = parsePoint(wpt); String pointName = parseName(wpt); gpxModel.getPoiList().add(new GpxPoi(pointName, location)); } @@ -69,15 +68,15 @@ private void readTracks(Element gpxElement) { NodeList trkList = gpxElement.getElementsByTagName(ELEMENT_TRK); for (int i = 0; i < trkList.getLength(); i++) { Element track = (Element) trkList.item(i); - List trackPoints = getTrackPoints(track); + List trackPoints = getTrackPoints(track); String trackName = parseName(track); gpxModel.getTracks().add(new GpxTrack(trackName, trackPoints)); } } @NotNull - private List getTrackPoints(Element track) { - List trackPoints = new ArrayList<>(); + private List getTrackPoints(Element track) { + List trackPoints = new ArrayList<>(); NodeList trksegList = track.getElementsByTagName(ELEMENT_TRKSEG); for (int j = 0; j < trksegList.getLength(); j++) { Element trkseg = (Element) trksegList.item(j); @@ -99,20 +98,19 @@ private String parseName(Element track) { } @NotNull - private GeoPoint parsePoint(Element point) { - GeoPoint newPoint; + private LatLng parsePoint(Element point) { + LatLng newPoint; double lat = Double.parseDouble(point.getAttributes().getNamedItem(ATTRIBUTE_LAT).getNodeValue()); double lon = Double.parseDouble(point.getAttributes().getNamedItem(ATTRIBUTE_LON).getNodeValue()); NodeList eleList = point.getElementsByTagName(ELEMENT_ELE); if (eleList.getLength() > 0) { double ele = Double.parseDouble(eleList.item(0).getTextContent()); - newPoint = new GeoPoint(lat, lon, ele); + newPoint = new LatLng(lat, lon, ele); } else { - newPoint = new GeoPoint(lat, lon); + newPoint = new LatLng(lat, lon); } return newPoint; } } -*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java index 52034d21..2119a771 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java @@ -1,4 +1,3 @@ -/* package de.stephanlindauer.criticalmaps.utils; import android.annotation.SuppressLint; @@ -15,4 +14,3 @@ public static void persistPermissionOnFile(Intent data, ContentResolver contentR } } } -*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java index d269fd8d..a8da2ae0 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java @@ -1,6 +1,10 @@ package de.stephanlindauer.criticalmaps.utils; +import static org.maplibre.android.style.layers.Property.LINE_CAP_ROUND; +import static org.maplibre.android.style.layers.Property.TEXT_ANCHOR_BOTTOM_RIGHT; + import android.app.Activity; +import android.graphics.Color; import android.view.Gravity; import androidx.appcompat.content.res.AppCompatResources; @@ -14,6 +18,7 @@ import org.maplibre.android.maps.Style; import org.maplibre.android.module.http.HttpRequestUtil; import org.maplibre.android.style.layers.Layer; +import org.maplibre.android.style.layers.LineLayer; import org.maplibre.android.style.layers.PropertyFactory; import org.maplibre.android.style.layers.SymbolLayer; import org.maplibre.android.style.sources.GeoJsonSource; @@ -58,10 +63,15 @@ public static MapView createMapView(Activity activity) { public static void setupSourcesAndLayers(Activity activity, Style mapStyle) { + GeoJsonSource gpxTrackSource = new GeoJsonSource("gpxTrackSource"); + GeoJsonSource gpxPoiSource = new GeoJsonSource("gpxPoiSource"); GeoJsonSource otherUsersLocationsSource = new GeoJsonSource("otherUsersLocationsSource"); GeoJsonSource ownUserLocationSource = new GeoJsonSource("ownUserLocationSource"); GeoJsonSource ownUserLocationSourceObserver = new GeoJsonSource("ownUserLocationSourceObserver"); + mapStyle.addImage( + "gpxPoi", + AppCompatResources.getDrawable(activity, R.drawable.ic_location)); //FIXME Icon mapStyle.addImage( "otherUser", AppCompatResources.getDrawable(activity, R.drawable.ic_map_marker)); @@ -72,6 +82,27 @@ public static void setupSourcesAndLayers(Activity activity, Style mapStyle) { "ownUserObserver", AppCompatResources.getDrawable(activity, R.drawable.ic_map_marker_observer)); + Layer gpxTrackLayer = + new LineLayer("gpxTrackLayer", gpxTrackSource.getId()); + gpxTrackLayer.setProperties( + PropertyFactory.lineWidth(6f), + PropertyFactory.lineCap(LINE_CAP_ROUND), + PropertyFactory.lineColor(Color.RED) + ); + + Layer gpxPoiLayer = + new SymbolLayer("gpxPoiLayer", gpxPoiSource.getId()); + gpxPoiLayer.setProperties( + PropertyFactory.iconImage("gpxPoi"), + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconIgnorePlacement(true), + PropertyFactory.iconOptional(false), + PropertyFactory.textFont(new String[]{"noto_sans_regular"}), + PropertyFactory.textSize(10f), + PropertyFactory.textAnchor(TEXT_ANCHOR_BOTTOM_RIGHT), + PropertyFactory.textField("{label}") + ); + Layer otherUsersLocationsLayer = new SymbolLayer("otherUsersLocationsLayer", otherUsersLocationsSource.getId()); otherUsersLocationsLayer.setProperties( @@ -93,9 +124,13 @@ public static void setupSourcesAndLayers(Activity activity, Style mapStyle) { PropertyFactory.iconAllowOverlap(true), PropertyFactory.iconIgnorePlacement(true)); + mapStyle.addLayer(gpxTrackLayer); + mapStyle.addLayer(gpxPoiLayer); mapStyle.addLayer(otherUsersLocationsLayer); mapStyle.addLayer(ownUserLocationLayer); mapStyle.addLayer(ownUserLocationLayerObserver); + mapStyle.addSource(gpxTrackSource); + mapStyle.addSource(gpxPoiSource); mapStyle.addSource(otherUsersLocationsSource); mapStyle.addSource(ownUserLocationSource); mapStyle.addSource(ownUserLocationSourceObserver); diff --git a/app/src/main/res/drawable/ic_location.xml b/app/src/main/res/drawable/ic_location.xml new file mode 100644 index 00000000..166f2044 --- /dev/null +++ b/app/src/main/res/drawable/ic_location.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 0881779b..40b4fa94 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -275,7 +275,6 @@ -