WIP
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package eu.konggdev.strikemaps.map;
|
||||
|
||||
import java.util.*;
|
||||
import eu.konggdev.strikemaps.Component;
|
||||
import eu.konggdev.strikemaps.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.renderer.implementation.VtmRenderer;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreNativeRenderer;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentMap;
|
||||
|
||||
public class MapComponent implements Component {
|
||||
MapRenderer mapRenderer;
|
||||
AppController app;
|
||||
|
||||
public String style;
|
||||
public Map<Class<? extends MapOverlay>, MapOverlay> overlays = new HashMap<>();
|
||||
public MapComponent(AppController ref) {
|
||||
this.app = ref;
|
||||
switch(UserPrefsHelper.mapRenderer(app.getPrefs())) {
|
||||
case "vtm":
|
||||
this.mapRenderer = new VtmRenderer(app, this);
|
||||
break;
|
||||
case "mapLibre":
|
||||
default: //This shouldn't happen
|
||||
this.mapRenderer = new MapLibreNativeRenderer(app, this);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
public FragmentLayoutContentMap toFragment() {
|
||||
return new FragmentLayoutContentMap(mapRenderer.getView());
|
||||
}
|
||||
|
||||
public void setStyle(String style) {
|
||||
this.style = style;
|
||||
mapRenderer.reload();
|
||||
}
|
||||
|
||||
public void switchOverlay(MapOverlay overlay) {
|
||||
if (hasOverlay(overlay)) overlays.remove(overlay.getClass());
|
||||
else overlays.put(overlay.getClass(), overlay);
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean hasOverlay(MapOverlay overlay) {
|
||||
return overlays.containsKey(overlay.getClass());
|
||||
}
|
||||
|
||||
public boolean hasOverlay(Class<? extends MapOverlay> overlay) {
|
||||
return overlays.containsKey(overlay);
|
||||
}
|
||||
|
||||
public void selectPoint(Feature selection) {
|
||||
//FIXME: Put back FragmentPointPreviewPopup (private code atm)
|
||||
}
|
||||
|
||||
public void onOverlayUpdate() {
|
||||
update();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(mapRenderer != null && style != null) mapRenderer.reload();
|
||||
}
|
||||
|
||||
public boolean onMapClick(LatLng point) {
|
||||
List<Feature> features = mapRenderer.featuresAtPoint(point);
|
||||
|
||||
switch (features.size()) {
|
||||
case 0:
|
||||
//TODO: Implement point selection for no POI found (MIGHT be done on long click??)
|
||||
//Maybe collapse UI? (Hide/show UI feature)... could be user configurable
|
||||
break;
|
||||
case 1:
|
||||
selectPoint(features.get(0));
|
||||
break;
|
||||
default:
|
||||
app.getUi().alert(
|
||||
AlertDialogFactory.pointSelector(app, features, selectedItem -> {
|
||||
selectPoint(selectedItem);
|
||||
}));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onMapLongClick(LatLng point) {
|
||||
//TODO: Likely Nonfeature(?) point selection
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package eu.konggdev.strikemaps.map.layer;
|
||||
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
//TOOD: Make not strictly MapLibre reliant
|
||||
public class MapLayer {
|
||||
public GeoJsonSource source;
|
||||
public Layer layer;
|
||||
public MapLayer(GeoJsonSource source, Layer layer) {
|
||||
this.source = source;
|
||||
this.layer = layer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package eu.konggdev.strikemaps.map.overlay;
|
||||
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
|
||||
/* More or less a data-driven layer factory */
|
||||
public interface MapOverlay {
|
||||
public MapLayer makeLayer();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package eu.konggdev.strikemaps.map.overlay.overlay;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import androidx.annotation.NonNull;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.provider.LocationDataProvider;
|
||||
import org.maplibre.android.style.layers.CircleLayer;
|
||||
import org.maplibre.android.style.layers.Property;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
import org.maplibre.geojson.Feature;
|
||||
import org.maplibre.geojson.FeatureCollection;
|
||||
import org.maplibre.geojson.Point;
|
||||
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
public class LocationOverlay implements MapOverlay, LocationListener {
|
||||
LocationDataProvider locationDataProvider;
|
||||
AppController app;
|
||||
MapComponent map;
|
||||
|
||||
public Location currentLocation = null;
|
||||
|
||||
public LocationOverlay(AppController app) {
|
||||
this.app = app;
|
||||
this.map = app.getMap();
|
||||
this.locationDataProvider = new LocationDataProvider(app.getActivity(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapLayer makeLayer() {
|
||||
GeoJsonSource source = new GeoJsonSource(
|
||||
"location",
|
||||
FeatureCollection.fromFeatures(new Feature[]{}) // empty
|
||||
);
|
||||
|
||||
if (currentLocation != null)
|
||||
source.setGeoJson(Feature.fromGeometry(Point.fromLngLat(currentLocation.getLongitude(), currentLocation.getLatitude())));
|
||||
|
||||
CircleLayer layer = new CircleLayer("location", "location");
|
||||
layer.setProperties(
|
||||
circleRadius(5f),
|
||||
circleColor(Color.parseColor("#1E88E5")),
|
||||
circleStrokeColor(Color.WHITE),
|
||||
circleStrokeWidth(1.5f),
|
||||
circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP)
|
||||
);
|
||||
|
||||
return new MapLayer(source, layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
this.currentLocation = location;
|
||||
map.onOverlayUpdate();
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package eu.konggdev.strikemaps.map.overlay.overlay;
|
||||
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
|
||||
public class PointSelectionOverlay implements MapOverlay {
|
||||
@Override
|
||||
public MapLayer makeLayer() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package eu.konggdev.strikemaps.map.renderer;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MapRenderer {
|
||||
void reload();
|
||||
|
||||
View getView();
|
||||
|
||||
List<Feature> featuresAtPoint(LatLng point);
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package eu.konggdev.strikemaps.map.renderer.implementation;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import eu.konggdev.strikemaps.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
import eu.konggdev.strikemaps.map.layer.MapLayer;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import org.maplibre.android.MapLibre;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
import org.maplibre.android.maps.MapView;
|
||||
import org.maplibre.android.maps.OnMapReadyCallback;
|
||||
import org.maplibre.android.maps.Style;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
|
||||
public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
|
||||
AppController app;
|
||||
MapComponent controller;
|
||||
MapLibreMap map;
|
||||
final MapView mapView;
|
||||
|
||||
public MapLibreNativeRenderer(AppController app, MapComponent controller) {
|
||||
this.app = app;
|
||||
this.controller = controller;
|
||||
MapLibre.getInstance(app.getActivity());
|
||||
this.mapView = new MapView(app.getActivity());
|
||||
mapView.onCreate(null);
|
||||
mapView.getMapAsync(this);
|
||||
}
|
||||
|
||||
void passLayer(MapLayer layer) {
|
||||
map.getStyle().addSource(layer.source);
|
||||
map.getStyle().addLayer(layer.layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
map.setStyle(new Style.Builder().fromJson(controller.style), style -> {
|
||||
for(MapOverlay overlay : controller.overlays.values()) {
|
||||
passLayer(overlay.makeLayer());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
return mapView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Feature> featuresAtPoint(LatLng point) {
|
||||
return map.queryRenderedFeatures(map.getProjection().toScreenLocation(point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapReady(@NonNull MapLibreMap maplibreMap) {
|
||||
this.map = maplibreMap;
|
||||
|
||||
controller.style = FileHelper.loadStringFromAssetFile(UserPrefsHelper.startupMapStyle(app.getPrefs()), app);
|
||||
|
||||
//I have my own implementation of attribution that credits MapLibre among others, it's not as bad as it looks :)
|
||||
map.getUiSettings().setLogoEnabled(false);
|
||||
map.getUiSettings().setAttributionEnabled(false);
|
||||
|
||||
map.addOnMapClickListener(point -> controller.onMapClick(point));
|
||||
map.addOnMapLongClickListener(point -> controller.onMapLongClick(point));
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package eu.konggdev.strikemaps.map.renderer.implementation;
|
||||
|
||||
import android.view.View;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.geojson.Feature;
|
||||
import org.oscim.android.MapView;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.tiling.source.OkHttpEngine;
|
||||
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class VtmRenderer implements MapRenderer {
|
||||
AppController app;
|
||||
MapComponent controller;
|
||||
|
||||
Map map;
|
||||
final MapView mapView;
|
||||
|
||||
public VtmRenderer(AppController app, MapComponent controller) {
|
||||
this.app = app;
|
||||
this.controller = controller;
|
||||
this.mapView = new MapView(app.getActivity());
|
||||
this.map = mapView.map();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
//TODO
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
OSciMap4TileSource tileSource = OSciMap4TileSource.builder().httpFactory(new OkHttpEngine.OkHttpFactory(builder)).build();
|
||||
|
||||
map.setBaseMap(tileSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
return mapView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Feature> featuresAtPoint(LatLng point) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package eu.konggdev.strikemaps.map.source;
|
||||
|
||||
public class MapSource {
|
||||
public final String url;
|
||||
public final String type;
|
||||
public final String schema;
|
||||
public MapSource(String url, String type, String schema) {
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
this.schema = schema;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user