commit 31c92aeae90bf50ef2c9ffa66fc3b0c6230cd47f Author: konggdev Date: Mon Apr 13 20:19:02 2026 +0200 WIP diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..825f06d --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.gradle +/local.properties +/.idea/ +DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +/legacy_code/ diff --git a/UNLICENSE b/UNLICENSE new file mode 100644 index 0000000..c32dd18 --- /dev/null +++ b/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100755 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100755 index 0000000..65d0dca --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,68 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "eu.konggdev.strikemaps" + compileSdk = 36 + + defaultConfig { + applicationId = "eu.konggdev.strikemaps" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlin { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) + } + } +} + +dependencies { + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.activity) + implementation(libs.constraintlayout) + implementation(libs.viewpager2) + + implementation("org.maplibre.gl:android-sdk:11.13.0") + implementation("com.github.mapsforge.vtm:vtm: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-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-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_64@jar") + implementation("com.google.guava:guava:33.2.1-android") + implementation("com.caverock:androidsvg:1.4") + 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) + androidTestImplementation(libs.espresso.core) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100755 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/eu/konggdev/strikemaps/ExampleInstrumentedTest.java b/app/src/androidTest/java/eu/konggdev/strikemaps/ExampleInstrumentedTest.java new file mode 100755 index 0000000..d7b24f5 --- /dev/null +++ b/app/src/androidTest/java/eu/konggdev/strikemaps/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package eu.konggdev.strikemaps; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("eu.konggdev.strikemaps", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..438c4aa --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/bundled/icon/classic.bmp b/app/src/main/assets/bundled/icon/classic.bmp new file mode 100644 index 0000000..faa1a3a Binary files /dev/null and b/app/src/main/assets/bundled/icon/classic.bmp differ diff --git a/app/src/main/assets/bundled/icon/satelite.bmp b/app/src/main/assets/bundled/icon/satelite.bmp new file mode 100644 index 0000000..0a2c833 Binary files /dev/null and b/app/src/main/assets/bundled/icon/satelite.bmp differ diff --git a/app/src/main/assets/bundled/style/classic.style.json b/app/src/main/assets/bundled/style/classic.style.json new file mode 100644 index 0000000..f877c58 --- /dev/null +++ b/app/src/main/assets/bundled/style/classic.style.json @@ -0,0 +1,2262 @@ +{ + "version": 8, + "name": "Classic", + "icon": "assets://classic.bmp", + "description": "An SmTs (StrikeMaps TileSchema) style made by and for the Strike Maps project, designed to ressemble OSM Carto", + "sources": { + "smts": { + "type": "vector", + "url": "https://tile.strikemaps.eu/dev", + "schema": "smts" + } + }, + "sprite": "https://api.maptiler.com/maps/openstreetmap/sprite", + "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=yMD02x1nBSBNl60HNyf2", + "layers": [ + { + "id": "Background", + "type": "background", + "paint": { + "background-color": "rgba(242, 239, 233, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Residential", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(225, 224, 224, 1)", + "fill-antialias": false + }, + "filter": [ + "all", + [ + "==", + "subclass", + "residential" + ] + ] + }, + { + "id": "Pedestrian path outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "#a5a19d", + "line-width": { + "stops": [ + [9, 6], + [11, 2.5], + [12, 3.2], + [13, 4.2], + [15, 8.2], + [16, 12.7], + [17, 16.7], + [18, 17.2], + [19, 25.2] + ] + } + }, + "filter": [ + "all", + [ + "==", + "subclass", + "pedestrian" + ], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Pedestrian", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "#DEDEE8" + }, + "filter": [ + "all", + ["==", "subclass", "pedestrian"] + ] + }, + { + "id": "Retail", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(255, 214, 209, 1)" + }, + "filter": [ + "all", + ["in", "subclass", "retail"] + ] + }, + { + "id": "Commercial", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(242, 218, 217, 1)" + }, + "filter": [ + "all", + ["in", "subclass", "commercial"] + ] + }, + { + "id": "Scrub", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "scrub"] + ], + "paint": { + "fill-color": "rgba(200, 215, 171, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Scrub Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "scrub"] + ], + "layout": { + "visibility": "visible" + }, + "paint": {"fill-pattern": "scrub"} + }, + { + "id": "Forest", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(173, 209, 158, 1)" + }, + "filter": [ + "all", + ["==", "subclass", "forest"] + ] + }, + { + "id": "Generic Forest Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "forest"], + ["!has", "leaf_type"] + ], + "paint": { + "fill-pattern": "leaftype_unknown", + "fill-opacity": 0.4 + } + }, + { + "id": "Broadleaved Forest Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "forest"], + [ + "==", + "leaf_type", + "broadleaved" + ] + ], + "paint": { + "fill-pattern": "leaftype_broadleaved", + "fill-opacity": 0.4 + } + }, + { + "id": "Leafless Forest Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "forest"], + ["==", "leaf_type", "leafless"] + ], + "paint": { + "fill-pattern": "leaftype_leafless", + "fill-opacity": 0.4 + } + }, + { + "id": "Mixed Forest Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "forest"], + ["==", "leaf_type", "mixed"] + ], + "paint": { + "fill-pattern": "leaftype_mixed", + "fill-opacity": 0.4 + } + }, + { + "id": "Wood", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "wood"] + ], + "paint": {"fill-color": "#ADD19E"} + }, + { + "id": "Wood Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "wood"] + ], + "paint": { + "fill-pattern": "leaftype_unknown" + } + }, + { + "id": "Grass", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(206, 236, 177, 1)" + }, + "filter": [ + "all", + ["==", "subclass", "grass"] + ], + "layout": { + "visibility": "visible" + } + }, + { + "id": "Dog Park", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "dog_park"] + ], + "paint": {"fill-color": "#dffce2"} + }, + { + "id": "Stadium", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "stadium"] + ], + "paint": { + "fill-color": "#D6FFDA" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Sports Centre", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + [ + "==", + "subclass", + "sports_centre" + ] + ], + "paint": {"fill-color": "#dffce2"} + }, + { + "id": "Sports Centre Outline", + "type": "line", + "source": "smts", + "source-layer": "landarea", + "paint": { + "line-color": "#82b39f", + "line-width": 0.5 + }, + "filter": [ + "all", + [ + "in", + "subclass", + "sports_centre" + ] + ] + }, + { + "id": "Track", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "track"] + ], + "paint": { + "fill-color": "#A9E0CB" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Park", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "paint": { + "fill-color": "rgba(200, 250, 204, 1)" + }, + "filter": [ + "all", + ["==", "subclass", "park"] + ] + }, + { + "id": "Pitch", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "pitch"] + ], + "paint": { + "fill-color": "#A9E0CB" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Stadium Outlines", + "type": "line", + "source": "smts", + "source-layer": "landarea", + "paint": { + "line-color": "#82b39f" + }, + "filter": [ + "all", + [ + "in", + "subclass", + "pitch", + "stadium", + "track" + ] + ] + }, + { + "id": "Pedestrian Outline", + "type": "line", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "pedestrian"] + ], + "paint": {"line-color": "#a5a19d"} + }, + { + "id": "Garden", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "garden"] + ], + "paint": { + "fill-color": "rgba(206, 236, 177, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Garden Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "garden"] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-pattern": "plant_nursery", + "fill-opacity": 0.6 + } + }, + { + "id": "Contour", + "type": "line", + "source": "smts", + "source-layer": "contour", + "paint": { + "line-color": "rgba(75, 73, 73, 0.43)", + "line-width": 0.3 + } + }, + { + "id": "Flowerbed", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "flowerbed"] + ], + "paint": { + "fill-color": "rgba(205, 235, 176, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Cemetery", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "cemetery"] + ], + "paint": { + "fill-color": "hsl(129, 24%, 73%)", + "fill-opacity": 1, + "fill-translate-anchor": "map" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Cemetery Pattern", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "cemetery"] + ], + "paint": { + "fill-pattern": "grave_yard_generic" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Education and Health", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + [ + "in", + "subclass", + "school", + "university", + "kindergarten", + "college", + "hospital" + ] + ], + "paint": { + "fill-color": "rgba(255, 255, 229, 1)" + } + }, + { + "id": "Parking", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "parking"] + ], + "paint": {"fill-color": "#eeeeee"} + }, + { + "id": "Parking Outline", + "type": "line", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "parking"] + ], + "paint": { + "line-width": 0.5, + "line-color": "#aeaeb2" + } + }, + { + "id": "Construction", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + [ + "==", + "subclass", + "construction" + ] + ], + "paint": { + "fill-color": "rgba(199, 199, 180, 1)" + } + }, + { + "id": "Ocean", + "type": "fill", + "source": "smts", + "source-layer": "ocean", + "paint": { + "fill-color": "rgba(170, 211, 223, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Building", + "type": "fill", + "source": "smts", + "source-layer": "building", + "paint": { + "fill-color": "rgba(217, 208, 201, 1)", + "fill-outline-color": "rgba(201, 185, 175, 1)" + } + }, + { + "id": "Breakwater", + "type": "fill", + "source": "smts", + "source-layer": "breakwater", + "filter": [ + "all", + ["==", "subclass", "breakwater"] + ], + "paint": { + "fill-color": "#aaaaaa", + "fill-translate-anchor": "map" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Water", + "type": "fill", + "source": "smts", + "source-layer": "water", + "paint": { + "fill-color": "rgba(168, 209, 218, 1)", + "fill-antialias": true + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Pier", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "pier"] + ], + "paint": { + "fill-color": "rgba(242, 239, 233, 1)" + } + }, + { + "id": "Tree Outline", + "type": "circle", + "source": "smts", + "source-layer": "poi", + "filter": [ + "all", + ["==", "subclass", "tree"] + ], + "paint": { + "circle-color": "#b8d4a8", + "circle-radius": { + "stops": [ + [16, 3], + [17.5, 7], + [18, 7.5], + [18.5, 8], + [19, 8.5], + [19.5, 10], + [20, 10.5] + ] + } + }, + "minzoom": 15 + }, + { + "id": "Tree", + "type": "circle", + "source": "smts", + "source-layer": "poi", + "paint": { + "circle-radius": 1, + "circle-color": "rgba(23, 81, 41, 1)" + }, + "filter": [ + "all", + ["==", "subclass", "tree"] + ], + "minzoom": 15 + }, + { + "id": "Building outline", + "type": "line", + "source": "smts", + "source-layer": "building", + "paint": { + "line-color": "rgba(201, 185, 175, 1)", + "line-width": 1 + }, + "minzoom": 13 + }, + { + "id": "Playground", + "type": "fill", + "source": "smts", + "source-layer": "landarea", + "filter": [ + "all", + ["==", "subclass", "playground"] + ], + "paint": { + "fill-color": "rgba(214, 255, 218, 1)" + }, + "layout": { + "visibility": "visible" + } + }, + { + "id": "Playground outline", + "type": "line", + "source": "smts", + "source-layer": "landarea", + "paint": { + "line-color": "rgba(129, 171, 134, 1)", + "line-width": 1.1 + }, + "filter": [ + "all", + ["==", "subclass", "playground"] + ] + }, + { + "id": "Playground Symbol", + "type": "symbol", + "source": "smts", + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "icon-image": "playground", + "symbol-placement": "point", + "symbol-z-order": "auto", + "icon-size": { + "stops": [ + [15, 0.2], + [15.5, 0.21], + [16.25, 0.25], + [16.5, 0.3], + [17, 0.9], + [17.35, 1], + [19, 1.1] + ] + }, + "symbol-avoid-edges": false, + "text-pitch-alignment": "auto", + "icon-rotation-alignment": "viewport" + }, + "filter": [ + "all", + ["==", "subclass", "playground"] + ], + "source-layer": "landarea" + }, + { + "id": "Tertiary tunnel outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "tertiary"], + ["==", "tunnel", "yes"] + ], + "paint": { + "line-width": { + "stops": [ + [9, 0.7], + [10, 0.7], + [11, 1.9], + [12, 3], + [13, 4.3], + [14, 7], + [15, 5.5], + [15.5, 7.2], + [16, 11.8], + [17, 12.8], + [18, 16.8], + [20, 24.5] + ], + "type": "exponential", + "base": 1.2 + }, + "line-translate-anchor": "map", + "line-color": "rgba(95, 91, 91, 1)" + }, + "layout": { + "line-join": "round", + "line-cap": "butt", + "visibility": "visible" + } + }, + { + "id": "Tertiary tunnel", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "tertiary"], + ["==", "tunnel", "yes"] + ], + "paint": { + "line-color": "rgba(255, 255, 255, 0.95)", + "line-width": { + "stops": [ + [9, 0.7], + [10, 0.7], + [11, 1.9], + [12, 3], + [13, 3.9], + [14, 6.5], + [15, 5], + [15.5, 6.7], + [16, 11.3], + [17, 12.3], + [18, 16.3], + [20, 23.8] + ], + "type": "exponential", + "base": 1.2 + }, + "line-translate-anchor": "map" + }, + "layout": { + "line-join": "round", + "line-cap": "butt", + "visibility": "visible" + } + }, + { + "id": "Footway tunnel higlight", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "tunnel", "yes"], + ["!has", "bridge"] + ], + "paint": { + "line-color": "#333333", + "line-width": { + "base": 1.2, + "stops": [ + [13, 3.7], + [14, 3.5], + [15, 4], + [17, 4], + [18, 5] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Footway tunnel outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "tunnel", "yes"], + ["!has", "bridge"] + ], + "paint": { + "line-dasharray": [1, 0.1], + "line-width": { + "base": 1.2, + "stops": [ + [13, 2.7], + [14, 3], + [15, 3.3], + [17, 3.3], + [18, 3.6] + ] + }, + "line-color": "#FFFFFF" + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt", + "visibility": "visible" + } + }, + { + "id": "Footway tunnel", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "tunnel", "yes"], + ["!has", "bridge"] + ], + "paint": { + "line-color": "rgba(250, 126, 112, 1)", + "line-width": { + "base": 1.2, + "stops": [ + [6, 0.1], + [10, 0.4], + [15, 1], + [17, 1.1], + [18, 1.5] + ] + }, + "line-dasharray": [2, 2] + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Generic Path", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "path"] + ], + "paint": { + "line-color": "rgba(250, 126, 112, 1)", + "line-dasharray": [2, 1], + "line-width": { + "base": 1.2, + "stops": [ + [6, 0.1], + [10, 0.4], + [15, 1], + [17, 1.1], + [18, 1.5] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Footway path", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["!has", "bridge"], + ["!has", "tunnel"] + ], + "paint": { + "line-color": "rgba(250, 126, 112, 1)", + "line-dasharray": [2, 1], + "line-width": { + "base": 1.2, + "stops": [ + [6, 0.1], + [10, 0.4], + [15, 1], + [17, 1.1], + [18, 1.5] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Primary road outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(158, 116, 0, 1)", + "line-width": { + "stops": [ + [9, 6], + [11, 2.5], + [12, 3.2], + [13, 4.2], + [15, 8.2], + [16, 12.7], + [17, 16.7], + [18, 17.2], + [19, 25.2] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Residential road outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + [ + "==", + "subclass", + "residential" + ], + ["==", "$type", "LineString"] + ], + "paint": { + "line-color": "rgba(197, 191, 191, 1)", + "line-width": [ + "interpolate", + ["linear"], + ["zoom"], + 13, + 3, + 14, + 5, + 15, + 6, + 16, + 11, + 17, + 12, + 18, + 17, + 19, + 19 + ] + }, + "layout": { + "visibility": "visible", + "line-cap": "round" + } + }, + { + "id": "Service road outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "service"], + ["!=", "tunnel", "yes"] + ], + "paint": { + "line-color": "rgba(197, 191, 191, 1)", + "line-width": { + "stops": [ + [10, 0.7], + [12, 0.8], + [13, 1], + [14, 2], + [15, 4], + [16, 5], + [17, 6], + [18, 9], + [19, 14.5] + ] + }, + "line-translate-anchor": "map" + }, + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Service road", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "service"], + ["!=", "tunnel", "yes"] + ], + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "stops": [ + [10, 0.1], + [12, 0.2], + [13, 0.4], + [14, 1], + [15, 3], + [16, 4], + [17, 5], + [18, 8], + [19, 12] + ], + "type": "exponential", + "base": 1.2 + }, + "line-translate-anchor": "map" + }, + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Pedestrian path", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(222, 222, 232, 1)", + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 12], + [17, 14.5], + [18, 16], + [19, 23] + ] + } + }, + "filter": [ + "all", + [ + "==", + "subclass", + "pedestrian" + ], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Secondary road outline-copy", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(109, 122, 5, 1)", + "line-width": { + "stops": [ + [9, 6], + [11, 2.5], + [12, 3.2], + [13, 4.2], + [15, 8.2], + [16, 12.7], + [17, 16.7], + [18, 17.2], + [19, 25.2] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Secondary tunnel outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(109, 122, 5, 1)", + "line-width": { + "stops": [ + [9, 6], + [11, 3.5], + [12, 5], + [13, 5], + [15, 8], + [16, 15], + [18, 17], + [19, 25.4] + ] + }, + "line-dasharray": [0.5, 0.25] + }, + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["==", "tunnel", "yes"], + ["!=", "bridge", "yes"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Residential road", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + [ + "==", + "subclass", + "residential" + ], + ["==", "$type", "LineString"] + ], + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "stops": [ + [12, 1], + [13, 1.9], + [14, 3.8], + [15, 4.8], + [16, 9.3], + [17, 10.3], + [18, 14.3], + [19, 16.3] + ] + } + }, + "layout": { + "visibility": "visible", + "line-cap": "round" + } + }, + { + "id": "Secondary road", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(247, 250, 189, 1)", + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 12], + [17, 14.5], + [18, 16], + [19, 23] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Secondary tunnel", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(250, 252, 217, 1)", + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 12], + [17, 14.5], + [18, 16], + [19, 23] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["==", "tunnel", "yes"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Primary tunnel outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(158, 116, 0, 1)", + "line-width": { + "stops": [ + [9, 6], + [11, 3.5], + [12, 5], + [13, 5], + [15, 8], + [16, 15], + [18, 17], + [19, 25.4] + ] + }, + "line-dasharray": [0.5, 0.25] + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["==", "tunnel", "yes"], + ["!=", "bridge", "yes"] + ], + "layout": { + "line-cap": "butt", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Primary tunnel", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(254, 237, 215, 1)", + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 14], + [17, 14.5], + [18, 16], + [19, 24] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["==", "tunnel", "yes"], + ["!=", "bridge", "yes"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Tertiary road outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "tertiary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "paint": { + "line-color": "rgba(197, 191, 191, 1)", + "line-width": { + "stops": [ + [11, 2.7], + [12, 4.2], + [13, 5.2], + [14, 8.2], + [15, 7.2], + [16, 13.2], + [17, 15.4], + [18, 19.2], + [20, 27] + ], + "type": "exponential", + "base": 1.2 + }, + "line-translate-anchor": "map" + }, + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Tertiary road", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "tertiary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "stops": [ + [9, 0.7], + [10, 0.7], + [11, 1.9], + [12, 3], + [13, 3.9], + [14, 6.5], + [15, 5], + [15.5, 6.7], + [16, 11.3], + [17, 12.3], + [18, 16.3], + [20, 24] + ], + "type": "exponential", + "base": 1.2 + }, + "line-translate-anchor": "map" + }, + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Primary road", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": { + "stops": [ + [ + 7, + "rgba(243, 196, 129, 1)" + ], + [ + 11, + "rgba(252, 215, 166, 1)" + ] + ] + }, + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 12], + [17, 14.5], + [18, 16], + [19, 23] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Primary bridge outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(0, 0, 0, 1)", + "line-width": { + "stops": [ + [9, 6], + [11, 2.5], + [12, 3.2], + [13, 4.2], + [15, 8.2], + [16, 12.7], + [17, 16.7], + [18, 17.2], + [19, 25.2] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["==", "bridge", "yes"], + ["!has", "tunnel"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + } + }, + { + "id": "Primary bridge", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "paint": { + "line-color": "rgba(252, 215, 166, 1)", + "line-width": { + "stops": [ + [7, 1], + [8, 1.4], + [9, 1.8], + [10, 1.8], + [11, 2], + [12, 3], + [13, 3], + [15, 6.6], + [16, 14], + [17, 14.5], + [18, 16], + [19, 24] + ] + } + }, + "filter": [ + "all", + ["==", "subclass", "primary"], + ["==", "bridge", "yes"], + ["!has", "tunnel"] + ], + "layout": { + "line-join": "round", + "line-cap": "round", + "visibility": "visible" + } + }, + { + "id": "Steps tunnel higlight ", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "steps"], + ["==", "tunnel", "yes"], + ["!has", "bridge"] + ], + "paint": { + "line-color": "#333333", + "line-width": { + "base": 1.2, + "stops": [ + [13, 3.7], + [14, 3.5], + [15, 4], + [17, 4], + [18, 5] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Steps tunnel outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "steps"], + ["==", "tunnel", "yes"], + ["!has", "bridge"] + ], + "paint": { + "line-dasharray": [1, 0.1], + "line-width": { + "base": 1.2, + "stops": [ + [13, 2.7], + [14, 3], + [15, 3.3], + [17, 3.3], + [18, 3.6] + ] + }, + "line-color": "#FFFFFF" + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt", + "visibility": "visible" + } + }, + { + "id": "Steps tunnel", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "steps"], + ["==", "tunnel", "yes"] + ], + "paint": { + "line-width": { + "stops": [ + [6, 0.1], + [10, 0.4], + [15, 1], + [17, 1.1], + [18, 1.75] + ] + }, + "line-color": "#FA7E70", + "line-dasharray": [1.5, 0.15] + }, + "minzoom": 13, + "layout": { + "line-join": "miter", + "line-cap": "square" + } + }, + { + "id": "Steps path", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "steps"], + ["!has", "tunnel"] + ], + "paint": { + "line-width": { + "stops": [ + [6, 0.1], + [10, 0.4], + [15, 1], + [17, 1.1], + [18, 1.75] + ] + }, + "line-color": "#FA7E70", + "line-dasharray": [1.5, 0.15] + }, + "minzoom": 13, + "layout": { + "line-join": "miter", + "line-cap": "square" + } + }, + { + "id": "Steps path label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "steps"], + ["!=", "tunnel", "yes"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "icon-offset": [0.9, 0.9], + "icon-pitch-alignment": "auto", + "icon-anchor": "center", + "text-offset": [0.75, 0.75] + } + }, + { + "id": "Footway path label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "footway"], + ["!has", "tunnel"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "symbol-placement": "line-center", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 350, + "symbol-avoid-edges": true, + "text-offset": [0, 0.9] + }, + "minzoom": 18, + "paint": { + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 2 + } + }, + { + "id": "Residential road label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + [ + "==", + "subclass", + "residential" + ], + ["!has", "tunnel"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 500, + "symbol-avoid-edges": true + }, + "paint": { + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "Secondary road label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["!has", "tunnel"], + ["!has", "bridge"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 300, + "symbol-avoid-edges": true + }, + "paint": {"text-halo-width": 2} + }, + { + "id": "Secondary tunnel label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "secondary"], + ["==", "tunnel", "yes"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 300, + "symbol-avoid-edges": true + }, + "paint": {"text-halo-width": 2} + }, + { + "id": "Primary tunnel label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "primary"], + ["==", "tunnel", "yes"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 300, + "symbol-avoid-edges": true + }, + "paint": {"text-halo-width": 2} + }, + { + "id": "Primary road label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "primary"], + ["!has", "tunnel"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 300, + "symbol-avoid-edges": true + }, + "paint": {"text-halo-width": 2} + }, + { + "id": "Tertiary road label", + "type": "symbol", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "subclass", "tertiary"], + ["!has", "tunnel"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "symbol-placement": "line", + "text-size": { + "base": 1, + "stops": [ + [14, 6], + [17, 8], + [18, 11] + ] + }, + "icon-allow-overlap": true, + "symbol-spacing": 300, + "symbol-avoid-edges": true + }, + "paint": {"text-halo-width": 2} + }, + { + "id": "Footway bridge higlight -copy", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "bridge", "yes"], + ["!has", "tunnel"] + ], + "paint": { + "line-color": "#333333", + "line-dasharray": [1, 0.5], + "line-width": { + "base": 1.2, + "stops": [ + [13, 3.7], + [14, 4.5], + [15, 5], + [17, 5], + [18, 6] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Footway bridge outline", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "bridge", "yes"], + ["!has", "tunnel"] + ], + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-dasharray": [1, 0.1], + "line-width": { + "base": 1.2, + "stops": [ + [13, 3.7], + [14, 4], + [15, 4.3], + [17, 4.3], + [18, 4.6] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Footway bridge", + "type": "line", + "source": "smts", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "highway"], + ["==", "subclass", "footway"], + ["==", "bridge", "yes"], + ["!has", "tunnel"] + ], + "paint": { + "line-color": "#FA7E70", + "line-dasharray": [2, 2], + "line-width": { + "base": 1.2, + "stops": [ + [13, 0.8], + [14, 1], + [15, 1.3], + [17, 1.3], + [18, 1.6] + ] + } + }, + "minzoom": 13, + "layout": { + "line-join": "round", + "line-cap": "butt" + } + }, + { + "id": "Building Labels", + "type": "symbol", + "source": "smts", + "source-layer": "poi", + "filter": [ + "all", + ["==", "class", "building"] + ], + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{housenumber}\n{name}", + "text-size": { + "stops": [ + [14, 0.5], + [15, 2.2], + [15.5, 3.5], + [16, 6.5], + [17.5, 9], + [18, 10.5], + [24, 13.5] + ] + }, + "visibility": "visible" + }, + "minzoom": 14, + "paint": { + "text-color": "rgba(30, 29, 29, 1)", + "text-halo-width": 1, + "text-halo-color": "rgba(255, 255, 255, 1)" + } + }, + { + "id": "Chain", + "type": "line", + "source": "smts", + "source-layer": "barrier", + "paint": { + "line-color": "#aaaaa5", + "line-width": 0.75 + }, + "filter": [ + "all", + ["==", "class", "chain"] + ] + }, + { + "id": "Park label", + "type": "symbol", + "source": "smts", + "source-layer": "poi", + "filter": [ + "all", + ["==", "subclass", "park"] + ], + "minzoom": 15, + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "text-field": "{name}", + "text-size": { + "stops": [[15, 7], [20, 15]] + }, + "text-max-width": { + "stops": [[12, 5], [18, 8]] + }, + "visibility": "visible" + }, + "paint": { + "text-color": "rgba(12, 131, 22, 1)", + "text-halo-blur": 0.5, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + } + }, + { + "id": "Territorial border", + "type": "line", + "source": "smts", + "source-layer": "boundary", + "paint": { + "line-color": "rgba(141, 83, 109, 1)", + "line-width": { + "stops": [ + [3, 0.9], + [5, 1.6], + [12, 2] + ] + } + }, + "filter": [ + "all", + [ + "==", + "border_type", + "territorial" + ] + ] + }, + { + "id": "Country border", + "type": "line", + "source": "smts", + "source-layer": "boundary", + "paint": { + "line-color": "rgba(145, 109, 142, 1)", + "line-width": { + "stops": [ + [3, 0.9], + [5, 1.6], + [12, 2] + ] + } + }, + "filter": [ + "all", + ["==", "border_type", "nation"] + ] + }, + { + "id": "Cliff", + "type": "symbol", + "source": "smts", + "source-layer": "landfeature", + "filter": [ + "all", + ["==", "subclass", ""] + ], + "layout": {"icon-image": "cliff"} + }, + { + "id": "Artwork", + "type": "symbol", + "source": "smts", + "source-layer": "poi", + "layout": { + "text-font": [ + "Open Sans Italic", + "Noto Sans Italic" + ], + "icon-image": "artwork", + "icon-allow-overlap": true, + "icon-optional": false, + "text-field": "{name}", + "text-size": { + "stops": [ + [16, 0], + [16.4, 5], + [16.5, 5], + [16.75, 8], + [17.35, 8.25], + [20, 11] + ] + }, + "text-offset": [0, 1.89], + "icon-size": { + "stops": [ + [15, 0.4], + [16.25, 0.8], + [16.5, 0.85], + [16.75, 0.87], + [17, 0.9], + [17.35, 1], + [19, 1.1] + ] + }, + "text-allow-overlap": false, + "text-optional": true + }, + "filter": [ + "all", + ["==", "subclass", "artwork"] + ], + "paint": { + "icon-opacity": 1, + "text-translate-anchor": "map", + "text-halo-color": "#FFFFFF", + "text-color": "rgba(82, 54, 12, 1)", + "text-halo-blur": 1, + "text-halo-width": 1 + }, + "minzoom": 14 + } + ], + "id": "strikemaps-classic" +} \ No newline at end of file diff --git a/app/src/main/assets/bundled/style/satelite.style.json b/app/src/main/assets/bundled/style/satelite.style.json new file mode 100644 index 0000000..bf2e166 --- /dev/null +++ b/app/src/main/assets/bundled/style/satelite.style.json @@ -0,0 +1,27 @@ +{ + "version": 8, + "name": "Satelite", + "icon": "assets://satelite.bmp", + "sources": { + "satelite": { + "type": "raster", + "tiles": [ + "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}" + ], + "minzoom": 0, + "maxzoom": 18, + "scheme": "xyz", + "tileSize": 512 + } + }, + "sprite": "", + "glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "satelite", + "type": "raster", + "source": "satelite" + } + ], + "id": "satellite" +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/Component.java b/app/src/main/java/eu/konggdev/strikemaps/Component.java new file mode 100644 index 0000000..f49f5ae --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/Component.java @@ -0,0 +1,5 @@ +package eu.konggdev.strikemaps; + +public interface Component { + //TODO: Implement base component methods +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/MainActivity.java b/app/src/main/java/eu/konggdev/strikemaps/MainActivity.java new file mode 100755 index 0000000..890eb31 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/MainActivity.java @@ -0,0 +1,31 @@ +package eu.konggdev.strikemaps; + +import static org.maplibre.android.style.layers.PropertyFactory.lineColor; +import static org.maplibre.android.style.layers.PropertyFactory.lineWidth; + +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); + app.init(); + } + + public void logcat(String tag, String log) { + Log.i(tag, log); + } + + public void logcat(String log) { + Log.i("LogcatGeneric", log); + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/app/AppController.java b/app/src/main/java/eu/konggdev/strikemaps/app/AppController.java new file mode 100644 index 0000000..d3d8434 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/app/AppController.java @@ -0,0 +1,45 @@ +package eu.konggdev.strikemaps.app; + +import android.content.SharedPreferences; +import androidx.appcompat.app.AppCompatActivity; + +import eu.konggdev.strikemaps.MainActivity; +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.map.MapComponent; +import eu.konggdev.strikemaps.ui.UIComponent; + +import static android.content.Context.MODE_PRIVATE; +public class AppController { + private final MainActivity appActivity; + + private MapComponent map; + private UIComponent ui; + public AppController(MainActivity refActivity) { + appActivity = refActivity; + } + 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 SharedPreferences getPrefs() { + return getActivity().getSharedPreferences("user_prefs", MODE_PRIVATE); + } + public AppCompatActivity getActivity() { return appActivity; } + public void init() { + if (getActivity().getSupportActionBar() != null) + getActivity().getSupportActionBar().hide(); + + if(map == null) map = new MapComponent(this); + if(ui == null) { + ui = new UIComponent(this, map); + ui.swapScreen(R.layout.screen_main); //Initial + } + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java b/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java new file mode 100644 index 0000000..b55c015 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/factory/AlertDialogFactory.java @@ -0,0 +1,41 @@ +package eu.konggdev.strikemaps.factory; + +import android.app.AlertDialog; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.ui.element.item.PreviewItem; +import org.maplibre.geojson.Feature; + +import java.util.List; +import java.util.function.Consumer; + +//FIXME: Move Item functions into specific classes for specific types - e.g. StyleItem +public final class AlertDialogFactory { + public static AlertDialog pointSelector(AppController app, List features, Consumer callback) { + LinearLayout layout = new LinearLayout(app.getActivity()); + layout.setOrientation(LinearLayout.VERTICAL); + + ScrollView scrollView = new ScrollView(app.getActivity()); + scrollView.addView(layout); + + AlertDialog dialog = new AlertDialog.Builder(app.getActivity()) + .setView(scrollView) + .create(); + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#000000"))); + + for (Feature feature : features) { + View itemView = PreviewItem.fromFeature(feature).makeView(app.getUi(), v -> { + dialog.dismiss(); + new android.os.Handler(android.os.Looper.getMainLooper()) + .post(() -> callback.accept(feature)); + }); + layout.addView(itemView); + } + + return dialog; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java b/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java new file mode 100644 index 0000000..3228ab8 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/helper/FileHelper.java @@ -0,0 +1,109 @@ +package eu.konggdev.strikemaps.helper; + +import android.content.res.AssetManager; +import android.os.Environment; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import eu.konggdev.strikemaps.app.AppController; + +//FIXME: Ugly +public final class FileHelper { + 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 String loadStringFromUserFile(String filePath) { + File file = new File(filePath); + + try (FileInputStream fis = new FileInputStream(file)) { + int size = fis.available(); + byte[] buffer = new byte[size]; + fis.read(buffer); + return new String(buffer, StandardCharsets.UTF_8); + } catch (IOException ex) { + ex.printStackTrace(); + return null; + } + } + + 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 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); + } + } + + public static String[] getUserFiles(String path, String fileExt, AppController app) { + String packageName = app.getActivity().getPackageName(); + File userDirectory = new File(Environment.getExternalStorageDirectory(), "Android/data/" + packageName + "/" + path); + + if (!userDirectory.exists() || !userDirectory.isDirectory()) + return new String[0]; + + File[] files = userDirectory.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String filename) { + if (fileExt == null || fileExt.isEmpty()) { + return true; + } + + return filename.toLowerCase().endsWith(fileExt.toLowerCase()); + } + }); + + if (files == null || files.length == 0) { + return new String[0]; + } + + List fileList = new ArrayList<>(); + for (File file : files) { + fileList.add(file.getAbsolutePath()); + } + + return fileList.toArray(new String[0]); + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/helper/UserPrefsHelper.java b/app/src/main/java/eu/konggdev/strikemaps/helper/UserPrefsHelper.java new file mode 100644 index 0000000..d6c4951 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/helper/UserPrefsHelper.java @@ -0,0 +1,40 @@ +package eu.konggdev.strikemaps.helper; + +import android.content.SharedPreferences; + +public final class UserPrefsHelper { + private UserPrefsHelper() {} // prevent instantiation + + //Keys + private static final String KEY_STARTUP_MAP_STYLE = "startupMapStyle"; + private static final String KEY_MAP_RENDERER = "mapRenderer"; + private static final String KEY_PERSIST_LOCATION_ENABLED = "persistLocationEnabled"; + private static final String KEY_LAST_LOCATION_ENABLED = "lastLocationEnabled"; + + //Defaults + private static final String DEFAULT_MAP_STYLE = "bundled/style/classic.style.json"; + private static final String DEFAULT_MAP_RENDERER = "mapLibre"; + private static final boolean DEFAULT_PERSIST_LOCATION_ENABLED = true; + private static final boolean DEFAULT_LAST_LOCATION_ENABLED = false; + + + public static String startupMapStyle(SharedPreferences prefs) { + return prefs.getString(KEY_STARTUP_MAP_STYLE, DEFAULT_MAP_STYLE); + } + + public static String mapRenderer(SharedPreferences prefs) { + return prefs.getString(KEY_MAP_RENDERER, DEFAULT_MAP_RENDERER); + } + + public static boolean persistLocationEnabled(SharedPreferences prefs) { + return prefs.getBoolean(KEY_PERSIST_LOCATION_ENABLED, DEFAULT_PERSIST_LOCATION_ENABLED); + } + + public static boolean lastLocationEnabled(SharedPreferences prefs) { + return prefs.getBoolean(KEY_LAST_LOCATION_ENABLED, DEFAULT_LAST_LOCATION_ENABLED); + } + + public static boolean lastLocationEnabled(SharedPreferences prefs, boolean status) { + return prefs.edit().putBoolean(KEY_LAST_LOCATION_ENABLED, status).commit(); + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java b/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java new file mode 100644 index 0000000..422c4cf --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/MapComponent.java @@ -0,0 +1,95 @@ +package eu.konggdev.strikemaps.map; + +import java.util.*; +import eu.konggdev.strikemaps.Component; +import eu.konggdev.strikemaps.factory.AlertDialogFactory; +import eu.konggdev.strikemaps.helper.UserPrefsHelper; +import eu.konggdev.strikemaps.map.renderer.implementation.VtmRenderer; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.geojson.Feature; + +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.map.overlay.MapOverlay; +import eu.konggdev.strikemaps.map.renderer.implementation.MapLibreNativeRenderer; +import eu.konggdev.strikemaps.map.renderer.MapRenderer; +import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentMap; + +public class MapComponent implements Component { + MapRenderer mapRenderer; + AppController app; + + public String style; + public Map, MapOverlay> overlays = new HashMap<>(); + public MapComponent(AppController ref) { + this.app = ref; + switch(UserPrefsHelper.mapRenderer(app.getPrefs())) { + case "vtm": + this.mapRenderer = new VtmRenderer(app, this); + break; + case "mapLibre": + default: //This shouldn't happen + this.mapRenderer = new MapLibreNativeRenderer(app, this); + break; + }; + } + + public FragmentLayoutContentMap toFragment() { + return new FragmentLayoutContentMap(mapRenderer.getView()); + } + + public void setStyle(String style) { + this.style = style; + mapRenderer.reload(); + } + + public void switchOverlay(MapOverlay overlay) { + if (hasOverlay(overlay)) overlays.remove(overlay.getClass()); + else overlays.put(overlay.getClass(), overlay); + update(); + } + + public boolean hasOverlay(MapOverlay overlay) { + return overlays.containsKey(overlay.getClass()); + } + + public boolean hasOverlay(Class overlay) { + return overlays.containsKey(overlay); + } + + public void selectPoint(Feature selection) { + //FIXME: Put back FragmentPointPreviewPopup (private code atm) + } + + public void onOverlayUpdate() { + update(); + } + + public void update() { + if(mapRenderer != null && style != null) mapRenderer.reload(); + } + + public boolean onMapClick(LatLng point) { + List features = mapRenderer.featuresAtPoint(point); + + switch (features.size()) { + case 0: + //TODO: Implement point selection for no POI found (MIGHT be done on long click??) + //Maybe collapse UI? (Hide/show UI feature)... could be user configurable + break; + case 1: + selectPoint(features.get(0)); + break; + default: + app.getUi().alert( + AlertDialogFactory.pointSelector(app, features, selectedItem -> { + selectPoint(selectedItem); + })); + } + return true; + } + + public boolean onMapLongClick(LatLng point) { + //TODO: Likely Nonfeature(?) point selection + return true; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java b/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java new file mode 100644 index 0000000..667338a --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/layer/MapLayer.java @@ -0,0 +1,16 @@ +package eu.konggdev.strikemaps.map.layer; + +import org.maplibre.android.style.layers.Layer; +import org.maplibre.android.style.sources.GeoJsonSource; + +import java.util.List; + +//TOOD: Make not strictly MapLibre reliant +public class MapLayer { + public GeoJsonSource source; + public Layer layer; + public MapLayer(GeoJsonSource source, Layer layer) { + this.source = source; + this.layer = layer; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/overlay/MapOverlay.java b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/MapOverlay.java new file mode 100644 index 0000000..3d55939 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/MapOverlay.java @@ -0,0 +1,8 @@ +package eu.konggdev.strikemaps.map.overlay; + +import eu.konggdev.strikemaps.map.layer.MapLayer; + +/* More or less a data-driven layer factory */ +public interface MapOverlay { + public MapLayer makeLayer(); +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/LocationOverlay.java b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/LocationOverlay.java new file mode 100644 index 0000000..a4277be --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/LocationOverlay.java @@ -0,0 +1,62 @@ +package eu.konggdev.strikemaps.map.overlay.overlay; + +import android.graphics.Color; +import android.location.Location; +import android.location.LocationListener; +import androidx.annotation.NonNull; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.map.MapComponent; +import eu.konggdev.strikemaps.map.layer.MapLayer; + +import eu.konggdev.strikemaps.map.overlay.MapOverlay; +import eu.konggdev.strikemaps.provider.LocationDataProvider; +import org.maplibre.android.style.layers.CircleLayer; +import org.maplibre.android.style.layers.Property; +import org.maplibre.android.style.sources.GeoJsonSource; +import org.maplibre.geojson.Feature; +import org.maplibre.geojson.FeatureCollection; +import org.maplibre.geojson.Point; + +import static org.maplibre.android.style.layers.PropertyFactory.*; + +public class LocationOverlay implements MapOverlay, LocationListener { + LocationDataProvider locationDataProvider; + AppController app; + MapComponent map; + + public Location currentLocation = null; + + public LocationOverlay(AppController app) { + this.app = app; + this.map = app.getMap(); + this.locationDataProvider = new LocationDataProvider(app.getActivity(), this); + } + + @Override + public MapLayer makeLayer() { + GeoJsonSource source = new GeoJsonSource( + "location", + FeatureCollection.fromFeatures(new Feature[]{}) // empty + ); + + if (currentLocation != null) + source.setGeoJson(Feature.fromGeometry(Point.fromLngLat(currentLocation.getLongitude(), currentLocation.getLatitude()))); + + CircleLayer layer = new CircleLayer("location", "location"); + layer.setProperties( + circleRadius(5f), + circleColor(Color.parseColor("#1E88E5")), + circleStrokeColor(Color.WHITE), + circleStrokeWidth(1.5f), + circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) + ); + + return new MapLayer(source, layer); + } + + @Override + public void onLocationChanged(@NonNull Location location) { + this.currentLocation = location; + map.onOverlayUpdate(); + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/PointSelectionOverlay.java b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/PointSelectionOverlay.java new file mode 100644 index 0000000..c9d7fef --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/overlay/overlay/PointSelectionOverlay.java @@ -0,0 +1,11 @@ +package eu.konggdev.strikemaps.map.overlay.overlay; + +import eu.konggdev.strikemaps.map.layer.MapLayer; +import eu.konggdev.strikemaps.map.overlay.MapOverlay; + +public class PointSelectionOverlay implements MapOverlay { + @Override + public MapLayer makeLayer() { + return null; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/MapRenderer.java b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/MapRenderer.java new file mode 100644 index 0000000..e77613d --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/MapRenderer.java @@ -0,0 +1,19 @@ +package eu.konggdev.strikemaps.map.renderer; + +import android.view.View; +import android.view.ViewGroup; + +import eu.konggdev.strikemaps.map.layer.MapLayer; +import org.maplibre.android.style.layers.Layer; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.geojson.Feature; + +import java.util.List; + +public interface MapRenderer { + void reload(); + + View getView(); + + List featuresAtPoint(LatLng point); +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java new file mode 100644 index 0000000..a8da472 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/MapLibreNativeRenderer.java @@ -0,0 +1,78 @@ +package eu.konggdev.strikemaps.map.renderer.implementation; + +import android.view.View; + +import androidx.annotation.NonNull; + +import eu.konggdev.strikemaps.helper.FileHelper; +import eu.konggdev.strikemaps.helper.UserPrefsHelper; +import eu.konggdev.strikemaps.map.overlay.MapOverlay; +import eu.konggdev.strikemaps.map.layer.MapLayer; +import eu.konggdev.strikemaps.map.renderer.MapRenderer; +import org.maplibre.android.MapLibre; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.android.maps.MapLibreMap; +import org.maplibre.android.maps.MapView; +import org.maplibre.android.maps.OnMapReadyCallback; +import org.maplibre.android.maps.Style; +import org.maplibre.geojson.Feature; + +import java.util.List; + +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.map.MapComponent; + +public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback { + AppController app; + MapComponent controller; + MapLibreMap map; + final MapView mapView; + + public MapLibreNativeRenderer(AppController app, MapComponent controller) { + this.app = app; + this.controller = controller; + MapLibre.getInstance(app.getActivity()); + this.mapView = new MapView(app.getActivity()); + mapView.onCreate(null); + mapView.getMapAsync(this); + } + + void passLayer(MapLayer layer) { + map.getStyle().addSource(layer.source); + map.getStyle().addLayer(layer.layer); + } + + @Override + public void reload() { + map.setStyle(new Style.Builder().fromJson(controller.style), style -> { + for(MapOverlay overlay : controller.overlays.values()) { + passLayer(overlay.makeLayer()); + } + }); + } + + @Override + public View getView() { + return mapView; + } + + @Override + public List featuresAtPoint(LatLng point) { + return map.queryRenderedFeatures(map.getProjection().toScreenLocation(point)); + } + + @Override + public void onMapReady(@NonNull MapLibreMap maplibreMap) { + this.map = maplibreMap; + + controller.style = FileHelper.loadStringFromAssetFile(UserPrefsHelper.startupMapStyle(app.getPrefs()), app); + + //I have my own implementation of attribution that credits MapLibre among others, it's not as bad as it looks :) + map.getUiSettings().setLogoEnabled(false); + map.getUiSettings().setAttributionEnabled(false); + + map.addOnMapClickListener(point -> controller.onMapClick(point)); + map.addOnMapLongClickListener(point -> controller.onMapLongClick(point)); + this.reload(); + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/VtmRenderer.java b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/VtmRenderer.java new file mode 100644 index 0000000..463849e --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/renderer/implementation/VtmRenderer.java @@ -0,0 +1,50 @@ +package eu.konggdev.strikemaps.map.renderer.implementation; + +import android.view.View; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.map.MapComponent; +import eu.konggdev.strikemaps.map.renderer.MapRenderer; +import okhttp3.OkHttpClient; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.geojson.Feature; +import org.oscim.android.MapView; +import org.oscim.map.Map; +import org.oscim.tiling.source.OkHttpEngine; +import org.oscim.tiling.source.oscimap4.OSciMap4TileSource; + +import java.util.Collections; +import java.util.List; + +public class VtmRenderer implements MapRenderer { + AppController app; + MapComponent controller; + + Map map; + final MapView mapView; + + public VtmRenderer(AppController app, MapComponent controller) { + this.app = app; + this.controller = controller; + this.mapView = new MapView(app.getActivity()); + this.map = mapView.map(); + } + + @Override + public void reload() { + //TODO + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + OSciMap4TileSource tileSource = OSciMap4TileSource.builder().httpFactory(new OkHttpEngine.OkHttpFactory(builder)).build(); + + map.setBaseMap(tileSource); + } + + @Override + public View getView() { + return mapView; + } + + @Override + public List featuresAtPoint(LatLng point) { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java b/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java new file mode 100644 index 0000000..22fcb50 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/map/source/MapSource.java @@ -0,0 +1,12 @@ +package eu.konggdev.strikemaps.map.source; + +public class MapSource { + public final String url; + public final String type; + public final String schema; + public MapSource(String url, String type, String schema) { + this.url = url; + this.type = type; + this.schema = schema; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/provider/HttpDataProvider.java b/app/src/main/java/eu/konggdev/strikemaps/provider/HttpDataProvider.java new file mode 100644 index 0000000..bca95ad --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/provider/HttpDataProvider.java @@ -0,0 +1,5 @@ +package eu.konggdev.strikemaps.provider; + +public class HttpDataProvider implements Provider { + //TODO +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/provider/LocationDataProvider.java b/app/src/main/java/eu/konggdev/strikemaps/provider/LocationDataProvider.java new file mode 100644 index 0000000..5424b64 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/provider/LocationDataProvider.java @@ -0,0 +1,43 @@ +package eu.konggdev.strikemaps.provider; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + +import java.util.List; + +public class LocationDataProvider implements Provider { + private LocationManager locationManager; + + private List locationManagerProviders = List.of(LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER); + public LocationDataProvider(AppCompatActivity activity, LocationListener listener) { + locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); + + //TODO: Move permission request to UI + if(ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + Location initLocation = null; + + for (String provider : locationManagerProviders) { + if(locationManager.isProviderEnabled(provider)) { + if (initLocation == null) { + initLocation = locationManager.getLastKnownLocation(provider); + if (initLocation != null) + listener.onLocationChanged(initLocation); + } + + locationManager.requestLocationUpdates( + provider, + 1000, + 1, + listener + ); + } + } + } + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/provider/Provider.java b/app/src/main/java/eu/konggdev/strikemaps/provider/Provider.java new file mode 100644 index 0000000..270971f --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/provider/Provider.java @@ -0,0 +1,5 @@ +package eu.konggdev.strikemaps.provider; + +public interface Provider { + +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java b/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java new file mode 100644 index 0000000..d5962a4 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/UIComponent.java @@ -0,0 +1,77 @@ +package eu.konggdev.strikemaps.ui; + +import android.app.AlertDialog; +import android.view.View; +import androidx.annotation.NonNull; +import com.google.common.collect.BiMap; +import eu.konggdev.strikemaps.Component; +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.map.MapComponent; +import eu.konggdev.strikemaps.ui.element.UIRegion; +import eu.konggdev.strikemaps.ui.fragment.layout.FragmentLayoutControls; +import eu.konggdev.strikemaps.ui.fragment.layout.content.main.FragmentLayoutContentSettings; +import eu.konggdev.strikemaps.ui.screen.Screen; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +public class UIComponent implements Component { + @NonNull AppController app; + private Map screens; + private Integer currentScreen; + + public UIComponent(AppController app, MapComponent map) { + this.app = app; + this.screens = Map.of( + //Main screen + R.layout.screen_main, new Screen( + //App reference + app, + //Map view + map.toFragment(), //FragmentLayoutContentMap + //Main screen init regions definition + Map.of(R.id.bottomUi, new UIRegion(new FragmentLayoutControls(app, R.id.bottomUi), R.id.bottomUi)), //TODO: Probably stop referencing layout 3(!) times everytime + //Layout + R.layout.screen_main //TODO: Define this for the Screen without duplicating the reference + ), + //Settings screen + R.layout.screen_settings, new Screen( + app, + //Settings + new FragmentLayoutContentSettings(), + /* No regions defined in settings + Entire screen is just the main view */ + new HashMap<>(), + //Layout + R.layout.screen_settings + ) + ); + } + + public void swapScreen(Integer screen) { + currentScreen = screen; + getCurrentScreen().attachAll(); + } + + public Screen getCurrentScreen() { + return getScreen(currentScreen); + } + + public Screen getScreen(Integer screen) { + return screens.get(screen); + } + + public void alert(AlertDialog dialog) { + dialog.show(); + } + + public void alert(AlertDialog dialog, Consumer callback) { + dialog.show(); + } + + public View inflateUi(int layout) { + return app.getActivity().getLayoutInflater().inflate(layout, null); + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/element/UIRegion.java b/app/src/main/java/eu/konggdev/strikemaps/ui/element/UIRegion.java new file mode 100644 index 0000000..bed3122 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/UIRegion.java @@ -0,0 +1,44 @@ +package eu.konggdev.strikemaps.ui.element; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import eu.konggdev.strikemaps.ui.fragment.layout.Layout; + +import java.util.ArrayDeque; + +public class UIRegion { + private final ArrayDeque previousFragments = new ArrayDeque<>(); + + private Fragment stockFragment; + private Fragment currentFragment; + public Integer layoutId; + + public UIRegion(@NonNull Fragment initFragment, Integer refLayoutId) { + this.currentFragment = initFragment; + this.stockFragment = initFragment; + + this.layoutId = refLayoutId; + } + + public Fragment getFragment() { + return currentFragment; + } + + public void setFragment(Fragment fragment) { + previousFragments.add(currentFragment); + currentFragment = fragment; + } + + public void overwriteStockFragment(Fragment fragment) { + stockFragment = fragment; + } + + public void back() { + if (!previousFragments.isEmpty()) { + currentFragment = previousFragments.pop(); + } else { + currentFragment = stockFragment; + } + } + +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java new file mode 100644 index 0000000..af2512e --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/GenericItem.java @@ -0,0 +1,77 @@ +package eu.konggdev.strikemaps.ui.element.item; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.View; +import android.widget.ImageButton; +import android.widget.TextView; + +import androidx.annotation.NonNull; +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.ui.UIComponent; +import org.json.JSONObject; + +import java.io.InputStream; + +public class GenericItem implements UIItem { + @NonNull public String name; + public Bitmap image; + public Runnable onClick; + boolean hasImage; + public GenericItem(String refName) { + this.name = refName; + hasImage = false; + } + public GenericItem(String refName, Runnable onClick) { + this.name = refName; + this.onClick = onClick; + hasImage = false; + } + public GenericItem(String refName, Bitmap refImage) { + this.name = refName; + this.image = refImage; + hasImage = true; + } + public GenericItem(String refName, Bitmap refImage, Runnable onClick) { + this.name = refName; + this.image = refImage; + this.onClick = onClick; + hasImage = true; + } + + //FIXME: Ugly glue static constructor + public final static GenericItem fromStyle(String style, AppController app, MapComponent map) { + try { + JSONObject styleJson = new JSONObject(style); + String name = "Unknown"; //Fallback name + if (styleJson.has("name")) name = styleJson.getString("name"); + if (styleJson.has("icon")) { + switch(styleJson.getString("icon").split("//")[0]) { + //TODO: https + case "assets:": + Bitmap icon = BitmapFactory.decodeStream(FileHelper.openAssetStream("bundled/icon/" + styleJson.getString("icon").split("//")[1], app)); + return new GenericItem(name, icon, () -> map.setStyle(style)); + default: + app.logcat("Unimplemented icon source requested in style: " + name); + return new GenericItem(name, () -> map.setStyle(style)); + } + } + return new GenericItem(name, () -> map.setStyle(style)); + } catch (Exception e) { + e.printStackTrace(); + return new GenericItem("Exception!", () -> map.setStyle(style)); + } + } + public View makeView(UIComponent spawner) { + View v = spawner.inflateUi(R.layout.item_generic); + //FIXME: These shouldn't be casted like that! + ((TextView) v.findViewById(R.id.name)).setText(name); + if(image != null) ((ImageButton) v.findViewById(R.id.image)).setImageBitmap(image); + if(onClick != null) v.findViewById(R.id.image).setOnClickListener(click(onClick)); + + return v; + } +} 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 new file mode 100644 index 0000000..773c272 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/PreviewItem.java @@ -0,0 +1,41 @@ +package eu.konggdev.strikemaps.ui.element.item; + +import android.graphics.Bitmap; +import android.view.View; +import android.widget.TextView; + +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; + public Bitmap image; + boolean hasImage; + public PreviewItem(String refName, String refType) { + this.name = refName; + this.type = refType; + hasImage = false; + } + public PreviewItem(String refName, String refType, Bitmap refImage) { + this.name = refName; + this.type = 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); + return view; + } + public View makeView(UIComponent spawner, View.OnClickListener onClick) { + View view = makeView(spawner); + view.setOnClickListener(onClick); + return view; + } +} 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 new file mode 100644 index 0000000..7f14bdc --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/element/item/UIItem.java @@ -0,0 +1,16 @@ +package eu.konggdev.strikemaps.ui.element.item; + +import android.view.View; + +import eu.konggdev.strikemaps.ui.UIComponent; + +public interface UIItem { + abstract View makeView(UIComponent spawner); + + default View.OnClickListener click(Runnable action) { + return v -> action.run(); + } + + default View.OnLongClickListener longClick(Runnable action) { return v -> { action.run(); return true; };} + +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/ContainerFragment.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/ContainerFragment.java new file mode 100644 index 0000000..3e44762 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/ContainerFragment.java @@ -0,0 +1,90 @@ +package eu.konggdev.strikemaps.ui.fragment; + +import android.view.MotionEvent; +import android.view.View; + +import androidx.fragment.app.Fragment; +import eu.konggdev.strikemaps.ui.element.UIRegion; + +public interface ContainerFragment { + abstract public Integer getRegion(); + + abstract public Fragment toFragment(); + + + //Helper methods (ugly) + //FIXME + default void setupButton(View view, int button, View.OnClickListener onClick) { + view.findViewById(button) + .setOnClickListener(onClick); + } + + default void setupButton(View view, int button, View.OnClickListener onClick, View.OnLongClickListener onLongClick) { + View buttonView = view.findViewById(button); + buttonView.setOnClickListener(onClick); + buttonView.setOnLongClickListener(onLongClick); + } + + default void setupButton(View view, int button, View.OnLongClickListener onLongClick) { + view.findViewById(button) + .setOnLongClickListener(onLongClick); + } + + default View.OnClickListener click(Runnable action) { + return v -> action.run(); + } + + default View.OnLongClickListener longClick(Runnable action) { return v -> { action.run(); return true; };} + + //TODO: Make animation less wonky + default void setupDragHandle(View dragHandle, View layout, Runnable closeAction) { + final float[] dY = new float[1]; + dragHandle.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + dY[0] = event.getRawY() - layout.getY(); + return true; + + case MotionEvent.ACTION_MOVE: + float newY = event.getRawY() - dY[0]; + if (newY >= 0) { + layout.setY(newY); + } + return true; + + case MotionEvent.ACTION_UP: + if (layout.getY() > layout.getHeight() / 4) { + layout.animate() + .scaleX(0f) + .scaleY(0f) + .alpha(0f) + .setDuration(300) + .withEndAction(new Runnable() { + @Override + public void run() { + layout.setVisibility(View.GONE); + closeAction.run(); + layout.setScaleX(1f); + layout.setScaleY(1f); + layout.setAlpha(1f); + layout.setY(0f); + } + }) + .start(); + } else { + layout.animate() + .translationY(0f) + .setDuration(200) + .start(); + } + return true; + + default: + return false; + } + } + }); + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/FragmentEmptyPlaceholder.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/FragmentEmptyPlaceholder.java new file mode 100644 index 0000000..eeebc1e --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/FragmentEmptyPlaceholder.java @@ -0,0 +1,7 @@ +package eu.konggdev.strikemaps.ui.fragment; + +import androidx.fragment.app.Fragment; + +public class FragmentEmptyPlaceholder extends Fragment { + //:) +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutControls.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutControls.java new file mode 100644 index 0000000..1adb1e3 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/FragmentLayoutControls.java @@ -0,0 +1,120 @@ +package eu.konggdev.strikemaps.ui.fragment.layout; + +import android.Manifest; +import android.app.AlertDialog; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import android.widget.TextView; +import android.widget.Toast; + +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.helper.UserPrefsHelper; +import eu.konggdev.strikemaps.map.overlay.overlay.LocationOverlay; +import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup; + +public class FragmentLayoutControls extends Fragment implements Layout { + AppController app; + View rootView; + + private final Integer region; + + // Action definitions + //*// + public void notImplemented() { //Should never be called in release + Toast.makeText(requireContext(), "Not implemented yet\nWait for release", Toast.LENGTH_SHORT).show(); + } + + public void toggleLocationService() { + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); + } else { + app.getMap().switchOverlay(new LocationOverlay(app)); + setupView(); + } + } + + public void zoomToLocation() { + if(!app.getMap().hasOverlay(LocationOverlay.class)) { + Toast.makeText(requireContext(), "Hold to enable location", Toast.LENGTH_SHORT).show(); + return; + } + } + + public void attributtionDialog() { + AlertDialog dialog = new AlertDialog.Builder(app.getActivity()) + .setTitle(app.getActivity().getString(R.string.attribution_title)) + .setMessage(app.getActivity().getString(R.string.shipped_attribution)) + .setPositiveButton("OK", null).show(); + } + //*// + + public FragmentLayoutControls(AppController app, Integer region) { + super(R.layout.fragment_controls); + this.app = app; + this.region = region; + } + + @Override + public Integer getRegion() { + return region; + } + + @Override + public Fragment toFragment() { + return this; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + this.rootView = view; + + /* Restores location enabled status from user prefs, + 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)) + toggleLocationService(); + + this.setupView(); + } + + public void setupView() { + if (rootView == null) return; + setupButton(rootView, R.id.layersButton, click(() -> app.getUi().getCurrentScreen().open(new FragmentMapChangePopup(app, R.id.bottomUi)))); + setupButton(rootView, R.id.attributionButton, click(this::attributtionDialog)); + setupButton(rootView, R.id.locationButton, click(this::zoomToLocation), longClick(this::toggleLocationService)); + + //TODO + setupButton(rootView, R.id.placesButton, click(this::notImplemented)); + setupButton(rootView, R.id.placesButton, click(this::notImplemented)); + setupButton(rootView, R.id.routeButton, click(this::notImplemented)); + setupButton(rootView, R.id.modeButton, click(this::notImplemented)); + + TextView locationServiceStatusIndicator = rootView.findViewById(R.id.locationServiceStatusIndicator); + if (app.getMap().hasOverlay(LocationOverlay.class)) { + locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#00FF00")); //green + } else { + locationServiceStatusIndicator.setBackgroundColor(Color.parseColor("#FB0303")); //red + } + + if(UserPrefsHelper.persistLocationEnabled(app.getPrefs())) + UserPrefsHelper.lastLocationEnabled(app.getPrefs(), app.getMap().hasOverlay(LocationOverlay.class)); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + switch (requestCode) { + case 1: + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) toggleLocationService(); + else Toast.makeText(requireContext(), "You need to grant location permission", Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/Layout.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/Layout.java new file mode 100644 index 0000000..fee75bc --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/Layout.java @@ -0,0 +1,8 @@ +package eu.konggdev.strikemaps.ui.fragment.layout; + + +import eu.konggdev.strikemaps.ui.fragment.ContainerFragment; + +public interface Layout extends ContainerFragment { + +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/ContentLayout.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/ContentLayout.java new file mode 100644 index 0000000..b6c9b6a --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/ContentLayout.java @@ -0,0 +1,6 @@ +package eu.konggdev.strikemaps.ui.fragment.layout.content; + +import eu.konggdev.strikemaps.ui.fragment.layout.Layout; + +public interface ContentLayout extends Layout { +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentMap.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentMap.java new file mode 100644 index 0000000..1f520a2 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentMap.java @@ -0,0 +1,33 @@ +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.ui.element.UIRegion; + +import eu.konggdev.strikemaps.R; + +public class FragmentLayoutContentMap extends Fragment implements MainContentLayout { + View mapView; + + public FragmentLayoutContentMap(View refMapView) { + super(R.layout.fragment_map); + this.mapView = refMapView; + } + + @Override + public Fragment toFragment() { + return this; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + LinearLayout layout = (LinearLayout) view; + layout.addView(mapView); + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentSettings.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentSettings.java new file mode 100644 index 0000000..6b30a80 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/FragmentLayoutContentSettings.java @@ -0,0 +1,10 @@ +package eu.konggdev.strikemaps.ui.fragment.layout.content.main; + +import androidx.fragment.app.Fragment; + +public class FragmentLayoutContentSettings implements MainContentLayout { + @Override + public Fragment toFragment() { + return null; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/MainContentLayout.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/MainContentLayout.java new file mode 100644 index 0000000..f4811cb --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/layout/content/main/MainContentLayout.java @@ -0,0 +1,10 @@ +package eu.konggdev.strikemaps.ui.fragment.layout.content.main; + +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.ui.fragment.layout.content.ContentLayout; + +public interface MainContentLayout extends ContentLayout { + default Integer getRegion() { + return R.id.mainContentView; + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java new file mode 100644 index 0000000..8bf547f --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/FragmentMapChangePopup.java @@ -0,0 +1,61 @@ +package eu.konggdev.strikemaps.ui.fragment.popup; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import android.widget.LinearLayout; + +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.helper.FileHelper; +import eu.konggdev.strikemaps.factory.AlertDialogFactory; +import eu.konggdev.strikemaps.map.MapComponent; + +import eu.konggdev.strikemaps.ui.UIComponent; +import eu.konggdev.strikemaps.ui.element.item.GenericItem; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.ArrayList; +import java.util.List; + + +public class FragmentMapChangePopup extends Fragment implements Popup { + @NonNull AppController app; + @NonNull MapComponent map; + @NonNull UIComponent ui; + + private final Integer region; + + public FragmentMapChangePopup(AppController app, Integer region) { + super(R.layout.popup_map_change); + this.app = app; + this.map = app.getMap(); + this.ui = app.getUi(); + this.region = region; + } + @Override + public Integer getRegion() { + return region; + } + + @Override + public Fragment toFragment() { + return this; + } + + @Override + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + //FIXME + setupButton(view, R.id.closeButton, click(() -> ui.getCurrentScreen().closePopup())); + setupDragHandle(view, view, () -> ui.getCurrentScreen().closePopup()); + String[] stylePaths = ArrayUtils.addAll(FileHelper.getAssetFiles("bundled/style", ".style.json", app), FileHelper.getUserFiles("style", ".style.json", app)); + List views = new ArrayList<>(); + LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout); + for(String i : stylePaths) { + if(i.startsWith("/storage")) stylesLayout.addView(GenericItem.fromStyle(FileHelper.loadStringFromUserFile(i), app, map).makeView(ui)); + else stylesLayout.addView(GenericItem.fromStyle(FileHelper.loadStringFromAssetFile(i, app), app, map).makeView(ui)); + } + } +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/Popup.java b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/Popup.java new file mode 100644 index 0000000..6792f04 --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/fragment/popup/Popup.java @@ -0,0 +1,8 @@ +package eu.konggdev.strikemaps.ui.fragment.popup; + +import androidx.fragment.app.Fragment; + +import eu.konggdev.strikemaps.ui.fragment.ContainerFragment; + +public interface Popup extends ContainerFragment { +} diff --git a/app/src/main/java/eu/konggdev/strikemaps/ui/screen/Screen.java b/app/src/main/java/eu/konggdev/strikemaps/ui/screen/Screen.java new file mode 100644 index 0000000..e1b434d --- /dev/null +++ b/app/src/main/java/eu/konggdev/strikemaps/ui/screen/Screen.java @@ -0,0 +1,77 @@ +package eu.konggdev.strikemaps.ui.screen; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +import java.util.List; +import java.util.Map; + +import eu.konggdev.strikemaps.R; +import eu.konggdev.strikemaps.app.AppController; +import eu.konggdev.strikemaps.ui.fragment.ContainerFragment; +import eu.konggdev.strikemaps.ui.fragment.layout.content.main.MainContentLayout; +import eu.konggdev.strikemaps.ui.fragment.popup.Popup; +import eu.konggdev.strikemaps.ui.element.UIRegion; + +public class Screen { + @NonNull AppController app; + public Screen(AppController app, MainContentLayout mainContent, Map regions, Integer layout) { + this.app = app; + this.layout = layout; + this.mainContent = mainContent; + this.uiRegions = regions; + } + + private final Integer layout; + + private MainContentLayout mainContent; + + Map uiRegions; + public Integer popup; + + public void open(ContainerFragment fragment) { + if(fragment instanceof Popup && popup != null) return; + + if(fragment instanceof Popup) + popup = fragment.getRegion(); + + setFragment(uiRegions.get(fragment.getRegion()), fragment.toFragment()); + } + + public void closePopup() { + if(popup != null) { + UIRegion popupRegion = uiRegions.get(popup); + popupRegion.back(); + /* If newFragment is still a popup, assign the current popup value to the new fragment + otherwise, set the current popup value to null */ + if(popupRegion.getFragment() instanceof Popup) { + popup = popupRegion.layoutId; + } else { + popup = null; + } + setFragment(popupRegion, popupRegion.getFragment()); + } + } + + public void setFragment(UIRegion region, Fragment fragment) { + if (region == null) return; + + region.setFragment(fragment); + fragmentTransaction(region.layoutId, fragment); + } + + public void fragmentTransaction(int layoutId, Fragment fragment) { + app.getActivity().getSupportFragmentManager() + .beginTransaction() + .replace(layoutId, fragment) + .commit(); + } + + public void attachAll() { + app.getActivity().setContentView(layout); + fragmentTransaction(R.id.mainContentView, mainContent.toFragment()); + for (UIRegion region : uiRegions.values()) { + setFragment(region, region.getFragment()); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_copy.bmp b/app/src/main/res/drawable/ic_copy.bmp new file mode 100644 index 0000000..322fad8 Binary files /dev/null and b/app/src/main/res/drawable/ic_copy.bmp differ diff --git a/app/src/main/res/drawable/ic_create.png b/app/src/main/res/drawable/ic_create.png new file mode 100644 index 0000000..f7716ef Binary files /dev/null and b/app/src/main/res/drawable/ic_create.png differ diff --git a/app/src/main/res/drawable/ic_hamburger_menu.png b/app/src/main/res/drawable/ic_hamburger_menu.png new file mode 100644 index 0000000..c6c049d Binary files /dev/null and b/app/src/main/res/drawable/ic_hamburger_menu.png differ diff --git a/app/src/main/res/drawable/ic_hide.bmp b/app/src/main/res/drawable/ic_hide.bmp new file mode 100644 index 0000000..b631a97 Binary files /dev/null and b/app/src/main/res/drawable/ic_hide.bmp differ diff --git a/app/src/main/res/drawable/ic_styles_menu.png b/app/src/main/res/drawable/ic_styles_menu.png new file mode 100644 index 0000000..1b2f880 Binary files /dev/null and b/app/src/main/res/drawable/ic_styles_menu.png differ diff --git a/app/src/main/res/layout/fragment_controls.xml b/app/src/main/res/layout/fragment_controls.xml new file mode 100644 index 0000000..d7a41e1 --- /dev/null +++ b/app/src/main/res/layout/fragment_controls.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + \ 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 new file mode 100644 index 0000000..e48b1ca --- /dev/null +++ b/app/src/main/res/layout/fragment_map.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_generic.xml b/app/src/main/res/layout/item_generic.xml new file mode 100644 index 0000000..7e9fa2c --- /dev/null +++ b/app/src/main/res/layout/item_generic.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/layout/item_preview.xml b/app/src/main/res/layout/item_preview.xml new file mode 100644 index 0000000..225c5a6 --- /dev/null +++ b/app/src/main/res/layout/item_preview.xml @@ -0,0 +1,58 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/popup_map_change.xml b/app/src/main/res/layout/popup_map_change.xml new file mode 100644 index 0000000..01905d4 --- /dev/null +++ b/app/src/main/res/layout/popup_map_change.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/screen_main.xml b/app/src/main/res/layout/screen_main.xml new file mode 100755 index 0000000..54c3289 --- /dev/null +++ b/app/src/main/res/layout/screen_main.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/screen_settings.xml b/app/src/main/res/layout/screen_settings.xml new file mode 100644 index 0000000..912a5d0 --- /dev/null +++ b/app/src/main/res/layout/screen_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..7fea486 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..7fea486 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..7fea486 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..7fea486 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..7fea486 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100755 index 0000000..5bf9e18 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100755 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100755 index 0000000..b5a8832 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + Strike Maps + Attribution + Earth map data Included;\n - © OpenStreetMap Contributors\nMap Rendering libraries Included;\n - MapLibre developed by MapLibre Organization\n - Vtm developed by Mapsforge\nStrike Maps made with <3 by konggdev + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100755 index 0000000..2ff8ad6 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100755 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100755 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/eu/konggdev/strikemaps/ExampleUnitTest.java b/app/src/test/java/eu/konggdev/strikemaps/ExampleUnitTest.java new file mode 100755 index 0000000..0150fa4 --- /dev/null +++ b/app/src/test/java/eu/konggdev/strikemaps/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package eu.konggdev.strikemaps; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100755 index 0000000..922f551 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,5 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +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.properties b/gradle.properties new file mode 100755 index 0000000..4387edc --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100755 index 0000000..2cbdcc4 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,30 @@ +[versions] +agp = "8.9.1" +junit = "4.13.2" +junitVersion = "1.1.5" +espressoCore = "3.5.1" +appcompat = "1.6.1" +material = "1.10.0" +activity = "1.8.0" +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" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +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" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100755 index 0000000..48b8a28 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Feb 19 10:31:32 CET 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100755 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100755 index 0000000..b268439 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,19 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven("https://jitpack.io") + } +} + +rootProject.name = "StrikeMaps" +include(":app")