From 6834bc65106e8cc6ad14097acfae81c9fe2915cc Mon Sep 17 00:00:00 2001 From: konggdev Date: Mon, 13 Jul 2026 00:57:52 +0200 Subject: [PATCH] Preparation skeleton for Offline maps implementation --- app/build.gradle.kts | 2 +- .../map/offline/OfflineTileResolver.java | 10 ++++ .../offline/download/OfflineDownloader.java | 22 +++++++ .../konggdev/strikemaps/ui/UIComponent.java | 8 +++ .../ui/element/item/PreviewItem.java | 13 +++-- .../strikemaps/ui/element/item/UIItem.java | 1 - .../fragment/layout/FragmentLayoutSearch.java | 42 +++++++++++++- .../FragmentLayoutContentOfflineMaps.java | 58 +++++++++++++++++++ .../ui/screen/definition/DefinedScreen.java | 3 +- .../main/res/drawable/ic_arrow_forward.xml | 10 ++++ app/src/main/res/drawable/ic_offline.xml | 5 ++ .../{menu_dropdown.xml => dropdown_main.xml} | 0 app/src/main/res/layout/dropdown_offline.xml | 34 +++++++++++ app/src/main/res/layout/fragment_map.xml | 1 - .../main/res/layout/fragment_offline_maps.xml | 41 +++++++++++++ app/src/main/res/layout/fragment_search.xml | 13 ++++- app/src/main/res/layout/item_preview.xml | 14 ++--- build.gradle.kts | 2 +- gradle/libs.versions.toml | 3 - 19 files changed, 257 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/eu/konggdev/strikemaps/map/offline/OfflineTileResolver.java create mode 100644 app/src/main/java/eu/konggdev/strikemaps/map/offline/download/OfflineDownloader.java create mode 100644 app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentOfflineMaps.java create mode 100644 app/src/main/res/drawable/ic_arrow_forward.xml create mode 100644 app/src/main/res/drawable/ic_offline.xml rename app/src/main/res/layout/{menu_dropdown.xml => dropdown_main.xml} (100%) create mode 100644 app/src/main/res/layout/dropdown_offline.xml create mode 100644 app/src/main/res/layout/fragment_offline_maps.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fa6c589..4751dd8 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { implementation(libs.constraintlayout) implementation(libs.viewpager2) + implementation("androidx.core:core-ktx:1.17.0") implementation("org.osmdroid:osmdroid-android:6.1.20") implementation("org.maplibre.gl:android-sdk:11.13.0") implementation("com.github.mapsforge.vtm:vtm:0.27.0") @@ -61,7 +62,6 @@ dependencies { implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.fasterxml.jackson.core:jackson-databind:2.15.0") implementation("org.apache.commons:commons-lang3:3.14.0") - implementation(libs.core.ktx) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/offline/OfflineTileResolver.java b/app/src/main/java/eu/konggdev/strikemaps/map/offline/OfflineTileResolver.java new file mode 100644 index 0000000..648c492 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/offline/OfflineTileResolver.java @@ -0,0 +1,10 @@ +package eu.konggdev.strikemaps.map.offline; + +import java.io.IOException; +public final class OfflineTileResolver { + public byte[] resolve(String url) throws IOException { + + //byte[] data = getOfflineTile(); + return null; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/offline/download/OfflineDownloader.java b/app/src/main/java/eu/konggdev/strikemaps/map/offline/download/OfflineDownloader.java new file mode 100644 index 0000000..fa35e30 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/offline/download/OfflineDownloader.java @@ -0,0 +1,22 @@ +package eu.konggdev.strikemaps.map.offline.download; + +import eu.konggdev.strikemaps.map.source.MapSource; + +import java.net.URI; + +public final class OfflineDownloader { + + public static String[] fetchAvailableExports(MapSource source) { + URI uri = URI.create(source.url); + String host = uri.getHost(); + return new String[0]; + } + + public static void download(MapSource source, String export) { + + } + + public static void download(MapSource source, int[] bounds) { + + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java b/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java index d52f22b..7f8195a 100644 --- a/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java @@ -12,6 +12,7 @@ import eu.konggdev.strikemaps.ui.element.region.content.MainContentRegion; import eu.konggdev.strikemaps.ui.element.region.UIRegion; 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 eu.konggdev.strikemaps.ui.screen.definition.DefinedScreen; @@ -51,6 +52,13 @@ public class UIComponent implements Component { 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) + ) ) ); } diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/PreviewItem.java b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/PreviewItem.java index 773c272..329d87c 100644 --- a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/PreviewItem.java +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/PreviewItem.java @@ -4,33 +4,36 @@ import android.graphics.Bitmap; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; import eu.konggdev.strikemaps.ui.UIComponent; import org.maplibre.geojson.Feature; import eu.konggdev.strikemaps.R; public class PreviewItem implements UIItem { - public String name; - public String type; + @NonNull public String name; + public String details; public Bitmap image; boolean hasImage; public PreviewItem(String refName, String refType) { this.name = refName; - this.type = refType; + this.details = refType; hasImage = false; } public PreviewItem(String refName, String refType, Bitmap refImage) { this.name = refName; - this.type = refType; + this.details = refType; this.image = refImage; hasImage = true; } + public static PreviewItem fromFeature(Feature feature) { return new PreviewItem(feature.getStringProperty("name"), feature.getStringProperty("class")); } public View makeView(UIComponent spawner) { View view = spawner.inflateUi(R.layout.item_preview); ((TextView) view.findViewById(R.id.choiceName)).setText(name); - ((TextView) view.findViewById(R.id.type)).setText(type); + if (details != null) + ((TextView) view.findViewById(R.id.details)).setText(details); return view; } public View makeView(UIComponent spawner, View.OnClickListener onClick) { diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/UIItem.java b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/UIItem.java index 7f14bdc..b901dd2 100644 --- a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/UIItem.java +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/UIItem.java @@ -12,5 +12,4 @@ public interface UIItem { } default View.OnLongClickListener longClick(Runnable action) { return v -> { action.run(); return true; };} - } diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutSearch.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutSearch.java index 4b9225a..7b0f5b6 100644 --- a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutSearch.java +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutSearch.java @@ -1,6 +1,5 @@ package eu.konggdev.strikemaps.ui.fragment.layout; -import android.app.AlertDialog; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; @@ -10,7 +9,6 @@ import android.view.ViewGroup; import android.widget.PopupWindow; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import android.widget.PopupMenu; import eu.konggdev.strikemaps.R; import eu.konggdev.strikemaps.app.AppController; @@ -41,9 +39,11 @@ public class FragmentLayoutSearch extends Fragment implements Layout { public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + + setupButton(view, R.id.hamburgerButton, click(() -> { - View menuView = getLayoutInflater().inflate(R.layout.menu_dropdown, null); + View menuView = getLayoutInflater().inflate(R.layout.dropdown_main, null); PopupWindow popupWindow = new PopupWindow( menuView, @@ -85,5 +85,41 @@ public class FragmentLayoutSearch extends Fragment implements Layout { }); })); + + setupButton(view, R.id.offlineMapsButton, click(() -> { + View offlineMapsPopupView = getLayoutInflater().inflate(R.layout.dropdown_offline, null); + + PopupWindow popupWindow = new PopupWindow( + offlineMapsPopupView, + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + true + ); + + popupWindow.setOutsideTouchable(true); + popupWindow.setFocusable(true); + popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + + View anchor = view.findViewById(R.id.searchContainer); + + setupButton(offlineMapsPopupView, R.id.offlineMaps, click(() -> { + popupWindow.dismiss(); + app.getUi().swapScreen(DefinedScreen.OFFLINE); + })); + + anchor.post(() -> { + + offlineMapsPopupView.measure( + View.MeasureSpec.UNSPECIFIED, + View.MeasureSpec.UNSPECIFIED + ); + + int popupWidth = offlineMapsPopupView.getMeasuredWidth(); + int containerWidth = anchor.getWidth(); + + int xOffset = containerWidth - popupWidth; + popupWindow.showAsDropDown(anchor, xOffset, 1); + }); + })); } } diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentOfflineMaps.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentOfflineMaps.java new file mode 100644 index 0000000..840f36d --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentOfflineMaps.java @@ -0,0 +1,58 @@ +package eu.konggdev.strikemaps.ui.fragment.layout.content.main; + +import android.os.Bundle; +import android.view.View; +import android.widget.LinearLayout; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.data.helper.FileHelper; +import eu.konggdev.strikemaps.map.source.MapSource; +import eu.konggdev.strikemaps.map.style.MapStyle; +import eu.konggdev.strikemaps.ui.element.item.GenericItem; +import eu.konggdev.strikemaps.ui.element.item.PreviewItem; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class FragmentLayoutContentOfflineMaps extends Fragment implements MainContentLayout { + @NonNull AppController app; + + public FragmentLayoutContentOfflineMaps(AppController app) { + super(R.layout.fragment_offline_maps); + this.app = app; + } + + @Override + public Fragment toFragment() { + return this; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + List sources = new ArrayList<>(); + + List stylePaths = new ArrayList<>(); + stylePaths.addAll(Arrays.asList(FileHelper.getAssetFiles("bundled/style", ".style.json", app))); + stylePaths.addAll(Arrays.asList(FileHelper.getUserFiles("style", ".style.json", app))); + /* Parsing an entire MapStyle is absolutely unnecessary and resource wasteful + TODO: A method should be implemented to parse a List directly from the JSON */ + for (String stylePath : stylePaths) { + MapStyle parsedStyle = MapStyle.fromFile(stylePath, app); + sources.addAll(parsedStyle.sources.values()); + } + + LinearLayout sourcesLayout = view.findViewById(R.id.llDownloadContainer); + for (MapSource source : sources) { + if (!Objects.equals(source.type, "raster")) + sourcesLayout.addView(new PreviewItem(source.url, "").makeView(app.getUi())); + else + sourcesLayout.addView(new PreviewItem(source.tiles.toString(), "").makeView(app.getUi())); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/screen/definition/DefinedScreen.java b/app/src/main/java/eu/konggdev/strikemaps/ui/screen/definition/DefinedScreen.java index 72abed5..436fd04 100644 --- a/app/src/main/java/eu/konggdev/strikemaps/ui/screen/definition/DefinedScreen.java +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/screen/definition/DefinedScreen.java @@ -1,5 +1,6 @@ package eu.konggdev.strikemaps.ui.screen.definition; public enum DefinedScreen { MAIN, - SETTINGS + SETTINGS, + OFFLINE } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_forward.xml b/app/src/main/res/drawable/ic_arrow_forward.xml new file mode 100644 index 0000000..91637db --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_forward.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_offline.xml b/app/src/main/res/drawable/ic_offline.xml new file mode 100644 index 0000000..88552c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_offline.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/menu_dropdown.xml b/app/src/main/res/layout/dropdown_main.xml similarity index 100% rename from app/src/main/res/layout/menu_dropdown.xml rename to app/src/main/res/layout/dropdown_main.xml diff --git a/app/src/main/res/layout/dropdown_offline.xml b/app/src/main/res/layout/dropdown_offline.xml new file mode 100644 index 0000000..a75f4e7 --- /dev/null +++ b/app/src/main/res/layout/dropdown_offline.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml index e48b1ca..34c1dc2 100644 --- a/app/src/main/res/layout/fragment_map.xml +++ b/app/src/main/res/layout/fragment_map.xml @@ -2,5 +2,4 @@ - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_offline_maps.xml b/app/src/main/res/layout/fragment_offline_maps.xml new file mode 100644 index 0000000..91356b6 --- /dev/null +++ b/app/src/main/res/layout/fragment_offline_maps.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index 2651ed8..739cd5c 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:padding="6dp"> + android:padding="12dp"> + + diff --git a/build.gradle.kts b/build.gradle.kts index 922f551..7f09f7c 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,4 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2cbdcc4..99c4324 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,6 @@ constraintlayout = "2.1.4" playServicesMaps = "19.0.0" viewpager2 = "1.1.0" kotlin = "2.3.10" -coreKtx = "1.18.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -20,9 +19,7 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a material = { group = "com.google.android.material", name = "material", version.ref = "material" } activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } -play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" } viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", version.ref = "viewpager2" } -core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }