Compare commits

...
8 Commits
Author SHA1 Message Date
konggd 004e9579c8 refactor: move getIcon away from FileTools
fix: use IconResolver in GenericItem
2026-09-15 14:07:35 +02:00
konggd f58cfdfabf refactor: define screens inside activity 2026-09-14 03:28:07 +02:00
konggd 580729dadb Fix activity location in AndroidManifest 2026-09-13 18:15:14 +02:00
konggd a3ae33812e Support android API 23 2026-09-13 16:43:29 +02:00
konggd 7a88939ea4 Migrate to modern OnBackPressedCallback inside MainActivity 2026-09-13 16:35:19 +02:00
konggd ecf3e4052a refactor: hold components inside activity 2026-09-13 16:25:39 +02:00
konggd abb6713798 Minor UI improvements 2026-09-13 16:25:39 +02:00
konggd 85734fa98d feat: add indicator to currently active style in map change ui 2026-09-13 16:25:36 +02:00
41 changed files with 695 additions and 637 deletions

No files matched your search

+3 -3
View File
@@ -9,8 +9,8 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.konggdev.strikemaps" applicationId = "eu.konggdev.strikemaps"
minSdk = 24 minSdk = 23
targetSdk = 35 targetSdk = 36
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
@@ -53,7 +53,7 @@ dependencies {
implementation("com.github.mapsforge.vtm:vtm-android:0.27.0") implementation("com.github.mapsforge.vtm:vtm-android:0.27.0")
implementation("com.github.mapsforge.vtm:vtm-http:0.27.0") implementation("com.github.mapsforge.vtm:vtm-http:0.27.0")
implementation ("com.github.mapsforge.vtm:vtm-android:0.27.0@jar") implementation ("com.github.mapsforge.vtm:vtm-android:0.27.0@jar")
runtimeOnly ("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-armeabi-v7a@jar") runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-armeabi-v7a@jar")
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-arm64-v8a@jar") runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-arm64-v8a@jar")
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86@jar") runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86@jar")
runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86_64@jar") runtimeOnly("com.github.mapsforge.vtm:vtm-android:0.27.0:natives-x86_64@jar")
+2 -3
View File
@@ -9,10 +9,9 @@
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=".MainActivity" android:name=".activity.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": {
"satelite": { "imagery": {
"type": "raster", "type": "raster",
"schema" : "raster", "schema" : "raster",
"tiles": [ "tiles": [
@@ -17,9 +17,9 @@
}, },
"layers": [ "layers": [
{ {
"id": "satelite", "id": "background",
"type": "raster", "type": "raster",
"source": "satelite" "source": "imagery"
} }
], ],
"id": "satellite" "id": "satellite"
@@ -1,35 +0,0 @@
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();
}
}
@@ -0,0 +1,90 @@
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();
}
}
});
}
}
@@ -1,60 +0,0 @@
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
}
}
}
@@ -0,0 +1,24 @@
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,101 +0,0 @@
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,12 +3,13 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
@@ -32,11 +33,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(AppController app) { public static Map<Integer, MapStyle> DEFAULT_STYLES(ComponentHolderActivity app) {
Map<Integer, MapStyle> styles = new HashMap<>(); Map<Integer, MapStyle> styles = new HashMap<>();
String[] styleAssets = FileHelper.getAssetFiles("bundled/style", ".style.json", app); String[] styleAssets = FileTools.getAssetFiles("bundled/style", ".style.json", app);
for (int i = 0; i < styleAssets.length; i++) { for (int i = 0; i < styleAssets.length; i++) {
String styleContents = FileHelper.loadStringFromAssetFile(styleAssets[i], app); String styleContents = FileTools.loadStringFromAssetFile(styleAssets[i], app);
styles.put( i, styles.put( i,
new MapStyle( new MapStyle(
styleContents, styleContents,
@@ -92,7 +93,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, AppController app) { public static Map<Integer, MapStyle> styles(SharedPreferences prefs, ComponentHolderActivity 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,45 +2,60 @@ 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.MapStyle; import eu.konggdev.strikemaps.map.style.document.StyleDocument;
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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 MapRenderer mapRenderer; private final String TAG = "MapComponent";
private final AppController app;
private final MapRenderer mapRenderer;
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(AppController ref) { public MapComponent(ComponentHolderActivity activity, RegistryStorageComponent registry, SharedPreferences userPrefs) {
this.app = ref; this.activity = activity;
switch(UserPrefsHelper.mapRenderer(app.getPrefs())) { this.registry = registry;
this.userPrefs = userPrefs;
switch(UserPrefsHelper.mapRenderer(userPrefs)) {
case 0: case 0:
this.mapRenderer = new MapLibreGLJSRenderer(app, this); this.mapRenderer = new MapLibreGLJSRenderer(activity, this);
break; break;
case 1: case 1:
this.mapRenderer = new MapLibreNativeRenderer(app, this); this.mapRenderer = new MapLibreNativeRenderer(activity, this);
break; break;
case 2: case 2:
this.mapRenderer = new VtmRenderer(app, this); this.mapRenderer = new VtmRenderer(activity, this);
break; break;
default: //This shouldn't happen default: //This shouldn't happen
Toast.makeText(app.getActivity(), "Invalid renderer value in preferences\nFalling back to MapLibre GL JS", Toast.LENGTH_SHORT).show(); Toast.makeText(activity, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS", Toast.LENGTH_SHORT).show();
this.mapRenderer = new MapLibreGLJSRenderer(app, this); Log.e(TAG, "Invalid renderer value in preferences\nFalling back to MapLibre GL JS");
this.mapRenderer = new MapLibreGLJSRenderer(activity, this);
break; break;
}; };
} }
@@ -51,6 +66,14 @@ 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) {
@@ -87,10 +110,12 @@ public class MapComponent implements Component {
selectPoint(features.get(0)); selectPoint(features.get(0));
break; break;
default: default:
app.getUi().alert( UIComponent ui = activity.getComponent(UIComponent.class);
AlertDialogFactory.pointSelector(app, features, selectedItem -> { if (ui != null) {
selectPoint(selectedItem); ui.alert(
})); AlertDialogFactory.pointSelector(activity, ui, features, this::selectPoint)
);
}
} }
return true; return true;
} }
@@ -102,7 +127,7 @@ public class MapComponent implements Component {
public void onMapInit() { public void onMapInit() {
setStyle( setStyle(
UserPrefsHelper.startupMapStyle(app.getPrefs()) UserPrefsHelper.startupMapStyle(userPrefs)
); );
} }
} }
@@ -1,10 +1,12 @@
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 byte[] resolve(String url) throws IOException {
//byte[] data = getOfflineTile(); public final class OfflineTileResolver {
public static byte[] resolve(String url) throws IOException {
//TODO
return null; return null;
} }
} }
@@ -3,8 +3,9 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
@@ -16,15 +17,13 @@ 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(AppController app) { public LocationOverlay(MapComponent map, AppCompatActivity activity) {
this.app = app; this.map = map;
this.map = app.getMap(); this.locationDataProvider = new LocationDataProvider(activity, this);
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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
AppController app; ComponentHolderActivity app;
MapComponent map; MapComponent map;
@Override @Override
public JsonNode makePatch() { public JsonNode makePatch() {
@@ -1,19 +1,20 @@
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.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.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.app.ComponentHolderActivity;
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.overlay.MapOverlay; import eu.konggdev.strikemaps.map.overlay.MapOverlay;
import eu.konggdev.strikemaps.map.renderer.MapRenderer; import eu.konggdev.strikemaps.map.renderer.MapRenderer;
@@ -27,19 +28,20 @@ import java.util.List;
//Stub for now //Stub for now
public class MapLibreGLJSRenderer implements MapRenderer { public class MapLibreGLJSRenderer implements MapRenderer {
@NonNull AppController app; private final static String TAG = "MapLibreGLJSRenderer";
private final AppCompatActivity activity;
@NonNull MapComponent controller; private final MapComponent controller;
final WebView webView; final WebView webView;
private JsonNode origin; private JsonNode origin;
@SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"}) @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
public MapLibreGLJSRenderer(AppController app, MapComponent controller) { public MapLibreGLJSRenderer(ComponentHolderActivity activity, MapComponent controller) {
this.app = app; this.activity = activity;
this.controller = controller; this.controller = controller;
webView = new WebView(app.getActivity()); webView = new WebView(activity);
webView.setLayoutParams( webView.setLayoutParams(
new ViewGroup.LayoutParams( new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -86,7 +88,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) {
app.logcat("Failed to parse style: " + style.name); Log.e(TAG, "Failed to parse style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -96,7 +98,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) {
app.logcat("Failed to set style: " + style.name); Log.e(TAG, "Failed to set style: " + style.name);
e.printStackTrace(); e.printStackTrace();
} }
@@ -127,7 +129,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) {
app.logcat("Failed to patch overlay: " + overlay.toString()); Log.e(TAG, "Failed to patch overlay: " + overlay.toString());
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -1,16 +1,17 @@
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.app.util.JsonPatcher; import eu.konggdev.strikemaps.util.json.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;
@@ -21,27 +22,26 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback { public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
@NonNull AppController app; private final static String TAG = "MapLibreNativeRenderer";
@NonNull MapComponent controller; private final AppCompatActivity activity;
private final MapComponent controller;
MapLibreMap map; MapLibreMap map;
final MapView mapView; final MapView mapView;
private JsonNode origin; private JsonNode origin;
public MapLibreNativeRenderer(AppController app, MapComponent controller) { public MapLibreNativeRenderer(ComponentHolderActivity activity, MapComponent controller) {
this.app = app; this.activity = activity;
this.controller = controller; this.controller = controller;
MapLibre.getInstance(app.getActivity()); MapLibre.getInstance(activity);
this.mapView = new MapView(app.getActivity()); this.mapView = new MapView(activity);
//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) {
app.logcat("Failed to parse style: " + style.name); Log.e(TAG, "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) {
app.logcat("Failed to set style: " + style.name); Log.e(TAG, "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) {
app.logcat("Failed to patch overlay: " + overlay.toString()); Log.e(TAG, "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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
AppController app; ComponentHolderActivity activity;
MapComponent controller; MapComponent controller;
Map map; Map map;
final MapView mapView; final MapView mapView;
public VtmRenderer(AppController app, MapComponent controller) { public VtmRenderer(ComponentHolderActivity activity, MapComponent controller) {
this.app = app; this.activity = activity;
this.controller = controller; this.controller = controller;
this.mapView = new MapView(app.getActivity()); this.mapView = new MapView(activity);
this.map = mapView.map(); this.map = mapView.map();
} }
@@ -2,7 +2,6 @@ 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,7 +4,6 @@ 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;
@@ -71,24 +70,6 @@ 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,31 +1,32 @@
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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
import eu.konggdev.strikemaps.map.style.management.StyleManagementMetadata;
import org.apache.commons.codec.digest.DigestUtils;
public class RegistryStorageComponent implements Component { public class RegistryStorageComponent implements Component {
private AppController app; private final ComponentHolderActivity activity;
private final SharedPreferences userPrefs;
private Map<Integer, MapStyle> styles; private Map<Integer, MapStyle> styles;
private Map<Integer, MapSource> sources; private Map<Integer, MapSource> sources;
public RegistryStorageComponent(AppController app) { public RegistryStorageComponent(ComponentHolderActivity activity, SharedPreferences userPrefs) {
this.app = app; this.activity = activity;
styles(); this.userPrefs = userPrefs;
initAll();
} }
private Map<Integer, MapSource> sources() { private Map<Integer, MapSource> sources() {
if (sources == null) sources = UserPrefsHelper.sources(app.getPrefs()); if (sources == null) sources = UserPrefsHelper.sources(userPrefs);
return sources; return sources;
} }
@@ -38,7 +39,7 @@ public class RegistryStorageComponent implements Component {
} }
private Map<Integer, MapStyle> styles() { private Map<Integer, MapStyle> styles() {
if (styles == null) styles = UserPrefsHelper.styles(app.getPrefs(), app); if (styles == null) styles = UserPrefsHelper.styles(userPrefs, activity);
return styles; return styles;
} }
@@ -73,10 +74,14 @@ public class RegistryStorageComponent implements Component {
} }
private void save() { private void save() {
UserPrefsHelper.styles(app.getPrefs(), styles); UserPrefsHelper.styles(userPrefs, styles);
} }
public void checkForUpdates() { public void checkForUpdates() {
// //
} }
private void initAll() {
styles(); sources();
}
} }
@@ -1,13 +1,14 @@
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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
@@ -15,57 +16,44 @@ 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 {
@NonNull AppController app; private final String TAG = "UIComponent";
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<>();
public UIComponent(AppController app, MapComponent map) { private Map<String, Screen> screens;
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 Map<DefinedScreen, Screen> getScreens(MapComponent map) { public void defineScreens(Map<String, Screen> screens) {
return Map.of( this.screens = screens;
//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(DefinedScreen screenKey) { public void swapScreen(String 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(getScreens(map).get(screenKey)); screenStack.add(newScreen);
getCurrentScreen().attachAll(); getCurrentScreen().attachAll();
} }
@@ -86,11 +74,7 @@ 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 app.getActivity().getLayoutInflater().inflate(layout, null); return activity.getLayoutInflater().inflate(layout, null);
} }
} }
@@ -5,67 +5,72 @@ import android.view.View;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity;
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 {
@NonNull public String name; 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 refName) { public GenericItem(String name) {
this.name = refName; this.name = name;
hasImage = false; hasImage = false;
} }
public GenericItem(String refName, Runnable onClick) {
this.name = refName; public GenericItem(String name, Runnable onClick) {
this.name = name;
this.onClick = onClick; this.onClick = onClick;
hasImage = false; hasImage = false;
} }
public GenericItem(String refName, Runnable onClick, Runnable onLongClick) {
this.name = refName; public GenericItem(String name, Runnable onClick, Runnable onLongClick) {
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) {
this.name = refName; public GenericItem(String name, Bitmap Image) {
this.image = refImage; this.name = name;
this.image = Image;
hasImage = true; hasImage = true;
} }
public GenericItem(String refName, Bitmap refImage, Runnable onClick) {
this.name = refName; public GenericItem(String name, Bitmap Image, Runnable onClick) {
this.image = refImage; this.name = name;
this.image = Image;
this.onClick = onClick; this.onClick = onClick;
hasImage = true; hasImage = true;
} }
public GenericItem(String refName, Bitmap refImage, Runnable onClick, Runnable onLongClick) { public GenericItem(String name, Bitmap Image, Runnable onClick, Runnable onLongClick) {
this.name = refName; this.name = name;
this.image = refImage; this.image = Image;
this.onClick = onClick; this.onClick = onClick;
this.onLongClick = onLongClick; this.onLongClick = onLongClick;
hasImage = true; hasImage = true;
} }
public static GenericItem fromStyle(StyleDocument style, AppController app, Runnable onClick) { public GenericItem(StyleDocument style, Runnable onClick, AppCompatActivity activity) {
if(style == null) return new GenericItem("Unknown"); if (style == null) return;
if(style.icon != null) this.name = style.name;
return new GenericItem(style.name, FileHelper.getIcon(style.icon, app), onClick); this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
return new GenericItem(style.name, onClick); this.onClick = onClick;
} }
public static GenericItem fromStyle(StyleDocument style, AppController app, Runnable onClick, Runnable onLongClick) {
if(style == null) return new GenericItem("Unknown"); public GenericItem(StyleDocument style, Runnable onClick, Runnable onLongClick, AppCompatActivity activity) {
if(style.icon != null) if (style == null) return;
return new GenericItem(style.name, FileHelper.getIcon(style.icon, app), onClick, onLongClick); this.name = style.name;
return new GenericItem(style.name, onClick, onLongClick); this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
this.onClick = onClick;
this.onLongClick = onLongClick;
} }
@Override @Override
@@ -8,13 +8,16 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
import eu.konggdev.strikemaps.app.util.JsonPatcher; import eu.konggdev.strikemaps.storage.RegistryStorageComponent;
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.options.StyleOptions; import eu.konggdev.strikemaps.map.style.options.StyleOptions;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.ui.element.item.PreviewItem; import eu.konggdev.strikemaps.ui.element.item.PreviewItem;
@@ -24,19 +27,43 @@ import org.maplibre.geojson.Feature;
import java.util.List; import java.util.List;
import java.util.function.Consumer; 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 copyBuiltInStyle(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) { public static AlertDialog styleManagementOptions(AppCompatActivity activity, StyleManagementMetadata metadata) {
String[] options = {
"Update style",
"Update automatically"
};
boolean[] checked = {
metadata.doUpdates,
metadata.autoUpdate
};
return new AlertDialog.Builder(activity)
.setTitle("Built-in Style")
.setMultiChoiceItems(options, checked, (dialog, which, isChecked) -> {
if (which == 0) {
metadata.doUpdates = isChecked;
} else if (which == 1) {
metadata.autoUpdate = isChecked;
}
})
.setNegativeButton("Cancel", null)
.setPositiveButton("OK", null)
.create();
}
public static AlertDialog copyBuiltInStyle(AppCompatActivity activity, 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(app.getActivity()); LinearLayout container = new LinearLayout(activity);
container.setOrientation(LinearLayout.VERTICAL); container.setOrientation(LinearLayout.VERTICAL);
ScrollView scrollView = new ScrollView(app.getActivity()); ScrollView scrollView = new ScrollView(activity);
scrollView.addView(container); scrollView.addView(container);
AlertDialog dialog = new AlertDialog.Builder(app.getActivity()) AlertDialog dialog = new AlertDialog.Builder(activity)
.setTitle("Copy from") .setTitle("Copy from")
.setView(scrollView) .setView(scrollView)
.setNegativeButton("Cancel", null) .setNegativeButton("Cancel", null)
@@ -45,19 +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(app.getActivity()); LinearLayout container = new LinearLayout(activity);
container.setOrientation(LinearLayout.VERTICAL); container.setOrientation(LinearLayout.VERTICAL);
int padding = (int) (20 * app.getActivity().getResources().getDisplayMetrics().density); int padding = (int) (20 * activity.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(app.getActivity()) AlertDialog dialog = new AlertDialog.Builder(activity)
.setTitle("Create") .setTitle("Create")
.setView(container) .setView(container)
.setPositiveButton("Create", null) .setPositiveButton("Create", null)
@@ -68,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 mapper = new ObjectMapper(); ObjectMapper mactivityer = new ObjectMapper();
boolean nameEntryRequired = true; boolean nameEntryRequired = true;
String styleContentName = ""; String styleContentName = "";
if (baseStyleContents != null) { if (baseStyleContents != null) {
try { try {
JsonNode root = mapper.readTree(baseStyleContents); JsonNode root = mactivityer.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();
@@ -98,28 +125,28 @@ public final class AlertDialogFactory {
JsonNode root; JsonNode root;
if(baseStyleContents != null) { if(baseStyleContents != null) {
if(!baseStyleContents.isEmpty()) { if(!baseStyleContents.isEmpty()) {
root = mapper.readTree(baseStyleContents); root = mactivityer.readTree(baseStyleContents);
} else { } else {
root = mapper.createObjectNode(); root = mactivityer.createObjectNode();
} }
} else { } else {
root = mapper.createObjectNode(); root = mactivityer.createObjectNode();
} }
if (!root.path("name").asText().isEmpty()) { if (!root.path("name").asText().isEmpty()) {
ObjectNode node = mapper.createObjectNode(); ObjectNode node = mactivityer.createObjectNode();
node.put("name", name); node.put("name", name);
root = JsonPatcher.patch(root, node); root = JsonPatcher.patch(root, node);
} }
app.getRegistry().addStyle(new MapStyle( registry.addStyle(new MapStyle(
mapper.writeValueAsString(root), mactivityer.writeValueAsString(root),
new StyleOptions(), new StyleOptions(),
null null
)); ));
dialog.dismiss(); dialog.dismiss();
} catch (Exception e) { } catch (Exception e) {
Toast.makeText(app.getActivity(), "Failed to create", Toast.LENGTH_SHORT).show(); Toast.makeText(activity, "Failed to create", Toast.LENGTH_SHORT).show();
e.printStackTrace(); e.printStackTrace();
} }
@@ -130,20 +157,20 @@ public final class AlertDialogFactory {
return dialog; return dialog;
} }
public static AlertDialog pointSelector(AppController app, List<Feature> features, Consumer<Feature> callback) { public static AlertDialog pointSelector(ComponentHolderActivity activity, UIComponent ui, List<Feature> features, Consumer<Feature> callback) {
LinearLayout layout = new LinearLayout(app.getActivity()); LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.VERTICAL); layout.setOrientation(LinearLayout.VERTICAL);
ScrollView scrollView = new ScrollView(app.getActivity()); ScrollView scrollView = new ScrollView(activity);
scrollView.addView(layout); scrollView.addView(layout);
AlertDialog dialog = new AlertDialog.Builder(app.getActivity()) AlertDialog dialog = new AlertDialog.Builder(activity)
.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(app.getUi(), v -> { View itemView = PreviewItem.fromFeature(feature).makeView(ui, v -> {
dialog.dismiss(); dialog.dismiss();
new Handler(Looper.getMainLooper()) new Handler(Looper.getMainLooper())
.post(() -> callback.accept(feature)); .post(() -> callback.accept(feature));
@@ -154,30 +181,30 @@ public final class AlertDialogFactory {
return dialog; return dialog;
} }
public static AlertDialog searchSettings(AppController app) { public static AlertDialog searchSettings(AppCompatActivity activity) {
return new AlertDialog.Builder(app.getActivity()) return new AlertDialog.Builder(activity)
.setTitle("Configure Search") .setTitle("Configure Search")
.setPositiveButton("OK", null) .setPositiveButton("OK", null)
.create(); .create();
} }
public static AlertDialog restartDialog(AppController app) { public static AlertDialog restartDialog(AppCompatActivity activity) {
return new AlertDialog.Builder(app.getActivity()) return new AlertDialog.Builder(activity)
.setTitle("Restart required") .setTitle("Restart required")
.setMessage("Restart the app to apply changes.") .setMessage("Restart the activity to activityly changes.")
.setCancelable(false) .setCancelable(false)
.setNegativeButton("Cancel", (d, w) -> { .setNegativeButton("Cancel", (d, w) -> {
Toast.makeText(app.getActivity(), Toast.makeText(activity,
"Changes will be applied on next restart", "Changes will be activitylied 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 = app.getActivity().getPackageManager() Intent i = activity.getPackageManager()
.getLaunchIntentForPackage(app.getActivity().getPackageName()); .getLaunchIntentForPackage(activity.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);
app.getActivity().startActivity(i); activity.startActivity(i);
} }
Runtime.getRuntime().exit(0); Runtime.getRuntime().exit(0);
}) })
@@ -14,13 +14,15 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
@@ -30,11 +32,15 @@ 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\"}";
@NonNull AppController app; private AppCompatActivity activity;
@NonNull MapComponent map;
@NonNull UIComponent ui; private MapComponent map;
@NonNull
FragmentMapChangePopup mapChangePopup; private UIComponent ui;
private RegistryStorageComponent registry;
private FragmentMapChangePopup mapChangePopup;
private final ActivityResultLauncher<Intent> importLauncher = private final ActivityResultLauncher<Intent> importLauncher =
registerForActivityResult( registerForActivityResult(
@@ -72,15 +78,16 @@ 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")) {
app.getUi().alert( ui.alert(
AlertDialogFactory.createStyle( AlertDialogFactory.createStyle(
app, activity,
registry,
content, content,
mapChangePopup mapChangePopup
) )
); );
} else { } else {
app.getRegistry().addStyle( registry.addStyle(
new MapStyle( new MapStyle(
content, content,
new StyleOptions(), new StyleOptions(),
@@ -108,10 +115,11 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
importLauncher.launch(intent); importLauncher.launch(intent);
} }
public NewStyleBottomSheet(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) { public NewStyleBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup) {
this.app = app; this.activity = activity;
this.map = map; this.map = map;
this.ui = ui; this.ui = ui;
this.registry = registry;
this.mapChangePopup = mapChangePopup; this.mapChangePopup = mapChangePopup;
} }
@@ -126,7 +134,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 -> {
app.getUi().alert(AlertDialogFactory.copyBuiltInStyle(app, map, ui, mapChangePopup)); ui.alert(AlertDialogFactory.copyBuiltInStyle(activity, map, ui, mapChangePopup));
}); });
fileBtn.setOnClickListener(v -> { fileBtn.setOnClickListener(v -> {
@@ -134,7 +142,7 @@ public class NewStyleBottomSheet extends BottomSheetDialogFragment {
}); });
emptyBtn.setOnClickListener(v -> { emptyBtn.setOnClickListener(v -> {
app.getUi().alert(AlertDialogFactory.createStyle(app, styleBase, mapChangePopup)); ui.alert(AlertDialogFactory.createStyle(activity, registry, styleBase, mapChangePopup));
}); });
return view; return view;
@@ -14,10 +14,11 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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;
@@ -29,16 +30,15 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class StyleDetailsBottomSheet extends BottomSheetDialogFragment { public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
@NonNull private final AppCompatActivity activity;
AppController app;
@NonNull private final MapComponent map;
MapComponent map;
@NonNull private final UIComponent ui;
UIComponent ui;
@NonNull private final RegistryStorageComponent registry;
RegistryStorageComponent registry;
@NonNull private final FragmentMapChangePopup mapChangePopup;
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(AppController app, FragmentMapChangePopup mapChangePopup, Integer styleId) { public StyleDetailsBottomSheet(AppCompatActivity activity, MapComponent map, UIComponent ui, RegistryStorageComponent registry, FragmentMapChangePopup mapChangePopup, Integer styleId) {
this.app = app; this.activity = activity;
this.map = app.getMap(); this.map = map;
this.ui = app.getUi(); this.ui = ui;
this.registry = app.getRegistry(); this.registry = registry;
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(app, style.managementMetadata) AlertDialogFactory.styleManagementOptions(activity, 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(app, style.json, mapChangePopup))); copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(activity, registry, style.json, mapChangePopup)));
exportButtonLayout.setOnClickListener(v -> showExportDialog()); exportButtonLayout.setOnClickListener(v -> showExportDialog());
deleteButtonLayout.setOnClickListener(v -> deleteStyle()); deleteButtonLayout.setOnClickListener(v -> deleteStyle());
@@ -2,31 +2,42 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
AppController app; private final AppCompatActivity activity;
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();
} }
@@ -35,29 +46,32 @@ 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 {
app.getMap().switchOverlay(new LocationOverlay(app)); map.switchOverlay(new LocationOverlay(map, activity));
setupView(); setupView();
} }
} }
public void zoomToLocation() { public void zoomToLocation() {
if(!app.getMap().hasOverlay(LocationOverlay.class)) { if(map.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(app.getActivity()) AlertDialog dialog = new AlertDialog.Builder(activity)
.setTitle(app.getActivity().getString(R.string.attribution_title)) .setTitle(activity.getString(R.string.attribution_title))
.setMessage(app.getActivity().getString(R.string.shipped_attribution)) .setMessage(activity.getString(R.string.shipped_attribution))
.setPositiveButton("OK", null).show(); .setPositiveButton("OK", null).show();
} }
//*//
public FragmentLayoutControls(AppController app, Integer region) { public FragmentLayoutControls(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs, Integer region) {
super(R.layout.fragment_controls); super(R.layout.fragment_controls);
this.app = app; this.activity = activity;
this.ui = ui;
this.map = map;
this.registry = registry;
this.userPrefs = userPrefs;
this.region = region; this.region = region;
} }
@@ -78,7 +92,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(app.getPrefs()) && UserPrefsHelper.lastLocationEnabled(app.getPrefs()) && !app.getMap().hasOverlay(LocationOverlay.class)) if(UserPrefsHelper.persistLocationEnabled(userPrefs) && UserPrefsHelper.lastLocationEnabled(userPrefs) && !map.hasOverlay(LocationOverlay.class))
toggleLocationService(); toggleLocationService();
this.setupView(); this.setupView();
@@ -86,7 +100,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(() -> app.getUi().getCurrentScreen().open(new FragmentMapChangePopup(app, R.id.bottomUi)))); setupButton(rootView, R.id.layersButton, click(() -> ui.getCurrentScreen().open(new FragmentMapChangePopup(activity, ui, map, registry, 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));
@@ -97,14 +111,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 (app.getMap().hasOverlay(LocationOverlay.class)) { if (map.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(app.getPrefs())) if(UserPrefsHelper.persistLocationEnabled(userPrefs))
UserPrefsHelper.lastLocationEnabled(app.getPrefs(), app.getMap().hasOverlay(LocationOverlay.class)); UserPrefsHelper.lastLocationEnabled(userPrefs, map.hasOverlay(LocationOverlay.class));
} }
@Override @Override
@@ -8,20 +8,21 @@ 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.app.AppController; 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.screen.definition.DefinedScreen;
public class FragmentLayoutSearch extends Fragment implements Layout { public class FragmentLayoutSearch extends Fragment implements Layout {
AppController app; private final AppCompatActivity activity;
private final UIComponent ui;
private final Integer region; private final Integer region;
public FragmentLayoutSearch(AppController app, Integer region) { public FragmentLayoutSearch(AppCompatActivity activity, UIComponent ui, Integer region) {
super(R.layout.fragment_search); super(R.layout.fragment_search);
this.app = app; this.activity = activity;
this.ui = ui;
this.region = region; this.region = region;
} }
@@ -55,12 +56,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(() -> {
app.getUi().alert(AlertDialogFactory.searchSettings(app)); ui.alert(AlertDialogFactory.searchSettings(activity));
})); }));
setupButton(menuView, R.id.menuSettings, click(() -> { setupButton(menuView, R.id.menuSettings, click(() -> {
popupWindow.dismiss(); popupWindow.dismiss();
app.getUi().swapScreen(DefinedScreen.SETTINGS); ui.swapScreen("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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout { public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout {
@NonNull AppController app; private final ComponentHolderActivity activity;
public FragmentLayoutContentOfflineMaps(AppController app) { public FragmentLayoutContentOfflineMaps(ComponentHolderActivity activity) {
super(R.layout.fragment_offline_maps); super(R.layout.fragment_offline_maps);
this.app = app; this.activity = activity;
} }
@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(app.getActivity(), "Work in progress", Toast.LENGTH_SHORT).show()).makeView(app.getUi())); // sourcesLayout.addView(new InlineItem(source.name, () -> Toast.makeText(activity.getActivity(), "Work in progress", Toast.LENGTH_SHORT).show()).makeView(app.getUi()));
} }
} }
@@ -1,5 +1,6 @@
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;
@@ -7,19 +8,26 @@ 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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
@NonNull AppController app; private final AppCompatActivity activity;
private final 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.app = app; this.activity = activity;
this.ui = ui;
this.userPrefs = userPrefs;
} }
@Override @Override
@@ -37,7 +45,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(app.getPrefs())); mapRendererSelector.setSelection(UserPrefsHelper.mapRenderer(userPrefs));
final boolean[] ignoreFirst = {true}; final boolean[] ignoreFirst = {true};
mapRendererSelector.setOnItemSelectedListener( mapRendererSelector.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() { new AdapterView.OnItemSelectedListener() {
@@ -48,8 +56,8 @@ public class FragmentLayoutContentSettings extends Fragment implements MainConte
return; return;
} }
UserPrefsHelper.mapRenderer(app.getPrefs(), position); UserPrefsHelper.mapRenderer(userPrefs, position);
app.getUi().alert(AlertDialogFactory.restartDialog(app)); ui.alert(AlertDialogFactory.restartDialog(activity));
} }
@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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
@NonNull AppController app; private final AppCompatActivity activity;
@NonNull MapComponent map; private final MapComponent map;
@NonNull UIComponent ui; private final UIComponent ui;
@NonNull RegistryStorageComponent registry; private final RegistryStorageComponent registry;
private final Integer region; private final Integer region;
@@ -52,14 +52,16 @@ 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();
app.getRegistry().getStyles().forEach((id, style) -> { registry.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)).makeView(ui); () -> this.styleDetails(id), activity).makeView(ui);
if (Objects.equals(map.styleId, id)) item.findViewById(R.id.indicator)
.setVisibility(View.VISIBLE);
stylesLayout.addView(item);
}); });
Bitmap addNewIcon = BitmapFactory.decodeResource(app.getActivity().getResources(), android.R.drawable.ic_menu_add); Bitmap addNewIcon = BitmapFactory.decodeResource(activity.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));
@@ -92,11 +94,11 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
} }
void newStyleFlow() { void newStyleFlow() {
new NewStyleBottomSheet(app, map, ui, this).show(app.getActivity().getSupportFragmentManager(), "NewStyleBottomSheet"); new NewStyleBottomSheet(activity, map, ui, registry, this).show(activity.getSupportFragmentManager(), "NewStyleBottomSheet");
} }
void styleDetails(Integer id) { void styleDetails(Integer id) {
new StyleDetailsBottomSheet(app, this, id).show(app.getActivity().getSupportFragmentManager(), "StyleDetailsBottomSheet"); new StyleDetailsBottomSheet(activity, map, ui, registry, this, id).show(activity.getSupportFragmentManager(), "StyleDetailsBottomSheet");
} }
void setStyle(Integer id) { void setStyle(Integer id) {
@@ -104,12 +106,12 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
reloadStyles(); reloadStyles();
} }
public FragmentMapChangePopup(AppController app, Integer region) { public FragmentMapChangePopup(AppCompatActivity activity, UIComponent ui, MapComponent map, RegistryStorageComponent registry, Integer region) {
super(R.layout.popup_map_change); super(R.layout.popup_map_change);
this.app = app; this.activity = activity;
this.map = app.getMap(); this.ui = ui;
this.ui = app.getUi(); this.map = map;
this.registry = app.getRegistry(); this.registry = registry;
this.region = region; this.region = region;
} }
@@ -1,23 +1,22 @@
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.AppController; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
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 {
@NonNull AppController app; private final ComponentHolderActivity activity;
Toolbar toolbar;
public Screen(AppController app, Map<Integer, UIRegion> regions) { public Screen(ComponentHolderActivity activity, Map<Integer, UIRegion> regions) {
this.app = app; this.activity = activity;
this.uiRegions = regions; this.uiRegions = regions;
} }
Map<Integer, UIRegion> uiRegions; Map<Integer, UIRegion> uiRegions;
@@ -55,7 +54,7 @@ public class Screen {
} }
public void fragmentTransaction(int layoutId, Fragment fragment) { public void fragmentTransaction(int layoutId, Fragment fragment) {
app.getActivity().getSupportFragmentManager() activity.getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.replace(layoutId, fragment) .replace(layoutId, fragment)
.commit(); .commit();
@@ -1,6 +0,0 @@
package eu.konggdev.strikemaps.ui.screen.definition;
public enum DefinedScreen {
MAIN,
SETTINGS,
OFFLINE
}
@@ -0,0 +1,67 @@
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);
}
}
}
@@ -0,0 +1,22 @@
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;
}
}
}
@@ -1,4 +1,4 @@
package eu.konggdev.strikemaps.app.util; package eu.konggdev.strikemaps.util.json;
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;
+1 -3
View File
@@ -4,13 +4,11 @@ The following files included inside the /res/drawable folder are derived from Go
* `ic_bubble.xml` * `ic_bubble.xml`
* `ic_stack.xml` * `ic_stack.xml`
* `ic_clarify.xml` * `ic_clarify.xml`
*
The following files included inside the /res/drawable folder are copies of Google Material Icons and are subject to the Apache License, Version 2.0:
* `ic_file.xml` * `ic_file.xml`
* `ic_offline.xml` * `ic_offline.xml`
* `ic_arrow_forward.xml` * `ic_arrow_forward.xml`
* `ic_hide.bmp` * `ic_hide.bmp`
* `ic_dropdown.xml` * `ic_dropdown.xml`
Unless otherwise noted in this file, all other files included in the `res` folder are subject to the standard license of this project Unless otherwise noted in this file, all other files included in the `res` folder are subject to the standard license of this project
+4 -9
View File
@@ -1,10 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
android:width="24dp"
android:height="24dp" <path android:fillColor="@android:color/white" android:pathData="M360,720Q327,720 303.5,696.5Q280,673 280,640L280,160Q280,127 303.5,103.5Q327,80 360,80L720,80Q753,80 776.5,103.5Q800,127 800,160L800,640Q800,673 776.5,696.5Q753,720 720,720L360,720ZM360,640L720,640Q720,640 720,640Q720,640 720,640L720,160Q720,160 720,160Q720,160 720,160L360,160Q360,160 360,160Q360,160 360,160L360,640Q360,640 360,640Q360,640 360,640ZM200,880Q167,880 143.5,856.5Q120,833 120,800L120,240L200,240L200,800Q200,800 200,800Q200,800 200,800L640,800L640,880L200,880ZM360,640Q360,640 360,640Q360,640 360,640L360,160Q360,160 360,160Q360,160 360,160L360,160Q360,160 360,160Q360,160 360,160L360,640Q360,640 360,640Q360,640 360,640Z"/>
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M16,1H4C2.9,1 2,1.9 2,3v14h2V3h12V1zM19,5H8C6.9,5 6,5.9 6,7v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2V7C21,5.9 20.1,5 19,5zM19,21H8V7h11V21z"/>
</vector> </vector>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M11.07,12.85c0.77,-1.39 2.25,-2.21 3.11,-3.44 0.91,-1.29 0.4,-3.7 -2.18,-3.7 -1.69,0 -2.52,1.28 -2.87,2.34L6.54,6.96C7.25,4.83 9.18,3 11.99,3c2.35,0 3.96,1.07 4.78,2.41 0.7,1.15 1.11,3.3 0.03,4.9 -1.2,1.77 -2.35,2.31 -2.97,3.45 -0.25,0.46 -0.35,0.76 -0.35,2.24h-2.89C10.58,15.22 10.46,13.95 11.07,12.85zM14,20c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2z"/>
</vector>
+7
View File
@@ -0,0 +1,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#FFFFFF" />
</shape>
+2 -2
View File
@@ -97,7 +97,7 @@
android:layout_height="30dp" android:layout_height="30dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:src="@drawable/ic_file" android:src="@drawable/ic_file"
app:tint="#A4A3A3" app:tint="#6d6c6c"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
@@ -148,7 +148,7 @@
android:layout_height="30dp" android:layout_height="30dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:src="@drawable/ic_create" android:src="@drawable/ic_create"
app:tint="#A4A3A3" app:tint="#6d6c6c"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
@@ -20,42 +20,42 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView <LinearLayout
android:id="@+id/styleType" android:id="@+id/styleManagementInfo"
android:layout_width="112dp" android:layout_width="wrap_content"
android:layout_height="27dp"
android:layout_marginTop="4dp"
android:gravity="center"
android:text="Style Type?"
android:textColor="#FDFDFD"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/styleName" />
<TextView
android:id="@+id/builtInStyleAlert"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="4dp"
android:paddingHorizontal="14dp" android:orientation="horizontal"
android:paddingVertical="12dp"
android:background="@drawable/bg_alert_warning"
android:text="Built-in styles can't be edited directly\nMake a copy to customize it"
android:textColor="#FFD54F"
android:textSize="14sp"
android:lineSpacingExtra="2dp"
android:gravity="center" android:gravity="center"
android:drawablePadding="8dp" app:layout_constraintTop_toBottomOf="@id/styleName"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/styleType"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/styleType"
android:layout_width="112dp"
android:layout_height="27dp"
android:gravity="center"
android:text="Style Type?"
android:textColor="#A4A3A3"
android:textSize="18sp" />
<ImageView
android:id="@+id/managedStyleIndicator"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_marginStart="-8dp"
android:layout_marginTop="2dp"
android:visibility="gone"
android:background="@android:color/transparent"
android:src="@drawable/ic_arrow_forward"
app:tint="#FFFFFF"
android:contentDescription="Manage updates" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:id="@+id/editButton" android:id="@+id/optionsButton"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="38dp" android:layout_height="38dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
@@ -67,7 +67,56 @@
app:cardElevation="0dp" app:cardElevation="0dp"
app:strokeColor="#292828" app:strokeColor="#292828"
app:strokeWidth="1dp" app:strokeWidth="1dp"
app:layout_constraintTop_toBottomOf="@id/builtInStyleAlert" app:layout_constraintTop_toBottomOf="@id/styleManagementInfo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/optionsIcon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="16dp"
android:src="@drawable/ic_sliders"
app:tint="#A4A3A3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/optionsBtnText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Options"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/editButton"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_marginTop="6dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="#1B1A1A"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"
app:strokeColor="#292828"
app:strokeWidth="1dp"
app:layout_constraintTop_toBottomOf="@id/optionsButton"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"> app:layout_constraintEnd_toEndOf="parent">
@@ -130,7 +179,7 @@
android:layout_height="30dp" android:layout_height="30dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:src="@drawable/ic_copy" android:src="@drawable/ic_copy"
app:tint="#A4A3A3" app:tint="#6d6c6c"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
@@ -251,55 +300,4 @@
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/closeButton"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="10dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="#1B1A1A"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"
app:strokeColor="#292828"
app:strokeWidth="1dp"
app:layout_constraintTop_toBottomOf="@id/deleteButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/closeIcon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="16dp"
android:src="@android:drawable/ic_menu_more"
app:tint="#A4A3A3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/closeText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Close"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
+28 -20
View File
@@ -1,27 +1,35 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:gravity="center" android:gravity="center"
android:padding="8dp"> android:padding="8dp">
<ImageButton <ImageButton
android:id="@+id/image" android:id="@+id/image"
android:layout_width="54dp" android:layout_width="54dp"
android:layout_height="47dp" android:layout_height="46dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="@android:color/transparent"
android:contentDescription="Style Image" android:contentDescription="Image"
android:src="@android:drawable/ic_menu_gallery" /> android:src="@android:drawable/ic_menu_gallery"
android:padding="0dp" />
<TextView <TextView
android:id="@+id/name" android:id="@+id/name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:gravity="center" android:gravity="center"
android:text="Item Name" android:text="Name"
android:textColor="#FFFFFF" android:textColor="#FFFFFF"
android:textSize="14sp" /> android:textSize="14sp" />
<View
android:id="@+id/indicator"
android:layout_width="24dp"
android:layout_height="3dp"
android:layout_marginTop="5dp"
android:visibility="gone"
android:background="@drawable/indicator"/>
</LinearLayout> </LinearLayout>