Compare commits

..
2 Commits
Author SHA1 Message Date
konggd 9d440ced2d Minor UI improvements 2026-09-10 03:38:44 +02:00
konggd ff8493a47c reword: add indicator to currently active style in map change ui 2026-09-10 03:38:27 +02:00
34 changed files with 516 additions and 536 deletions

No files matched your search

+2 -2
View File
@@ -9,8 +9,8 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.konggdev.strikemaps" applicationId = "eu.konggdev.strikemaps"
minSdk = 23 minSdk = 24
targetSdk = 36 targetSdk = 35
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
+3 -2
View File
@@ -9,9 +9,10 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.StrikeMaps"> android:theme="@style/Theme.StrikeMaps"
tools:targetApi="31">
<activity <activity
android:name=".activity.MainActivity" android:name=".MainActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@@ -3,7 +3,7 @@
"name": "Satellite", "name": "Satellite",
"icon": "assets://satellite.bmp", "icon": "assets://satellite.bmp",
"sources": { "sources": {
"imagery": { "satelite": {
"type": "raster", "type": "raster",
"schema" : "raster", "schema" : "raster",
"tiles": [ "tiles": [
@@ -17,9 +17,9 @@
}, },
"layers": [ "layers": [
{ {
"id": "background", "id": "satelite",
"type": "raster", "type": "raster",
"source": "imagery" "source": "satelite"
} }
], ],
"id": "satellite" "id": "satellite"
+35
View File
@@ -0,0 +1,35 @@
package eu.konggdev.strikemaps;
import eu.konggdev.strikemaps.app.AppController;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
AppController app;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = new AppController(this);
setContentView(R.layout.view_main);
app.init();
}
public void logcat(String tag, String log) {
Log.i(tag, log);
}
public void logcat(String log) {
Log.i("LogcatGeneric", log);
}
@Override
public void onBackPressed() {
if (!app.getUi().back())
super.onBackPressed();
}
}
@@ -1,90 +0,0 @@
package eu.konggdev.strikemaps.activity;
import android.content.SharedPreferences;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
import android.os.Bundle;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.element.region.UIRegion;
import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion;
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls;
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutSearch;
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentOfflineMaps;
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings;
import eu.konggdev.strikemaps.ui.screen.Screen;
import java.util.List;
import java.util.Map;
public class MainActivity extends ComponentHolderActivity {
private List<Component> components;
private UIComponent ui;
private Map<String, Screen> initScreens(UIComponent ui, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs) {
return Map.of(
//Main screen
"main", new Screen(
this,
//Main screen init regions definition
Map.of(
R.id.mainContentView, new MainContentRegion(map.toFragment(), R.id.mainContentView),
R.id.bottomUi, new UIRegion(new FragmentLayoutControls(this, ui, map, registry, userPrefs, R.id.bottomUi), R.id.bottomUi),
R.id.topUi, new UIRegion(new FragmentLayoutSearch(this, ui, R.id.topUi), R.id.topUi)
) //TODO: Probably stop referencing layout 3(!) times everytime
),
//Settings screen
"settings", new Screen(
this,
//Just the settings content fragment
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentSettings(this, ui, userPrefs), R.id.mainContentView)
)
),
//Offline maps screen
"offline", new Screen(
this,
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentOfflineMaps(this), R.id.mainContentView)
)
)
);
}
@NonNull
private List<Component> initComponents() {
SharedPreferences userPrefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
RegistryStorageComponent registry = new RegistryStorageComponent(this, userPrefs);
MapComponent map = new MapComponent(this, registry, userPrefs);
UIComponent ui = new UIComponent(this, map, registry, userPrefs);
ui.defineScreens(initScreens(ui, map, registry, userPrefs));
this.ui = ui;
return List.of(
map,
ui,
registry
);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.components = initComponents();
ui.swapScreen("main");
setContentView(R.layout.view_main);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (!ui.back()) {
setEnabled(false);
getOnBackPressedDispatcher().onBackPressed();
}
}
});
}
}
@@ -0,0 +1,60 @@
package eu.konggdev.strikemaps.app;
import android.content.SharedPreferences;
import androidx.appcompat.app.AppCompatActivity;
import eu.konggdev.strikemaps.MainActivity;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.screen.definition.DefinedScreen;
import static android.content.Context.MODE_PRIVATE;
public class AppController {
private final MainActivity appActivity;
private MapComponent map;
private UIComponent ui;
private RegistryStorageComponent registry;
public AppController(MainActivity appActivity) { this.appActivity = appActivity;}
public void logcat(String log) {
appActivity.logcat(log);
}
public UIComponent getUi() {
if (ui == null) init();
return ui;
}
public MapComponent getMap() {
if (map == null) init();
return map;
}
public RegistryStorageComponent getRegistry() {
if (registry == null) init();
return registry;
}
public SharedPreferences getPrefs() {
return getActivity().getSharedPreferences("user_prefs", MODE_PRIVATE);
}
public AppCompatActivity getActivity() { return appActivity; }
public void init() {
if (getActivity().getSupportActionBar() != null)
getActivity().getSupportActionBar().show();
if(registry == null) registry = new RegistryStorageComponent(this);
if(map == null) map = new MapComponent(this);
if(ui == null) {
ui = new UIComponent(this, map);
ui.swapScreen(DefinedScreen.MAIN); //Initial
}
}
}
@@ -1,24 +0,0 @@
package eu.konggdev.strikemaps.app;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import eu.konggdev.strikemaps.Component;
import java.util.ArrayList;
import java.util.List;
public abstract class ComponentHolderActivity extends AppCompatActivity {
private List<Component> components = new ArrayList<>();
public final <T extends Component> T getComponent(Class<T> type) {
return components.stream()
.filter(type::isInstance)
.findFirst()
.map(type::cast)
.orElse(null);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
@@ -1,4 +1,4 @@
package eu.konggdev.strikemaps.util.json; package eu.konggdev.strikemaps.app.util;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -0,0 +1,101 @@
package eu.konggdev.strikemaps.helper;
import android.content.res.AssetManager;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import eu.konggdev.strikemaps.app.AppController;
//FIXME: Ugly
public final class FileHelper {
public static Bitmap getIcon(String iconLocator, AppController app) {
switch (iconLocator.split("//")[0]) {
//TODO: https
case "assets:":
return BitmapFactory.decodeStream(FileHelper.openAssetStream("bundled/icon/" + iconLocator.split("//")[1], app));
default:
app.logcat("Unimplemented icon locator space: " + iconLocator);
return null;
}
}
public static String loadStringFromAssetFile(String filePath, AppController app) {
try (InputStream is = app.getActivity().getAssets().open(filePath)) {
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
return new String(buffer, StandardCharsets.UTF_8);
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
public static void writeUserFile(String path, String fileName, String content, AppController app) throws IOException {
try {
File userDirectory = new File(app.getActivity().getExternalFilesDir(null), path);
if (!userDirectory.exists() && !userDirectory.mkdirs()) {
app.logcat("Failed to create directory: " + userDirectory.getAbsolutePath());
return;
}
File file = new File(userDirectory, fileName);
try (FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
writer.write(content);
writer.flush();
}
} catch (IOException e) {
throw e;
}
}
public static String[] getAssetFiles(String path, String fileExt, AppController app) {
AssetManager assetManager = app.getActivity().getAssets();
try {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
String fullPath = (path == null || path.isEmpty()) ? "" : path;
String[] files = assetManager.list(fullPath);
if (files == null) return new String[0];
if (fileExt == null || fileExt.isEmpty())
return files;
List<String> filtered = new ArrayList<>();
for (String file : files) {
if (file.toLowerCase().endsWith(fileExt.toLowerCase())) {
filtered.add((fullPath.isEmpty() ? "" : fullPath + "/") + file);
}
}
return filtered.toArray(new String[0]);
} catch (IOException e) {
e.printStackTrace();
return new String[0];
}
}
public static InputStream openAssetStream(String path, AppController app) {
try {
return app.getActivity().getAssets().open(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -3,13 +3,12 @@ package eu.konggdev.strikemaps.helper;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.source.MapSource; import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.source.tiles.SourceTiles; import eu.konggdev.strikemaps.map.source.tiles.SourceTiles;
import eu.konggdev.strikemaps.map.style.MapStyle; import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata; import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import eu.konggdev.strikemaps.map.style.options.StyleOptions; import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.util.file.FileTools;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@@ -33,11 +32,11 @@ public final class UserPrefsHelper {
private static final boolean DEFAULT_PERSIST_LOCATION_ENABLED = true; private static final boolean DEFAULT_PERSIST_LOCATION_ENABLED = true;
private static final boolean DEFAULT_LAST_LOCATION_ENABLED = false; private static final boolean DEFAULT_LAST_LOCATION_ENABLED = false;
public static Map<Integer, MapStyle> DEFAULT_STYLES(ComponentHolderActivity app) { public static Map<Integer, MapStyle> DEFAULT_STYLES(AppController app) {
Map<Integer, MapStyle> styles = new HashMap<>(); Map<Integer, MapStyle> styles = new HashMap<>();
String[] styleAssets = FileTools.getAssetFiles("bundled/style", ".style.json", app); String[] styleAssets = FileHelper.getAssetFiles("bundled/style", ".style.json", app);
for (int i = 0; i < styleAssets.length; i++) { for (int i = 0; i < styleAssets.length; i++) {
String styleContents = FileTools.loadStringFromAssetFile(styleAssets[i], app); String styleContents = FileHelper.loadStringFromAssetFile(styleAssets[i], app);
styles.put( i, styles.put( i,
new MapStyle( new MapStyle(
styleContents, styleContents,
@@ -93,7 +92,7 @@ public final class UserPrefsHelper {
return prefs.edit().putBoolean(KEY_LAST_LOCATION_ENABLED, status).commit(); return prefs.edit().putBoolean(KEY_LAST_LOCATION_ENABLED, status).commit();
} }
public static Map<Integer, MapStyle> styles(SharedPreferences prefs, ComponentHolderActivity app) { public static Map<Integer, MapStyle> styles(SharedPreferences prefs, AppController app) {
String json = prefs.getString(KEY_STYLES, null); String json = prefs.getString(KEY_STYLES, null);
if (json == null) return DEFAULT_STYLES(app); if (json == null) return DEFAULT_STYLES(app);
Type type = new TypeToken<Map<Integer, MapStyle.StoredRepresentation>>() {}.getType(); Type type = new TypeToken<Map<Integer, MapStyle.StoredRepresentation>>() {}.getType();
@@ -2,60 +2,45 @@ package eu.konggdev.strikemaps.map;
import java.util.*; import java.util.*;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import eu.konggdev.strikemaps.Component; import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreGLJSRenderer; import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreGLJSRenderer;
import eu.konggdev.strikemaps.map.style.document.StyleDocument; 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.factory.AlertDialogFactory;
import eu.konggdev.strikemaps.helper.UserPrefsHelper; import eu.konggdev.strikemaps.helper.UserPrefsHelper;
import eu.konggdev.strikemaps.map.renderer.implementation.VtmRenderer; import eu.konggdev.strikemaps.map.renderer.implementation.VtmRenderer;
import org.maplibre.android.geometry.LatLng; import org.maplibre.android.geometry.LatLng;
import org.maplibre.geojson.Feature; import org.maplibre.geojson.Feature;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreNativeRenderer; import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreNativeRenderer;
import eu.konggdev.strikemaps.map.renderer.MapRenderer; import eu.konggdev.strikemaps.map.renderer.MapRenderer;
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentMap; import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentMap;
public class MapComponent implements Component { public class MapComponent implements Component {
private final String TAG = "MapComponent";
private final MapRenderer mapRenderer; private final MapRenderer mapRenderer;
private final AppController app;
private final ComponentHolderActivity activity;
private final RegistryStorageComponent registry;
private final SharedPreferences userPrefs;
//Current style
public Integer styleId; public Integer styleId;
public Map<Class<? extends MapOverlay>, MapOverlay> overlays = new HashMap<>(); public Map<Class<? extends MapOverlay>, MapOverlay> overlays = new HashMap<>();
public MapComponent(ComponentHolderActivity activity, RegistryStorageComponent registry, SharedPreferences userPrefs) { public MapComponent(AppController ref) {
this.activity = activity; this.app = ref;
this.registry = registry; switch(UserPrefsHelper.mapRenderer(app.getPrefs())) {
this.userPrefs = userPrefs;
switch(UserPrefsHelper.mapRenderer(userPrefs)) {
case 0: case 0:
this.mapRenderer = new MapLibreGLJSRenderer(activity, this); this.mapRenderer = new MapLibreGLJSRenderer(app, this);
break; break;
case 1: case 1:
this.mapRenderer = new MapLibreNativeRenderer(activity, this); this.mapRenderer = new MapLibreNativeRenderer(app, this);
break; break;
case 2: case 2:
this.mapRenderer = new VtmRenderer(activity, this); this.mapRenderer = new VtmRenderer(app, this);
break; break;
default: //This shouldn't happen default: //This shouldn't happen
Toast.makeText(activity, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS", Toast.LENGTH_SHORT).show(); Toast.makeText(app.getActivity(), "Invalid renderer value in preferences\nFalling back to MapLibre GL JS", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS"); this.mapRenderer = new MapLibreGLJSRenderer(app, this);
this.mapRenderer = new MapLibreGLJSRenderer(activity, this);
break; break;
}; };
} }
@@ -66,14 +51,6 @@ public class MapComponent implements Component {
public void setStyle(Integer id) { public void setStyle(Integer id) {
styleId = id; styleId = id;
//Pass to renderer
StyleDocument document = registry.getStyle(styleId)
.effectiveDocument(registry);
if (document == null) {
Log.e(TAG, "Received null style from registry");
return;
}
mapRenderer.styleUpdate(document);
} }
public void switchOverlay(MapOverlay overlay) { public void switchOverlay(MapOverlay overlay) {
@@ -110,12 +87,10 @@ public class MapComponent implements Component {
selectPoint(features.get(0)); selectPoint(features.get(0));
break; break;
default: default:
UIComponent ui = activity.getComponent(UIComponent.class); app.getUi().alert(
if (ui != null) { AlertDialogFactory.pointSelector(app, features, selectedItem -> {
ui.alert( selectPoint(selectedItem);
AlertDialogFactory.pointSelector(activity, ui, features, this::selectPoint) }));
);
}
} }
return true; return true;
} }
@@ -127,7 +102,7 @@ public class MapComponent implements Component {
public void onMapInit() { public void onMapInit() {
setStyle( setStyle(
UserPrefsHelper.startupMapStyle(userPrefs) UserPrefsHelper.startupMapStyle(app.getPrefs())
); );
} }
} }
@@ -1,12 +1,10 @@
package eu.konggdev.strikemaps.map.offline; package eu.konggdev.strikemaps.map.offline;
import okhttp3.*;
import java.io.IOException; import java.io.IOException;
public final class OfflineTileResolver { public final class OfflineTileResolver {
public byte[] resolve(String url) throws IOException {
public static byte[] resolve(String url) throws IOException { //byte[] data = getOfflineTile();
//TODO
return null; return null;
} }
} }
@@ -3,9 +3,8 @@ package eu.konggdev.strikemaps.map.overlay.implementation;
import android.location.Location; import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
@@ -17,13 +16,15 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
public class LocationOverlay implements MapOverlay, LocationListener { public class LocationOverlay implements MapOverlay, LocationListener {
LocationDataProvider locationDataProvider; LocationDataProvider locationDataProvider;
AppController app;
MapComponent map; MapComponent map;
public Location currentLocation = null; public Location currentLocation = null;
public LocationOverlay(MapComponent map, AppCompatActivity activity) { public LocationOverlay(AppController app) {
this.map = map; this.app = app;
this.locationDataProvider = new LocationDataProvider(activity, this); this.map = app.getMap();
this.locationDataProvider = new LocationDataProvider(app.getActivity(), this);
} }
@Override @Override
@@ -1,12 +1,12 @@
package eu.konggdev.strikemaps.map.overlay.implementation; package eu.konggdev.strikemaps.map.overlay.implementation;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
public class PointSelectionOverlay implements MapOverlay { public class PointSelectionOverlay implements MapOverlay {
ComponentHolderActivity app; AppController app;
MapComponent map; MapComponent map;
@Override @Override
public JsonNode makePatch() { public JsonNode makePatch() {
@@ -1,20 +1,19 @@
package eu.konggdev.strikemaps.map.renderer.implementation; package eu.konggdev.strikemaps.map.renderer.implementation;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.webkit.WebChromeClient; import android.webkit.WebChromeClient;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.appcompat.app.AppCompatActivity; import androidx.annotation.NonNull;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.util.json.JsonPatcher; import eu.konggdev.strikemaps.app.util.JsonPatcher;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer; import eu.konggdev.strikemaps.map.renderer.MapRenderer;
@@ -28,20 +27,19 @@ import java.util.List;
//Stub for now //Stub for now
public class MapLibreGLJSRenderer implements MapRenderer { public class MapLibreGLJSRenderer implements MapRenderer {
private final static String TAG = "MapLibreGLJSRenderer"; @NonNull AppController app;
private final AppCompatActivity activity;
private final MapComponent controller; @NonNull MapComponent controller;
final WebView webView; final WebView webView;
private JsonNode origin; private JsonNode origin;
@SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"}) @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
public MapLibreGLJSRenderer(ComponentHolderActivity activity, MapComponent controller) { public MapLibreGLJSRenderer(AppController app, MapComponent controller) {
this.activity = activity; this.app = app;
this.controller = controller; this.controller = controller;
webView = new WebView(activity); webView = new WebView(app.getActivity());
webView.setLayoutParams( webView.setLayoutParams(
new ViewGroup.LayoutParams( new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -88,7 +86,7 @@ public class MapLibreGLJSRenderer implements MapRenderer {
root.set("layers", layers); root.set("layers", layers);
this.origin = root; this.origin = root;
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to parse style: " + style.name); app.logcat("Failed to parse style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -98,7 +96,7 @@ public class MapLibreGLJSRenderer implements MapRenderer {
webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null); webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null);
webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to set style: " + style.name); app.logcat("Failed to set style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
@@ -129,7 +127,7 @@ public class MapLibreGLJSRenderer implements MapRenderer {
webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null); webView.evaluateJavascript("map.setStyle(" + mapped + ", { diff: false });", null);
webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible webView.evaluateJavascript("map.redraw()", null); //Force redraw to make the style change visible
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to patch overlay: " + overlay.toString()); app.logcat("Failed to patch overlay: " + overlay.toString());
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -1,17 +1,16 @@
package eu.konggdev.strikemaps.map.renderer.implementation; package eu.konggdev.strikemaps.map.renderer.implementation;
import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import eu.konggdev.strikemaps.util.json.JsonPatcher; 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.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer; import eu.konggdev.strikemaps.map.renderer.MapRenderer;
import eu.konggdev.strikemaps.map.style.document.StyleDocument; import eu.konggdev.strikemaps.map.style.document.StyleDocument;
@@ -22,26 +21,27 @@ import org.maplibre.android.maps.MapLibreMap;
import org.maplibre.android.maps.MapView; import org.maplibre.android.maps.MapView;
import org.maplibre.android.maps.OnMapReadyCallback; import org.maplibre.android.maps.OnMapReadyCallback;
import org.maplibre.android.maps.Style; 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 org.maplibre.geojson.Feature;
import java.util.List; import java.util.List;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback { public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
private final static String TAG = "MapLibreNativeRenderer"; @NonNull AppController app;
private final AppCompatActivity activity; @NonNull MapComponent controller;
private final MapComponent controller;
MapLibreMap map; MapLibreMap map;
final MapView mapView; final MapView mapView;
private JsonNode origin; private JsonNode origin;
public MapLibreNativeRenderer(ComponentHolderActivity activity, MapComponent controller) { public MapLibreNativeRenderer(AppController app, MapComponent controller) {
this.activity = activity; this.app = app;
this.controller = controller; this.controller = controller;
MapLibre.getInstance(activity); MapLibre.getInstance(app.getActivity());
this.mapView = new MapView(activity); this.mapView = new MapView(app.getActivity());
//TODO: Investigate if we might want to restore any savedInstanceState for MapLibre //TODO: Investigate if we might want to restore any savedInstanceState for MapLibre
mapView.onCreate(null); mapView.onCreate(null);
//We need this to get the onMapReady callback //We need this to get the onMapReady callback
@@ -75,7 +75,7 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
root.set("layers", layers); root.set("layers", layers);
this.origin = root; this.origin = root;
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to parse style: " + style.name); app.logcat("Failed to parse style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -83,7 +83,7 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
try { try {
map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(origin))); map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(origin)));
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to set style: " + style.name); app.logcat("Failed to set style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
@@ -115,7 +115,7 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(merged))); map.setStyle(new Style.Builder().fromJson(mapper.writeValueAsString(merged)));
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to patch overlay: " + overlay.toString()); app.logcat("Failed to patch overlay: " + overlay.toString());
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -1,7 +1,7 @@
package eu.konggdev.strikemaps.map.renderer.implementation; package eu.konggdev.strikemaps.map.renderer.implementation;
import android.view.View; import android.view.View;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer; import eu.konggdev.strikemaps.map.renderer.MapRenderer;
@@ -19,16 +19,16 @@ import java.util.List;
public class VtmRenderer implements MapRenderer { public class VtmRenderer implements MapRenderer {
ComponentHolderActivity activity; AppController app;
MapComponent controller; MapComponent controller;
Map map; Map map;
final MapView mapView; final MapView mapView;
public VtmRenderer(ComponentHolderActivity activity, MapComponent controller) { public VtmRenderer(AppController app, MapComponent controller) {
this.activity = activity; this.app = app;
this.controller = controller; this.controller = controller;
this.mapView = new MapView(activity); this.mapView = new MapView(app.getActivity());
this.map = mapView.map(); this.map = mapView.map();
} }
@@ -2,6 +2,7 @@ package eu.konggdev.strikemaps.map.style;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.style.document.StyleDocument; import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata; import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import eu.konggdev.strikemaps.map.style.options.StyleOptions; import eu.konggdev.strikemaps.map.style.options.StyleOptions;
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.source.MapSource; import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.style.options.StyleOptions; import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.map.style.source.StyleSource; import eu.konggdev.strikemaps.map.style.source.StyleSource;
@@ -70,6 +71,24 @@ public class StyleDocument {
if (effectiveSource != null) source.current = effectiveSource; if (effectiveSource != null) source.current = effectiveSource;
} }
for (JsonNode layer : result.layerDefinitions) {
JsonNode option = layer.get("option");
if (option == null)
continue;
if ("enable".equals(option.path("type").asText())) {
String id = layer.path("id").asText();
boolean enabled = options.getBoolean(
id,
option.path("default").asBoolean(true)
);
}
}
return result; return result;
} }
} }
@@ -1,32 +1,31 @@
package eu.konggdev.strikemaps.storage; package eu.konggdev.strikemaps.storage;
import android.content.SharedPreferences;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import eu.konggdev.strikemaps.Component; import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.source.MapSource; import eu.konggdev.strikemaps.map.source.MapSource;
import eu.konggdev.strikemaps.map.style.MapStyle; import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.helper.UserPrefsHelper; import eu.konggdev.strikemaps.helper.UserPrefsHelper;
import java.util.Map; import java.util.Map;
public class RegistryStorageComponent implements Component { import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
private final ComponentHolderActivity activity; import org.apache.commons.codec.digest.DigestUtils;
private final SharedPreferences userPrefs; public class RegistryStorageComponent implements Component {
private AppController app;
private Map<Integer, MapStyle> styles; private Map<Integer, MapStyle> styles;
private Map<Integer, MapSource> sources; private Map<Integer, MapSource> sources;
public RegistryStorageComponent(ComponentHolderActivity activity, SharedPreferences userPrefs) { public RegistryStorageComponent(AppController app) {
this.activity = activity; this.app = app;
this.userPrefs = userPrefs; styles();
initAll();
} }
private Map<Integer, MapSource> sources() { private Map<Integer, MapSource> sources() {
if (sources == null) sources = UserPrefsHelper.sources(userPrefs); if (sources == null) sources = UserPrefsHelper.sources(app.getPrefs());
return sources; return sources;
} }
@@ -39,7 +38,7 @@ public class RegistryStorageComponent implements Component {
} }
private Map<Integer, MapStyle> styles() { private Map<Integer, MapStyle> styles() {
if (styles == null) styles = UserPrefsHelper.styles(userPrefs, activity); if (styles == null) styles = UserPrefsHelper.styles(app.getPrefs(), app);
return styles; return styles;
} }
@@ -74,14 +73,10 @@ public class RegistryStorageComponent implements Component {
} }
private void save() { private void save() {
UserPrefsHelper.styles(userPrefs, styles); UserPrefsHelper.styles(app.getPrefs(), styles);
} }
public void checkForUpdates() { public void checkForUpdates() {
// //
} }
private void initAll() {
styles(); sources();
}
} }
@@ -1,14 +1,13 @@
package eu.konggdev.strikemaps.ui; package eu.konggdev.strikemaps.ui;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import eu.konggdev.strikemaps.Component; import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion; import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion;
import eu.konggdev.strikemaps.ui.element.region.UIRegion; import eu.konggdev.strikemaps.ui.element.region.UIRegion;
import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls; import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls;
@@ -16,44 +15,57 @@ import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutSearch;
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentOfflineMaps; import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentOfflineMaps;
import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings; import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings;
import eu.konggdev.strikemaps.ui.screen.Screen; import eu.konggdev.strikemaps.ui.screen.Screen;
import eu.konggdev.strikemaps.ui.screen.definition.DefinedScreen;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
public class UIComponent implements Component { public class UIComponent implements Component {
private final String TAG = "UIComponent"; @NonNull AppController app;
MapComponent map;
private final ComponentHolderActivity activity;
private final MapComponent map;
private final RegistryStorageComponent registry;
private final SharedPreferences userPrefs;
private final ArrayDeque<Screen> screenStack = new ArrayDeque<>(); private final ArrayDeque<Screen> screenStack = new ArrayDeque<>();
private Map<String, Screen> screens; public UIComponent(AppController app, MapComponent map) {
this.app = app;
public UIComponent(ComponentHolderActivity activity, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs) {
this.activity = activity;
this.map = map; this.map = map;
this.registry = registry;
this.userPrefs = userPrefs;
} }
public void defineScreens(Map<String, Screen> screens) { public Map<DefinedScreen, Screen> getScreens(MapComponent map) {
this.screens = screens; return Map.of(
//Main screen
DefinedScreen.MAIN, new Screen(
//App reference
app,
//Main screen init regions definition
Map.of(
R.id.mainContentView, new MainContentRegion(map.toFragment(), R.id.mainContentView),
R.id.bottomUi, new UIRegion(new FragmentLayoutControls(app, R.id.bottomUi), R.id.bottomUi),
R.id.topUi, new UIRegion(new FragmentLayoutSearch(app, R.id.topUi), R.id.topUi)
) //TODO: Probably stop referencing layout 3(!) times everytime
),
//Settings screen
DefinedScreen.SETTINGS, new Screen(
app,
//Just the settings content fragment
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentSettings(app), R.id.mainContentView)
)
),
//Offline maps screen
DefinedScreen.OFFLINE, new Screen(
app,
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentOfflineMaps(app), R.id.mainContentView)
)
)
);
} }
public void swapScreen(String screenKey) { public void swapScreen(DefinedScreen screenKey) {
if (screens == null) return;
Screen newScreen = screens.get(screenKey);
if (newScreen == null) {
Log.e(TAG, "Invalid screen " + screenKey + " invoked");
return;
}
if (!screenStack.isEmpty()) getCurrentScreen().detachAll(); if (!screenStack.isEmpty()) getCurrentScreen().detachAll();
screenStack.add(newScreen); screenStack.add(getScreens(map).get(screenKey));
getCurrentScreen().attachAll(); getCurrentScreen().attachAll();
} }
@@ -74,7 +86,11 @@ public class UIComponent implements Component {
dialog.show(); dialog.show();
} }
public <T> void alert(AlertDialog dialog, Consumer<T> callback) {
dialog.show();
}
public View inflateUi(int layout) { public View inflateUi(int layout) {
return activity.getLayoutInflater().inflate(layout, null); return app.getActivity().getLayoutInflater().inflate(layout, null);
} }
} }
@@ -5,70 +5,75 @@ import android.view.View;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity; import androidx.annotation.NonNull;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.helper.FileHelper;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.document.StyleDocument; import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.util.icon.IconResolver;
public class GenericItem implements UIItem { public class GenericItem implements UIItem {
public String name; @NonNull public String name;
public Bitmap image; public Bitmap image;
public Runnable onClick; public Runnable onClick;
public Runnable onLongClick; public Runnable onLongClick;
boolean hasImage; boolean hasImage;
public GenericItem(String name) { public GenericItem(String refName) {
this.name = name; this.name = refName;
hasImage = false; hasImage = false;
} }
public GenericItem(String refName, Runnable onClick) {
public GenericItem(String name, Runnable onClick) { this.name = refName;
this.name = name;
this.onClick = onClick; this.onClick = onClick;
hasImage = false; hasImage = false;
} }
public GenericItem(String refName, Runnable onClick, Runnable onLongClick) {
public GenericItem(String name, Runnable onClick, Runnable onLongClick) { this.name = refName;
this.name = name;
this.onClick = onClick; this.onClick = onClick;
this.onLongClick = onLongClick; this.onLongClick = onLongClick;
hasImage = false; hasImage = false;
} }
public GenericItem(String refName, Bitmap refImage) {
public GenericItem(String name, Bitmap Image) { this.name = refName;
this.name = name; this.image = refImage;
this.image = Image;
hasImage = true; hasImage = true;
} }
public GenericItem(String refName, Bitmap refImage, Runnable onClick) {
public GenericItem(String name, Bitmap Image, Runnable onClick) { this.name = refName;
this.name = name; this.image = refImage;
this.image = Image;
this.onClick = onClick; this.onClick = onClick;
hasImage = true; hasImage = true;
} }
public GenericItem(String name, Bitmap Image, Runnable onClick, Runnable onLongClick) { public GenericItem(String refName, Bitmap refImage, Runnable onClick, Runnable onLongClick) {
this.name = name; this.name = refName;
this.image = Image; this.image = refImage;
this.onClick = onClick; this.onClick = onClick;
this.onLongClick = onLongClick; this.onLongClick = onLongClick;
hasImage = true; hasImage = true;
} }
public GenericItem(StyleDocument style, Runnable onClick, AppCompatActivity activity) { public GenericItem(StyleDocument style, AppController app, Runnable onClick) {
if (style == null) return; if (style == null) {
this.name = "Unknown";
return;
}
this.name = style.name; this.name = style.name;
this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null; this.image = style.icon != null ? FileHelper.getIcon(style.icon, app) : null;
this.onClick = onClick; this.onClick = onClick;
} }
public GenericItem(StyleDocument style, Runnable onClick, Runnable onLongClick, AppCompatActivity activity) { public GenericItem(StyleDocument style, AppController app, Runnable onClick, Runnable onLongClick) {
if (style == null) return; if (style == null) {
this.name = "Unknown";
return;
}
this.name = style.name; this.name = style.name;
this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null; this.image = style.icon != null ? FileHelper.getIcon(style.icon, app) : null;
this.onClick = onClick; this.onClick = onClick;
this.onLongClick = onLongClick; this.onLongClick = onLongClick;
} }
@@ -8,13 +8,11 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.view.View; import android.view.View;
import android.widget.*; import android.widget.*;
import androidx.appcompat.app.AppCompatActivity;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent; import eu.konggdev.strikemaps.app.util.JsonPatcher;
import eu.konggdev.strikemaps.util.json.JsonPatcher;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle; import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata; import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
@@ -29,7 +27,10 @@ import java.util.function.Consumer;
//FIXME: Cleaner architecture would be having a class for each AlertDialog type //FIXME: Cleaner architecture would be having a class for each AlertDialog type
public final class AlertDialogFactory { public final class AlertDialogFactory {
public static AlertDialog styleManagementOptions(AppCompatActivity activity, StyleManagementMetadata metadata) { public static AlertDialog styleManagementOptions(
AppController app,
StyleManagementMetadata metadata
) {
String[] options = { String[] options = {
"Update style", "Update style",
"Update automatically" "Update automatically"
@@ -40,7 +41,7 @@ public final class AlertDialogFactory {
metadata.autoUpdate metadata.autoUpdate
}; };
return new AlertDialog.Builder(activity) return new AlertDialog.Builder(app.getActivity())
.setTitle("Built-in Style") .setTitle("Built-in Style")
.setMultiChoiceItems(options, checked, (dialog, which, isChecked) -> { .setMultiChoiceItems(options, checked, (dialog, which, isChecked) -> {
if (which == 0) { if (which == 0) {
@@ -54,16 +55,16 @@ public final class AlertDialogFactory {
.create(); .create();
} }
public static AlertDialog copyBuiltInStyle(AppCompatActivity activity, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) { public static AlertDialog copyBuiltInStyle(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) {
//TODO: Use an UI element that's supposed to be vertical, instead of GenericItem //TODO: Use an UI element that's supposed to be vertical, instead of GenericItem
LinearLayout container = new LinearLayout(activity); LinearLayout container = new LinearLayout(app.getActivity());
container.setOrientation(LinearLayout.VERTICAL); container.setOrientation(LinearLayout.VERTICAL);
ScrollView scrollView = new ScrollView(activity); ScrollView scrollView = new ScrollView(app.getActivity());
scrollView.addView(container); scrollView.addView(container);
AlertDialog dialog = new AlertDialog.Builder(activity) AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
.setTitle("Copy from") .setTitle("Copy from")
.setView(scrollView) .setView(scrollView)
.setNegativeButton("Cancel", null) .setNegativeButton("Cancel", null)
@@ -71,20 +72,19 @@ public final class AlertDialogFactory {
return dialog; return dialog;
} }
public static AlertDialog createStyle(AppController app, String baseStyleContents, FragmentMapChangePopup mapChangePopup) {
public static AlertDialog createStyle(AppCompatActivity activity, RegistryStorageComponent registry, String baseStyleContents, FragmentMapChangePopup mapChangePopup) { final EditText nameInput = new EditText(app.getActivity());
final EditText nameInput = new EditText(activity);
nameInput.setHint("Name"); nameInput.setHint("Name");
LinearLayout container = new LinearLayout(activity); LinearLayout container = new LinearLayout(app.getActivity());
container.setOrientation(LinearLayout.VERTICAL); container.setOrientation(LinearLayout.VERTICAL);
int padding = (int) (20 * activity.getResources().getDisplayMetrics().density); int padding = (int) (20 * app.getActivity().getResources().getDisplayMetrics().density);
container.setPadding(padding, padding, padding, 0); container.setPadding(padding, padding, padding, 0);
container.addView(nameInput); container.addView(nameInput);
AlertDialog dialog = new AlertDialog.Builder(activity) AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
.setTitle("Create") .setTitle("Create")
.setView(container) .setView(container)
.setPositiveButton("Create", null) .setPositiveButton("Create", null)
@@ -95,12 +95,12 @@ public final class AlertDialogFactory {
Button createButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); Button createButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
createButton.setOnClickListener(v -> { createButton.setOnClickListener(v -> {
ObjectMapper mactivityer = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
boolean nameEntryRequired = true; boolean nameEntryRequired = true;
String styleContentName = ""; String styleContentName = "";
if (baseStyleContents != null) { if (baseStyleContents != null) {
try { try {
JsonNode root = mactivityer.readTree(baseStyleContents); JsonNode root = mapper.readTree(baseStyleContents);
if (!root.path("name").asText().isEmpty()) { if (!root.path("name").asText().isEmpty()) {
nameEntryRequired = false; //We can take the name from the style nameEntryRequired = false; //We can take the name from the style
styleContentName = root.path("name").asText(); styleContentName = root.path("name").asText();
@@ -125,28 +125,28 @@ public final class AlertDialogFactory {
JsonNode root; JsonNode root;
if(baseStyleContents != null) { if(baseStyleContents != null) {
if(!baseStyleContents.isEmpty()) { if(!baseStyleContents.isEmpty()) {
root = mactivityer.readTree(baseStyleContents); root = mapper.readTree(baseStyleContents);
} else { } else {
root = mactivityer.createObjectNode(); root = mapper.createObjectNode();
} }
} else { } else {
root = mactivityer.createObjectNode(); root = mapper.createObjectNode();
} }
if (!root.path("name").asText().isEmpty()) { if (!root.path("name").asText().isEmpty()) {
ObjectNode node = mactivityer.createObjectNode(); ObjectNode node = mapper.createObjectNode();
node.put("name", name); node.put("name", name);
root = JsonPatcher.patch(root, node); root = JsonPatcher.patch(root, node);
} }
registry.addStyle(new MapStyle( app.getRegistry().addStyle(new MapStyle(
mactivityer.writeValueAsString(root), mapper.writeValueAsString(root),
new StyleOptions(), new StyleOptions(),
null null
)); ));
dialog.dismiss(); dialog.dismiss();
} catch (Exception e) { } catch (Exception e) {
Toast.makeText(activity, "Failed to create", Toast.LENGTH_SHORT).show(); Toast.makeText(app.getActivity(), "Failed to create", Toast.LENGTH_SHORT).show();
e.printStackTrace(); e.printStackTrace();
} }
@@ -157,20 +157,20 @@ public final class AlertDialogFactory {
return dialog; return dialog;
} }
public static AlertDialog pointSelector(ComponentHolderActivity activity, UIComponent ui, List<Feature> features, Consumer<Feature> callback) { public static AlertDialog pointSelector(AppController app, List<Feature> features, Consumer<Feature> callback) {
LinearLayout layout = new LinearLayout(activity); LinearLayout layout = new LinearLayout(app.getActivity());
layout.setOrientation(LinearLayout.VERTICAL); layout.setOrientation(LinearLayout.VERTICAL);
ScrollView scrollView = new ScrollView(activity); ScrollView scrollView = new ScrollView(app.getActivity());
scrollView.addView(layout); scrollView.addView(layout);
AlertDialog dialog = new AlertDialog.Builder(activity) AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
.setView(scrollView) .setView(scrollView)
.create(); .create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#000000"))); dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#000000")));
for (Feature feature : features) { for (Feature feature : features) {
View itemView = PreviewItem.fromFeature(feature).makeView(ui, v -> { View itemView = PreviewItem.fromFeature(feature).makeView(app.getUi(), v -> {
dialog.dismiss(); dialog.dismiss();
new Handler(Looper.getMainLooper()) new Handler(Looper.getMainLooper())
.post(() -> callback.accept(feature)); .post(() -> callback.accept(feature));
@@ -181,30 +181,30 @@ public final class AlertDialogFactory {
return dialog; return dialog;
} }
public static AlertDialog searchSettings(AppCompatActivity activity) { public static AlertDialog searchSettings(AppController app) {
return new AlertDialog.Builder(activity) return new AlertDialog.Builder(app.getActivity())
.setTitle("Configure Search") .setTitle("Configure Search")
.setPositiveButton("OK", null) .setPositiveButton("OK", null)
.create(); .create();
} }
public static AlertDialog restartDialog(AppCompatActivity activity) { public static AlertDialog restartDialog(AppController app) {
return new AlertDialog.Builder(activity) return new AlertDialog.Builder(app.getActivity())
.setTitle("Restart required") .setTitle("Restart required")
.setMessage("Restart the activity to activityly changes.") .setMessage("Restart the app to apply changes.")
.setCancelable(false) .setCancelable(false)
.setNegativeButton("Cancel", (d, w) -> { .setNegativeButton("Cancel", (d, w) -> {
Toast.makeText(activity, Toast.makeText(app.getActivity(),
"Changes will be activitylied on next restart", "Changes will be applied on next restart",
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
d.dismiss(); d.dismiss();
}) })
.setPositiveButton("Restart", (d, w) -> { .setPositiveButton("Restart", (d, w) -> {
Intent i = activity.getPackageManager() Intent i = app.getActivity().getPackageManager()
.getLaunchIntentForPackage(activity.getPackageName()); .getLaunchIntentForPackage(app.getActivity().getPackageName());
if (i != null) { if (i != null) {
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i); app.getActivity().startActivity(i);
} }
Runtime.getRuntime().exit(0); Runtime.getRuntime().exit(0);
}) })
@@ -14,15 +14,13 @@ import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle; import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.map.style.options.StyleOptions; import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory; import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup; import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
@@ -32,15 +30,11 @@ import java.io.*;
public class NewStyleBottomSheet extends BottomSheetDialogFragment { public class NewStyleBottomSheet extends BottomSheetDialogFragment {
private final String styleBase = "{\"name\":\"None\"}"; private final String styleBase = "{\"name\":\"None\"}";
private AppCompatActivity activity; @NonNull AppController app;
@NonNull MapComponent map;
private MapComponent map; @NonNull UIComponent ui;
@NonNull
private UIComponent ui; FragmentMapChangePopup mapChangePopup;
private RegistryStorageComponent registry;
private FragmentMapChangePopup mapChangePopup;
private final ActivityResultLauncher<Intent> importLauncher = private final ActivityResultLauncher<Intent> importLauncher =
registerForActivityResult( registerForActivityResult(
@@ -78,16 +72,15 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
String content = contentBuilder.toString(); String content = contentBuilder.toString();
if (fileName != null && !fileName.endsWith(".style.json")) { if (fileName != null && !fileName.endsWith(".style.json")) {
ui.alert( app.getUi().alert(
AlertDialogFactory.createStyle( AlertDialogFactory.createStyle(
activity, app,
registry,
content, content,
mapChangePopup mapChangePopup
) )
); );
} else { } else {
registry.addStyle( app.getRegistry().addStyle(
new MapStyle( new MapStyle(
content, content,
new StyleOptions(), new StyleOptions(),
@@ -115,11 +108,10 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
importLauncher.launch(intent); importLauncher.launch(intent);
} }
public NewStyleBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup) { public NewStyleBottomSheet(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) {
this.activity = activity; this.app = app;
this.map = map; this.map = map;
this.ui = ui; this.ui = ui;
this.registry = registry;
this.mapChangePopup = mapChangePopup; this.mapChangePopup = mapChangePopup;
} }
@@ -134,7 +126,7 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
MaterialCardView emptyBtn = view.findViewById(R.id.buttonCreateEmpty); MaterialCardView emptyBtn = view.findViewById(R.id.buttonCreateEmpty);
builtInBtn.setOnClickListener(v -> { builtInBtn.setOnClickListener(v -> {
ui.alert(AlertDialogFactory.copyBuiltInStyle(activity, map, ui, mapChangePopup)); app.getUi().alert(AlertDialogFactory.copyBuiltInStyle(app, map, ui, mapChangePopup));
}); });
fileBtn.setOnClickListener(v -> { fileBtn.setOnClickListener(v -> {
@@ -142,7 +134,7 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
}); });
emptyBtn.setOnClickListener(v -> { emptyBtn.setOnClickListener(v -> {
ui.alert(AlertDialogFactory.createStyle(activity, registry, styleBase, mapChangePopup)); app.getUi().alert(AlertDialogFactory.createStyle(app, styleBase, mapChangePopup));
}); });
return view; return view;
@@ -14,11 +14,10 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts; import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle; import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent; import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
@@ -30,15 +29,16 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class StyleDetailsBottomSheet extends BottomSheetDialogFragment { public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
private final AppCompatActivity activity; @NonNull
AppController app;
private final MapComponent map; @NonNull
MapComponent map;
private final UIComponent ui; @NonNull
UIComponent ui;
private final RegistryStorageComponent registry; @NonNull
RegistryStorageComponent registry;
private final FragmentMapChangePopup mapChangePopup; @NonNull
final FragmentMapChangePopup mapChangePopup;
private final Integer styleId; private final Integer styleId;
@@ -58,11 +58,11 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
exportLauncher.launch(intent); exportLauncher.launch(intent);
} }
public StyleDetailsBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup, Integer styleId) { public StyleDetailsBottomSheet(AppController app, FragmentMapChangePopup mapChangePopup, Integer styleId) {
this.activity = activity; this.app = app;
this.map = map; this.map = app.getMap();
this.ui = ui; this.ui = app.getUi();
this.registry = registry; this.registry = app.getRegistry();
this.mapChangePopup = mapChangePopup; this.mapChangePopup = mapChangePopup;
this.styleId = styleId; this.styleId = styleId;
} }
@@ -118,7 +118,7 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
managedStyleIndicator.setVisibility(View.VISIBLE); managedStyleIndicator.setVisibility(View.VISIBLE);
styleManagementInfo.setOnClickListener(v -> styleManagementInfo.setOnClickListener(v ->
ui.alert( ui.alert(
AlertDialogFactory.styleManagementOptions(activity, style.managementMetadata) AlertDialogFactory.styleManagementOptions(app, style.managementMetadata)
) )
); );
@@ -127,7 +127,7 @@ public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
} }
editButtonLayout.setOnClickListener(v -> Toast.makeText(requireContext(), "Editor not implemented yet\nWait for release", Toast.LENGTH_SHORT).show()); editButtonLayout.setOnClickListener(v -> Toast.makeText(requireContext(), "Editor not implemented yet\nWait for release", Toast.LENGTH_SHORT).show());
copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(activity, registry, style.json, mapChangePopup))); copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(app, style.json, mapChangePopup)));
exportButtonLayout.setOnClickListener(v -> showExportDialog()); exportButtonLayout.setOnClickListener(v -> showExportDialog());
deleteButtonLayout.setOnClickListener(v -> deleteStyle()); deleteButtonLayout.setOnClickListener(v -> deleteStyle());
@@ -2,42 +2,31 @@ package eu.konggdev.strikemaps.ui.fragment.layout;
import android.Manifest; import android.Manifest;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Color; import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.helper.UserPrefsHelper; import eu.konggdev.strikemaps.helper.UserPrefsHelper;
import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.overlay.implementation.LocationOverlay; import eu.konggdev.strikemaps.map.overlay.implementation.LocationOverlay;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup; import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
public class FragmentLayoutControls extends Fragment implements Layout { public class FragmentLayoutControls extends Fragment implements Layout {
private final AppCompatActivity activity; AppController app;
private final UIComponent ui;
private final MapComponent map;
private final RegistryStorageComponent registry;
private final SharedPreferences userPrefs;
View rootView; View rootView;
private final Integer region; private final Integer region;
// Action definitions
//*//
public void notImplemented() { //Should never be called in release public void notImplemented() { //Should never be called in release
Toast.makeText(requireContext(), "Not implemented yet\nWait for release", Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), "Not implemented yet\nWait for release", Toast.LENGTH_SHORT).show();
} }
@@ -46,32 +35,29 @@ public class FragmentLayoutControls extends Fragment implements Layout {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else { } else {
map.switchOverlay(new LocationOverlay(map, activity)); app.getMap().switchOverlay(new LocationOverlay(app));
setupView(); setupView();
} }
} }
public void zoomToLocation() { public void zoomToLocation() {
if(map.hasOverlay(LocationOverlay.class)) { if(!app.getMap().hasOverlay(LocationOverlay.class)) {
Toast.makeText(requireContext(), "Hold to enable location", Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), "Hold to enable location", Toast.LENGTH_SHORT).show();
return; return;
} }
} }
public void attributtionDialog() { public void attributtionDialog() {
AlertDialog dialog = new AlertDialog.Builder(activity) AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
.setTitle(activity.getString(R.string.attribution_title)) .setTitle(app.getActivity().getString(R.string.attribution_title))
.setMessage(activity.getString(R.string.shipped_attribution)) .setMessage(app.getActivity().getString(R.string.shipped_attribution))
.setPositiveButton("OK", null).show(); .setPositiveButton("OK", null).show();
} }
//*//
public FragmentLayoutControls(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs, Integer region) { public FragmentLayoutControls(AppController app, Integer region) {
super(R.layout.fragment_controls); super(R.layout.fragment_controls);
this.activity = activity; this.app = app;
this.ui = ui;
this.map = map;
this.registry = registry;
this.userPrefs = userPrefs;
this.region = region; this.region = region;
} }
@@ -92,7 +78,7 @@ public class FragmentLayoutControls extends Fragment implements Layout {
/* Restores location enabled status from user prefs, /* Restores location enabled status from user prefs,
TODO: Should be moved out of UI code in the future */ TODO: Should be moved out of UI code in the future */
if(UserPrefsHelper.persistLocationEnabled(userPrefs) && UserPrefsHelper.lastLocationEnabled(userPrefs) && !map.hasOverlay(LocationOverlay.class)) if(UserPrefsHelper.persistLocationEnabled(app.getPrefs()) && UserPrefsHelper.lastLocationEnabled(app.getPrefs()) && !app.getMap().hasOverlay(LocationOverlay.class))
toggleLocationService(); toggleLocationService();
this.setupView(); this.setupView();
@@ -100,7 +86,7 @@ public class FragmentLayoutControls extends Fragment implements Layout {
public void setupView() { public void setupView() {
if (rootView == null) return; if (rootView == null) return;
setupButton(rootView, R.id.layersButton, click(() -> ui.getCurrentScreen().open(new FragmentMapChangePopup(activity, ui, map, registry, R.id.bottomUi)))); setupButton(rootView, R.id.layersButton, click(() -> app.getUi().getCurrentScreen().open(new FragmentMapChangePopup(app, R.id.bottomUi))));
setupButton(rootView, R.id.attributionButton, click(this::attributtionDialog)); setupButton(rootView, R.id.attributionButton, click(this::attributtionDialog));
setupButton(rootView, R.id.locationButton, click(this::zoomToLocation), longClick(this::toggleLocationService)); setupButton(rootView, R.id.locationButton, click(this::zoomToLocation), longClick(this::toggleLocationService));
@@ -111,14 +97,14 @@ public class FragmentLayoutControls extends Fragment implements Layout {
setupButton(rootView, R.id.modeButton, click(this::notImplemented)); setupButton(rootView, R.id.modeButton, click(this::notImplemented));
TextView locationServiceStatusIndicator = rootView.findViewById(R.id.locationServiceStatusIndicator); TextView locationServiceStatusIndicator = rootView.findViewById(R.id.locationServiceStatusIndicator);
if (map.hasOverlay(LocationOverlay.class)) { if (app.getMap().hasOverlay(LocationOverlay.class)) {
locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#00FF00")); //green locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#00FF00")); //green
} else { } else {
locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#FB0303")); //red locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#FB0303")); //red
} }
if(UserPrefsHelper.persistLocationEnabled(userPrefs)) if(UserPrefsHelper.persistLocationEnabled(app.getPrefs()))
UserPrefsHelper.lastLocationEnabled(userPrefs, map.hasOverlay(LocationOverlay.class)); UserPrefsHelper.lastLocationEnabled(app.getPrefs(), app.getMap().hasOverlay(LocationOverlay.class));
} }
@Override @Override
@@ -8,21 +8,20 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory; import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
import eu.konggdev.strikemaps.ui.screen.definition.DefinedScreen;
public class FragmentLayoutSearch extends Fragment implements Layout { public class FragmentLayoutSearch extends Fragment implements Layout {
private final AppCompatActivity activity; AppController app;
private final UIComponent ui;
private final Integer region; private final Integer region;
public FragmentLayoutSearch(AppCompatActivity activity, UIComponent ui, Integer region) { public FragmentLayoutSearch(AppController app, Integer region) {
super(R.layout.fragment_search); super(R.layout.fragment_search);
this.activity = activity; this.app = app;
this.ui = ui;
this.region = region; this.region = region;
} }
@@ -56,12 +55,12 @@ public class FragmentLayoutSearch extends Fragment implements Layout {
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
setupButton(menuView, R.id.menuSearchSettings, click(() -> { setupButton(menuView, R.id.menuSearchSettings, click(() -> {
ui.alert(AlertDialogFactory.searchSettings(activity)); app.getUi().alert(AlertDialogFactory.searchSettings(app));
})); }));
setupButton(menuView, R.id.menuSettings, click(() -> { setupButton(menuView, R.id.menuSettings, click(() -> {
popupWindow.dismiss(); popupWindow.dismiss();
ui.swapScreen("settings"); app.getUi().swapScreen(DefinedScreen.SETTINGS);
})); }));
menuView.findViewById(R.id.menuSearchSettings).setOnClickListener(v -> popupWindow.dismiss()); menuView.findViewById(R.id.menuSearchSettings).setOnClickListener(v -> popupWindow.dismiss());
@@ -5,14 +5,14 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout { public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout {
private final ComponentHolderActivity activity; @NonNull AppController app;
public FragmentLayoutContentOfflineMaps(ComponentHolderActivity activity) { public FragmentLayoutContentOfflineMaps(AppController app) {
super(R.layout.fragment_offline_maps); super(R.layout.fragment_offline_maps);
this.activity = activity; this.app = app;
} }
@Override @Override
@@ -27,6 +27,6 @@ public class FragmentLayoutContentOfflineMaps extends Fragment implements MainCo
// LinearLayout sourcesLayout = view.findViewById(R.id.llDownloadContainer); // LinearLayout sourcesLayout = view.findViewById(R.id.llDownloadContainer);
// for (MapSource source : sources) // for (MapSource source : sources)
// sourcesLayout.addView(new InlineItem(source.name, () -> Toast.makeText(activity.getActivity(), "Work in progress", Toast.LENGTH_SHORT).show()).makeView(app.getUi())); // sourcesLayout.addView(new InlineItem(source.name, () -> Toast.makeText(app.getActivity(), "Work in progress", Toast.LENGTH_SHORT).show()).makeView(app.getUi()));
} }
} }
@@ -1,6 +1,5 @@
package eu.konggdev.strikemaps.ui.fragment.layout.content.main; package eu.konggdev.strikemaps.ui.fragment.layout.content.main;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
@@ -8,26 +7,21 @@ import android.widget.Spinner;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.helper.UserPrefsHelper; import eu.konggdev.strikemaps.helper.UserPrefsHelper;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory; import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
public class FragmentLayoutContentSettings extends Fragment implements MainContentLayout { public class FragmentLayoutContentSettings extends Fragment implements MainContentLayout {
private final AppCompatActivity activity; @NonNull AppController app;
private final UIComponent ui; @NonNull UIComponent ui;
public FragmentLayoutContentSettings(AppController app) {
private final SharedPreferences userPrefs;
public FragmentLayoutContentSettings(AppCompatActivity activity, UIComponent ui, SharedPreferences userPrefs) {
super(R.layout.fragment_settings); super(R.layout.fragment_settings);
this.activity = activity; this.app = app;
this.ui = ui; this.ui = app.getUi();
this.userPrefs = userPrefs;
} }
@Override @Override
@@ -45,7 +39,7 @@ public class FragmentLayoutContentSettings extends Fragment implements MainConte
); );
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mapRendererSelector.setAdapter(adapter); mapRendererSelector.setAdapter(adapter);
mapRendererSelector.setSelection(UserPrefsHelper.mapRenderer(userPrefs)); mapRendererSelector.setSelection(UserPrefsHelper.mapRenderer(app.getPrefs()));
final boolean[] ignoreFirst = {true}; final boolean[] ignoreFirst = {true};
mapRendererSelector.setOnItemSelectedListener( mapRendererSelector.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() { new AdapterView.OnItemSelectedListener() {
@@ -56,8 +50,8 @@ public class FragmentLayoutContentSettings extends Fragment implements MainConte
return; return;
} }
UserPrefsHelper.mapRenderer(userPrefs, position); UserPrefsHelper.mapRenderer(app.getPrefs(), position);
ui.alert(AlertDialogFactory.restartDialog(activity)); ui.alert(AlertDialogFactory.restartDialog(app));
} }
@Override @Override
@@ -10,14 +10,14 @@ import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
import eu.konggdev.strikemaps.map.style.MapStyle;
import eu.konggdev.strikemaps.storage.RegistryStorageComponent; import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.fragment.dialog.NewStyleBottomSheet; import eu.konggdev.strikemaps.ui.fragment.dialog.NewStyleBottomSheet;
@@ -28,10 +28,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
public class FragmentMapChangePopup extends Fragment implements Popup { public class FragmentMapChangePopup extends Fragment implements Popup {
private final AppCompatActivity activity; @NonNull AppController app;
private final MapComponent map; @NonNull MapComponent map;
private final UIComponent ui; @NonNull UIComponent ui;
private final RegistryStorageComponent registry; @NonNull RegistryStorageComponent registry;
private final Integer region; private final Integer region;
@@ -52,16 +52,17 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
public void reloadStyles() { public void reloadStyles() {
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout); LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
stylesLayout.removeAllViews(); stylesLayout.removeAllViews();
registry.getStyles().forEach((id, style) -> { app.getRegistry().getStyles().forEach((id, style) -> {
View item = new GenericItem( View item = new GenericItem(
style.document, style.document,
app,
() -> this.setStyle(id), () -> this.setStyle(id),
() -> this.styleDetails(id), activity).makeView(ui); () -> this.styleDetails(id)).makeView(ui);
if (Objects.equals(map.styleId, id)) item.findViewById(R.id.indicator) if (Objects.equals(map.styleId, id)) item.findViewById(R.id.indicator)
.setVisibility(View.VISIBLE); .setVisibility(View.VISIBLE);
stylesLayout.addView(item); stylesLayout.addView(item);
}); });
Bitmap addNewIcon = BitmapFactory.decodeResource(activity.getResources(), android.R.drawable.ic_menu_add); Bitmap addNewIcon = BitmapFactory.decodeResource(app.getActivity().getResources(), android.R.drawable.ic_menu_add);
stylesLayout.addView(new GenericItem("", stylesLayout.addView(new GenericItem("",
addNewIcon, addNewIcon,
this::newStyleFlow).makeView(ui)); this::newStyleFlow).makeView(ui));
@@ -94,11 +95,11 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
} }
void newStyleFlow() { void newStyleFlow() {
new NewStyleBottomSheet(activity, map, ui, registry, this).show(activity.getSupportFragmentManager(), "NewStyleBottomSheet"); new NewStyleBottomSheet(app, map, ui, this).show(app.getActivity().getSupportFragmentManager(), "NewStyleBottomSheet");
} }
void styleDetails(Integer id) { void styleDetails(Integer id) {
new StyleDetailsBottomSheet(activity, map, ui, registry, this, id).show(activity.getSupportFragmentManager(), "StyleDetailsBottomSheet"); new StyleDetailsBottomSheet(app, this, id).show(app.getActivity().getSupportFragmentManager(), "StyleDetailsBottomSheet");
} }
void setStyle(Integer id) { void setStyle(Integer id) {
@@ -106,12 +107,12 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
reloadStyles(); reloadStyles();
} }
public FragmentMapChangePopup(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, Integer region) { public FragmentMapChangePopup(AppController app, Integer region) {
super(R.layout.popup_map_change); super(R.layout.popup_map_change);
this.activity = activity; this.app = app;
this.ui = ui; this.map = app.getMap();
this.map = map; this.ui = app.getUi();
this.registry = registry; this.registry = app.getRegistry();
this.region = region; this.region = region;
} }
@@ -1,22 +1,23 @@
package eu.konggdev.strikemaps.ui.screen; package eu.konggdev.strikemaps.ui.screen;
import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import java.util.Map; import java.util.Map;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.AppController;
import eu.konggdev.strikemaps.ui.fragment.ContainerFragment; import eu.konggdev.strikemaps.ui.fragment.ContainerFragment;
import eu.konggdev.strikemaps.ui.fragment.FragmentEmptyPlaceholder; import eu.konggdev.strikemaps.ui.fragment.FragmentEmptyPlaceholder;
import eu.konggdev.strikemaps.ui.fragment.popup.Popup; import eu.konggdev.strikemaps.ui.fragment.popup.Popup;
import eu.konggdev.strikemaps.ui.element.region.UIRegion; import eu.konggdev.strikemaps.ui.element.region.UIRegion;
public class Screen { public class Screen {
private final ComponentHolderActivity activity; @NonNull AppController app;
Toolbar toolbar;
public Screen(ComponentHolderActivity activity, Map<Integer, UIRegion> regions) { public Screen(AppController app, Map<Integer, UIRegion> regions) {
this.activity = activity; this.app = app;
this.uiRegions = regions; this.uiRegions = regions;
} }
Map<Integer, UIRegion> uiRegions; Map<Integer, UIRegion> uiRegions;
@@ -54,7 +55,7 @@ public class Screen {
} }
public void fragmentTransaction(int layoutId, Fragment fragment) { public void fragmentTransaction(int layoutId, Fragment fragment) {
activity.getSupportFragmentManager() app.getActivity().getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.replace(layoutId, fragment) .replace(layoutId, fragment)
.commit(); .commit();
@@ -0,0 +1,6 @@
package eu.konggdev.strikemaps.ui.screen.definition;
public enum DefinedScreen {
MAIN,
SETTINGS,
OFFLINE
}
@@ -1,67 +0,0 @@
package eu.konggdev.strikemaps.util.file;
import android.content.res.AssetManager;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import androidx.appcompat.app.AppCompatActivity;
//FIXME: Ugly
public final class FileTools {
private static final String TAG = "FileTools";
public static String loadStringFromAssetFile(String filePath, AppCompatActivity activity) {
try (InputStream is = activity.getAssets().open(filePath)) {
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
return new String(buffer, StandardCharsets.UTF_8);
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
public static String[] getAssetFiles(String path, String fileExt, AppCompatActivity activity) {
AssetManager assetManager = activity.getAssets();
try {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
String fullPath = (path == null || path.isEmpty()) ? "" : path;
String[] files = assetManager.list(fullPath);
if (files == null) return new String[0];
if (fileExt == null || fileExt.isEmpty())
return files;
List<String> filtered = new ArrayList<>();
for (String file : files) {
if (file.toLowerCase().endsWith(fileExt.toLowerCase())) {
filtered.add((fullPath.isEmpty() ? "" : fullPath + "/") + file);
}
}
return filtered.toArray(new String[0]);
} catch (IOException e) {
e.printStackTrace();
return new String[0];
}
}
public static InputStream openAssetStream(String path, AppCompatActivity activity) {
try {
return activity.getAssets().open(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -1,22 +0,0 @@
package eu.konggdev.strikemaps.util.icon;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import eu.konggdev.strikemaps.util.file.FileTools;
public final class IconResolver {
private static final String TAG = "IconResolver";
public static Bitmap getIcon(String iconLocator, AppCompatActivity activity) {
switch (iconLocator.split("//")[0]) {
//TODO: https
case "assets:":
return BitmapFactory.decodeStream(FileTools.openAssetStream("bundled/icon/" + iconLocator.split("//")[1], activity));
default:
Log.e(TAG, "Unimplemented icon locator space: " + iconLocator);
return null;
}
}
}