Compare commits

...
5 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
10 changed files with 108 additions and 86 deletions

No files matched your search

+2 -2
View File
@@ -9,7 +9,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.konggdev.strikemaps" applicationId = "eu.konggdev.strikemaps"
minSdk = 24 minSdk = 23
targetSdk = 36 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" />
@@ -1,6 +1,8 @@
package eu.konggdev.strikemaps.activity; package eu.konggdev.strikemaps.activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import eu.konggdev.strikemaps.Component; import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
@@ -10,21 +12,60 @@ import android.os.Bundle;
import eu.konggdev.strikemaps.map.MapComponent; import eu.konggdev.strikemaps.map.MapComponent;
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.screen.definition.DefinedScreen; 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.List;
import java.util.Map;
public class MainActivity extends ComponentHolderActivity { public class MainActivity extends ComponentHolderActivity {
private List<Component> components; private List<Component> components;
private UIComponent ui; 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() { private List<Component> initComponents() {
SharedPreferences userPrefs = getSharedPreferences("user_prefs", MODE_PRIVATE); SharedPreferences userPrefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
RegistryStorageComponent registry = new RegistryStorageComponent(this, userPrefs); RegistryStorageComponent registry = new RegistryStorageComponent(this, userPrefs);
MapComponent mapComponent = new MapComponent(this, registry, userPrefs); MapComponent map = new MapComponent(this, registry, userPrefs);
this.ui = new UIComponent(this, mapComponent, registry, userPrefs, DefinedScreen.MAIN); UIComponent ui = new UIComponent(this, map, registry, userPrefs);
ui.defineScreens(initScreens(ui, map, registry, userPrefs));
this.ui = ui;
return List.of( return List.of(
mapComponent, map,
ui, ui,
registry registry
); );
@@ -33,13 +74,17 @@ public class MainActivity extends ComponentHolderActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
components = initComponents(); this.components = initComponents();
ui.swapScreen("main");
setContentView(R.layout.view_main); setContentView(R.layout.view_main);
} getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
@Override public void handleOnBackPressed() {
public void onBackPressed() { if (!ui.back()) {
if (ui.back()) setEnabled(false);
super.onBackPressed(); getOnBackPressedDispatcher().onBackPressed();
}
}
});
} }
} }
@@ -2,6 +2,7 @@ package eu.konggdev.strikemaps.ui;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log;
import android.view.View; import android.view.View;
import eu.konggdev.strikemaps.Component; import eu.konggdev.strikemaps.Component;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
@@ -15,12 +16,13 @@ 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;
public class UIComponent implements Component { public class UIComponent implements Component {
private final String TAG = "UIComponent";
private final ComponentHolderActivity activity; private final ComponentHolderActivity activity;
private final MapComponent map; private final MapComponent map;
@@ -30,47 +32,28 @@ public class UIComponent implements Component {
private final ArrayDeque<Screen> screenStack = new ArrayDeque<>(); private final ArrayDeque<Screen> screenStack = new ArrayDeque<>();
public UIComponent(ComponentHolderActivity activity, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs, DefinedScreen firstScreen) { private Map<String, Screen> screens;
public UIComponent(ComponentHolderActivity activity, MapComponent map, RegistryStorageComponent registry, SharedPreferences userPrefs) {
this.activity = activity; this.activity = activity;
this.map = map; this.map = map;
this.registry = registry; this.registry = registry;
this.userPrefs = userPrefs; this.userPrefs = userPrefs;
swapScreen(firstScreen);
} }
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(
activity,
//Main screen init regions definition
Map.of(
R.id.mainContentView, new MainContentRegion(map.toFragment(), R.id.mainContentView),
R.id.bottomUi, new UIRegion(new FragmentLayoutControls(activity, this, map, registry, userPrefs, R.id.bottomUi), R.id.bottomUi),
R.id.topUi, new UIRegion(new FragmentLayoutSearch(activity, this, R.id.topUi), R.id.topUi)
) //TODO: Probably stop referencing layout 3(!) times everytime
),
//Settings screen
DefinedScreen.SETTINGS, new Screen(
activity,
//Just the settings content fragment
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentSettings(activity, this, userPrefs), R.id.mainContentView)
)
),
//Offline maps screen
DefinedScreen.OFFLINE, new Screen(
activity,
Map.of(
R.id.mainContentView, new MainContentRegion(new FragmentLayoutContentOfflineMaps(activity), 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();
} }
@@ -5,13 +5,11 @@ 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 androidx.appcompat.app.AppCompatActivity;
import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity;
import eu.konggdev.strikemaps.util.file.FileTools;
import eu.konggdev.strikemaps.map.style.document.StyleDocument; import eu.konggdev.strikemaps.map.style.document.StyleDocument;
import eu.konggdev.strikemaps.ui.UIComponent; import eu.konggdev.strikemaps.ui.UIComponent;
import eu.konggdev.strikemaps.util.icon.IconResolver;
public class GenericItem implements UIItem { public class GenericItem implements UIItem {
public String name; public String name;
@@ -63,14 +61,14 @@ public class GenericItem implements UIItem {
public GenericItem(StyleDocument style, Runnable onClick, AppCompatActivity activity) { public GenericItem(StyleDocument style, Runnable onClick, AppCompatActivity activity) {
if (style == null) return; if (style == null) return;
this.name = style.name; this.name = style.name;
this.image = style.icon != null ? FileTools.getIcon(style.icon, activity) : null; this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
this.onClick = onClick; this.onClick = onClick;
} }
public GenericItem(StyleDocument style, Runnable onClick, Runnable onLongClick, AppCompatActivity activity) { public GenericItem(StyleDocument style, Runnable onClick, Runnable onLongClick, AppCompatActivity activity) {
if (style == null) return; if (style == null) return;
this.name = style.name; this.name = style.name;
this.image = style.icon != null ? FileTools.getIcon(style.icon, activity) : null; this.image = style.icon != null ? IconResolver.getIcon(style.icon, activity) : null;
this.onClick = onClick; this.onClick = onClick;
this.onLongClick = onLongClick; this.onLongClick = onLongClick;
} }
@@ -10,12 +10,9 @@ import android.widget.PopupWindow;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; 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.ComponentHolderActivity;
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.screen.definition.DefinedScreen;
public class FragmentLayoutSearch extends Fragment implements Layout { public class FragmentLayoutSearch extends Fragment implements Layout {
private final AppCompatActivity activity; private final AppCompatActivity activity;
@@ -64,7 +61,7 @@ public class FragmentLayoutSearch extends Fragment implements Layout {
setupButton(menuView, R.id.menuSettings, click(() -> { setupButton(menuView, R.id.menuSettings, click(() -> {
popupWindow.dismiss(); popupWindow.dismiss();
ui.swapScreen(DefinedScreen.SETTINGS); ui.swapScreen("settings");
})); }));
menuView.findViewById(R.id.menuSearchSettings).setOnClickListener(v -> popupWindow.dismiss()); menuView.findViewById(R.id.menuSearchSettings).setOnClickListener(v -> popupWindow.dismiss());
@@ -8,12 +8,11 @@ import eu.konggdev.strikemaps.R;
import eu.konggdev.strikemaps.app.ComponentHolderActivity; import eu.konggdev.strikemaps.app.ComponentHolderActivity;
public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout { public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout {
@NonNull private final ComponentHolderActivity activity;
ComponentHolderActivity app;
public FragmentLayoutContentOfflineMaps(ComponentHolderActivity 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
@@ -28,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,6 +0,0 @@
package eu.konggdev.strikemaps.ui.screen.definition;
public enum DefinedScreen {
MAIN,
SETTINGS,
OFFLINE
}
@@ -7,26 +7,11 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import android.util.Log;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
//FIXME: Ugly //FIXME: Ugly
public final class FileTools { public final class FileTools {
private static final String TAG = "FileUtils"; private static final String TAG = "FileTools";
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;
}
}
public static String loadStringFromAssetFile(String filePath, AppCompatActivity activity) { public static String loadStringFromAssetFile(String filePath, AppCompatActivity activity) {
try (InputStream is = activity.getAssets().open(filePath)) { try (InputStream is = activity.getAssets().open(filePath)) {
@@ -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;
}
}
}