diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 438c4aa..b0f2995 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,4 +25,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java b/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java
index b55c015..3cefcb0 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java
@@ -13,8 +13,9 @@ import org.maplibre.geojson.Feature;
import java.util.List;
import java.util.function.Consumer;
-//FIXME: Move Item functions into specific classes for specific types - e.g. StyleItem
public final class AlertDialogFactory {
+ private AlertDialogFactory() {} // prevent instantiation
+
public static AlertDialog pointSelector(AppController app, List features, Consumer callback) {
LinearLayout layout = new LinearLayout(app.getActivity());
layout.setOrientation(LinearLayout.VERTICAL);
diff --git a/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java b/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java
index 3228ab8..2b889c4 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java
@@ -10,8 +10,10 @@ import java.util.List;
import eu.konggdev.strikemaps.app.AppController;
-//FIXME: Ugly
+//FIXME: Spaghetti code
public final class FileHelper {
+ private FileHelper() {} // prevent instantiation
+
public static String loadStringFromAssetFile(String filePath, AppController app) {
try (InputStream is = app.getActivity().getAssets().open(filePath)) {
int size = is.available();
@@ -106,4 +108,4 @@ public final class FileHelper {
return fileList.toArray(new String[0]);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java b/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java
index 422c4cf..b64a91f 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java
@@ -18,8 +18,9 @@ public class MapComponent implements Component {
MapRenderer mapRenderer;
AppController app;
- public String style;
+ public MapStyle currentStyle;
public Map, MapOverlay> overlays = new HashMap<>();
+
public MapComponent(AppController ref) {
this.app = ref;
switch(UserPrefsHelper.mapRenderer(app.getPrefs())) {
@@ -37,9 +38,9 @@ public class MapComponent implements Component {
return new FragmentLayoutContentMap(mapRenderer.getView());
}
- public void setStyle(String style) {
+ public void setStyle(MapStyle style) {
this.style = style;
- mapRenderer.reload();
+ update();
}
public void switchOverlay(MapOverlay overlay) {
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java b/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java
index 667338a..efc1e35 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java
@@ -1,16 +1,29 @@
-package eu.konggdev.strikemaps.map.layer;
+import org.json.JSONObject;
-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) {
+ private final String id;
+ private final String type;
+ private final MapSource source;
+ private final String sourceLayer;
+ private final JSONObject paint;
+ private final JSONObject filter;
+ private final JSONObject layout;
+
+ public MapLayer(String id, String type, MapSource source, String sourceLayer, JSONObject paint, JSONObject filter, JSONObject layout) {
+ this.id = id;
+ this.type = type;
this.source = source;
- this.layer = layer;
+ this.sourceLayer = sourceLayer;
+ this.paint = paint;
+ this.filter = filter;
+ this.layout = layout;
}
+
+ public String getId() { return id; }
+ public String getType() { return type; }
+ public MapSource getSource() { return source; }
+ public String getSourceLayer() { return sourceLayer; }
+ public JSONObject getPaint() { return paint; }
+ public JSONObject getFilter() { return filter; }
+ public JSONObject getLayout() { return layout; }
}
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java
index a8da472..81ed3f7 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java
@@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import eu.konggdev.strikemaps.helper.FileHelper;
import eu.konggdev.strikemaps.helper.UserPrefsHelper;
+import eu.konggdev.strikemaps.map.renderer.implementation.additionals.MapLibreLayerFactory;
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.layer.MapLayer;
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
@@ -38,17 +39,31 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
}
void passLayer(MapLayer layer) {
+ map.getStyle().
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());
- }
- });
+ map.setStyle(
+ new Style.Builder()
+ .withLayers(
+ controller.style.layers.stream()
+ .map(layer -> MapLibreLayerFactory.parseLayer(layer))
+ .collect(Collectors.toList())
+ )
+ .withSources(
+ controller.style.sources.stream()
+ .map(source -> MapLibreLayerFactory.parseSource(source))
+ .collect(Collectors.toList())
+ ),
+ style -> {
+ for (MapOverlay overlay : controller.overlays.values()) {
+ passLayer(overlay.makeLayer());
+ }
+ }
+ );
}
@Override
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/additionals/MapLibreLayerFactory.java b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/additionals/MapLibreLayerFactory.java
new file mode 100644
index 0000000..ba20c86
--- /dev/null
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/additionals/MapLibreLayerFactory.java
@@ -0,0 +1,292 @@
+package eu.konggdev.strikemaps.map.renderer.implementation.additionals;
+
+import org.maplibre.android.style.layers.*;
+import org.maplibre.android.style.sources.*;
+import org.maplibre.android.maps.MapLibreMap;
+import org.json.JSONObject;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MapLibreLayerFactory {
+ private MapLibreLayerFactory() {} // prevent instantiation
+
+ public static Source parseSource(MapSource mapSource) {
+ switch (mapSource.type.toLowerCase()) {
+ case "vector":
+ return new VectorSource(mapSource.id, mapSource.defUrl);
+ case "raster":
+ return new RasterSource(mapSource.id, mapSource.defUrl);
+ case "geojson":
+ return new GeoJsonSource(mapSource.id, mapSource.defUrl);
+ case "raster-dem":
+ return new RasterDemSource(mapSource.id, mapSource.defUrl);
+ default:
+ throw new IllegalArgumentException("Unsupported source type: " + mapSource.type);
+ }
+ }
+
+ public static Layer parseLayer(MapLayer mapLayer) {
+ String id = mapLayer.getId();
+ String sourceId = mapLayer.getSource() != null ? mapLayer.getSource().id : null;
+ String sourceLayer = mapLayer.getSourceLayer();
+ JSONObject paint = mapLayer.getPaint();
+ JSONObject layout = mapLayer.getLayout();
+ JSONObject filter = mapLayer.getFilter();
+
+ Layer layer;
+
+ switch (mapLayer.getType().toLowerCase()) {
+ case "fill":
+ layer = buildFillLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "line":
+ layer = buildLineLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "symbol":
+ layer = buildSymbolLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "circle":
+ layer = buildCircleLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "raster":
+ layer = buildRasterLayer(id, sourceId, paint, layout);
+ break;
+ case "fill-extrusion":
+ layer = buildFillExtrusionLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "heatmap":
+ layer = buildHeatmapLayer(id, sourceId, sourceLayer, paint, layout);
+ break;
+ case "hillshade":
+ layer = buildHillshadeLayer(id, sourceId, paint, layout);
+ break;
+ case "background":
+ layer = buildBackgroundLayer(id, paint, layout);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported layer type: " + mapLayer.getType());
+ }
+
+ if (filter != null && layer instanceof BaseLayer) {
+ layer.setFilter(parseFilter(filter));
+ }
+
+ return layer;
+ }
+
+ private static FillLayer buildFillLayer(String id, String sourceId, String sourceLayer, JSONObject paint, JSONObject layout) {
+ FillLayer layer = new FillLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "fill-color", v -> props.add(PropertyFactory.fillColor(v)));
+ safeFloat (paint, "fill-opacity", v -> props.add(PropertyFactory.fillOpacity(v)));
+ safeColor(paint, "fill-outline-color", v -> props.add(PropertyFactory.fillOutlineColor(v)));
+ safeString(paint, "fill-translate-anchor", v -> props.add(PropertyFactory.fillTranslateAnchor(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static LineLayer buildLineLayer(String id, String sourceId, String sourceLayer, JSONObject paint, JSONObject layout) {
+ LineLayer layer = new LineLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "line-color", v -> props.add(PropertyFactory.lineColor(v)));
+ safeFloat (paint, "line-width", v -> props.add(PropertyFactory.lineWidth(v)));
+ safeFloat (paint, "line-opacity", v -> props.add(PropertyFactory.lineOpacity(v)));
+ safeFloat (paint, "line-blur", v -> props.add(PropertyFactory.lineBlur(v)));
+ safeFloat (paint, "line-gap-width", v -> props.add(PropertyFactory.lineGapWidth(v)));
+ safeFloat (paint, "line-offset", v -> props.add(PropertyFactory.lineOffset(v)));
+ safeColor(paint, "line-translate", v -> {}); // handled below
+ }
+ if (layout != null) {
+ safeString(layout, "line-cap", v -> props.add(PropertyFactory.lineCap(v)));
+ safeString(layout, "line-join", v -> props.add(PropertyFactory.lineJoin(v)));
+ safeFloat (layout, "line-miter-limit", v -> props.add(PropertyFactory.lineMiterLimit(v)));
+ safeFloat (layout, "line-round-limit", v -> props.add(PropertyFactory.lineRoundLimit(v)));
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static SymbolLayer buildSymbolLayer(String id, String sourceId, String sourceLayer, JSONObject paint, JSONObject layout) {
+ SymbolLayer layer = new SymbolLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "text-color", v -> props.add(PropertyFactory.textColor(v)));
+ safeFloat (paint, "text-opacity", v -> props.add(PropertyFactory.textOpacity(v)));
+ safeColor(paint, "text-halo-color", v -> props.add(PropertyFactory.textHaloColor(v)));
+ safeFloat (paint, "text-halo-width", v -> props.add(PropertyFactory.textHaloWidth(v)));
+ safeColor(paint, "icon-color", v -> props.add(PropertyFactory.iconColor(v)));
+ safeFloat (paint, "icon-opacity", v -> props.add(PropertyFactory.iconOpacity(v)));
+ safeColor(paint, "icon-halo-color", v -> props.add(PropertyFactory.iconHaloColor(v)));
+ safeFloat (paint, "icon-halo-width", v -> props.add(PropertyFactory.iconHaloWidth(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "text-field", v -> props.add(PropertyFactory.textField(v)));
+ safeFloat (layout, "text-size", v -> props.add(PropertyFactory.textSize(v)));
+ safeString(layout, "icon-image", v -> props.add(PropertyFactory.iconImage(v)));
+ safeFloat (layout, "icon-size", v -> props.add(PropertyFactory.iconSize(v)));
+ safeString(layout, "symbol-placement", v -> props.add(PropertyFactory.symbolPlacement(v)));
+ safeString(layout, "text-anchor", v -> props.add(PropertyFactory.textAnchor(v)));
+ safeFloat (layout, "text-max-width", v -> props.add(PropertyFactory.textMaxWidth(v)));
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static CircleLayer buildCircleLayer(String id, String sourceId, String sourceLayer, JSONObject paint, JSONObject layout) {
+ CircleLayer layer = new CircleLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "circle-color", v -> props.add(PropertyFactory.circleColor(v)));
+ safeFloat (paint, "circle-radius", v -> props.add(PropertyFactory.circleRadius(v)));
+ safeFloat (paint, "circle-opacity", v -> props.add(PropertyFactory.circleOpacity(v)));
+ safeFloat (paint, "circle-blur", v -> props.add(PropertyFactory.circleBlur(v)));
+ safeFloat (paint, "circle-stroke-width", v -> props.add(PropertyFactory.circleStrokeWidth(v)));
+ safeColor(paint, "circle-stroke-color", v -> props.add(PropertyFactory.circleStrokeColor(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static RasterLayer buildRasterLayer(String id, String sourceId,
+ JSONObject paint, JSONObject layout) {
+ RasterLayer layer = new RasterLayer(id, sourceId);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeFloat(paint, "raster-opacity", v -> props.add(PropertyFactory.rasterOpacity(v)));
+ safeFloat(paint, "raster-hue-rotate", v -> props.add(PropertyFactory.rasterHueRotate(v)));
+ safeFloat(paint, "raster-brightness-min", v -> props.add(PropertyFactory.rasterBrightnessMin(v)));
+ safeFloat(paint, "raster-brightness-max", v -> props.add(PropertyFactory.rasterBrightnessMax(v)));
+ safeFloat(paint, "raster-saturation", v -> props.add(PropertyFactory.rasterSaturation(v)));
+ safeFloat(paint, "raster-contrast", v -> props.add(PropertyFactory.rasterContrast(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static FillExtrusionLayer buildFillExtrusionLayer(String id, String sourceId, String sourceLayer,
+ JSONObject paint, JSONObject layout) {
+ FillExtrusionLayer layer = new FillExtrusionLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "fill-extrusion-color", v -> props.add(PropertyFactory.fillExtrusionColor(v)));
+ safeFloat (paint, "fill-extrusion-height", v -> props.add(PropertyFactory.fillExtrusionHeight(v)));
+ safeFloat (paint, "fill-extrusion-base", v -> props.add(PropertyFactory.fillExtrusionBase(v)));
+ safeFloat (paint, "fill-extrusion-opacity", v -> props.add(PropertyFactory.fillExtrusionOpacity(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static HeatmapLayer buildHeatmapLayer(String id, String sourceId, String sourceLayer,
+ JSONObject paint, JSONObject layout) {
+ HeatmapLayer layer = new HeatmapLayer(id, sourceId);
+ if (sourceLayer != null) layer.setSourceLayer(sourceLayer);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeFloat(paint, "heatmap-weight", v -> props.add(PropertyFactory.heatmapWeight(v)));
+ safeFloat(paint, "heatmap-intensity", v -> props.add(PropertyFactory.heatmapIntensity(v)));
+ safeFloat(paint, "heatmap-radius", v -> props.add(PropertyFactory.heatmapRadius(v)));
+ safeFloat(paint, "heatmap-opacity", v -> props.add(PropertyFactory.heatmapOpacity(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static HillshadeLayer buildHillshadeLayer(String id, String sourceId, JSONObject paint, JSONObject layout) {
+ HillshadeLayer layer = new HillshadeLayer(id, sourceId);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeFloat(paint, "hillshade-illumination-direction", v -> props.add(PropertyFactory.hillshadeIlluminationDirection(v)));
+ safeFloat(paint, "hillshade-exaggeration", v -> props.add(PropertyFactory.hillshadeExaggeration(v)));
+ safeColor(paint, "hillshade-shadow-color", v -> props.add(PropertyFactory.hillshadeShadowColor(v)));
+ safeColor(paint, "hillshade-highlight-color", v -> props.add(PropertyFactory.hillshadeHighlightColor(v)));
+ safeColor(paint, "hillshade-accent-color", v -> props.add(PropertyFactory.hillshadeAccentColor(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ private static BackgroundLayer buildBackgroundLayer(String id, JSONObject paint, JSONObject layout) {
+ BackgroundLayer layer = new BackgroundLayer(id);
+
+ List> props = new ArrayList<>();
+ if (paint != null) {
+ safeColor(paint, "background-color", v -> props.add(PropertyFactory.backgroundColor(v)));
+ safeFloat (paint, "background-opacity", v -> props.add(PropertyFactory.backgroundOpacity(v)));
+ }
+ if (layout != null) {
+ safeString(layout, "visibility", v -> props.add(PropertyFactory.visibility(v)));
+ }
+ layer.setProperties(props.toArray(new PropertyValue[0]));
+ return layer;
+ }
+
+ public static Expression parseFilter(JSONObject filterObj) {
+ try {
+ if (filterObj.has("expr")) {
+ return Expression.raw(filterObj.getJSONArray("expr").toString());
+ }
+ return Expression.raw(filterObj.toString());
+ } catch (JSONException e) {
+ throw new IllegalArgumentException("Failed to parse filter: " + e.getMessage(), e);
+ }
+ }
+
+ @FunctionalInterface
+ private interface Consumer { void accept(T t); }
+
+ private static void safeString(JSONObject obj, String key, Consumer action) {
+ if (obj.has(key)) {
+ try { action.accept(obj.getString(key)); } catch (JSONException ignored) {}
+ }
+ }
+
+ private static void safeFloat(JSONObject obj, String key, Consumer action) {
+ if (obj.has(key)) {
+ try { action.accept((float) obj.getDouble(key)); } catch (JSONException ignored) {}
+ }
+ }
+
+ private static void safeColor(JSONObject obj, String key, Consumer action) {
+ safeString(obj, key, action);
+ }
+}
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java b/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java
index 22fcb50..1288991 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java
@@ -1,11 +1,14 @@
package eu.konggdev.strikemaps.map.source;
public class MapSource {
- public final String url;
+ public final String id;
+ public final String defUrl;
public final String type;
public final String schema;
- public MapSource(String url, String type, String schema) {
- this.url = url;
+
+ public MapSource(String id, String url, String type, String schema) {
+ this.id = id;
+ this.defUrl = url;
this.type = type;
this.schema = schema;
}
diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/style/MapStyle.java b/app/src/main/java/eu/konggdev/strikemaps/map/style/MapStyle.java
new file mode 100644
index 0000000..b7f8793
--- /dev/null
+++ b/app/src/main/java/eu/konggdev/strikemaps/map/style/MapStyle.java
@@ -0,0 +1,90 @@
+package eu.konggdev.strikemaps;
+
+import android.graphics.Bitmap;
+
+import androidx.annotation.NonNull;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MapStyle {
+ @NonNull public final String name;
+ public Bitmap icon;
+ public final List sources;
+ public final List layers;
+
+ public MapStyle(String name, List sources, List layers) {
+ this.name = name;
+ this.sources = sources;
+ this.layers = layers;
+ }
+
+ public MapStyle(String name, Bitmap icon, List sources, List layers) {
+ this.name = name;
+ this.icon = icon;
+ this.sources = sources;
+ this.layers = layers;
+ }
+
+ //FIXME
+ public static MapStyle fromMapLibreJsonFile(String filename, AppController app) {
+ try {
+ String styleContents;
+ if (filename.startsWith("/storage")) {
+ styleContents = FileHelper.loadStringFromUserFile(filename);
+ } else {
+ styleContents = FileHelper.loadStringFromAssetFile(filename, app);
+ }
+
+ JSONObject styleJson = new JSONObject(styleContents);
+ String name = styleJson.optString("name", "Unknown");
+
+ Map thisSources = new HashMap<>();
+ JSONObject sourcesObject = styleJson.optJSONObject("sources");
+ if (sourcesObject != null) {
+ for (String key : sourcesObject.keySet()) {
+ JSONObject sourceObject = sourcesObject.optJSONObject(key);
+ if (sourceObject == null) continue;
+ thisSources.put(
+ key,
+ new MapSource(
+ key,
+ sourceObject.optString("url", "unknown"),
+ sourceObject.optString("type", "unknown"),
+ sourceObject.optString("schema", "unknown")
+ )
+ );
+ }
+ }
+
+ List thisLayers = new ArrayList<>();
+ JSONArray layersArray = styleJson.optJSONArray("layers");
+ if (layersArray != null) {
+ for (int i = 0; i < layersArray.length(); i++) {
+ JSONObject layer = layersArray.optJSONObject(i);
+ if (layer == null) continue;
+ String sourceKey = layer.optString("source", "");
+ thisLayers.add(new MapLayer(
+ layer.optString("id", "unknown"),
+ layer.optString("type", "unknown"),
+ thisSources.computeIfAbsent(sourceKey, k -> new MapSource(k, "unknown", "unknown", "unknown", null)),
+ layer.optString("source-layer", "unknown"),
+ layer.optJSONObject("paint"),
+ layer.optJSONObject("filter"),
+ layer.optJSONObject("layout")
+ ));
+ }
+ }
+
+ return new MapStyle(name, thisSources, thisLayers);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new MapStyle("Name parsing Exception!", new HashMap<>(), new ArrayList<>());
+ }
+ }
+}
diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java
index af2512e..9e1ca67 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java
@@ -12,7 +12,6 @@ import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.helper.FileHelper;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
-import org.json.JSONObject;
import java.io.InputStream;
@@ -21,6 +20,7 @@ public class GenericItem implements UIItem {
public Bitmap image;
public Runnable onClick;
boolean hasImage;
+
public GenericItem(String refName) {
this.name = refName;
hasImage = false;
@@ -42,29 +42,12 @@ public class GenericItem implements UIItem {
hasImage = true;
}
- //FIXME: Ugly glue static constructor
- public final static GenericItem fromStyle(String style, AppController app, MapComponent map) {
- try {
- JSONObject styleJson = new JSONObject(style);
- String name = "Unknown"; //Fallback name
- if (styleJson.has("name")) name = styleJson.getString("name");
- if (styleJson.has("icon")) {
- switch(styleJson.getString("icon").split("//")[0]) {
- //TODO: https
- case "assets:":
- Bitmap icon = BitmapFactory.decodeStream(FileHelper.openAssetStream("bundled/icon/" + styleJson.getString("icon").split("//")[1], app));
- return new GenericItem(name, icon, () -> map.setStyle(style));
- default:
- app.logcat("Unimplemented icon source requested in style: " + name);
- return new GenericItem(name, () -> map.setStyle(style));
- }
- }
- return new GenericItem(name, () -> map.setStyle(style));
- } catch (Exception e) {
- e.printStackTrace();
- return new GenericItem("Exception!", () -> map.setStyle(style));
- }
+ public final static GenericItem fromStyle(MapStyle style, MapComponent map) {
+ if(style.icon != null)
+ return new GenericItem(style.name, style.icon, () -> map.setStyle(style));
+ return new GenericItem(style,name, () -> map.setStyle(style))
}
+
public View makeView(UIComponent spawner) {
View v = spawner.inflateUi(R.layout.item_generic);
//FIXME: These shouldn't be casted like that!
diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java
index 8bf547f..b147c7b 100644
--- a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java
+++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java
@@ -35,6 +35,7 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
this.ui = app.getUi();
this.region = region;
}
+
@Override
public Integer getRegion() {
return region;
@@ -51,11 +52,7 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
setupButton(view, R.id.closeButton, click(() -> ui.getCurrentScreen().closePopup()));
setupDragHandle(view, view, () -> ui.getCurrentScreen().closePopup());
String[] stylePaths = ArrayUtils.addAll(FileHelper.getAssetFiles("bundled/style", ".style.json", app), FileHelper.getUserFiles("style", ".style.json", app));
- List views = new ArrayList<>();
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
- for(String i : stylePaths) {
- if(i.startsWith("/storage")) stylesLayout.addView(GenericItem.fromStyle(FileHelper.loadStringFromUserFile(i), app, map).makeView(ui));
- else stylesLayout.addView(GenericItem.fromStyle(FileHelper.loadStringFromAssetFile(i, app), app, map).makeView(ui));
- }
+ stylePaths.forEach(style -> stylesLayout.addView(GenericItem.fromStyle(MapStyle.fromMapLibreJsonFile(style, app), map).makeView(ui)));
}
}