Seperate style source fields from MapSource

This commit is contained in:
2026-09-10 03:25:59 +02:00
parent c97c7c24a3
commit 19d0a768fd
14 changed files with 174 additions and 138 deletions
@@ -5,12 +5,11 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.source.MapSource.MapSourceContractType;
import eu.konggdev.strikemaps.map.source.model.TileSource;
import eu.konggdev.strikemaps.map.source.tiles.SourceTiles;
import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import org.apache.commons.codec.digest.DigestUtils;
import java.lang.reflect.Type;
import java.util.HashMap;
@@ -36,11 +35,15 @@ public final class UserPrefsHelper {
public static Map<Integer, MapStyle> DEFAULT_STYLES(AppController app) {
Map<Integer, MapStyle> styles = new HashMap<>();
String[] styleAssets = FileHelper.getAssetFiles("bundled/style", ".style.json", app);
for (int i = 0; i < styleAssets.length; i++) { styles.put( i,
for (int i = 0; i < styleAssets.length; i++) {
String styleContents = FileHelper.loadStringFromAssetFile(styleAssets[i], app);
styles.put( i,
new MapStyle(
FileHelper.loadStringFromAssetFile(styleAssets[i], app),
styleContents,
new StyleOptions(),
new StyleManagementMetadata()
new StyleManagementMetadata( //Set the style to automatically update from assets
false, true, true,
"assets://" + styleAssets[i], DigestUtils.sha256Hex(styleContents))
));
}
return styles;
@@ -48,16 +51,14 @@ public final class UserPrefsHelper {
private static final Map<Integer, MapSource> DEFAULT_SOURCES = Map.of(
0, new MapSource(
MapSourceContractType.DEFINITION,
"Strike Maps Planet",
new TileSource("https://tiles.strikemaps.eu/planet"),
new SourceTiles("https://tiles.strikemaps.eu/planet"),
"vector",
"smts"
),
1, new MapSource(
MapSourceContractType.DEFINITION,
"ArcGIS Imagery",
new TileSource(new String[]{"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}),
new SourceTiles(new String[]{"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}),
"raster",
"raster"
)
@@ -22,7 +22,8 @@ public class MapComponent implements Component {
private final MapRenderer mapRenderer;
private final AppController app;
public MapStyle style;
public Integer styleId;
public Map<Class<? extends MapOverlay>, MapOverlay> overlays = new HashMap<>();
public MapComponent(AppController ref) {
@@ -48,9 +49,8 @@ public class MapComponent implements Component {
return new FragmentLayoutContentMap(mapRenderer.getView());
}
public void setStyle(MapStyle style) {
this.style = style;
mapRenderer.styleUpdate(style.effectiveDocument());
public void setStyle(Integer id) {
styleId = id;
}
public void switchOverlay(MapOverlay overlay) {
@@ -102,9 +102,7 @@ public class MapComponent implements Component {
public void onMapInit() {
setStyle(
app.getRegistry().getStyle(
UserPrefsHelper.startupMapStyle(app.getPrefs())
)
UserPrefsHelper.startupMapStyle(app.getPrefs())
);
}
}
@@ -17,8 +17,8 @@ import eu.konggdev.strikemaps.app.util.JsonPatcher;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.map.style.source.StyleSource;
import org.maplibre.android.geometry.LatLng;
import org.maplibre.geojson.Feature;
@@ -72,8 +72,9 @@ public class MapLibreGLJSRenderer implements MapRenderer {
//Sources
ObjectNode sources = mapper.createObjectNode();
if (style.sources != null)
for (MapSource source : style.sources)
sources.set(source.name, source.makeJson());
for (StyleSource source : style.sources)
sources.set(source.key,
source.current.makeJson());
//Layers
ArrayNode layers = mapper.createArrayNode();
@@ -10,16 +10,19 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import eu.konggdev.strikemaps.app.util.JsonPatcher;
import eu.konggdev.strikemaps.map.offline.OfflineTileResolver;
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer;
import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.map.style.source.StyleSource;
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.android.module.http.HttpRequestUtil;
import org.maplibre.android.offline.OfflineManager;
import org.maplibre.geojson.Feature;
import java.util.List;
@@ -39,7 +42,9 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
this.controller = controller;
MapLibre.getInstance(app.getActivity());
this.mapView = new MapView(app.getActivity());
//TODO: Investigate if we might want to restore any savedInstanceState for MapLibre
mapView.onCreate(null);
//We need this to get the onMapReady callback
mapView.getMapAsync(this);
}
@@ -56,8 +61,9 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
//Sources
ObjectNode sources = mapper.createObjectNode();
if (style.sources != null)
for (MapSource source : style.sources)
sources.set(source.name, source.makeJson());
for (StyleSource source : style.sources)
sources.set(source.key,
source.current.makeJson());
//Layers
ArrayNode layers = mapper.createArrayNode();
@@ -1,52 +1,14 @@
package eu.konggdev.strikemaps.map.source;
import androidx.annotation.NonNull;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.konggdev.strikemaps.map.source.model.TileSource;
import eu.konggdev.strikemaps.map.source.tiles.SourceTiles;
public class MapSource {
public enum MapSourceContractType {
REQUEST,
DEFINITION
}
/*
* Contract describes the "purpose" of the source.
*
* This exists because we effectively have two types
* of sources:
* - Sources that are the style asking for a specific type of source
* and defining a fallback, which is also used as a default for
*
* and
* - Sources that are the actual source
*/
@NonNull
public final MapSourceContractType contract;
/*
* For a request contract:
* name is the internal key used by the style.
*
* For a definition contract:
* name is the user-facing source name
* (e.g. "ArcGIS Imagery").
*
* When converting a request into a definition
* (when importing a style whose requests
* cannot be satisfied), we look for a name
* field and fall back to normalizing the key instead
*/
public String name;
/*
* For a request contract, this is the fallback
* for when we absolutely cannot satisfy the requirement,
* or the defaults for converting into a definition contract.
*/
public TileSource tileSource;
public SourceTiles tileSource;
public String type;
public String schema;
@@ -59,41 +21,33 @@ public class MapSource {
public String encoding;
public MapSource(@NonNull MapSourceContractType contract, String name, TileSource tileSource, String type, String schema) {
this.contract = contract;
public MapSource(String name, SourceTiles tileSource, String type, String schema) {
this.name = name;
this.tileSource = tileSource;
this.type = type;
this.schema = schema;
}
private MapSource(@NonNull MapSourceContractType contract) {
this.contract = contract;
public MapSource(String key, JsonNode sourceNode) {
this.name = key;
this.type = sourceNode.path("type").asText(null);
this.schema = sourceNode.path("schema").asText(null);
this.scheme = sourceNode.path("scheme").asText(null);
this.encoding = sourceNode.path("encoding").asText(null);
this.minzoom = sourceNode.path("minZoom").asInt(0);
this.maxzoom = sourceNode.path("maxZoom").asInt(24);
this.tileSize = sourceNode.path("tileSize").asInt(256);
this.tileSource = handleJsonTileSource(sourceNode);
}
public static MapSource fromJson(MapSourceContractType contract, String key, JsonNode sourceNode) {
MapSource result = new MapSource(contract);
result.name = key;
result.schema = sourceNode.path("schema").asText(null);
result.scheme = sourceNode.path("scheme").asText(null);
result.encoding = sourceNode.path("encoding").asText(null);
result.type = sourceNode.path("type").asText(null);
result.minzoom = sourceNode.path("minZoom").asInt(0);
result.maxzoom = sourceNode.path("maxZoom").asInt(24);
result.tileSize = sourceNode.path("tileSize").asInt(256);
result.tileSource = handleJsonTileSource(contract, sourceNode);
return result;
}
private static TileSource handleJsonTileSource(MapSourceContractType contract, JsonNode sourceNode) {
private static SourceTiles handleJsonTileSource(JsonNode sourceNode) {
// By design, a source must use either "url" or "tiles", never both
// In case both are present, we prefer URL over tiles... because I don't know, we just do, m'kay?
if (sourceNode.has("url"))
return new TileSource(sourceNode.get("url").asText());
return new SourceTiles(sourceNode.get("url").asText());
if (sourceNode.has("tiles")) {
String[] tiles = new String[0];
@@ -105,15 +59,12 @@ public class MapSource {
e.printStackTrace();
}
return new TileSource(tiles);
return new SourceTiles(tiles);
}
if (contract == MapSourceContractType.REQUEST) //No tile source is only acceptable for a request contract
//TODO: Define an empty tile source?
return null;
//TODO: Decide what to do when we have a definition that doesn't define the most important part - the tile source
//Maybe throwing some custom exception, catching it in fromJson calls and propagating it back to the user would be appropriate
//Maybe throwing some custom exception and propagating it back to the user would be appropriate
return null;
}
@@ -0,0 +1,14 @@
package eu.konggdev.strikemaps.map.source.properties;
import com.fasterxml.jackson.databind.JsonNode;
public class SourceProperties {
public String type;
public String schema;
// Json constructor
public SourceProperties(JsonNode sourceNode) {
this.type = sourceNode.path("type").asText(null);
this.schema = sourceNode.path("schema").asText(null);
}
}
@@ -1,35 +1,36 @@
package eu.konggdev.strikemaps.map.source.model;
package eu.konggdev.strikemaps.map.source.tiles;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class TileSource {
public enum TileSourceType {
public class SourceTiles {
public enum TilesType {
URL,
TILES,
DATA
}
private TileSourceType type;
private final TilesType type;
private String url;
private String[] tiles;
private JsonNode data;
public TileSource(String url) {
public SourceTiles(String url) {
this.url = url;
this.type = TileSourceType.URL;
this.type = TilesType.URL;
}
public TileSource(String[] tiles) {
public SourceTiles(String[] tiles) {
this.tiles = tiles;
this.type = TileSourceType.TILES;
this.type = TilesType.TILES;
}
public TileSource(JsonNode data) {
public SourceTiles(JsonNode data) {
this.data = data;
this.type = TileSourceType.DATA;
this.type = TilesType.DATA;
}
public void makeJson(ObjectMapper mapper, ObjectNode node) {
@@ -2,9 +2,11 @@ package eu.konggdev.strikemaps.map.style;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
public class MapStyle {
public static final class StoredRepresentation {
@@ -20,13 +22,11 @@ public class MapStyle {
}
public MapStyle restore() {
MapStyle style = new MapStyle(
return new MapStyle(
json,
options,
managementMetadata
);
return style;
}
}
@@ -39,7 +39,6 @@ public class MapStyle {
// Original json representation of the style document, as we got it
@NonNull public final String json;
public MapStyle(@NonNull String json, @NonNull StyleOptions styleOptions, @Nullable StyleManagementMetadata managementMetadata) {
this.json = json;
this.document = new StyleDocument(json);
@@ -58,7 +57,7 @@ public class MapStyle {
return new StoredRepresentation(json, options, managementMetadata);
}
public StyleDocument effectiveDocument() {
return document.effectiveDocument(options);
public StyleDocument effectiveDocument(RegistryStorageComponent registry) {
return document.effectiveDocument(options, registry);
}
}
@@ -1,27 +1,25 @@
package eu.konggdev.strikemaps.map.style.document;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.helper.FileHelper;
import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.map.style.source.StyleSource;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import java.util.ArrayList;
import java.util.List;
public class StyleDocument {
//Only local data
public String name;
public String icon;
public JsonNode metadata; // everything except layers + sources
public List<MapSource> sources;
public List<StyleSource> sources;
public ArrayNode layerDefinitions; // "layers" array
// Json constructor
@@ -35,9 +33,9 @@ public class StyleDocument {
this.icon = root.path("icon").asText();
JsonNode jsonSources = root.path("sources");
List<MapSource> sources = new ArrayList<>();
List<StyleSource> sources = new ArrayList<>();
jsonSources.fields().forEachRemaining(entry -> {
sources.add(MapSource.fromJson(MapSource.MapSourceContractType.REQUEST, entry.getKey(), entry.getValue()));
sources.add(new StyleSource(entry.getKey(), entry.getValue()));
});
this.sources = sources;
@@ -47,8 +45,8 @@ public class StyleDocument {
metadata.remove("layers");
metadata.remove("sources");
this.metadata = metadata;
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("Invalid style document", e);
}
}
@@ -63,8 +61,16 @@ public class StyleDocument {
}
// The style that is presented to the renderer, with its options applied
public StyleDocument effectiveDocument(StyleOptions options) {
public StyleDocument effectiveDocument(StyleOptions options, RegistryStorageComponent registry) {
StyleDocument result = new StyleDocument(this); //Copy
for (int i = 0; i < sources.size(); i++) {
StyleSource source = sources.get(i);
MapSource effectiveSource = registry.getSource(
options.getInteger(source.key, 0)
);
if (effectiveSource != null) source.current = effectiveSource;
}
for (JsonNode layer : result.layerDefinitions) {
JsonNode option = layer.get("option");
@@ -0,0 +1,28 @@
package eu.konggdev.strikemaps.map.style.source;
import androidx.annotation.NonNull;
import com.fasterxml.jackson.databind.JsonNode;
import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.source.properties.SourceProperties;
// Stores a source currently used by a style
// Along with requirements of what source the style needs here
public class StyleSource {
public String key;
// Requirement properties
public SourceProperties properties;
// In an effective style, this is the actual source matched to the
// style's requirements according to user's preferences (StyleOptions).
// Otherwise, this is the fallback source.
// It also preserves the default source defined by the JSON for non-effective style documents
@NonNull public MapSource current;
// Json constructor
public StyleSource(String key, JsonNode sourceNode) {
this.key = key;
this.properties = new SourceProperties(sourceNode);
this.current = new MapSource(key, sourceNode);
}
}
@@ -1,5 +1,6 @@
package eu.konggdev.strikemaps.storage;
import androidx.annotation.Nullable;
import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.source.MapSource;
@@ -8,6 +9,9 @@ import eu.konggdev.strikemaps.helper.UserPrefsHelper;
import java.util.Map;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import org.apache.commons.codec.digest.DigestUtils;
public class RegistryStorageComponent implements Component {
private AppController app;
@@ -29,6 +33,10 @@ public class RegistryStorageComponent implements Component {
return sources();
}
@Nullable public MapSource getSource(Integer id) {
return sources().get(id);
}
private Map<Integer, MapStyle> styles() {
if (styles == null) styles = UserPrefsHelper.styles(app.getPrefs(), app);
return styles;
@@ -38,7 +46,7 @@ public class RegistryStorageComponent implements Component {
return styles();
}
public MapStyle getStyle(Integer id) {
@Nullable public MapStyle getStyle(Integer id) {
return styles().get(id);
}
@@ -6,6 +6,8 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
@@ -18,6 +20,7 @@ import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
@@ -33,15 +36,16 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
@NonNull
UIComponent ui;
@NonNull
RegistryStorageComponent registry;
@NonNull
final FragmentMapChangePopup mapChangePopup;
private final MapStyle style;
private final Integer id;
private final Integer styleId;
private ActivityResultLauncher<Intent> exportLauncher;
void deleteStyle() {
app.getRegistry().deleteStyle(id);
registry.deleteStyle(styleId);
mapChangePopup.reloadStyles();
dismiss();
@@ -54,13 +58,13 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
exportLauncher.launch(intent);
}
public StyleDetailsBottomSheet(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup, MapStyle style, Integer id) {
public StyleDetailsBottomSheet(AppController app, FragmentMapChangePopup mapChangePopup, Integer styleId) {
this.app = app;
this.map = map;
this.ui = ui;
this.map = app.getMap();
this.ui = app.getUi();
this.registry = app.getRegistry();
this.mapChangePopup = mapChangePopup;
this.style = style;
this.id = id;
this.styleId = styleId;
}
@Override
@@ -81,7 +85,8 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
.openOutputStream(uri)) {
if (out != null) {
out.write(style.json.getBytes());
String styleJson = registry.getStyle(styleId).json;
if (styleJson != null) out.write(styleJson.getBytes());
}
} catch (IOException e) {
@@ -96,20 +101,27 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_style_details, container, false);
MapStyle style = registry.getStyle(styleId);
TextView styleNameView = view.findViewById(R.id.styleName);
LinearLayout styleManagementInfo = view.findViewById(R.id.styleManagementInfo);
TextView styleTypeView = view.findViewById(R.id.styleType);
ImageView managedStyleIndicator = view.findViewById(R.id.managedStyleIndicator);
TextView builtInStyleAlert = view.findViewById(R.id.builtInStyleAlert);
MaterialCardView editButtonLayout = view.findViewById(R.id.editButton);
MaterialCardView copyButtonLayout = view.findViewById(R.id.copyButton);
MaterialCardView exportButtonLayout = view.findViewById(R.id.exportButton);
MaterialCardView deleteButtonLayout = view.findViewById(R.id.deleteButton);
MaterialCardView closeButtonLayout = view.findViewById(R.id.closeButton);
styleNameView.setText(style.document.name);
if (style.managementMetadata != null) {
styleTypeView.setText("Built-In Style");
managedStyleIndicator.setVisibility(View.VISIBLE);
styleManagementInfo.setOnClickListener(v ->
ui.alert(
AlertDialogFactory.styleManagementOptions(app, style.managementMetadata)
)
);
} else {
styleTypeView.setText("User Style");
}
@@ -118,7 +130,6 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(app, style.json, mapChangePopup)));
exportButtonLayout.setOnClickListener(v -> showExportDialog());
deleteButtonLayout.setOnClickListener(v -> deleteStyle());
closeButtonLayout.setOnClickListener(v -> dismiss());
return view;
}
@@ -18,17 +18,20 @@ import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.fragment.dialog.NewStyleBottomSheet;
import eu.konggdev.strikemaps.ui.fragment.dialog.StyleDetailsBottomSheet;
import eu.konggdev.strikemaps.ui.element.item.GenericItem;
import java.util.Map;
import java.util.Objects;
public class FragmentMapChangePopup extends Fragment implements Popup {
@NonNull AppController app;
@NonNull MapComponent map;
@NonNull UIComponent ui;
@NonNull RegistryStorageComponent registry;
private final Integer region;
@@ -49,11 +52,13 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
public void reloadStyles() {
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
stylesLayout.removeAllViews();
app.getRegistry().getStyles().forEach((id, style) ->
stylesLayout.addView(GenericItem.fromStyle(style.document, app,
() -> map.setStyle(style),
() -> this.styleDetails(style, id)).makeView(ui))
);
app.getRegistry().getStyles().forEach((id, style) -> {
View item = new GenericItem(
style.document,
app,
() -> this.setStyle(id),
() -> this.styleDetails(id)).makeView(ui);
});
Bitmap addNewIcon = BitmapFactory.decodeResource(app.getActivity().getResources(), android.R.drawable.ic_menu_add);
stylesLayout.addView(new GenericItem("",
addNewIcon,
@@ -90,8 +95,13 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
new NewStyleBottomSheet(app, map, ui, this).show(app.getActivity().getSupportFragmentManager(), "NewStyleBottomSheet");
}
void styleDetails(MapStyle entry, Integer id) {
new StyleDetailsBottomSheet(app, map, ui, this, entry, id).show(app.getActivity().getSupportFragmentManager(), "StyleDetailsBottomSheet");
void styleDetails(Integer id) {
new StyleDetailsBottomSheet(app, this, id).show(app.getActivity().getSupportFragmentManager(), "StyleDetailsBottomSheet");
}
void setStyle(Integer id) {
map.setStyle(id);
reloadStyles();
}
public FragmentMapChangePopup(AppController app, Integer region) {
@@ -99,6 +109,7 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
this.app = app;
this.map = app.getMap();
this.ui = app.getUi();
this.registry = app.getRegistry();
this.region = region;
}