diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index a3f288fd..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,120 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'de.mobilej.unmock' -apply plugin: 'net.ltgt.errorprone' - -// Place actual signing configuration in "keystore.properties" -// "keystore.properties" is in .gitignore and will not be checked into repo -def keystorePropertiesFile = rootProject.file("keystore.properties") -if (!keystorePropertiesFile.exists()) { - keystorePropertiesFile = rootProject.file("dummy_keystore.properties") -} -def keystoreProperties = new Properties() -keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) - -android { - signingConfigs { - releaseConfig { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile file(keystoreProperties['storeFile']) - storePassword keystoreProperties['storePassword'] - } - } - - compileSdk 35 - - defaultConfig { - applicationId "de.stephanlindauer.criticalmaps" - minSdkVersion 16 - targetSdkVersion 35 - versionCode 50 - versionName "2.9.2" - vectorDrawables.useSupportLibrary = true - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - testInstrumentationRunnerArguments disableAnalytics: 'true' - } - - buildTypes { - debug { - applicationIdSuffix ".debug" - pseudoLocalesEnabled true - minifyEnabled false - shrinkResources false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - release { - minifyEnabled true - shrinkResources false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.releaseConfig - } - } - - packagingOptions { - resources { - excludes += ['META-INF/services/javax.annotation.processing.Processor'] - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - buildFeatures { - viewBinding = true - buildConfig true - } - - lint { - warning 'MissingTranslation', 'StringFormatInvalid', 'NewApi', 'InvalidPackage' - } - - namespace 'de.stephanlindauer.criticalmaps' -} - -dependencies { - implementation 'com.squareup:otto:1.3.8' - implementation 'org.osmdroid:osmdroid-android:6.1.8' - implementation 'com.squareup.picasso:picasso:2.8' - implementation 'androidx.core:core:1.12.0' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'androidx.annotation:annotation:1.9.1' - implementation 'com.google.android.material:material:1.9.0' - implementation 'androidx.exifinterface:exifinterface:1.3.7' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation 'com.jakewharton.timber:timber:5.0.1' - - implementation 'com.squareup.okhttp3:okhttp:3.12.13' - - implementation 'info.metadude.android:typed-preferences:2.1.0' - - implementation "com.google.dagger:dagger:$dagger_version" - annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" - - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' - - errorprone("com.google.errorprone:error_prone_core:2.18.0") - - testImplementation 'junit:junit:4.13.2' - testImplementation 'com.google.truth:truth:1.1.3' - testImplementation 'org.mockito:mockito-core:5.4.0' - - androidTestImplementation 'androidx.test:core:1.5.0' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - - // https://youtrack.jetbrains.com/issue/KT-54136/Duplicated-classes-cause-build-failure-if-a-dependency-to-kotlin-stdlib-specified-in-an-android-project#focus=Comments-27-6583109.0-0 - constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { - because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") - } - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { - because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") - } - } -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..660e1c66 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,122 @@ +import java.util.Properties +import java.io.FileInputStream + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.unmock) +} + +// Place actual signing configuration in "keystore.properties" +// "keystore.properties" is in .gitignore and will not be checked into repo +val keystorePropertiesFile = rootProject.file("keystore.properties").let { + if (it.exists()) it else rootProject.file("dummy_keystore.properties") +} +val keystoreProperties = Properties().apply { + load(FileInputStream(keystorePropertiesFile)) +} + +android { + namespace = "de.stephanlindauer.criticalmaps" + + signingConfigs { + create("releaseConfig") { + keyAlias = keystoreProperties["keyAlias"] as String + keyPassword = keystoreProperties["keyPassword"] as String + storeFile = file(keystoreProperties["storeFile"] as String) + storePassword = keystoreProperties["storePassword"] as String + } + } + + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "de.stephanlindauer.criticalmaps" + minSdk = 26 + targetSdk = 36 + versionCode = 50 + versionName = "2.9.2" + vectorDrawables.useSupportLibrary = true + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments["disableAnalytics"] = "true" + } + + buildTypes { + debug { + applicationIdSuffix = ".debug" + isPseudoLocalesEnabled = true + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + signingConfig = signingConfigs["releaseConfig"] + } + } + + packaging { + resources { + excludes += "META-INF/services/javax.annotation.processing.Processor" + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + buildFeatures { + viewBinding = true + buildConfig = true + } + + lint { + warning.addAll( + listOf( + "MissingTranslation", + "StringFormatInvalid", + "NewApi", + "InvalidPackage" + ) + ) + } +} + +dependencies { + implementation(libs.otto) + implementation(libs.maplibre) + implementation(libs.picasso) + implementation(libs.timber) + implementation(libs.okhttp) + implementation(libs.typed.preferences) + implementation(libs.material) + implementation(libs.androidx.core) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.annotation) + implementation(libs.androidx.exifinterface) + implementation(libs.androidx.constraintlayout) + + implementation(libs.dagger) + annotationProcessor(libs.dagger.compiler) + + debugImplementation(libs.leakcanary) + + testImplementation(libs.junit) + testImplementation(libs.com.google.truth) + testImplementation(libs.org.mockito.core) + + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.androidx.test.rules) + androidTestImplementation(libs.androidx.espresso.core) +} diff --git a/app/src/androidTest/java/de/stephanlindauer/criticalmaps/ApplicationTest.java b/app/src/androidTest/java/de/stephanlindauer/criticalmaps/ApplicationTest.java index 966c0abb..a1092d54 100644 --- a/app/src/androidTest/java/de/stephanlindauer/criticalmaps/ApplicationTest.java +++ b/app/src/androidTest/java/de/stephanlindauer/criticalmaps/ApplicationTest.java @@ -1,7 +1,7 @@ package de.stephanlindauer.criticalmaps; +import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.filters.LargeTest; -import androidx.test.rule.ActivityTestRule; import org.junit.Rule; import org.junit.Test; @@ -15,7 +15,7 @@ public class ApplicationTest { @Rule - public ActivityTestRule
mActivityRule = new ActivityTestRule<>(Main.class); + public ActivityScenarioRule
mActivityRule = new ActivityScenarioRule<>(Main.class); @Test public void verifyAppLaunches() { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66de55b5..34603445 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,10 +7,8 @@ - - + OpenStreetMap contributors", + "tiles": [ + "https://vector.openstreetmap.org/shortbread_v1/{z}/{x}/{y}.mvt" + ], + "type": "vector", + "scheme": "xyz", + "bounds": [-180, -85.0511287798066, 180, 85.0511287798066], + "minzoom": 0, + "maxzoom": 14 + } + }, + "sprite": [ + {"id": "basics", "url": "https://vector.openstreetmap.org/demo/shortbread/sprites/basics/sprites"} + ], + "glyphs": "https://vector.openstreetmap.org/demo/shortbread/fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": {"background-color": "rgb(249,244,238)"} + }, + { + "id": "water-ocean", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "ocean", + "paint": {"fill-color": "rgb(190,221,243)"} + }, + { + "id": "land-glacier", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "water_polygons", + "filter": ["all", ["==", "kind", "glacier"]], + "paint": {"fill-color": "rgb(255,255,255)"} + }, + { + "id": "land-commercial", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "commercial", "retail"]], + "paint": { + "fill-color": "rgba(247,222,237,0.251)", + "fill-opacity": {"stops": [[10, 0], [11, 1]]} + } + }, + { + "id": "land-industrial", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "industrial", "quarry", "railway"]], + "paint": { + "fill-color": "rgba(255,244,194,0.333)", + "fill-opacity": {"stops": [[10, 0], [11, 1]]} + } + }, + { + "id": "land-residential", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "garages", "residential"]], + "paint": { + "fill-color": "rgba(234,230,225,0.2)", + "fill-opacity": {"stops": [[10, 0], [11, 1]]} + } + }, + { + "id": "land-agriculture", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": [ + "all", + [ + "in", + "kind", + "brownfield", + "farmland", + "farmyard", + "greenfield", + "greenhouse_horticulture", + "orchard", + "plant_nursery", + "vineyard" + ] + ], + "paint": { + "fill-color": "rgb(240,231,209)", + "fill-opacity": {"stops": [[10, 0], [11, 1]]} + } + }, + { + "id": "land-waste", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "landfill"]], + "paint": { + "fill-color": "rgb(219,214,189)", + "fill-opacity": {"stops": [[10, 0], [11, 1]]} + } + }, + { + "id": "land-park", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": [ + "all", + ["in", "kind", "park", "village_green", "recreation_ground"] + ], + "paint": { + "fill-color": "rgb(217,217,165)", + "fill-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "land-garden", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "allotments", "garden"]], + "paint": { + "fill-color": "rgb(217,217,165)", + "fill-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "land-burial", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "cemetery", "grave_yard"]], + "paint": { + "fill-color": "rgb(221,219,202)", + "fill-opacity": {"stops": [[13, 0], [14, 1]]} + } + }, + { + "id": "land-leisure", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": [ + "all", + ["in", "kind", "miniature_golf", "playground", "golf_course"] + ], + "paint": {"fill-color": "rgb(231,237,222)"} + }, + { + "id": "land-rock", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "bare_rock", "scree", "shingle"]], + "paint": {"fill-color": "rgb(224,228,229)"} + }, + { + "id": "land-forest", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "forest"]], + "paint": { + "fill-color": "rgb(102,170,68)", + "fill-opacity": {"stops": [[7, 0], [8, 0.1]]} + } + }, + { + "id": "land-grass", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": [ + "all", + ["in", "kind", "grass", "grassland", "meadow", "wet_meadow"] + ], + "paint": { + "fill-color": "rgb(216,232,200)", + "fill-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "land-vegetation", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "heath", "scrub"]], + "paint": { + "fill-color": "rgb(217,217,165)", + "fill-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "land-sand", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "beach", "sand"]], + "paint": {"fill-color": "rgb(250,250,237)"} + }, + { + "id": "land-wetland", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "land", + "filter": ["all", ["in", "kind", "bog", "marsh", "string_bog", "swamp"]], + "paint": {"fill-color": "rgb(211,230,219)"} + }, + { + "id": "water-river", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "water_lines", + "filter": [ + "all", + ["in", "kind", "river"], + ["!=", "tunnel", true], + ["!=", "bridge", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(190,221,243)", + "line-width": { + "stops": [[9, 0], [10, 3], [15, 5], [17, 9], [18, 20], [20, 60]] + } + } + }, + { + "id": "water-canal", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "water_lines", + "filter": [ + "all", + ["in", "kind", "canal"], + ["!=", "tunnel", true], + ["!=", "bridge", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(190,221,243)", + "line-width": { + "stops": [[9, 0], [10, 2], [15, 4], [17, 8], [18, 17], [20, 50]] + } + } + }, + { + "id": "water-stream", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "water_lines", + "filter": [ + "all", + ["in", "kind", "stream"], + ["!=", "tunnel", true], + ["!=", "bridge", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(190,221,243)", + "line-width": { + "stops": [[13, 0], [14, 1], [15, 2], [17, 6], [18, 12], [20, 30]] + } + } + }, + { + "id": "water-ditch", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "water_lines", + "filter": [ + "all", + ["in", "kind", "ditch"], + ["!=", "tunnel", true], + ["!=", "bridge", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(190,221,243)", + "line-width": {"stops": [[14, 0], [15, 1], [17, 4], [18, 8], [20, 20]]} + } + }, + { + "id": "water-area", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "water_polygons", + "filter": ["==", "kind", "water"], + "paint": { + "fill-color": "rgb(190,221,243)", + "fill-opacity": {"stops": [[4, 0], [6, 1]]} + } + }, + { + "id": "water-area-river", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "water_polygons", + "filter": ["==", "kind", "river"], + "paint": { + "fill-color": "rgb(190,221,243)", + "fill-opacity": {"stops": [[4, 0], [6, 1]]} + } + }, + { + "id": "water-area-small", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "water_polygons", + "filter": ["in", "kind", "reservoir", "basin", "dock"], + "paint": { + "fill-color": "rgb(190,221,243)", + "fill-opacity": {"stops": [[4, 0], [6, 1]]} + } + }, + { + "id": "water-dam-area", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "dam_polygons", + "filter": ["==", "kind", "dam"], + "paint": { + "fill-color": "rgb(249,244,238)", + "fill-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "water-dam", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "dam_lines", + "filter": ["==", "kind", "dam"], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": {"line-color": "rgb(190,221,243)"} + }, + { + "id": "water-pier-area", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "pier_polygons", + "filter": ["in", "kind", "pier", "breakwater", "groyne"], + "paint": { + "fill-color": "rgb(249,244,238)", + "fill-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "water-pier", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "pier_lines", + "filter": ["in", "kind", "pier", "breakwater", "groyne"], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": {"line-color": "rgb(249,244,238)"} + }, + { + "id": "site-dangerarea", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "danger_area"], + "paint": { + "fill-color": "rgb(255,0,0)", + "fill-outline-color": "rgb(255,0,0)", + "fill-opacity": 0.3, + "fill-pattern": "basics:pattern-warning" + } + }, + { + "id": "site-university", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "university"], + "paint": {"fill-color": "rgb(255,255,128)", "fill-opacity": 0.1} + }, + { + "id": "site-college", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "college"], + "paint": {"fill-color": "rgb(255,255,128)", "fill-opacity": 0.1} + }, + { + "id": "site-school", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "school"], + "paint": {"fill-color": "rgb(255,255,128)", "fill-opacity": 0.1} + }, + { + "id": "site-hospital", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "hospital"], + "paint": {"fill-color": "rgb(255,102,102)", "fill-opacity": 0.1} + }, + { + "id": "site-prison", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "prison"], + "paint": { + "fill-color": "rgb(253,242,252)", + "fill-pattern": "basics:pattern-striped", + "fill-opacity": 0.1 + } + }, + { + "id": "site-parking", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "parking"], + "paint": {"fill-color": "rgb(235,232,230)"} + }, + { + "id": "site-bicycleparking", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "bicycle_parking"], + "paint": {"fill-color": "rgb(235,232,230)"} + }, + { + "id": "site-construction", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "sites", + "filter": ["in", "kind", "construction"], + "paint": { + "fill-color": "rgb(169,169,169)", + "fill-pattern": "basics:pattern-hatched_thin", + "fill-opacity": 0.1 + } + }, + { + "id": "airport-area", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "street_polygons", + "filter": ["in", "kind", "runway", "taxiway"], + "paint": {"fill-color": "rgb(255,255,255)", "fill-opacity": 0.5} + }, + { + "id": "airport-taxiway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["==", "kind", "taxiway"], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[13, 0], [14, 2], [15, 10], [16, 14], [18, 20], [20, 40]] + } + } + }, + { + "id": "airport-runway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["==", "kind", "runway"], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [ + [11, 0], + [12, 6], + [13, 9], + [14, 16], + [15, 24], + [16, 40], + [17, 100], + [18, 160], + [20, 300] + ] + } + } + }, + { + "id": "airport-taxiway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["==", "kind", "taxiway"], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[13, 0], [14, 1], [15, 8], [16, 12], [18, 18], [20, 36]] + }, + "line-opacity": {"stops": [[13, 0], [14, 1]]} + } + }, + { + "id": "airport-runway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["==", "kind", "runway"], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [ + [11, 0], + [12, 5], + [13, 8], + [14, 14], + [15, 22], + [16, 38], + [17, 98], + [18, 158], + [20, 298] + ] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "building:outline", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "buildings", + "paint": { + "fill-color": "rgb(223,219,215)", + "fill-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "building", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "buildings", + "paint": { + "fill-color": "rgb(242,234,226)", + "fill-opacity": {"stops": [[14, 0], [15, 1]]}, + "fill-translate": [-2, -2] + } + }, + { + "id": "tunnel-street-pedestrian-zone", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "street_polygons", + "filter": ["all", ["==", "tunnel", true], ["==", "kind", "pedestrian"]], + "paint": { + "fill-color": "rgb(247,247,247)", + "fill-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-way-footway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "footway"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "hsl(288,13%,86%)" + } + }, + { + "id": "tunnel-way-steps:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "steps"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "hsl(288,13%,86%)" + } + }, + { + "id": "tunnel-way-path:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "path"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "hsl(288,13%,86%)" + } + }, + { + "id": "tunnel-way-cycleway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "cycleway"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "hsl(203,11%,87%)" + } + }, + { + "id": "tunnel-street-track:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "track"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[14, 2], [16, 4], [18, 18], [19, 48], [20, 96]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "tunnel-street-pedestrian:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "pedestrian"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "service"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(221,220,218)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 12], [19, 32], [20, 48]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "tunnel-street-livingstreet:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-residential:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "residential"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-unclassified:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "unclassified"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-tertiary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-secondary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "tunnel-street-primary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "tunnel-street-trunk-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "tunnel-street-motorway-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "tunnel-street-tertiary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(222,222,222)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-secondary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": { + "stops": [[11, 2], [14, 5], [16, 8], [18, 30], [19, 68], [20, 138]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "tunnel-street-primary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": { + "stops": [ + [8, 0], + [9, 1], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "tunnel-street-trunk:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": { + "stops": [ + [7, 0], + [8, 2], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "tunnel-street-motorway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(234,176,126)", + "line-dasharray": [1, 0.3], + "line-width": { + "stops": [ + [5, 0], + [6, 2], + [10, 5], + [14, 5], + [16, 14], + [18, 38], + [19, 84], + [20, 168] + ] + } + } + }, + { + "id": "tunnel-way-footway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "footway"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "hsl(288,33%,94%)", + "line-dasharray": [1, 0.2] + } + }, + { + "id": "tunnel-way-steps", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "steps"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "hsl(288,33%,94%)", + "line-dasharray": [1, 0.2] + } + }, + { + "id": "tunnel-way-path", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "path"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "hsl(288,33%,94%)", + "line-dasharray": [1, 0.2] + } + }, + { + "id": "tunnel-way-cycleway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "tunnel", true], ["in", "kind", "cycleway"]], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "hsl(203,30%,95%)", + "line-dasharray": [1, 0.2] + } + }, + { + "id": "tunnel-street-track", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "track"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 16], [19, 44], [20, 88]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "tunnel-street-pedestrian", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "pedestrian"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "service"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[14, 1], [16, 2], [18, 10], [19, 28], [20, 40]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "tunnel-street-livingstreet", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-residential", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "residential"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-unclassified", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "unclassified"], ["==", "tunnel", true]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-track-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "track"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": {"line-color": "rgb(247,247,247)"} + }, + { + "id": "tunnel-street-pedestrian-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "pedestrian"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-service-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "service"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": {"line-color": "rgb(247,247,247)"} + }, + { + "id": "tunnel-street-livingstreet-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-residential-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "residential"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-unclassified-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "unclassified"], + ["==", "bicycle", "designated"], + ["==", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-tertiary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-secondary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "tunnel-street-primary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "tunnel-street-trunk-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "tunnel-street-motorway-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,209,148)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "tunnel-street-tertiary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "tunnel-street-secondary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": { + "stops": [[11, 1], [14, 4], [16, 6], [18, 28], [19, 64], [20, 130]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "tunnel-street-primary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": { + "stops": [ + [8, 0], + [9, 2], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[8, 0], [9, 1]]} + } + }, + { + "id": "tunnel-street-trunk", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,240,179)", + "line-width": { + "stops": [ + [7, 0], + [8, 1], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[7, 0], [8, 1]]} + } + }, + { + "id": "tunnel-street-motorway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "tunnel", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,209,148)", + "line-width": { + "stops": [ + [5, 0], + [6, 1], + [10, 4], + [14, 4], + [16, 12], + [18, 36], + [19, 80], + [20, 160] + ] + }, + "line-opacity": {"stops": [[5, 0], [6, 1]]} + } + }, + { + "id": "tunnel-transport-tram:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "tunnel-transport-narrowgauge:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "tunnel-transport-subway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(166,184,199)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 3], + [16, 3], + [18, 6], + [19, 8], + [20, 10] + ] + }, + "line-opacity": {"stops": [[11, 0], [12, 0.5]]} + } + }, + { + "id": "tunnel-transport-lightrail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[11, 0], [12, 0.5]]} + } + }, + { + "id": "tunnel-transport-lightrail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "tunnel-transport-rail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[8, 0], [9, 0.3]]} + } + }, + { + "id": "tunnel-transport-rail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "tunnel-transport-monorail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["in", "kind", "monorail"], ["==", "tunnel", true]], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "tunnel-transport-funicular:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["in", "kind", "funicular"], ["==", "tunnel", true]], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "tunnel-transport-tram", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "tunnel-transport-narrowgauge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "tunnel-transport-subway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(188,202,213)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 2], + [16, 2], + [18, 5], + [19, 6], + [20, 8] + ] + }, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "tunnel-transport-lightrail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "tunnel-transport-lightrail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "tunnel-transport-rail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 0.3]]} + } + }, + { + "id": "tunnel-transport-rail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["==", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "tunnel-transport-monorail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": ["all", ["in", "kind", "monorail"], ["==", "tunnel", true]], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "tunnel-transport-funicular", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": ["all", ["in", "kind", "funicular"], ["==", "tunnel", true]], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "bridge", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "bridges", + "paint": { + "fill-color": "rgb(244,239,233)", + "fill-antialias": true, + "fill-opacity": 0.8 + } + }, + { + "id": "street-pedestrian-zone", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "street_polygons", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["==", "kind", "pedestrian"] + ], + "paint": { + "fill-color": "rgba(251,235,255,0.25)", + "fill-opacity": {"stops": [[12, 0], [13, 1], [14, 0], [15, 1]]} + } + }, + { + "id": "way-footway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "footway"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "way-steps:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "steps"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "way-path:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "path"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "way-cycleway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "cycleway"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(215,224,230)" + } + }, + { + "id": "street-track:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "track"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[14, 2], [16, 4], [18, 18], [19, 48], [20, 96]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "street-pedestrian:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "pedestrian"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(221,220,218)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 12], [19, 32], [20, 48]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "street-livingstreet:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-residential:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "residential"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-unclassified:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "unclassified"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-tertiary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-secondary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "street-primary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "street-trunk-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "street-motorway-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "street-tertiary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(207,205,202)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-secondary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [[11, 2], [14, 5], [16, 8], [18, 30], [19, 68], [20, 138]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "street-primary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [8, 0], + [9, 1], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "street-trunk:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [7, 0], + [8, 2], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "street-motorway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [5, 0], + [6, 2], + [10, 5], + [14, 5], + [16, 14], + [18, 38], + [19, 84], + [20, 168] + ] + } + } + }, + { + "id": "way-footway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "footway"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "way-steps", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "steps"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "way-path", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "path"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "way-cycleway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "cycleway"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(239,249,255)" + } + }, + { + "id": "street-track", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "track"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 16], [19, 44], [20, 88]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "street-pedestrian", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "pedestrian"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(251,235,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 0], [14, 1]]} + } + }, + { + "id": "street-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[14, 1], [16, 2], [18, 10], [19, 28], [20, 40]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "street-livingstreet", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-residential", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "residential"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-unclassified", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "unclassified"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-track-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "track"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": {"line-color": "rgb(255,255,255)"} + }, + { + "id": "street-pedestrian-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "pedestrian"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-service-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "service"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": {"line-color": "rgb(255,255,255)"} + }, + { + "id": "street-livingstreet-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-residential-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "residential"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-unclassified-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "unclassified"], + ["==", "bicycle", "designated"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-tertiary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-secondary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "street-primary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "street-trunk-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "street-motorway-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,204,136)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "street-tertiary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "street-secondary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [[11, 1], [14, 4], [16, 6], [18, 28], [19, 64], [20, 130]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "street-primary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [ + [8, 0], + [9, 2], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[8, 0], [9, 1]]} + } + }, + { + "id": "street-trunk", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [ + [7, 0], + [8, 1], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[7, 0], [8, 1]]} + } + }, + { + "id": "street-motorway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["!=", "bridge", true], + ["!=", "tunnel", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(255,204,136)", + "line-width": { + "stops": [ + [5, 0], + [6, 1], + [10, 4], + [14, 4], + [16, 12], + [18, 36], + [19, 80], + [20, 160] + ] + }, + "line-opacity": {"stops": [[5, 0], [6, 1]]} + } + }, + { + "id": "transport-tram:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "transport-narrowgauge:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "transport-subway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(166,184,199)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 3], + [16, 3], + [18, 6], + [19, 8], + [20, 10] + ] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "transport-lightrail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "transport-lightrail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "transport-rail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[8, 0], [9, 1]]} + } + }, + { + "id": "transport-rail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "transport-monorail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "monorail"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "transport-funicular:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "funicular"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "transport-tram", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "transport-narrowgauge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "transport-subway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(188,202,213)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 2], + [16, 2], + [18, 5], + [19, 6], + [20, 8] + ] + }, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "transport-lightrail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "transport-lightrail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "transport-rail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "transport-rail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "transport-monorail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "monorail"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "transport-funicular", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "funicular"], + ["!=", "bridge", true], + ["!=", "tunnel", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "transport-ferry", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "ferries", + "minzoom": 10, + "paint": { + "line-color": "rgb(171,199,219)", + "line-width": {"stops": [[10, 1], [13, 2], [14, 3], [16, 4], [17, 6]]}, + "line-opacity": {"stops": [[10, 0], [11, 1]]}, + "line-dasharray": [1, 1] + } + }, + { + "id": "bridge-way-footway:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "footway"]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[15, 0], [16, 7], [18, 10], [19, 17], [20, 31]] + } + } + }, + { + "id": "bridge-way-steps:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "steps"]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[15, 0], [16, 7], [18, 10], [19, 17], [20, 31]] + } + } + }, + { + "id": "bridge-way-path:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "path"]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[15, 0], [16, 7], [18, 10], [19, 17], [20, 31]] + } + } + }, + { + "id": "bridge-way-cycleway:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "cycleway"]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[15, 0], [16, 7], [18, 10], [19, 17], [20, 31]] + } + } + }, + { + "id": "bridge-street-track:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "track"], ["==", "bridge", true]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[14, 0], [15, 1]]}, + "line-width": { + "stops": [[14, 3], [16, 6], [18, 25], [19, 67], [20, 134]] + } + } + }, + { + "id": "bridge-street-pedestrian:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "pedestrian"], ["==", "bridge", true]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-service:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "service"], ["==", "bridge", true]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[14, 0], [15, 1]]}, + "line-width": { + "stops": [[14, 3], [16, 6], [18, 25], [19, 67], [20, 134]] + } + } + }, + { + "id": "bridge-street-livingstreet:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bridge", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-residential:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "residential"], ["==", "bridge", true]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-unclassified:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "unclassified"], ["==", "bridge", true]], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-tertiary-link:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-secondary-link:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 10], [18, 20], [20, 56]] + } + } + }, + { + "id": "bridge-street-primary-link:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 10], [18, 20], [20, 56]] + } + } + }, + { + "id": "bridge-street-trunk-link:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 10], [18, 20], [20, 56]] + } + } + }, + { + "id": "bridge-street-motorway-link:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 10], [18, 20], [20, 56]] + } + } + }, + { + "id": "bridge-street-tertiary:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[12, 0], [13, 1]]}, + "line-width": { + "stops": [[12, 3], [14, 4], [16, 8], [18, 36], [19, 90], [20, 179]] + } + } + }, + { + "id": "bridge-street-secondary:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": {"stops": [[11, 0], [12, 1]]}, + "line-width": { + "stops": [[11, 3], [14, 7], [16, 11], [18, 42], [19, 95], [20, 193]] + } + } + }, + { + "id": "bridge-street-primary:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [ + [8, 0], + [9, 1], + [10, 6], + [14, 8], + [16, 17], + [18, 50], + [19, 104], + [20, 202] + ] + } + } + }, + { + "id": "bridge-street-trunk:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [ + [7, 0], + [8, 3], + [10, 6], + [14, 8], + [16, 17], + [18, 50], + [19, 104], + [20, 202] + ] + } + } + }, + { + "id": "bridge-street-motorway:bridge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-cap": "butt", "line-join": "round"}, + "paint": { + "line-color": "rgb(244,239,233)", + "line-opacity": 0.5, + "line-width": { + "stops": [ + [5, 0], + [6, 3], + [10, 7], + [14, 7], + [16, 20], + [18, 53], + [19, 118], + [20, 235] + ] + } + } + }, + { + "id": "bridge-street-pedestrian-zone", + "type": "fill", + "source": "versatiles-shortbread", + "source-layer": "street_polygons", + "filter": ["all", ["==", "bridge", true], ["==", "kind", "pedestrian"]], + "paint": { + "fill-color": "rgb(255,255,255)", + "fill-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-way-footway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "footway"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "bridge-way-steps:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "steps"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "bridge-way-path:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "path"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(226,212,230)" + } + }, + { + "id": "bridge-way-cycleway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "cycleway"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 5], [18, 7], [19, 12], [20, 22]] + }, + "line-color": "rgb(215,224,230)" + } + }, + { + "id": "bridge-street-track:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "track"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[14, 2], [16, 4], [18, 18], [19, 48], [20, 96]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "bridge-street-pedestrian:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "pedestrian"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "service"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(221,220,218)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 12], [19, 32], [20, 48]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "bridge-street-livingstreet:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-residential:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "residential"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-unclassified:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "unclassified"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-tertiary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-secondary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "bridge-street-primary-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "bridge-street-trunk-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "bridge-street-motorway-link:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": {"stops": [[12, 2], [14, 3], [16, 7], [18, 14], [20, 40]]} + } + }, + { + "id": "bridge-street-tertiary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(217,217,217)", + "line-width": { + "stops": [[12, 2], [14, 3], [16, 6], [18, 26], [19, 64], [20, 128]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-secondary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [[11, 2], [14, 5], [16, 8], [18, 30], [19, 68], [20, 138]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "bridge-street-primary:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [8, 0], + [9, 1], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "bridge-street-trunk:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [7, 0], + [8, 2], + [10, 4], + [14, 6], + [16, 12], + [18, 36], + [19, 74], + [20, 144] + ] + } + } + }, + { + "id": "bridge-street-motorway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(233,172,119)", + "line-width": { + "stops": [ + [5, 0], + [6, 2], + [10, 5], + [14, 5], + [16, 14], + [18, 38], + [19, 84], + [20, 168] + ] + } + } + }, + { + "id": "bridge-way-footway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "footway"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "bridge-way-steps", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "steps"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "bridge-way-path", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "path"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(251,235,255)" + } + }, + { + "id": "bridge-way-cycleway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["==", "bridge", true], ["in", "kind", "cycleway"]], + "layout": {"line-cap": "butt"}, + "paint": { + "line-width": { + "stops": [[15, 0], [16, 4], [18, 6], [19, 10], [20, 20]] + }, + "line-color": "rgb(239,249,255)" + } + }, + { + "id": "bridge-street-track", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "track"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[14, 1], [16, 3], [18, 16], [19, 44], [20, 88]] + }, + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "bridge-street-pedestrian", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "pedestrian"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "service"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(247,247,247)", + "line-width": { + "stops": [[14, 1], [16, 2], [18, 10], [19, 28], [20, 40]] + }, + "line-opacity": {"stops": [[15, 0], [16, 1]]} + } + }, + { + "id": "bridge-street-livingstreet", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-residential", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "residential"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-unclassified", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": ["all", ["==", "kind", "unclassified"], ["==", "bridge", true]], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-track-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "track"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": {"line-color": "rgb(255,255,255)"} + }, + { + "id": "bridge-street-pedestrian-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "pedestrian"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-service-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "service"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": {"line-color": "rgb(255,255,255)"} + }, + { + "id": "bridge-street-livingstreet-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "living_street"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-residential-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "residential"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-unclassified-bicycle", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "kind", "unclassified"], + ["==", "bicycle", "designated"], + ["==", "bridge", true] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "rgb(239,249,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-tertiary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-secondary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "bridge-street-primary-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "bridge-street-trunk-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "bridge-street-motorway-link", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 12, + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["==", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,204,136)", + "line-width": {"stops": [[12, 1], [14, 2], [16, 5], [18, 12], [20, 38]]} + } + }, + { + "id": "bridge-street-tertiary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "tertiary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,255,255)", + "line-width": { + "stops": [[12, 1], [14, 2], [16, 5], [18, 24], [19, 60], [20, 120]] + }, + "line-opacity": {"stops": [[12, 0], [13, 1]]} + } + }, + { + "id": "bridge-street-secondary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "secondary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [[11, 1], [14, 4], [16, 6], [18, 28], [19, 64], [20, 130]] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "bridge-street-primary", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "primary"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [ + [8, 0], + [9, 2], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[8, 0], [9, 1]]} + } + }, + { + "id": "bridge-street-trunk", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "trunk"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,238,170)", + "line-width": { + "stops": [ + [7, 0], + [8, 1], + [10, 3], + [14, 5], + [16, 10], + [18, 34], + [19, 70], + [20, 140] + ] + }, + "line-opacity": {"stops": [[7, 0], [8, 1]]} + } + }, + { + "id": "bridge-street-motorway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["==", "bridge", true], + ["in", "kind", "motorway"], + ["!=", "link", true] + ], + "layout": {"line-join": "round", "line-cap": "butt"}, + "paint": { + "line-color": "rgb(255,204,136)", + "line-width": { + "stops": [ + [5, 0], + [6, 1], + [10, 4], + [14, 4], + [16, 12], + [18, 36], + [19, 80], + [20, 160] + ] + }, + "line-opacity": {"stops": [[5, 0], [6, 1]]} + } + }, + { + "id": "bridge-transport-tram:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "bridge-transport-narrowgauge:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "bridge-transport-subway:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(166,184,199)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 3], + [16, 3], + [18, 6], + [19, 8], + [20, 10] + ] + }, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "bridge-transport-lightrail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[11, 0], [12, 1]]} + } + }, + { + "id": "bridge-transport-lightrail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "bridge-transport-rail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 8, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[8, 1], [13, 1], [15, 1], [20, 14]]}, + "line-opacity": {"stops": [[8, 0], [9, 1]]} + } + }, + { + "id": "bridge-transport-rail-service:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[14, 0], [15, 1], [16, 1], [20, 14]]} + } + }, + { + "id": "bridge-transport-monorail:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["in", "kind", "monorail"], ["==", "bridge", true]], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "bridge-transport-funicular:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": ["all", ["in", "kind", "funicular"], ["==", "bridge", true]], + "paint": { + "line-color": "rgb(177,187,196)", + "line-width": {"stops": [[15, 0], [16, 5], [18, 7], [20, 20]]}, + "line-dasharray": [0.1, 0.5] + } + }, + { + "id": "bridge-transport-tram", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "tram"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "bridge-transport-narrowgauge", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "narrow_gauge"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "bridge-transport-subway", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "filter": [ + "all", + ["in", "kind", "subway"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(188,202,213)", + "line-width": { + "stops": [ + [11, 0], + [12, 1], + [15, 2], + [16, 2], + [18, 5], + [19, 6], + [20, 8] + ] + }, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "bridge-transport-lightrail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "bridge-transport-lightrail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "light_rail"], + ["has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "bridge-transport-rail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "rail"], + ["!has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[14, 0], [15, 1], [20, 10]]}, + "line-dasharray": [2, 2], + "line-opacity": {"stops": [[14, 0], [15, 1]]} + } + }, + { + "id": "bridge-transport-rail-service", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 15, + "filter": [ + "all", + ["in", "kind", "rail"], + ["has", "service"], + ["==", "bridge", true] + ], + "paint": { + "line-color": "rgb(197,204,211)", + "line-width": {"stops": [[15, 0], [16, 1], [20, 10]]}, + "line-dasharray": [2, 2] + } + }, + { + "id": "bridge-transport-monorail", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": ["all", ["in", "kind", "monorail"], ["==", "bridge", true]], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "bridge-transport-funicular", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 13, + "filter": ["all", ["in", "kind", "funicular"], ["==", "bridge", true]], + "paint": { + "line-width": {"stops": [[13, 0], [16, 1], [17, 2], [18, 3], [20, 5]]}, + "line-color": "rgb(177,187,196)" + } + }, + { + "id": "poi-amenity", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "amenity"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "amenity"], + "arts_centre", + "basics:icon-art_gallery", + "atm", + "basics:icon-atm", + "bank", + "basics:icon-bank", + "bar", + "basics:icon-bar", + "bench", + "basics:icon-bench", + "bicycle_rental", + "basics:icon-bicycle_share", + "biergarten", + "basics:icon-beergarden", + "cafe", + "basics:icon-cafe", + "car_rental", + "basics:icon-car_rental", + "car_sharing", + "basics:icon-car_rental", + "car_wash", + "basics:icon-car_wash", + "cinema", + "basics:icon-cinema", + "college", + "basics:icon-college", + "community_centre", + "basics:icon-community", + "dentist", + "basics:icon-dentist", + "doctors", + "basics:icon-doctor", + "dog_park", + "basics:icon-dog_park", + "drinking_water", + "basics:icon-drinking_water", + "embassy", + "basics:icon-embassy", + "fast_food", + "basics:icon-fast_food", + "fire_station", + "basics:icon-fire_station", + "fountain", + "basics:icon-fountain", + "grave_yard", + "basics:icon-cemetery", + "hospital", + "basics:icon-hospital", + "hunting_stand", + "basics:icon-huntingstand", + "library", + "basics:icon-library", + "marketplace", + "basics:icon-marketplace", + "nightclub", + "basics:icon-nightclub", + "nursing_home", + "basics:icon-nursinghome", + "pharmacy", + "basics:icon-pharmacy", + "place_of_worship", + "basics:icon-place_of_worship", + "playground", + "basics:icon-playground", + "police", + "basics:icon-police", + "post_box", + "basics:icon-postbox", + "post_office", + "basics:icon-post", + "prison", + "basics:icon-prison", + "pub", + "basics:icon-beer", + "recycling", + "basics:icon-recycling", + "restaurant", + "basics:icon-restaurant", + "school", + "basics:icon-school", + "shelter", + "basics:icon-shelter", + "telephone", + "basics:icon-telephone", + "theatre", + "basics:icon-theatre", + "toilets", + "basics:icon-toilet", + "townhall", + "basics:icon-town_hall", + "vending_machine", + "basics:icon-vendingmachine", + "veterinary", + "basics:icon-veterinary", + "waste_basket", + "basics:icon-waste_basket", + "" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-leisure", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "leisure"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "leisure"], + "golf_course", + "basics:icon-golf", + "ice_rink", + "basics:icon-icerink", + "pitch", + "basics:icon-pitch", + "stadium", + "basics:icon-stadium", + "swimming_pool", + "basics:icon-swimming", + "water_park", + "basics:icon-waterpark", + "basics:icon-sports" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-tourism", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "tourism"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "tourism"], + "chalet", + "basics:icon-chalet", + "information", + "basics:transport-information", + "picnic_site", + "basics:icon-picnic_site", + "viewpoint", + "basics:icon-viewpoint", + "zoo", + "basics:icon-zoo", + "" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-shop", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "shop"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "shop"], + "alcohol", + "basics:icon-alcohol_shop", + "bakery", + "basics:icon-bakery", + "beauty", + "basics:icon-beauty", + "beverages", + "basics:icon-beverages", + "books", + "basics:icon-books", + "butcher", + "basics:icon-butcher", + "chemist", + "basics:icon-chemist", + "clothes", + "basics:icon-clothes", + "doityourself", + "basics:icon-doityourself", + "dry_cleaning", + "basics:icon-drycleaning", + "florist", + "basics:icon-florist", + "furniture", + "basics:icon-furniture", + "garden_centre", + "basics:icon-garden_centre", + "general", + "basics:icon-shop", + "gift", + "basics:icon-gift", + "greengrocer", + "basics:icon-greengrocer", + "hairdresser", + "basics:icon-hairdresser", + "hardware", + "basics:icon-hardware", + "jewelry", + "basics:icon-jewelry_store", + "kiosk", + "basics:icon-kiosk", + "laundry", + "basics:icon-laundry", + "newsagent", + "basics:icon-newsagent", + "optican", + "basics:icon-optician", + "outdoor", + "basics:icon-outdoor", + "shoes", + "basics:icon-shoes", + "sports", + "basics:icon-sports", + "stationery", + "basics:icon-stationery", + "toys", + "basics:icon-toys", + "travel_agency", + "basics:icon-travel_agent", + "video", + "basics:icon-video", + "basics:icon-shop" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-man_made", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "man_made"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "man_made"], + "lighthouse", + "basics:icon-lighthouse", + "surveillance", + "basics:icon-surveillance", + "tower", + "basics:icon-observation_tower", + "watermill", + "basics:icon-watermill", + "windmill", + "basics:icon-windmill", + "" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-historic", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "historic"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "historic"], + "artwork", + "basics:icon-artwork", + "castle", + "basics:icon-castle", + "monument", + "basics:icon-monument", + "wayside_shrine", + "basics:icon-shrine", + "basics:icon-historic" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-emergency", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "emergency"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"], + "icon-image": [ + "match", + ["get", "emergency"], + "defibrillator", + "basics:icon-defibrillator", + "fire_hydrant", + "basics:icon-hydrant", + "phone", + "basics:icon-emergency_phone", + "" + ] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-highway", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "highway"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "poi-office", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "pois", + "minzoom": 16, + "filter": ["to-boolean", ["get", "office"]], + "layout": { + "icon-size": {"stops": [[16, 0.5], [19, 0.5], [20, 1]]}, + "symbol-placement": "point", + "icon-optional": true, + "text-font": ["noto_sans_regular"] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4]]}, + "icon-color": "rgb(85,85,85)", + "text-color": "rgb(85,85,85)" + } + }, + { + "id": "boundary-country:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 2], + ["!=", "maritime", true], + ["!=", "disputed", true], + ["!=", "coastline", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(249,245,239)", + "line-blur": 1, + "line-width": {"stops": [[2, 0], [3, 2], [10, 8]]}, + "line-opacity": 0.75 + } + }, + { + "id": "boundary-country-disputed:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", true], + ["!=", "maritime", true], + ["!=", "coastline", true] + ], + "paint": { + "line-width": {"stops": [[2, 0], [3, 2], [10, 8]]}, + "line-opacity": 0.75, + "line-color": "rgb(249,245,239)" + } + }, + { + "id": "boundary-state:outline", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 4], + ["!=", "maritime", true], + ["!=", "disputed", true], + ["!=", "coastline", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(250,245,240)", + "line-blur": 1, + "line-width": {"stops": [[7, 0], [8, 2], [10, 4]]}, + "line-opacity": 0.75 + } + }, + { + "id": "boundary-country", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 2], + ["!=", "maritime", true], + ["!=", "disputed", true], + ["!=", "coastline", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(166,166,200)", + "line-width": {"stops": [[2, 0], [3, 1], [10, 4]]} + } + }, + { + "id": "boundary-country-disputed", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", true], + ["!=", "maritime", true], + ["!=", "coastline", true] + ], + "layout": {"line-cap": "square"}, + "paint": { + "line-width": {"stops": [[2, 0], [3, 1], [10, 4]]}, + "line-color": "rgb(190,188,207)", + "line-dasharray": [2, 1] + } + }, + { + "id": "boundary-state", + "type": "line", + "source": "versatiles-shortbread", + "source-layer": "boundaries", + "filter": [ + "all", + ["==", "admin_level", 4], + ["!=", "maritime", true], + ["!=", "disputed", true], + ["!=", "coastline", true] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "rgb(166,166,200)", + "line-width": {"stops": [[7, 0], [8, 1], [10, 2]]} + } + }, + { + "id": "label-address-housenumber", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "addresses", + "minzoom": 17, + "filter": ["has", "housenumber"], + "layout": { + "text-field": "{housenumber}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "point", + "text-anchor": "center", + "text-size": {"stops": [[17, 8], [19, 10]]} + }, + "paint": { + "text-halo-color": "rgb(243,235,227)", + "text-halo-width": 2, + "text-halo-blur": 1, + "icon-color": "rgb(169,164,158)", + "text-color": "rgb(169,164,158)" + } + }, + { + "id": "label-motorway-shield", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 14, + "filter": ["==", "kind", "motorway"], + "layout": { + "text-field": "{ref}", + "text-font": ["noto_sans_bold"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[14, 10], [18, 12], [20, 16]]} + }, + "paint": { + "icon-color": "rgb(255,255,255)", + "text-color": "rgb(255,255,255)", + "text-halo-color": "rgb(255,204,136)", + "text-halo-width": 0.1, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-pedestrian", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "pedestrian"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-livingstreet", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "living_street"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-residential", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "residential"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-unclassified", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "unclassified"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-tertiary", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "tertiary"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-secondary", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "secondary"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-primary", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "primary"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-street-trunk", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "street_labels", + "minzoom": 12, + "filter": ["==", "kind", "trunk"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "symbol-placement": "line", + "text-anchor": "center", + "text-size": {"stops": [[12, 10], [15, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-neighbourhood", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 14, + "filter": ["==", "kind", "neighbourhood"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[14, 12]]}, + "text-transform": "uppercase" + }, + "paint": { + "icon-color": "rgb(40,67,73)", + "text-color": "rgb(40,67,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-quarter", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 13, + "filter": ["==", "kind", "quarter"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[13, 13]]}, + "text-transform": "uppercase" + }, + "paint": { + "icon-color": "rgb(40,62,73)", + "text-color": "rgb(40,62,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-suburb", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 11, + "filter": ["==", "kind", "suburb"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[11, 11], [13, 14]]}, + "text-transform": "uppercase" + }, + "paint": { + "icon-color": "rgb(40,57,73)", + "text-color": "rgb(40,57,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-hamlet", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 13, + "filter": ["==", "kind", "hamlet"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[10, 11], [12, 14]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-village", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 11, + "filter": ["==", "kind", "village"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[9, 11], [12, 14]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-town", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 9, + "filter": ["==", "kind", "town"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[8, 11], [12, 14]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-boundary-state", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "boundary_labels", + "minzoom": 5, + "filter": ["in", "admin_level", 4, "4"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-transform": "uppercase", + "text-anchor": "top", + "text-offset": [0, 0.2], + "text-padding": 0, + "text-optional": true, + "text-size": {"stops": [[5, 8], [8, 12]]} + }, + "paint": { + "icon-color": "rgb(61,61,77)", + "text-color": "rgb(61,61,77)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-city", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 7, + "filter": ["==", "kind", "city"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[7, 11], [10, 14]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-statecapital", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 6, + "filter": ["==", "kind", "state_capital"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[6, 11], [10, 15]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-place-capital", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "place_labels", + "minzoom": 5, + "filter": ["==", "kind", "capital"], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-size": {"stops": [[5, 12], [10, 16]]} + }, + "paint": { + "icon-color": "rgb(40,48,73)", + "text-color": "rgb(40,48,73)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-boundary-country-small", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "boundary_labels", + "minzoom": 4, + "filter": [ + "all", + ["in", "admin_level", 2, "2"], + ["<=", "way_area", 10000000] + ], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-transform": "uppercase", + "text-anchor": "top", + "text-offset": [0, 0.2], + "text-padding": 0, + "text-optional": true, + "text-size": {"stops": [[4, 8], [5, 11]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-boundary-country-medium", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "boundary_labels", + "minzoom": 3, + "filter": [ + "all", + ["in", "admin_level", 2, "2"], + ["<", "way_area", 90000000], + [">", "way_area", 10000000] + ], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-transform": "uppercase", + "text-anchor": "top", + "text-offset": [0, 0.2], + "text-padding": 0, + "text-optional": true, + "text-size": {"stops": [[3, 8], [5, 12]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "label-boundary-country-large", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "boundary_labels", + "minzoom": 2, + "filter": [ + "all", + ["in", "admin_level", 2, "2"], + [">=", "way_area", 90000000] + ], + "layout": { + "text-field": "{name}", + "text-font": ["noto_sans_regular"], + "text-transform": "uppercase", + "text-anchor": "top", + "text-offset": [0, 0.2], + "text-padding": 0, + "text-optional": true, + "text-size": {"stops": [[2, 8], [5, 13]]} + }, + "paint": { + "icon-color": "rgb(51,51,68)", + "text-color": "rgb(51,51,68)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "marking-oneway", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 16, + "filter": [ + "all", + ["==", "oneway", true], + [ + "in", + "kind", + "trunk", + "primary", + "secondary", + "tertiary", + "unclassified", + "residential", + "living_street" + ] + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 175, + "icon-rotate": 90, + "icon-rotation-alignment": "map", + "icon-padding": 5, + "symbol-avoid-edges": true, + "icon-image": "basics:marking-arrow", + "text-font": ["noto_sans_regular"] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4], [20, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4], [20, 0.4]]} + } + }, + { + "id": "marking-oneway-reverse", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "streets", + "minzoom": 16, + "filter": [ + "all", + ["==", "oneway_reverse", true], + [ + "in", + "kind", + "trunk", + "primary", + "secondary", + "tertiary", + "unclassified", + "residential", + "living_street" + ] + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 75, + "icon-rotate": -90, + "icon-rotation-alignment": "map", + "icon-padding": 5, + "symbol-avoid-edges": true, + "icon-image": "basics:marking-arrow", + "text-font": ["noto_sans_regular"] + }, + "paint": { + "icon-opacity": {"stops": [[16, 0], [17, 0.4], [20, 0.4]]}, + "text-opacity": {"stops": [[16, 0], [17, 0.4], [20, 0.4]]} + } + }, + { + "id": "symbol-transit-bus", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 16, + "filter": ["==", "kind", "bus_stop"], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[16, 0.5], [18, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-bus" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-tram", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 15, + "filter": ["==", "kind", "tram_stop"], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[15, 0.5], [17, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:transport-tram" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-subway", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "station", "halt"], + ["==", "station", "subway"] + ], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[14, 0.5], [16, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-rail_metro" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-lightrail", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 14, + "filter": [ + "all", + ["in", "kind", "station", "halt"], + ["==", "station", "light_rail"] + ], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[14, 0.5], [16, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-rail_light" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-station", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 13, + "filter": [ + "all", + ["in", "kind", "station", "halt"], + ["!in", "station", "light_rail", "subway"] + ], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[13, 0.5], [15, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-rail" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-airfield", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 13, + "filter": ["all", ["==", "kind", "aerodrome"], ["!has", "iata"]], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[13, 0.5], [15, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-airfield" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + }, + { + "id": "symbol-transit-airport", + "type": "symbol", + "source": "versatiles-shortbread", + "source-layer": "public_transport", + "minzoom": 12, + "filter": ["all", ["==", "kind", "aerodrome"], ["has", "iata"]], + "layout": { + "text-field": "{name}", + "icon-size": {"stops": [[12, 0.5], [14, 1]]}, + "symbol-placement": "point", + "icon-keep-upright": true, + "text-font": ["noto_sans_regular"], + "text-size": 10, + "icon-anchor": "bottom", + "text-anchor": "top", + "icon-image": "basics:icon-airport" + }, + "paint": { + "icon-opacity": 0.7, + "icon-color": "rgb(102,98,106)", + "text-color": "rgb(102,98,106)", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 2, + "text-halo-blur": 1 + } + } + ], + "id": "by9sgsc" +} \ No newline at end of file diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/App.java b/app/src/main/java/de/stephanlindauer/criticalmaps/App.java index 6e43fbb4..344261de 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/App.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/App.java @@ -3,6 +3,7 @@ import android.app.Application; import org.jetbrains.annotations.NotNull; +import org.maplibre.android.MapLibre; import timber.log.Timber; @@ -25,6 +26,7 @@ public void onCreate() { } appComponent = DaggerAppComponent.builder().app(this).build(); + MapLibre.getInstance(this); } private static class NoOpTree extends Timber.Tree { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/AppComponent.java b/app/src/main/java/de/stephanlindauer/criticalmaps/AppComponent.java index 27fae478..46e221a7 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/AppComponent.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/AppComponent.java @@ -12,7 +12,6 @@ import de.stephanlindauer.criticalmaps.fragments.MapFragment; import de.stephanlindauer.criticalmaps.fragments.SettingsFragment; import de.stephanlindauer.criticalmaps.model.OwnLocationModel; -import de.stephanlindauer.criticalmaps.provider.StorageLocationProvider; import de.stephanlindauer.criticalmaps.service.ServerSyncService; import okhttp3.OkHttpClient; @@ -30,7 +29,6 @@ public interface AppComponent { OwnLocationModel ownLocationmodel(); OkHttpClient okHttpClient(); SharedPreferences sharedPreferences(); - StorageLocationProvider storageProvider(); @Component.Builder interface Builder { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/AppModule.java b/app/src/main/java/de/stephanlindauer/criticalmaps/AppModule.java index 1ddfaf13..273a8361 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/AppModule.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/AppModule.java @@ -3,9 +3,12 @@ import android.content.Context; import android.content.SharedPreferences; +import androidx.annotation.NonNull; + import com.squareup.picasso.OkHttp3Downloader; import com.squareup.picasso.Picasso; +import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.inject.Singleton; @@ -13,14 +16,42 @@ import dagger.Module; import dagger.Provides; import dagger.Reusable; +import okhttp3.Interceptor; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; @Module abstract class AppModule { @Provides @Singleton static OkHttpClient provideOKHttpClient() { - return new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).build(); + + class UserAgentInterceptor implements Interceptor { + private final String userAgent; + + public UserAgentInterceptor() { + userAgent = BuildConfig.APPLICATION_ID + + "/" + BuildConfig.VERSION_NAME + + " (stephanlindauer@posteo.de, criticalmaps.net)"; + } + + @NonNull + @Override + public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + Request requestWithUserAgent = originalRequest.newBuilder() + .removeHeader("User-Agent") + .header("User-Agent", userAgent) + .build(); + return chain.proceed(requestWithUserAgent); + } + } + + return new OkHttpClient.Builder() + .connectTimeout(15, TimeUnit.SECONDS) + .addInterceptor(new UserAgentInterceptor()) + .build(); } @Provides diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/Main.java b/app/src/main/java/de/stephanlindauer/criticalmaps/Main.java index e052efcd..0dc2a2d0 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/Main.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/Main.java @@ -1,6 +1,5 @@ package de.stephanlindauer.criticalmaps; -import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Intent; @@ -20,17 +19,20 @@ import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.Toast; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.IdRes; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; -import androidx.core.content.ContextCompat; +import androidx.core.graphics.Insets; import androidx.core.view.GravityCompat; import androidx.core.view.ViewCompat; +import androidx.core.view.ViewGroupCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.navigation.NavigationView; @@ -105,41 +107,69 @@ public void onCreate(Bundle bundle) { App.components().inject(this); binding = ActivityMainBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - binding.drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + // Setup windows inset handling + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); - // inset the toolbar down by the status bar height - ViewCompat.setOnApplyWindowInsetsListener(binding.toolbar, (v, insets) -> { - ViewGroup.MarginLayoutParams lpToolbar = - (ViewGroup.MarginLayoutParams) binding.toolbar.getLayoutParams(); - lpToolbar.topMargin += insets.getSystemWindowInsetTop(); - - binding.toolbar.setLayoutParams(lpToolbar); - - // clear this listener so insets aren't re-applied - ViewCompat.setOnApplyWindowInsetsListener(binding.toolbar, null); - return insets; - }); - - // inset header in nav drawer down by the status bar height - View navHeader = binding.drawerNavigation.getHeaderView(0); - ViewCompat.setOnApplyWindowInsetsListener(navHeader, (v, insets) -> { - v.setPaddingRelative( - v.getPaddingStart(), v.getPaddingTop() + insets.getSystemWindowInsetTop(), - v.getPaddingEnd(), v.getPaddingBottom()); - - // clear this listener so insets aren't re-applied - ViewCompat.setOnApplyWindowInsetsListener(navHeader, null); - return insets; - }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + getWindow().setStatusBarContrastEnforced(false); + getWindow().setNavigationBarContrastEnforced(false); } - // This is a little hacky and might break with a materialcomponents lib update - RecyclerView navigationMenuView = findViewById(R.id.design_navigation_view); - navigationMenuView.setNestedScrollingEnabled(false); + WindowInsetsControllerCompat insetsController = + WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()); + ViewGroupCompat.installCompatInsetsDispatch(binding.getRoot()); + + insetsController.setAppearanceLightStatusBars(true); + insetsController.setAppearanceLightNavigationBars(true); + + setContentView(binding.getRoot()); + + OnBackPressedCallback callback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) { + binding.drawerLayout.closeDrawers(); + } else if (currentNavId != R.id.navigation_map) { + navigateTo(R.id.navigation_map); + } + } + }; + getOnBackPressedDispatcher().addCallback(this, callback); + + // Apply window insets + View navHeader = binding.drawerNavigation.getHeaderView(0); + final int originalNavHeaderPaddingTop = navHeader.getPaddingTop(); + + ViewCompat.setOnApplyWindowInsetsListener(binding.drawerNavigation, (v, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); + + // Apply insets to toolbar + int toolbarMargin = currentNavId == R.id.navigation_map ? getResources().getDimensionPixelSize(R.dimen.map_toolbar_margins) : 0; + ViewGroup.MarginLayoutParams lpToolbar = + (ViewGroup.MarginLayoutParams) binding.toolbar.getLayoutParams(); + + lpToolbar.topMargin = insets.top + toolbarMargin; + lpToolbar.leftMargin = insets.left + toolbarMargin; + lpToolbar.rightMargin = insets.right + toolbarMargin; + binding.toolbar.setLayoutParams(lpToolbar); + + // Apply insets to the NavigationView + View navView = binding.drawerNavigation.findViewById(com.google.android.material.R.id.design_navigation_view); + navView.setPadding( + insets.left, // navbar horizontal + navView.getPaddingTop(), + navView.getPaddingEnd(), + insets.bottom); + + navHeader.setPadding( + navHeader.getPaddingStart(), + originalNavHeaderPaddingTop + insets.top, + navHeader.getPaddingEnd(), + navHeader.getPaddingBottom()); + + return WindowInsetsCompat.CONSUMED; + }); setShowOnLockscreen(); setKeepScreenOn(); @@ -213,12 +243,6 @@ public void onDrawerClosed(@NonNull View drawerView) { // set toolbar background ((GradientDrawable) binding.toolbar.getBackground()).setCornerRadius(0F); - - // set statusbar color - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - getWindow().setStatusBarColor( - ContextCompat.getColor(this, R.color.main_statusbarcolor_others)); - } } } else { navigateTo(R.id.navigation_map); @@ -229,7 +253,7 @@ public void onDrawerClosed(@NonNull View drawerView) { final boolean isPrivacyPolicyAccepted = privacyPolicyAcceptedPreference.get(); if (!isPrivacyPolicyAccepted) { binding.introductionText.setMovementMethod(LinkMovementMethod.getInstance()); - binding.introductionText.setText(Html.fromHtml(getString(R.string.introduction_gps))); + binding.introductionText.setText(Html.fromHtml(getString(R.string.introduction_gps), Html.FROM_HTML_MODE_LEGACY)); binding.introductionView.setVisibility(View.VISIBLE); } } @@ -277,17 +301,6 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; } - @Override - public void onBackPressed() { - if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) { - binding.drawerLayout.closeDrawers(); - } else if (currentNavId != R.id.navigation_map) { - navigateTo(R.id.navigation_map); - } else { - super.onBackPressed(); - } - } - private void handleCloseRequested() { new ApplicationCloseHandler(this).execute(); } @@ -404,19 +417,20 @@ private void navigateTo(@IdRes int navId) { getSupportFragmentManager().beginTransaction() .replace(R.id.content_frame, nextFragment).commit(); + WindowInsetsControllerCompat insetsController = + WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()); + // animate toolbar and statusbar color if (currentNavId == R.id.navigation_map) { // from map to other fragment animateToolbar(200, false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - fadeInStatusBarColor(200, false); - } + insetsController.setAppearanceLightStatusBars(false); + insetsController.setAppearanceLightNavigationBars(false); } else if (navId == R.id.navigation_map && currentNavId != 0) { // from other fragment to map AND not app start animateToolbar(500, true); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - fadeInStatusBarColor(500, true); - } + insetsController.setAppearanceLightStatusBars(true); + insetsController.setAppearanceLightNavigationBars(true); } currentNavId = navId; @@ -463,24 +477,6 @@ private void animateToolbar(int durationMillis, boolean toMap) { radiusAnimator.start(); } - @RequiresApi(Build.VERSION_CODES.LOLLIPOP) - private void fadeInStatusBarColor(int duration, boolean toMap) { - int colorMap = ContextCompat.getColor(this, R.color.main_statusbarcolor_map); - int colorOthers = ContextCompat.getColor(this, R.color.main_statusbarcolor_others); - int colorFrom = toMap ? colorOthers : colorMap; - int colorTo = toMap ? colorMap : colorOthers; - - ValueAnimator valueAnimator = - ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); - valueAnimator.setDuration(duration); - valueAnimator.addUpdateListener(animation -> { - int color = (int) animation.getAnimatedValue(); - getWindow().setStatusBarColor(color); - }); - - valueAnimator.start(); - } - @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/AboutFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/AboutFragment.java index 6b84da46..1c041fbe 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/AboutFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/AboutFragment.java @@ -27,7 +27,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - LayoutTransition layoutTransition = binding.aboutContentLayout.getLayoutTransition(); // make LicensePanelView animations look nice layoutTransition.enableTransitionType(LayoutTransition.CHANGING); @@ -38,8 +37,8 @@ public void onActivityCreated(Bundle savedInstanceState) { binding.aboutFacebookButton.setOnClickListener( new URLOpenOnActivityOnClickListener("https://www.facebook.com/criticalmaps")); - binding.aboutTwitterButton.setOnClickListener( - new URLOpenOnActivityOnClickListener("https://twitter.com/CriticalMaps")); + binding.aboutInstagramButton.setOnClickListener( + new URLOpenOnActivityOnClickListener("https://instagram.com/CriticalMaps")); binding.aboutGithubButton.setOnClickListener( new URLOpenOnActivityOnClickListener("https://github.com/criticalmaps/criticalmaps-android")); } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java index 6fc6762f..addd0c95 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java @@ -148,24 +148,18 @@ private void handleSendClicked() { // TODO handle UI state while sending, even though it shouldn't be noticeable JSONObject messageObject = chatModel.createNewOutgoingMessage(message); - new PostChatmessagesHandler(messageObject, new Runnable() { - @Override - public void run() { - // TODO check if still alive; else bail! - // TODO reset UI state - // clearAnimation(); + new PostChatmessagesHandler(messageObject, () -> { + // TODO check if still alive; else bail! + // TODO reset UI state + // clearAnimation(); - // Restart timer task so sent message shows up in list immediately - stopGetChatmessagesTimer(); - startGetChatmessagesTimer(); - } - }, new Runnable() { - @Override - public void run() { - // TODO check if still alive; else bail! - // TODO reset UI state - Toast.makeText(getContext(), R.string.something_went_wrong, Toast.LENGTH_LONG).show(); - } + // Restart timer task so sent message shows up in list immediately + stopGetChatmessagesTimer(); + startGetChatmessagesTimer(); + }, () -> { + // TODO check if still alive; else bail! + // TODO reset UI state + Toast.makeText(getContext(), R.string.something_went_wrong, Toast.LENGTH_LONG).show(); }).execute(); binding.chatMessageEdittext.setText(""); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java index a1cc2aa2..9a2ea1e9 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java @@ -1,39 +1,48 @@ package de.stephanlindauer.criticalmaps.fragments; +import static de.stephanlindauer.criticalmaps.events.Events.NEW_LOCATION_EVENT; +import static de.stephanlindauer.criticalmaps.utils.MapViewUtils.dpToInt; + import android.animation.AnimatorInflater; import android.animation.ObjectAnimator; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; +import android.graphics.Outline; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewOutlineProvider; import android.widget.Toast; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.ContextCompat; +import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; +import com.google.gson.JsonObject; import com.squareup.otto.Subscribe; -import org.osmdroid.tileprovider.modules.SqlTileWriter; -import org.osmdroid.util.GeoPoint; -import org.osmdroid.views.MapView; -import org.osmdroid.views.overlay.Overlay; -import org.osmdroid.views.overlay.gestures.RotationGestureOverlay; -import org.osmdroid.views.overlay.infowindow.InfoWindow; - +import org.maplibre.android.camera.CameraPosition; +import org.maplibre.android.camera.CameraUpdateFactory; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.android.maps.MapLibreMap; +import org.maplibre.android.maps.MapView; +import org.maplibre.android.maps.Style; +import org.maplibre.android.style.sources.GeoJsonSource; +import org.maplibre.geojson.Feature; +import org.maplibre.geojson.FeatureCollection; +import org.maplibre.geojson.Point; + +import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; @@ -48,11 +57,10 @@ import de.stephanlindauer.criticalmaps.events.NewLocationEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; import de.stephanlindauer.criticalmaps.handler.GetLocationHandler; -import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; +// import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.model.OtherUsersLocationModel; import de.stephanlindauer.criticalmaps.model.OwnLocationModel; -import de.stephanlindauer.criticalmaps.overlays.LocationMarker; import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.AlertBuilder; @@ -61,9 +69,6 @@ public class MapFragment extends Fragment { - private final static String KEY_MAP_ZOOMLEVEL = "map_zoomlevel"; - private final static String KEY_MAP_POSITION = "map_position"; - private final static String KEY_MAP_ORIENTATION = "map_orientation"; private final static String KEY_INITIAL_LOCATION_SET = "initial_location_set"; private final static double DEFAULT_ZOOM_LEVEL = 12; @@ -85,24 +90,23 @@ public class MapFragment extends Fragment { @Inject LocationUpdateManager locationUpdateManager; + /* @Inject ShowGpxHandler showGpxHandler; + */ @Inject SharedPreferences sharedPreferences; private MapView mapView; - private InfoWindow observerInfoWindow; + private MapLibreMap map; + private Style mapStyle; + // private InfoWindow observerInfoWindow; - private final GeoPoint defaultGeoPoint = new GeoPoint(52.499571, 13.4140875, 15); + private final LatLng defaultGeoPoint = new LatLng(52.499571, 13.4140875); private boolean isInitialLocationSet = false; private ObjectAnimator gpsSearchingAnimator; - // cache drawables - private Drawable locationIcon; - private Drawable ownLocationIcon; - private Drawable ownLocationIconObserver; - private FragmentMapBinding binding; private Timer timerGetLocation; @@ -110,34 +114,11 @@ public class MapFragment extends Fragment { private final View.OnClickListener centerLocationOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { - if (ownLocationModel.ownLocation != null) - animateToLocation(ownLocationModel.ownLocation); - } - }; - - private final View.OnClickListener rotationNorthOnClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - float currentRotation = mapView.getMapOrientation() % 360; - - if (currentRotation == 0.0f) { - // no animation required; also works around bug where map does a full rotation - // because of mapView wrapping 360° to 0° while View allows 360° - return; - } - - if (currentRotation < 0.0f) { - currentRotation = 360.0f + currentRotation; - binding.mapSetNorthFab.setRotation(currentRotation); - mapView.setMapOrientation(currentRotation); + if (ownLocationModel.ownLocation != null) { + CameraPosition cameraPosition = + new CameraPosition.Builder().target(ownLocationModel.ownLocation).build(); + animateToCameraPosition(cameraPosition); } - - float destinationRotation = currentRotation > 180.0f ? 360.0f : 0.0f; - ViewCompat.animate(binding.mapSetNorthFab) - .rotation(destinationRotation) - .setDuration(300L) - .setUpdateListener(view -> mapView.setMapOrientation(view.getRotation())) - .start(); } }; @@ -188,13 +169,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, binding = FragmentMapBinding.inflate(inflater, container, false); - //noinspection ConstantConditions - locationIcon = AppCompatResources.getDrawable(getActivity(), R.drawable.ic_map_marker); - ownLocationIcon = AppCompatResources.getDrawable( - getActivity(), R.drawable.ic_map_marker_own); - ownLocationIconObserver = AppCompatResources.getDrawable( - getActivity(), R.drawable.ic_map_marker_observer); - return binding.getRoot(); } @@ -202,9 +176,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public void onActivityCreated(final Bundle savedState) { super.onActivityCreated(savedState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - adjustToWindowsInsets(); - } + adjustToWindowsInsets(); App.components().inject(this); @@ -213,113 +185,161 @@ public void onActivityCreated(final Bundle savedState) { mapView = MapViewUtils.createMapView(getActivity()); binding.mapContainerLayout.addView(mapView); - observerInfoWindow = MapViewUtils.createObserverInfoWindow(mapView); + mapView.getMapAsync(map -> { + this.map = map; + + // Set shadow on compass + // NOTE: Needs to be before updating uiSettings below, otherwise compassView will be null! + View compassView = mapView.findViewWithTag("compassView"); + compassView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setOval(0, 0, view.getWidth(), view.getHeight()); + } + }); + compassView.setElevation(dpToInt(6)); + + // Set compass y position to align it with other fabs + View setCenterFab = binding.getRoot().findViewById(R.id.map_set_center_fab); + float setCenterFabY = setCenterFab.getY(); + map.getUiSettings().setCompassMargins( + dpToInt(18) + binding.mapOverlayContainerLayout.getPaddingLeft(), // when started + Math.round(setCenterFabY + dpToInt(18)), + 0, + 0); + + // TODO: save sprites and glyphs as local asset, + // see https://github.com/maplibre/flutter-maplibre-gl/issues/338 + Style.Builder styleBuilder = new Style.Builder().fromUri("asset://styles/versatilescolorful.json"); + + map.setStyle(styleBuilder, style -> { + mapStyle = style; + MapViewUtils.setupSourcesAndLayers(getActivity(), mapStyle); + + // trigger fake location update in case fix was acquired already during map init + handleNewLocation(NEW_LOCATION_EVENT); + }); + }); + mapView.onCreate(savedState); // TODO: Should be onViewCreated + + // observerInfoWindow = MapViewUtils.createObserverInfoWindow(mapView); binding.mapSetCenterFab.setOnClickListener(centerLocationOnClickListener); - binding.mapSetNorthFab.setOnClickListener(rotationNorthOnClickListener); binding.mapNoDataConnectivityFab.setOnClickListener(v -> AlertBuilder.show(getActivity(), R.string.map_no_internet_connection_title, R.string.map_no_internet_connection_text)); - if (new BooleanPreference(sharedPreferences, SharedPrefsKeys.DISABLE_MAP_ROTATION).get()) { - binding.mapSetNorthFab.setVisibility(View.GONE); - } else { - RotationGestureOverlay rotationGestureOverlay = new RotationGestureOverlay(mapView) { - @Override - public void onRotate(float deltaAngle) { - super.onRotate(deltaAngle); - binding.mapSetNorthFab.setRotation(mapView.getMapOrientation()); - } - }; - rotationGestureOverlay.setEnabled(true); - mapView.setMultiTouchControls(true); - mapView.getOverlays().add(rotationGestureOverlay); - } - if (savedState != null) { - Double zoomLevel = (Double) savedState.get(KEY_MAP_ZOOMLEVEL); - GeoPoint position = savedState.getParcelable(KEY_MAP_POSITION); - Float orientation = (Float) savedState.get(KEY_MAP_ORIENTATION); - - if (zoomLevel != null && position != null && orientation != null) { - mapView.getController().setZoom(zoomLevel); - if (!new BooleanPreference(sharedPreferences, SharedPrefsKeys.DISABLE_MAP_ROTATION) - .get()) { - mapView.setMapOrientation(orientation); - } - setToLocation(position); - } - isInitialLocationSet = savedState.getBoolean(KEY_INITIAL_LOCATION_SET, false); } - binding.mapSetNorthFab.setRotation(mapView.getMapOrientation()); - showGpxHandler.showGpx(mapView); + // showGpxHandler.showGpx(mapView); if (!LocationUpdateManager.checkPermission()) { zoomToLocation(defaultGeoPoint, NO_GPS_PERMISSION_ZOOM_LEVEL); } } - @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private void adjustToWindowsInsets() { - // No-op on < API21 + // inset the map overlays for the status bar + final int originalContainerPaddingTop = binding.mapOverlayContainerLayout.getPaddingTop(); + final int originalContainerPaddingLeft = binding.mapOverlayContainerLayout.getPaddingLeft(); + final int originalContainerPaddingRight = binding.mapOverlayContainerLayout.getPaddingRight(); ViewCompat.setOnApplyWindowInsetsListener(binding.mapOverlayContainerLayout, (v, insets) -> { - // inset the map overlays for the status bar - v.setPaddingRelative( - v.getPaddingStart(), v.getPaddingTop() + insets.getSystemWindowInsetTop(), - v.getPaddingEnd(), v.getPaddingBottom()); + Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding( + originalContainerPaddingLeft + systemBarsInsets.left, + originalContainerPaddingTop + systemBarsInsets.top, + originalContainerPaddingRight + systemBarsInsets.right, + v.getPaddingBottom()); + + if (map != null) { + map.getUiSettings().setCompassMargins( + dpToInt(18) + binding.mapOverlayContainerLayout.getPaddingLeft(), // when started + map.getUiSettings().getCompassMarginTop(), + 0, + 0); + } - // clear this listener so insets aren't re-applied - ViewCompat.setOnApplyWindowInsetsListener(binding.mapOverlayContainerLayout, null); return insets; }); - // without this insets aren't reapplied on fragment changes - ViewCompat.requestApplyInsets(binding.mapOverlayContainerLayout); + // inset attribution + ViewGroup.MarginLayoutParams lpNoticeText = + (ViewGroup.MarginLayoutParams) binding.mapOsmNoticeText.getLayoutParams(); + final int originalNoticeTextBottomMargin = lpNoticeText.bottomMargin; + ViewCompat.setOnApplyWindowInsetsListener(binding.mapOsmNoticeText, (v, insets) -> { + Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + lpNoticeText.bottomMargin = originalNoticeTextBottomMargin + systemBarsInsets.bottom; + v.setLayoutParams(lpNoticeText); + + return WindowInsetsCompat.CONSUMED; + }); + } + + private FeatureCollection getOtherUsersFeatureCollection() { + ArrayList features = new ArrayList<>(); + + otherUsersLocationModel.getOtherUsersLocations().forEach((deviceId, location) -> { + JsonObject properties = new JsonObject(); + properties.addProperty("deviceId", deviceId); + features.add(Feature.fromGeometry(Point.fromLngLat(location.getLongitude(), location.getLatitude()), properties)); + }); + return FeatureCollection.fromFeatures(features); + } + + private FeatureCollection getOwnUserFeatureCollection() { + ArrayList features = new ArrayList<>(); + + LatLng location = ownLocationModel.ownLocation; + JsonObject properties = new JsonObject(); + properties.addProperty("deviceId", "own"); + features.add(Feature.fromGeometry(Point.fromLngLat(location.getLongitude(), location.getLatitude()), properties)); + + return FeatureCollection.fromFeatures(features); } private void refreshView() { - for (Overlay overlay : mapView.getOverlays()) { - if (overlay instanceof LocationMarker) { - mapView.getOverlays().remove(overlay); - } + if (map == null || mapStyle == null) { + return; } - for (GeoPoint currentOtherUsersLocation : otherUsersLocationModel.getOtherUsersLocations()) { - LocationMarker otherPeoplesMarker = new LocationMarker(mapView); - otherPeoplesMarker.setPosition(currentOtherUsersLocation); - otherPeoplesMarker.setIcon(locationIcon); - mapView.getOverlays().add(otherPeoplesMarker); - } + FeatureCollection otherUsersFeatures = getOtherUsersFeatureCollection(); + GeoJsonSource otherUsersLocationsSource = + (GeoJsonSource) mapStyle.getSource("otherUsersLocationsSource"); + otherUsersLocationsSource.setGeoJson(otherUsersFeatures); if (ownLocationModel.ownLocation != null) { - GeoPoint currentUserLocation = ownLocationModel.ownLocation; - LocationMarker ownMarker = new LocationMarker(mapView); - ownMarker.setPosition(currentUserLocation); - if (new BooleanPreference( - sharedPreferences, SharedPrefsKeys.OBSERVER_MODE_ACTIVE).get()) { - ownMarker.setIcon(ownLocationIconObserver); - ownMarker.setInfoWindow(observerInfoWindow); - // since we're currently creating new markers on every refresh, this workaround - // is needed to update the info window's position if it's open - if (observerInfoWindow.isOpen()) { - ownMarker.showInfoWindow(); - } + FeatureCollection ownUserFeatures = getOwnUserFeatureCollection(); + FeatureCollection emptyFeatures = + FeatureCollection.fromJson("{\"type\":\"FeatureCollection\",\"features\":[]}"); + + GeoJsonSource ownUserLocationSourceObserver = + (GeoJsonSource) mapStyle.getSource("ownUserLocationSourceObserver"); + GeoJsonSource ownUserLocationSource = + (GeoJsonSource) mapStyle.getSource("ownUserLocationSource"); + + if (new BooleanPreference(sharedPreferences, SharedPrefsKeys.OBSERVER_MODE_ACTIVE).get()) { + ownUserLocationSource.setGeoJson(emptyFeatures); + ownUserLocationSourceObserver.setGeoJson(ownUserFeatures); } else { - observerInfoWindow.close(); - ownMarker.setIcon(ownLocationIcon); + ownUserLocationSource.setGeoJson(ownUserFeatures); + ownUserLocationSourceObserver.setGeoJson(emptyFeatures); } - mapView.getOverlays().add(ownMarker); } + } - mapView.invalidate(); + @Override + public void onStart() { + super.onStart(); + mapView.onStart(); } @Override public void onResume() { super.onResume(); + mapView.onResume(); eventBus.register(this); sharedPreferences.registerOnSharedPreferenceChangeListener( @@ -329,6 +349,9 @@ public void onResume() { } private void handleFirstLocationUpdate() { + if (map == null) { + return; + } setGpsStatusFixed(); zoomToLocation(ownLocationModel.ownLocation, DEFAULT_ZOOM_LEVEL); isInitialLocationSet = true; @@ -338,9 +361,9 @@ private void handleFirstLocationUpdate() { public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); - outState.putDouble(KEY_MAP_ZOOMLEVEL, mapView.getZoomLevelDouble()); - outState.putParcelable(KEY_MAP_POSITION, (GeoPoint) mapView.getMapCenter()); - outState.putFloat(KEY_MAP_ORIENTATION, mapView.getMapOrientation()); + if (mapView != null && !mapView.isDestroyed()) { + mapView.onSaveInstanceState(outState); + } outState.putBoolean(KEY_INITIAL_LOCATION_SET, isInitialLocationSet); } @@ -348,22 +371,33 @@ public void onSaveInstanceState(@NonNull Bundle outState) { public void onPause() { super.onPause(); + mapView.onPause(); stopGetLocationTimer(); eventBus.unregister(this); sharedPreferences.unregisterOnSharedPreferenceChangeListener( observerModeOnSharedPreferenceChangeListener); } + @Override + public void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + if (mapView != null && !mapView.isDestroyed()) { + mapView.onLowMemory(); + } + } + @Override public void onDestroyView() { super.onDestroyView(); - // properly closes the cache db since it's stored in a static field in osmdroid... - try { - ((SqlTileWriter) mapView.getTileProvider().getTileWriter()).refreshDb(); - } catch (Exception ignored) { - // nothing we can do - } + mapView.onDestroy(); mapView = null; + map = null; binding = null; } @@ -465,9 +499,6 @@ private void setGpsStatusCommon(@ColorRes int colorResId, @DrawableRes int iconR binding.mapSetCenterFab.setBackgroundTintList( ContextCompat.getColorStateList(getActivity(), colorResId)); binding.mapSetCenterFab.setImageResource(iconResId); - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) { - binding.mapSetCenterFab.refreshDrawableState(); - } binding.mapSetCenterFab.setOnClickListener(onClickListener); } @@ -478,18 +509,19 @@ private void cancelGpsSearchingAnimationIfRunning() { } } - private void zoomToLocation(final GeoPoint location, final double zoomLevel) { - // TODO use setCenter() + zoomTo() here; currently broken and ends up in a wrong location - mapView.getController().setZoom(zoomLevel); - animateToLocation(location); + private void zoomToLocation(final LatLng location, final double zoomLevel) { + CameraPosition cameraPosition = + new CameraPosition.Builder().target(location).zoom(zoomLevel).build(); + animateToCameraPosition(cameraPosition); } - private void animateToLocation(final GeoPoint location) { - mapView.getController().animateTo(location); - } + private void animateToCameraPosition(final CameraPosition cameraPosition) { + if (map == null) { + return; + } - private void setToLocation(final GeoPoint location) { - mapView.getController().setCenter(location); + map.animateCamera( + CameraUpdateFactory.newCameraPosition(cameraPosition), 2000, null); } private void startGetLocationTimer() { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java index 99026c05..413048e6 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/SettingsFragment.java @@ -1,14 +1,13 @@ package de.stephanlindauer.criticalmaps.fragments; -import android.annotation.SuppressLint; -import android.app.Activity; +// import android.annotation.SuppressLint; +// import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; +// import android.database.Cursor; +// import android.net.Uri; import android.os.Bundle; -import android.provider.OpenableColumns; +// import android.provider.OpenableColumns; import android.text.format.Formatter; import android.view.LayoutInflater; import android.view.View; @@ -16,36 +15,33 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; -import java.util.ArrayList; - import javax.inject.Inject; import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.R; import de.stephanlindauer.criticalmaps.databinding.FragmentSettingsBinding; -import de.stephanlindauer.criticalmaps.handler.ChooseGpxFileHandler; +// import de.stephanlindauer.criticalmaps.handler.ChooseGpxFileHandler; import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; -import de.stephanlindauer.criticalmaps.provider.StorageLocationProvider; -import de.stephanlindauer.criticalmaps.vo.RequestCodes; +import de.stephanlindauer.criticalmaps.model.StorageLocation; +// import de.stephanlindauer.criticalmaps.vo.RequestCodes; import info.metadude.android.typedpreferences.BooleanPreference; -import info.metadude.android.typedpreferences.StringPreference; +// import info.metadude.android.typedpreferences.StringPreference; import timber.log.Timber; -import static de.stephanlindauer.criticalmaps.utils.GpxUtils.persistPermissionOnFile; +// import static de.stephanlindauer.criticalmaps.utils.GpxUtils.persistPermissionOnFile; -public class SettingsFragment extends Fragment { - @Inject - StorageLocationProvider storageLocationProvider; +import org.maplibre.android.offline.OfflineManager; +public class SettingsFragment extends Fragment { @Inject SharedPreferences sharedPreferences; private FragmentSettingsBinding binding; + private StorageLocation storageLocation; + @Inject App app; @@ -65,6 +61,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); App.components().inject(this); + storageLocation = new StorageLocation(app.getFilesDir()); } @Override @@ -73,8 +70,7 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { updateClearCachePref(); updateStorageGraph(); - updateChooseStoragePref(); - updateGpxFileName(); + // updateGpxFileName(); binding.settingsShowOnLockscreenCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.SHOW_ON_LOCKSCREEN).get()); @@ -82,36 +78,29 @@ public void onViewStateRestored(@Nullable Bundle savedInstanceState) { binding.settingsKeepScreenOnCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.KEEP_SCREEN_ON).get()); - binding.settingsMapRotationCheckbox.setChecked( - !new BooleanPreference(sharedPreferences, SharedPrefsKeys.DISABLE_MAP_ROTATION).get()); - + /* binding.settingsShowGpxCheckbox.setChecked( new BooleanPreference(sharedPreferences, SharedPrefsKeys.SHOW_GPX).get()); + */ binding.settingsClearCacheButton.setOnClickListener(v -> handleClearCacheClicked()); - binding.settingsChooseStorageContainer.setOnClickListener(v -> handleChooseStorageClicked()); binding.settingsShowOnLockscreenCheckbox.setOnCheckedChangeListener( (buttonView, isChecked) -> handleShowOnLockscreenChecked(isChecked)); binding.settingsKeepScreenOnCheckbox.setOnCheckedChangeListener( (buttonView, isChecked) -> handleKeepScreenOnChecked(isChecked)); - binding.settingsMapRotationCheckbox.setOnCheckedChangeListener( - (buttonView, isChecked) -> handleDisableMapRotationChecked(isChecked)); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - binding.settingsShowGpxCheckbox.setOnCheckedChangeListener( - (buttonView, isChecked) -> handleShowTrack(isChecked)); - binding.settingsChooseGpxContainer.setOnClickListener(v -> handleChooseTrackClicked()); - } else { - binding.settingsShowGpxContainer.setVisibility(View.GONE); - binding.settingsChooseGpxContainer.setVisibility(View.GONE); - } + /* + binding.settingsShowGpxCheckbox.setOnCheckedChangeListener( + (buttonView, isChecked) -> handleShowTrack(isChecked)); + binding.settingsChooseGpxContainer.setOnClickListener(v -> handleChooseTrackClicked()); + */ } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); + /* if (requestCode == RequestCodes.CHOOSE_GPX_RESULT_CODE && resultCode == Activity.RESULT_OK) { Uri fileUri = data.getData(); if (fileUri == null) { @@ -123,33 +112,28 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { persistPermissionOnFile(data, app.getContentResolver()); updateGpxFileName(); } + */ } private void updateStorageGraph() { - StorageLocationProvider.StorageLocation currentStorageLocation = - storageLocationProvider.getActiveStorageLocation(); - float usedPercentage = - (float) currentStorageLocation.usedSpace / currentStorageLocation.totalSize; - - long tileSize = currentStorageLocation.getCacheSize(); - - float tilePercentage = (float) tileSize / currentStorageLocation.totalSize; + (float) storageLocation.getUsedSpace() / storageLocation.getTotalSizeBytes(); + long tileSize = storageLocation.getCacheSize(); + float tilePercentage = (float) tileSize / storageLocation.getTotalSizeBytes(); binding.settingsCacheUsedSpaceText.setText(String.format(getString(R.string.settings_cache_used_mb), - Formatter.formatShortFileSize(getActivity(), currentStorageLocation.usedSpace))); + Formatter.formatShortFileSize(getActivity(), storageLocation.getUsedSpace()))); binding.settingsCacheUsedCacheSpaceText.setText(String.format(getString(R.string.settings_cache_cache_mb), Formatter.formatShortFileSize(getActivity(), tileSize))); binding.settingsCacheFreeSpaceText.setText(String.format(getString(R.string.settings_cache_free_mb), - Formatter.formatShortFileSize(getActivity(), currentStorageLocation.freeSpace))); + Formatter.formatShortFileSize(getActivity(), storageLocation.getFreeSpaceBytes()))); binding.settingsCacheStoragespacegraph.setBarPercentagesAnimated( usedPercentage, tilePercentage); } private void updateClearCachePref() { - long currentSize = - storageLocationProvider.getActiveStorageLocation().getCacheSize(); + long currentSize = storageLocation.getCacheSize(); Timber.d("Current cache size: %s", Formatter.formatShortFileSize(getActivity(), currentSize)); binding.settingsClearCacheSummaryText.setText( @@ -157,88 +141,38 @@ private void updateClearCachePref() { Formatter.formatShortFileSize(getActivity(), currentSize))); } - private void updateChooseStoragePref() { - binding.settingsChooseStorageSummaryText.setText( - storageLocationProvider.getActiveStorageLocation().displayName); - } - - @SuppressLint("Range") // FIXME + /* + @SuppressLint("Range") private void updateGpxFileName() { String gpxFile = new StringPreference( sharedPreferences, SharedPrefsKeys.GPX_FILE).get(); String filename = gpxFile; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - Cursor fileCursor = getContext().getContentResolver().query(Uri.parse(gpxFile), null, null, null); - if (fileCursor != null) { - fileCursor.moveToFirst(); - filename = fileCursor.getString(fileCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - fileCursor.close(); - } + + Cursor fileCursor = getContext().getContentResolver().query(Uri.parse(gpxFile), null, null, null); + if (fileCursor != null) { + fileCursor.moveToFirst(); + filename = fileCursor.getString(fileCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + fileCursor.close(); } + binding.settingsChooseGpxSummaryText.setText(filename); } + */ void handleClearCacheClicked() { - storageLocationProvider.getActiveStorageLocation().clearCache(); - updateClearCachePref(); - updateStorageGraph(); - } - - void handleChooseStorageClicked() { - ArrayList storageLocations = - storageLocationProvider.getAllWritableStorageLocations(); - - StorageLocationProvider.StorageLocation activeStorageLocation = - storageLocationProvider.getActiveStorageLocation(); - - int currentlyActive = 0; - ArrayList storageLocationNames = new ArrayList<>(4); - - for (int i = 0; i < storageLocations.size(); i++) { - StorageLocationProvider.StorageLocation sL = storageLocations.get(i); - storageLocationNames.add(sL.displayName + " " + String.format( - getString(R.string.settings_choose_storage_mb_free), - Formatter.formatShortFileSize(getActivity(), sL.freeSpace))); + OfflineManager.getInstance(getActivity()).clearAmbientCache(new OfflineManager.FileSourceCallback() { + @Override + public void onSuccess() { + updateClearCachePref(); + updateStorageGraph(); + } - if (storageLocations.get(i).storagePath.equals(activeStorageLocation.storagePath)) { - currentlyActive = i; + @Override + public void onError(@NonNull String s) { + Timber.e("Error clearing cache: %s", s); } - } + }); - Activity activity = getActivity(); - int finalCurrentlyActive = currentlyActive; - //noinspection ConstantConditions - new AlertDialog.Builder(activity, R.style.AlertDialogTheme) - .setTitle(R.string.settings_choose_storage_choose_title) - .setSingleChoiceItems( - storageLocationNames.toArray(new String[0]), currentlyActive, null) - .setPositiveButton(R.string.ok, (dialog, id) -> { - int selectedStorage = - ((AlertDialog) dialog).getListView().getCheckedItemPosition(); - if (selectedStorage == finalCurrentlyActive) { - return; - } - - new AlertDialog.Builder(activity, R.style.AlertDialogTheme) - .setTitle(R.string.settings_choose_storage_confirm_title) - .setMessage(R.string.settings_choose_storage_confirm_message) - .setPositiveButton(R.string.settings_cache_clear, (dialog1, which) -> { - // clear old cache - activeStorageLocation.clearCache(); - // set new storage - storageLocationProvider.setActiveStorageLocation( - storageLocations.get(selectedStorage)); - updateClearCachePref(); - updateStorageGraph(); - updateChooseStoragePref(); - }) - .setNegativeButton(R.string.cancel, null) - .create() - .show(); - - }) - .create() - .show(); } void handleShowOnLockscreenChecked(boolean isChecked) { @@ -251,20 +185,16 @@ void handleKeepScreenOnChecked(boolean isChecked) { sharedPreferences, SharedPrefsKeys.KEEP_SCREEN_ON).set(isChecked); } - void handleDisableMapRotationChecked(boolean isChecked) { - new BooleanPreference( - sharedPreferences, SharedPrefsKeys.DISABLE_MAP_ROTATION).set(!isChecked); - } - + /* void handleShowTrack(boolean isChecked) { new BooleanPreference( sharedPreferences, SharedPrefsKeys.SHOW_GPX).set(isChecked); } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) void handleChooseTrackClicked() { new ChooseGpxFileHandler(this).openChooser(); } + */ @Override public void onDestroyView() { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ApplicationCloseHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ApplicationCloseHandler.java index bf0d7844..f5ab68b6 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ApplicationCloseHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ApplicationCloseHandler.java @@ -17,18 +17,15 @@ public ApplicationCloseHandler(Activity activity) { } public void execute() { - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - ServerSyncService.stopService(); - activity.finish(); - break; - case DialogInterface.BUTTON_NEGATIVE: - dialog.cancel(); - break; - } + DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + ServerSyncService.stopService(); + activity.finish(); + break; + case DialogInterface.BUTTON_NEGATIVE: + dialog.cancel(); + break; } }; diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ChooseGpxFileHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ChooseGpxFileHandler.java index ed87f4e8..bd23ffeb 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ChooseGpxFileHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ChooseGpxFileHandler.java @@ -1,9 +1,6 @@ package de.stephanlindauer.criticalmaps.handler; import android.content.Intent; -import android.os.Build; - -import androidx.annotation.RequiresApi; import de.stephanlindauer.criticalmaps.R; import de.stephanlindauer.criticalmaps.fragments.SettingsFragment; @@ -16,7 +13,6 @@ public ChooseGpxFileHandler(SettingsFragment activity) { this.activity = activity; } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) public void openChooser() { Intent chooseTrack = new Intent(Intent.ACTION_OPEN_DOCUMENT); chooseTrack.setType("*/*"); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java index 70c84def..c666e643 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java @@ -40,7 +40,6 @@ protected String doInBackground(Void... params) { if (!response.isSuccessful()) { Timber.d("Get locations unsuccessful with code %d", response.code()); } - //noinspection ConstantConditions "Returns a non-null value if this response was [...] returned from Call.execute()." responseString = response.body().string(); response.body().close(); } catch (IOException e) { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ImageUploadHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ImageUploadHandler.java index d3daed61..c2157cdc 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ImageUploadHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ImageUploadHandler.java @@ -58,12 +58,7 @@ protected ResultType doInBackground(Void... params) { final OkHttpClient okHttpClient = App.components().okHttpClient(); - final ProgressListener progressListener = new ProgressListener() { - @Override - public void update(long bytesRead, long contentLength) { - publishProgress((int) ((100 * bytesRead) / contentLength)); - } - }; + final ProgressListener progressListener = (bytesRead, contentLength) -> publishProgress((int) ((100 * bytesRead) / contentLength)); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) @@ -79,7 +74,6 @@ public void update(long bytesRead, long contentLength) { try { Response response = okHttpClient.newCall(request).execute(); - //noinspection ConstantConditions "Returns a non-null value if this response was [...] returned from Call.execute()." if (response.isSuccessful() && response.body().string().equals("success")) { return ResultType.SUCCEEDED; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ProcessCameraResultHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ProcessCameraResultHandler.java index 8c99c4fd..e56c2bda 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ProcessCameraResultHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ProcessCameraResultHandler.java @@ -101,18 +101,15 @@ protected void onPostExecute(ResultType resultType) { builder.setView(view); - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - new ImageUploadHandler(processedImageFile, activity).execute(); - break; - case DialogInterface.BUTTON_NEGATIVE: - //noinspection ResultOfMethodCallIgnored - processedImageFile.delete(); - break; - } + DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + new ImageUploadHandler(processedImageFile, activity).execute(); + break; + case DialogInterface.BUTTON_NEGATIVE: + //noinspection ResultOfMethodCallIgnored + processedImageFile.delete(); + break; } }; diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java index c600a9f0..7dd83e4b 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ShowGpxHandler.java @@ -1,3 +1,4 @@ +/* package de.stephanlindauer.criticalmaps.handler; import android.content.SharedPreferences; @@ -89,4 +90,5 @@ private void addPoiToMap(MapView mapView, GpxPoi poi) { marker.setTitle(poi.getName()); mapView.getOverlayManager().add(marker); } -} \ No newline at end of file +} + */ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/StartCameraHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/StartCameraHandler.java index ec4e9ef6..623c745e 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/StartCameraHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/StartCameraHandler.java @@ -1,10 +1,8 @@ package de.stephanlindauer.criticalmaps.handler; import android.content.ActivityNotFoundException; -import android.content.ClipData; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.provider.MediaStore; import androidx.core.content.FileProvider; @@ -44,13 +42,6 @@ public void execute() { outputFile); Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); - // Workaround for permission issue on older devices, see: - // https://medium.com/@quiro91/sharing-files-through-intents-part-2-fixing-the-permissions-before-lollipop-ceb9bb0eec3a - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) { - cameraIntent.setClipData(ClipData.newRawUri("", imageCaptureUri)); - cameraIntent.addFlags( - Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); - } cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageCaptureUri); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/helper/clientinfo/DeviceInformation.java b/app/src/main/java/de/stephanlindauer/criticalmaps/helper/clientinfo/DeviceInformation.java index 2737885a..3cfdb2be 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/helper/clientinfo/DeviceInformation.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/helper/clientinfo/DeviceInformation.java @@ -14,12 +14,7 @@ public static String getString() { returnString += "PRODUCT= " + Build.PRODUCT + "\n"; returnString += "BRAND= " + Build.BRAND + "\n"; returnString += "DISPLAY= " + Build.DISPLAY + "\n"; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - returnString += "CPU_ABI= " + Build.CPU_ABI + "\n"; - returnString += "CPU_ABI2= " + Build.CPU_ABI2 + "\n"; - } else { - returnString += "SUPPORTED_ABIS= " + TextUtils.join(", ", Build.SUPPORTED_ABIS) + "\n"; - } + returnString += "SUPPORTED_ABIS= " + TextUtils.join(", ", Build.SUPPORTED_ABIS) + "\n"; returnString += "HARDWARE= " + Build.HARDWARE + "\n"; returnString += "ID= " + Build.ID + "\n"; returnString += "MANUFACTURER= " + Build.MANUFACTURER + "\n"; diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/managers/LocationUpdateManager.java b/app/src/main/java/de/stephanlindauer/criticalmaps/managers/LocationUpdateManager.java index 52d64a8a..f6b07ba0 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/managers/LocationUpdateManager.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/managers/LocationUpdateManager.java @@ -9,11 +9,12 @@ import android.location.LocationManager; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import com.squareup.otto.Produce; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; import java.util.List; @@ -57,7 +58,7 @@ public class LocationUpdateManager { private final LocationListener locationListener = new LocationListener() { @Override - public void onLocationChanged(final Location location) { + public void onLocationChanged(@NonNull final Location location) { if (shouldPublishNewLocation(location)) { publishNewLocation(location); lastPublishedLocation = location; @@ -74,12 +75,12 @@ public void onStatusChanged(String s, int i, Bundle bundle) { } @Override - public void onProviderEnabled(String s) { + public void onProviderEnabled(@NonNull String s) { postStatusEvent(); } @Override - public void onProviderDisabled(String s) { + public void onProviderDisabled(@NonNull String s) { postStatusEvent(); } }; @@ -166,16 +167,6 @@ public void initialize() { eventBus.register(this); isEventBusRegistered = true; } - - // Short-circuit here: if no provider exists don't start listening - if (noProviderExists) { - return; - } - - // If permissions are not granted, don't start listening - if (noPermission) { - return; - } } public void startListening() { @@ -241,7 +232,7 @@ public void handleShutdown() { } private void publishNewLocation(Location location) { - GeoPoint newLocation = new GeoPoint(location.getLatitude(), location.getLongitude()); + LatLng newLocation = new LatLng(location); ownLocationModel.setLocation(newLocation, location.getAccuracy()); eventBus.post(Events.NEW_LOCATION_EVENT); } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java index 89eab988..f8630a6f 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java @@ -10,7 +10,7 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; -import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.List; @@ -19,7 +19,6 @@ import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import de.stephanlindauer.criticalmaps.utils.AeSimpleSHA1; -import okhttp3.internal.Util; import timber.log.Timber; @@ -29,7 +28,7 @@ public class ChatModel { private final UserModel userModel; private List receivedChatMessages = new ArrayList<>(); - public static int MESSAGE_MAX_LENGTH = 255; + public static final int MESSAGE_MAX_LENGTH = 255; @Inject public ChatModel(UserModel userModel) { @@ -48,16 +47,15 @@ public void setFromJson(JSONArray jsonArray) throws JSONException, for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); - String device = URLDecoder.decode(jsonObject.getString("device"), Util.UTF_8.name()); - String identifier = URLDecoder.decode(jsonObject.getString("identifier"), Util.UTF_8.name()); - String message = URLDecoder.decode(jsonObject.getString("message"), Util.UTF_8.name()); + String device = URLDecoder.decode(jsonObject.getString("device"), "UTF-8"); + String identifier = URLDecoder.decode(jsonObject.getString("identifier"), "UTF-8"); + String message = URLDecoder.decode(jsonObject.getString("message"), "UTF-8"); Date timestamp = new Date(Long.parseLong(jsonObject.getString("timestamp")) * 1000); receivedChatMessages.add(new ReceivedChatMessage(message, timestamp)); } - Collections.sort(receivedChatMessages, - (oneChatMessages, otherChatMessage) -> oneChatMessages.getTimestamp().compareTo(otherChatMessage.getTimestamp())); + receivedChatMessages.sort(Comparator.comparing(ReceivedChatMessage::getTimestamp)); } public JSONObject createNewOutgoingMessage(String message) { @@ -74,7 +72,7 @@ public JSONObject createNewOutgoingMessage(String message) { private String urlEncodeMessage(String messageToEncode) { try { - return URLEncoder.encode(messageToEncode, Util.UTF_8.name()); + return URLEncoder.encode(messageToEncode, "UTF-8"); } catch (UnsupportedEncodingException e) { return ""; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java index b45a3154..f1e84546 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java @@ -3,9 +3,10 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; -import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; @@ -13,7 +14,7 @@ @Singleton public class OtherUsersLocationModel { - private ArrayList otherUsersLocations = new ArrayList<>(); + private final Map otherUsersLocations = new HashMap<>(); private final UserModel userModel; @@ -24,21 +25,20 @@ public OtherUsersLocationModel(UserModel userModel) { public void setFromJson(JSONArray jsonArray) throws JSONException { - otherUsersLocations = new ArrayList<>(jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { JSONObject locationObject = jsonArray.getJSONObject(i); if (locationObject.getString("device").equals(userModel.getChangingDeviceToken())) { continue; // Ignore own location } + String deviceId = locationObject.getString("device"); int latitudeE6 = Integer.parseInt(locationObject.getString("latitude")); int longitudeE6 = Integer.parseInt(locationObject.getString("longitude")); - otherUsersLocations.add( - new GeoPoint(latitudeE6 / 1000000.0D, longitudeE6 / 1000000.0D)); + otherUsersLocations.put(deviceId, new LatLng(latitudeE6 / 1E6, longitudeE6 / 1E6)); } } - public ArrayList getOtherUsersLocations() { + public Map getOtherUsersLocations() { return otherUsersLocations; } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OwnLocationModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OwnLocationModel.java index fc8d1d99..053c659a 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OwnLocationModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OwnLocationModel.java @@ -4,7 +4,7 @@ import org.json.JSONException; import org.json.JSONObject; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; import javax.inject.Inject; import javax.inject.Singleton; @@ -16,14 +16,14 @@ public class OwnLocationModel { private static final float ACCURACY_PRECISE_THRESHOLD = 50.0f; //meters - public GeoPoint ownLocation; + public LatLng ownLocation; private boolean isLocationPrecise; @Inject public OwnLocationModel() { } - public void setLocation(@NonNull GeoPoint location, float accuracy) { + public void setLocation(@NonNull LatLng location, float accuracy) { ownLocation = location; isLocationPrecise = accuracy < ACCURACY_PRECISE_THRESHOLD; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/StorageLocation.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/StorageLocation.java new file mode 100644 index 00000000..3f078dc4 --- /dev/null +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/StorageLocation.java @@ -0,0 +1,38 @@ +package de.stephanlindauer.criticalmaps.model; + +import android.os.StatFs; +import java.io.File; + + +public class StorageLocation { + private final File dbFile; + + public StorageLocation(File path) { + if (!path.exists()) { + throw new IllegalArgumentException("Path does not exist or is read only: " + path); + } + + dbFile = new File(path + File.separator + "mbgl-offline.db"); + } + + public long getFreeSpaceBytes() { + return new StatFs(dbFile.getAbsolutePath()).getAvailableBytes(); + } + + public long getTotalSizeBytes() { + return new StatFs(dbFile.getAbsolutePath()).getTotalBytes(); + } + + public long getUsedSpace() { + return getTotalSizeBytes() - getFreeSpaceBytes(); + } + + public long getCacheSize() { + long cacheSize = 0; + if (dbFile.exists()) { + cacheSize = dbFile.length(); + } + + return cacheSize; + } +} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java index ce5493a2..336fa5ac 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxModel.java @@ -1,3 +1,4 @@ +/* package de.stephanlindauer.criticalmaps.model.gpx; import java.util.ArrayList; @@ -47,3 +48,4 @@ public void clear() { uri = null; } } +*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java index e71fff63..84410d4b 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxPoi.java @@ -1,3 +1,4 @@ +/* package de.stephanlindauer.criticalmaps.model.gpx; import org.osmdroid.util.GeoPoint; @@ -20,3 +21,4 @@ public GeoPoint getPosition() { return position; } } +*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java index 6673a1f4..30527e5d 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/gpx/GpxTrack.java @@ -1,3 +1,4 @@ +/* package de.stephanlindauer.criticalmaps.model.gpx; import org.osmdroid.util.GeoPoint; @@ -22,3 +23,4 @@ public List getWaypoints() { return waypoints; } } +*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/overlays/LocationMarker.java b/app/src/main/java/de/stephanlindauer/criticalmaps/overlays/LocationMarker.java deleted file mode 100644 index 728add14..00000000 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/overlays/LocationMarker.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.stephanlindauer.criticalmaps.overlays; - -import org.osmdroid.views.MapView; -import org.osmdroid.views.overlay.Marker; - -public class LocationMarker extends Marker { - - public LocationMarker(MapView mapView) { - super(mapView); - setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER); - setInfoWindow(null); - } -} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java b/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java index 6114927b..6d0c8e3b 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/prefs/SharedPrefsKeys.java @@ -5,20 +5,16 @@ public interface SharedPrefsKeys { String PRIVACY_POLICY_ACCEPTED = BuildConfig.APPLICATION_ID + ".PRIVACY_POLICY_ACCEPTED"; - String OSMDROID_BASE_PATH = - BuildConfig.APPLICATION_ID + ".OSMDROID_BASE_PATH"; String OBSERVER_MODE_ACTIVE = BuildConfig.APPLICATION_ID + ".OBSERVER_MODE_ACTIVE"; String SHOW_ON_LOCKSCREEN = BuildConfig.APPLICATION_ID + ".SHOW_ON_LOCKSCREEN"; String KEEP_SCREEN_ON = BuildConfig.APPLICATION_ID + ".KEEP_SCREEN_ON"; - String DISABLE_MAP_ROTATION = - BuildConfig.APPLICATION_ID + ".DISABLE_MAP_ROTATION"; - String USE_HIGH_RES_MAP_TILES = - BuildConfig.APPLICATION_ID + ".USE_HIGH_RES_MAP_TILES"; + /* String SHOW_GPX = BuildConfig.APPLICATION_ID + ".SHOW_GPX"; String GPX_FILE = BuildConfig.APPLICATION_ID + ".GPX_FILE"; + */ } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/provider/StorageLocationProvider.java b/app/src/main/java/de/stephanlindauer/criticalmaps/provider/StorageLocationProvider.java deleted file mode 100644 index a1f496db..00000000 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/provider/StorageLocationProvider.java +++ /dev/null @@ -1,234 +0,0 @@ -package de.stephanlindauer.criticalmaps.provider; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Build; -import android.os.Environment; -import android.os.StatFs; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.core.os.EnvironmentCompat; - -import org.osmdroid.tileprovider.modules.SqlTileWriter; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import de.stephanlindauer.criticalmaps.App; -import de.stephanlindauer.criticalmaps.R; -import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; -import info.metadude.android.typedpreferences.StringPreference; -import timber.log.Timber; - -@Singleton -public class StorageLocationProvider { - - private final App app; - private final StringPreference osmdroidBasePathPref; - - @SuppressWarnings("WeakerAccess") - @Inject - public StorageLocationProvider(App app, SharedPreferences sharedPreferences) { - this.app = app; - - osmdroidBasePathPref = - new StringPreference(sharedPreferences, SharedPrefsKeys.OSMDROID_BASE_PATH); - } - - @NonNull - public ArrayList getAllWritableStorageLocations() { - ArrayList availableStorageLocations = new ArrayList<>(4); - - Timber.d("Finding storage locations."); - ArrayList storageDirs = new ArrayList<>(4); - storageDirs.add(app.getFilesDir()); - - File[] externalDirs = ContextCompat.getExternalFilesDirs(app, null); - for (File externalDir : externalDirs) { - // "Returned paths may be null if a storage device is unavailable." - if (externalDir == null) { - Timber.d("An external storage location is null (=unavailable), skipping."); - continue; - } - - String state = EnvironmentCompat.getStorageState(externalDir); - if (Environment.MEDIA_MOUNTED.equals(state)) { - storageDirs.add(externalDir); - } - } - - for (File storageDir : storageDirs) { - Timber.d("Found storage location: %s", storageDir.getAbsolutePath()); - availableStorageLocations.add(new StorageLocation(app, storageDir)); - } - - return availableStorageLocations; - } - - @Nullable - public StorageLocation getActiveStorageLocation() { - String savedOsmdroidBasePath = osmdroidBasePathPref.get(); - Timber.d("Saved path is: %s", savedOsmdroidBasePath); - - String savedFilePath = savedOsmdroidBasePath.replace("/osmdroid", ""); - - try { - return new StorageLocation(app, new File(savedFilePath)); - } catch (IllegalArgumentException e) { - Timber.d(e); - return null; - } - } - - public StorageLocation getAndSaveBestStorageLocation() { - Timber.d("Finding best storage location."); - - ArrayList storageLocations = getAllWritableStorageLocations(); - - StorageLocation bestLocation = null; - long bestFreeSpace = 0; - for (StorageLocation storageLocation : storageLocations) { - Timber.d("Available storage: " + storageLocation.storagePath - + ", free space: " + storageLocation.freeSpace); - if (storageLocation.freeSpace > bestFreeSpace) { - bestLocation = storageLocation; - bestFreeSpace = storageLocation.freeSpace; - } - } - - Timber.d("Determined best storage location: %s", - bestLocation != null ? bestLocation.storagePath : "null"); - - setActiveStorageLocation(bestLocation); - - return bestLocation; - } - - public void setActiveStorageLocation(StorageLocation storageLocation) { - File osmdroidBasePath = new File(storageLocation.storagePath, "osmdroid"); - //noinspection ResultOfMethodCallIgnored - osmdroidBasePath.mkdirs(); - File osmdroidTilePath = new File(osmdroidBasePath, "tiles"); - //noinspection ResultOfMethodCallIgnored - osmdroidTilePath.mkdirs(); - - storageLocation.osmdroidBasePath = osmdroidBasePath; - storageLocation.osmdroidTilePath = osmdroidTilePath; - osmdroidBasePathPref.set(storageLocation.osmdroidBasePath.getAbsolutePath()); - Timber.d("Saved location: %s", osmdroidBasePath.getAbsolutePath()); - } - - private static long getFreeSpaceBytes(File storageDir) { - long freeSpace; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - // gives more accurate information - freeSpace = new StatFs(storageDir.getAbsolutePath()).getAvailableBytes(); - } else { - freeSpace = storageDir.getFreeSpace(); - } - - return freeSpace; - } - - private static long getTotalSizeBytes(File storageDir) { - long totalSize; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - // gives more accurate information - totalSize = new StatFs(storageDir.getAbsolutePath()).getTotalBytes(); //TODO - } else { - totalSize = storageDir.getTotalSpace(); //TODO - } - - return totalSize; - } - - private static boolean isPathInInternalFilesDir(Context context, File path) { - String canonicalPath; - String canonicalInternal; - try { - canonicalPath = path.getCanonicalPath(); - canonicalInternal = context.getFilesDir().getCanonicalPath(); - } catch (IOException e) { - return false; - } - return canonicalPath.startsWith(canonicalInternal); - } - - private static boolean isPathOnRemovableStorage(File path) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return Environment.isExternalStorageRemovable(path); - } else { - return Environment.isExternalStorageRemovable(); - } - } - - private static boolean isPathAvailableForWrite(Context context, File path) { - boolean pathAvailable = false; - if (path.exists()) { - if (!isPathInInternalFilesDir(context, path)) { - String state = EnvironmentCompat.getStorageState(path); - pathAvailable = Environment.MEDIA_MOUNTED.equals(state); - } else { - // result of getFilesDir() is guaranteed to be writable - pathAvailable = true; - } - } - return pathAvailable; - } - - public static class StorageLocation { - public String displayName; - public File storagePath; - public File osmdroidBasePath; - public File osmdroidTilePath; - public long totalSize; - public long freeSpace; - public long usedSpace; - - private final File dbFile; - - public StorageLocation(Context context, File path) { - if (!path.exists() || !isPathAvailableForWrite(context, path)) { - throw new IllegalArgumentException("Path does not exist or is read only: " + path); - } - - this.storagePath = path; - this.osmdroidBasePath = new File(storagePath, "osmdroid"); - this.osmdroidTilePath = new File(osmdroidBasePath, "tiles"); - - if (isPathInInternalFilesDir(context, storagePath)) { - displayName = context.getString(R.string.storage_name_internal); - } else if (isPathOnRemovableStorage(storagePath)) { - displayName = context.getString(R.string.storage_name_external); - } else { - displayName = context.getString(R.string.storage_name_emulated); - } - - totalSize = getTotalSizeBytes(storagePath); - freeSpace = getFreeSpaceBytes(storagePath); - usedSpace = totalSize - freeSpace; - - dbFile = new File(osmdroidTilePath.getAbsolutePath() + File.separator - + SqlTileWriter.DATABASE_FILENAME); - } - - public long getCacheSize() { - long cacheSize = 0; - if (dbFile.exists()) { - cacheSize = dbFile.length(); - } - - return cacheSize; - } - - public boolean clearCache() { - return dbFile.delete(); - } - } -} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java index 785f741d..ee020444 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxReader.java @@ -1,3 +1,4 @@ +/* package de.stephanlindauer.criticalmaps.utils; import org.jetbrains.annotations.NotNull; @@ -114,3 +115,4 @@ private GeoPoint parsePoint(Element point) { } } +*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java index 0cceb109..52034d21 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/GpxUtils.java @@ -1,17 +1,18 @@ +/* package de.stephanlindauer.criticalmaps.utils; import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Intent; -import android.os.Build; public class GpxUtils { @SuppressLint("WrongConstant") // Flags from getFlags() are valid public static void persistPermissionOnFile(Intent data, ContentResolver contentResolver) { final int permissionFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && data.getData() != null) { + if (data.getData() != null) { contentResolver.takePersistableUriPermission(data.getData(), permissionFlags); } } } +*/ diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java index c7b2e709..d269fd8d 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/MapViewUtils.java @@ -1,88 +1,107 @@ package de.stephanlindauer.criticalmaps.utils; import android.app.Activity; -import android.view.ViewGroup; +import android.view.Gravity; +import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.ContextCompat; - -import org.osmdroid.config.Configuration; -import org.osmdroid.config.IConfigurationProvider; -import org.osmdroid.tileprovider.MapTileProviderBasic; -import org.osmdroid.tileprovider.modules.SqlTileWriter; -import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase; -import org.osmdroid.tileprovider.tilesource.TileSourceFactory; -import org.osmdroid.util.GeoPoint; -import org.osmdroid.views.CustomZoomButtonsController; -import org.osmdroid.views.MapView; -import org.osmdroid.views.overlay.infowindow.InfoWindow; - -import java.io.File; +import androidx.core.view.GravityCompat; + +import org.maplibre.android.camera.CameraPosition; +import org.maplibre.android.geometry.LatLng; +import org.maplibre.android.maps.MapLibreMapOptions; +import org.maplibre.android.maps.MapView; +import org.maplibre.android.maps.Style; +import org.maplibre.android.module.http.HttpRequestUtil; +import org.maplibre.android.style.layers.Layer; +import org.maplibre.android.style.layers.PropertyFactory; +import org.maplibre.android.style.layers.SymbolLayer; +import org.maplibre.android.style.sources.GeoJsonSource; import de.stephanlindauer.criticalmaps.App; -import de.stephanlindauer.criticalmaps.BuildConfig; import de.stephanlindauer.criticalmaps.R; -import de.stephanlindauer.criticalmaps.provider.StorageLocationProvider; -import timber.log.Timber; public class MapViewUtils { private MapViewUtils() { } + public static int dpToInt(int dp) { + return Math.round(dp * App.components().app().getResources().getDisplayMetrics().density); + } + public static MapView createMapView(Activity activity) { - IConfigurationProvider configuration = Configuration.getInstance(); - - StorageLocationProvider.StorageLocation storageLocation = - App.components().storageProvider().getActiveStorageLocation(); - boolean noStoredTilesExist = storageLocation == null; - if (noStoredTilesExist) { - storageLocation = App.components().storageProvider().getAndSaveBestStorageLocation(); - } - File osmdroidBasePath = storageLocation.osmdroidBasePath; - File osmdroidTileCache = storageLocation.osmdroidTilePath; - - Timber.d("Setting osmdroidBasePath to: %s", osmdroidBasePath.getAbsolutePath()); - configuration.setOsmdroidBasePath(osmdroidBasePath); - Timber.d("Setting osmdroidTileCache to: %s", osmdroidTileCache.getAbsolutePath()); - configuration.setOsmdroidTileCache(osmdroidTileCache); - - setMaxCacheSize(configuration); - - // TODO Add option to adjust expiration? - // setExpirationExtendedDuration() OR setExpirationOverrideDuration() - - configuration.setMapViewHardwareAccelerated(true); - configuration.setUserAgentValue(BuildConfig.APPLICATION_ID + "/" - + BuildConfig.VERSION_NAME + " " + org.osmdroid.library.BuildConfig.APPLICATION_ID - + "/" + org.osmdroid.library.BuildConfig.VERSION_NAME - + " (" + activity.getString(R.string.contact_email) + ")"); - - OnlineTileSourceBase onlineTileSourceBase = TileSourceFactory.MAPNIK; - - MapTileProviderBasic mapTileProviderBasic = - new MapTileProviderBasic(activity.getApplicationContext(), onlineTileSourceBase); - - MapView mapView = new MapView(activity, mapTileProviderBasic); - mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER); - - mapView.setMultiTouchControls(true); - mapView.getController().setZoom(1.0d); - mapView.getController().setCenter(new GeoPoint(0.0d, 0.0d)); - mapView.setClickable(true); - mapView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mapView.setTilesScaledToDpi(true); - mapView.getOverlayManager() - .getTilesOverlay() - .setLoadingBackgroundColor( - ContextCompat.getColor(activity, R.color.map_loading_tile_color)); - mapView.getOverlayManager() - .getTilesOverlay() - .setLoadingLineColor( - ContextCompat.getColor(activity, R.color.map_loading_line_color)); - - return mapView; + HttpRequestUtil.setOkHttpClient(App.components().okHttpClient()); + + MapLibreMapOptions options = MapLibreMapOptions.createFromAttributes(activity); + + options.attributionEnabled(false); + options.logoEnabled(false); + options.foregroundLoadColor(ContextCompat.getColor(activity, R.color.map_loading_tile_color)); + + options.compassEnabled(true); + options.compassFadesWhenFacingNorth(true); + options.compassMargins(new int[]{dpToInt(18), dpToInt(18), 0, 0}); // LTRB + options.compassGravity(Gravity.TOP | GravityCompat.START); + options.compassImage(AppCompatResources.getDrawable(activity, R.drawable.ic_map_compass)); + + options.camera( + new CameraPosition.Builder() + .target(new LatLng(0, 0)) + .bearing(0.0) + .zoom(1.0) + .tilt(0.0) + .build() + ); + + return new MapView(activity, options); } + public static void setupSourcesAndLayers(Activity activity, Style mapStyle) { + + GeoJsonSource otherUsersLocationsSource = new GeoJsonSource("otherUsersLocationsSource"); + GeoJsonSource ownUserLocationSource = new GeoJsonSource("ownUserLocationSource"); + GeoJsonSource ownUserLocationSourceObserver = new GeoJsonSource("ownUserLocationSourceObserver"); + + mapStyle.addImage( + "otherUser", + AppCompatResources.getDrawable(activity, R.drawable.ic_map_marker)); + mapStyle.addImage( + "ownUser", + AppCompatResources.getDrawable(activity, R.drawable.ic_map_marker_own)); + mapStyle.addImage( + "ownUserObserver", + AppCompatResources.getDrawable(activity, R.drawable.ic_map_marker_observer)); + + Layer otherUsersLocationsLayer = + new SymbolLayer("otherUsersLocationsLayer", otherUsersLocationsSource.getId()); + otherUsersLocationsLayer.setProperties( + PropertyFactory.iconImage("otherUser"), + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconIgnorePlacement(true)); + + Layer ownUserLocationLayer = + new SymbolLayer("ownUserLocationLayer", ownUserLocationSource.getId()); + ownUserLocationLayer.setProperties( + PropertyFactory.iconImage("ownUser"), + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconIgnorePlacement(true)); + + Layer ownUserLocationLayerObserver = + new SymbolLayer("ownUserLocationLayerObserver", ownUserLocationSourceObserver.getId()); + ownUserLocationLayerObserver.setProperties( + PropertyFactory.iconImage("ownUserObserver"), + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconIgnorePlacement(true)); + + mapStyle.addLayer(otherUsersLocationsLayer); + mapStyle.addLayer(ownUserLocationLayer); + mapStyle.addLayer(ownUserLocationLayerObserver); + mapStyle.addSource(otherUsersLocationsSource); + mapStyle.addSource(ownUserLocationSource); + mapStyle.addSource(ownUserLocationSourceObserver); + } + + /* public static InfoWindow createObserverInfoWindow(MapView mapView) { return new InfoWindow(R.layout.view_observer_infowindow, mapView) { @Override @@ -96,30 +115,5 @@ public void onClose() { } }; } - - private static void setMaxCacheSize(IConfigurationProvider configuration) { - // code adapted from osmdroid's DefaultConfigurationProvider.load() - long cacheSize = 0; - File dbFile = new File(configuration.getOsmdroidTileCache().getAbsolutePath() - + File.separator + SqlTileWriter.DATABASE_FILENAME); - if (dbFile.exists()) { - cacheSize = dbFile.length(); - } - - long freeSpace = configuration.getOsmdroidTileCache().getFreeSpace(); - Timber.d("cacheSize: %d", cacheSize); - Timber.d("freeSpace: %d", freeSpace); - Timber.d("getTileFileSystemCacheMaxBytes(): %d", - configuration.getTileFileSystemCacheMaxBytes()); - - if (configuration.getTileFileSystemCacheMaxBytes() > (freeSpace + cacheSize)) { - configuration.setTileFileSystemCacheMaxBytes((long) ((freeSpace + cacheSize) * 0.95)); - configuration.setTileFileSystemCacheTrimBytes((long) ((freeSpace + cacheSize) * 0.90)); - } - - Timber.d("getTileFileSystemCacheMaxBytes(): %d", - configuration.getTileFileSystemCacheMaxBytes()); - Timber.d("getTileFileSystemCacheTrimBytes(): %d", - configuration.getTileFileSystemCacheTrimBytes()); - } + */ } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/TrackingInfoNotificationBuilder.java b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/TrackingInfoNotificationBuilder.java index 74b0fd2a..ab842ff2 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/utils/TrackingInfoNotificationBuilder.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/utils/TrackingInfoNotificationBuilder.java @@ -19,10 +19,7 @@ public class TrackingInfoNotificationBuilder { private static final String NOTIFICATION_CHANNEL_ID = "cm_notification_channel_id"; public static Notification getNotification(Application application) { - int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - pendingIntentFlags += PendingIntent.FLAG_IMMUTABLE; - } + int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE; Intent openIntent = new Intent(application, Main.class); openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -36,25 +33,23 @@ public static Notification getNotification(Application application) { PendingIntent closePendingIntent = PendingIntent.getActivity(application, INTENT_CLOSE_ID, closeIntent, pendingIntentFlags); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - NotificationManager mNotificationManager = - (NotificationManager) application.getSystemService(Application.NOTIFICATION_SERVICE); + NotificationManager mNotificationManager = + (NotificationManager) application.getSystemService(Application.NOTIFICATION_SERVICE); - NotificationChannel notificationChannel = - new NotificationChannel(NOTIFICATION_CHANNEL_ID, - application.getString(R.string.notification_channel_name), - NotificationManager.IMPORTANCE_LOW); // no sound, status bar visibility + NotificationChannel notificationChannel = + new NotificationChannel(NOTIFICATION_CHANNEL_ID, + application.getString(R.string.notification_channel_name), + NotificationManager.IMPORTANCE_LOW); // no sound, status bar visibility - notificationChannel.setDescription( - application.getString(R.string.notification_channel_description_max300chars)); - notificationChannel.setBypassDnd(true); - notificationChannel.setShowBadge(false); - notificationChannel.enableLights(false); - notificationChannel.enableVibration(false); - notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC); + notificationChannel.setDescription( + application.getString(R.string.notification_channel_description_max300chars)); + notificationChannel.setBypassDnd(true); + notificationChannel.setShowBadge(false); + notificationChannel.enableLights(false); + notificationChannel.enableVibration(false); + notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC); - mNotificationManager.createNotificationChannel(notificationChannel); - } + mNotificationManager.createNotificationChannel(notificationChannel); NotificationCompat.Builder builder = new NotificationCompat.Builder(application, NOTIFICATION_CHANNEL_ID) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/views/LicensePanelView.java b/app/src/main/java/de/stephanlindauer/criticalmaps/views/LicensePanelView.java index 173fd906..98fe2849 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/views/LicensePanelView.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/views/LicensePanelView.java @@ -121,7 +121,7 @@ protected void dispatchRestoreInstanceState(SparseArray c } protected static class SavedState extends BaseSavedState { - public static final Parcelable.Creator CREATOR = new Creator() { + public static final Parcelable.Creator CREATOR = new Creator<>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); diff --git a/app/src/main/res/drawable/ic_about_instagram.xml b/app/src/main/res/drawable/ic_about_instagram.xml new file mode 100644 index 00000000..1335912f --- /dev/null +++ b/app/src/main/res/drawable/ic_about_instagram.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_about_twitter.xml b/app/src/main/res/drawable/ic_about_twitter.xml deleted file mode 100644 index 5da445bc..00000000 --- a/app/src/main/res/drawable/ic_about_twitter.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_map_compass.xml b/app/src/main/res/drawable/ic_map_compass.xml new file mode 100644 index 00000000..14c6cdad --- /dev/null +++ b/app/src/main/res/drawable/ic_map_compass.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_map_orientation.xml b/app/src/main/res/drawable/ic_map_orientation.xml deleted file mode 100644 index 111d039d..00000000 --- a/app/src/main/res/drawable/ic_map_orientation.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_nav_twitter.xml b/app/src/main/res/drawable/ic_nav_twitter.xml deleted file mode 100644 index 07442e53..00000000 --- a/app/src/main/res/drawable/ic_nav_twitter.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_twitter_post.xml b/app/src/main/res/drawable/ic_twitter_post.xml deleted file mode 100644 index 168ec564..00000000 --- a/app/src/main/res/drawable/ic_twitter_post.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c2e160e8..2322ad5f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,25 +1,29 @@ - - + android:layout_height="match_parent" /> - + - - - - + - + + - + - - - + + android:visibility="gone" + tools:visibility="gone"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 710ef12d..b893b5ca 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -37,10 +37,10 @@ app:srcCompat="@drawable/ic_about_facebook" /> + android:contentDescription="@string/instagram" + app:srcCompat="@drawable/ic_about_instagram" /> @@ -86,6 +86,14 @@ app:name="@string/licenses_name_aospsupport" app:notice="@string/licenses_notice_aospsupport" /> + + - - - - + app:copyright="@string/licenses_copyright_maplibre" + app:link="@string/licenses_link_maplibre" + app:name="@string/licenses_name_maplibre" + app:notice="@string/licenses_notice_maplibre" /> - - diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 2c1a6941..0881779b 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -72,7 +72,6 @@ android:layout_height="wrap_content" android:layout_below="@id/settings_clear_cache_title" android:layout_alignStart="@id/settings_clear_cache_title" - android:layout_alignLeft="@id/settings_clear_cache_title" android:maxLines="4" android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" android:textColor="?android:attr/textColorSecondary" @@ -113,7 +112,6 @@ android:layout_height="10dp" android:layout_gravity="center" android:layout_marginEnd="4dp" - android:layout_marginRight="4dp" android:background="@color/settings_used_space" /> + tools:text="Cache: 126 MB" /> - - - - - - - - - - - - @@ -245,7 +196,6 @@ android:layout_height="wrap_content" android:layout_below="@id/settings_show_on_lockscreen_title" android:layout_alignStart="@id/settings_show_on_lockscreen_title" - android:layout_alignLeft="@id/settings_show_on_lockscreen_title" android:maxLines="4" android:text="@string/settings_show_on_lockscreen_summary" android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" @@ -276,6 +226,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" + android:baselineAligned="false" android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeight"> @@ -302,7 +253,6 @@ android:layout_height="wrap_content" android:layout_below="@id/settings_keep_screen_on_title" android:layout_alignStart="@id/settings_keep_screen_on_title" - android:layout_alignLeft="@id/settings_keep_screen_on_title" android:maxLines="4" android:text="@string/settings_keep_screen_on_summary" android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" @@ -325,6 +275,7 @@ + diff --git a/app/src/main/res/layout/navdrawer_observer_mode_text.xml b/app/src/main/res/layout/navdrawer_observer_mode_text.xml new file mode 100644 index 00000000..62df7967 --- /dev/null +++ b/app/src/main/res/layout/navdrawer_observer_mode_text.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/menu/menu_navdrawer.xml b/app/src/main/res/menu/menu_navdrawer.xml index 0bf9de04..f3ea143b 100644 --- a/app/src/main/res/menu/menu_navdrawer.xml +++ b/app/src/main/res/menu/menu_navdrawer.xml @@ -38,5 +38,10 @@ android:icon="@drawable/ic_nav_observer" android:title="@string/observer_mode" app:actionLayout="@layout/navdrawer_observer_mode_switch" /> + diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index ae1bcd77..9977b1f9 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -3,7 +3,6 @@ Mapa Normes - Twitter Informació Xat Obrir calaix @@ -46,8 +45,6 @@ Imatges per criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Tots els tuits que contenen \"CriticalMaps\" - Torna-ho a provar! Els missatges s\'esborraran en 30 minuts diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index fc43601e..0d65b0b2 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -3,7 +3,6 @@ Mapa Pravidla - Twitter O nás Chat Nastavení @@ -67,8 +66,6 @@ Ostatní uživatelé vaši polohu neuvidí, ale vy můžete sledovat události.< Obrázky od criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Všechny tweety obsahující \"CriticalMaps\" - Zkuste to znovu! Zprávy budou po 30 minutách smazány. @@ -96,25 +93,16 @@ Ostatní uživatelé vaši polohu neuvidí, ale vy můžete sledovat události.< Mezipaměť: %s Volné: %s V současnosti používá %s - Zvolte místo uložení - (%s volný) - Umístění úložiště - Aktuální mezipaměť bude vymazána - Změna umístění úložiště vymaže aktuální mezipaměť. Dlaždice mapy bude nutné při prohlížení znovu stáhnout. Nastavení obrazovky Zobrazení na uzamčené obrazovce Ponechání aplikace v popředí i při uzamčení telefonu Nechat obrazovku zapnutou Zabránit automatickému vypnutí displeje při otevřené aplikaci Nastavení mapy - Rotace - Umožnit otáčení mapy Zobrazit soubor GPX Zobrazení souboru GPX na mapě Vybrat GPX soubor Žádný - Vysoká kvalita - Vypadá mnohem lépe, ale také využívá větší šířku pásma a úložiště. právě teď @@ -159,9 +147,6 @@ Chcete nahrát svůj obrázek na criticalmap Zrušit Udělit potřebné povolení? Otevřít nastavení - Interní úložiště - Externí SD karta - Emulovaná SD karta Věnujte prosím trochu času přečtení tohoto stručného úvodu. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 881a1888..472eb934 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -3,7 +3,6 @@ Map Knigge - Twitter Info Chat Einstellungen @@ -65,8 +64,6 @@ Bilder von criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Alle Tweets die \"CriticalMaps\" enthalten - Versuch\'s nochmal! Nachrichten werden nach 30 Minuten wieder gelöscht. @@ -94,25 +91,16 @@ Cache: %s Frei: %s Momentan %s verwendet - Speicherort wählen - (%s frei) - Speicherort - Cache wird gelöscht - Wenn du den Speicherort änderst wird der aktuelle Cache gelöscht. Die Kartendaten werden beim Betrachten neu heruntergeladen. Bildschirmeinstellungen Auf Sperrbildschirm anzeigen Nutze die App weiter, selbst wenn der Bildschirm gesperrt ist Bildschirm anlassen Bildschirm geht nicht automatisch aus, während die App offen ist Karteneinstellungen - Drehung - Drehen der Karte erlauben GPX-Daten anzeigen GPX-Daten auf der Karte anzeigen GPX-Daten auswählen Nichts - Hohe Qualität - Bessere Darstellung, verbraucht aber mehr Daten und Speicherplatz gerade eben @@ -153,9 +141,6 @@ Abbrechen Benötigte Rechte erteilen? Einstellungen öffnen - Interner Speicher - Externe SD Karte - Emulierte SD Karte Lies dir bitte kurz folgende Infos durch, damit du weißt, was hier abgeht. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b2abaf4c..ce61a244 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -3,7 +3,6 @@ Mapa Normas - Twitter Info Chat Abrir cajón @@ -46,8 +45,6 @@ Imágenes por criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Todos los Tweets que contienen \"CriticalMaps\" - Inténtalo de nuevo! Los mensajes se borrarán después de 30 minutos. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9feb3c61..2e350264 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -3,7 +3,6 @@ Plan Règles - Twitter À propos Messagerie instantanée Paramètres @@ -68,8 +67,6 @@ Les autres utilisateurs ne peuvent pas voir ta position mais tu peux suivre la C Images de criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Tout les tweets contenant \"CriticalMaps\" - Essaye de nouveau ! Les messages seront supprimés après 30 minutes. @@ -97,19 +94,12 @@ Les autres utilisateurs ne peuvent pas voir ta position mais tu peux suivre la C Cache : %s Libre : %s Utilisation en cours %s - Choisir l\'emplacement de stockage - (%s libre) - Emplacement de stockage - Le cache va être vidé - Changer l\'emplacement de stockage va vider le cache. Les cartes devront être téléchargées à nouveau. Paramètres d\'affichage Afficher sur l\'écran de verrouillage Garder l\'app au premier plan même quand le téléphone est verrouillé Garder l\'écran allumé Empêcher l\'écran de s\'éteindre quand l\'app est ouverte Paramètres de la carte - Rotation - Permettre la rotation de la carte il y a un instant @@ -151,9 +141,6 @@ Les autres utilisateurs ne peuvent pas voir ta position mais tu peux suivre la C Annuler Donner la permission requise ? Ouvrir les Paramètres - Stockage interne - Carte SD externe - Carte SD émulée Prends le temps de lire cette petite introduction stp. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d97cf57b..6d0d104b 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -3,7 +3,6 @@ Mappa Regole - Twitter Info Chat Impostazioni @@ -52,8 +51,6 @@ Immagini di criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Tutti i tweet che contengono\"CriticalMaps\" - Riprovaci! I messaggi si cancelleranno dopo 30 minuti. diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6e82cda0..10170fde 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -3,7 +3,6 @@ 地図 ルール - Twitter アプリ情報 チャット 設定 @@ -64,8 +63,6 @@ イメージは criticalmass-hh.de (CC BY-NC-ND 3.0 DE) から - すべての「CriticalMaps」を含むツイート - もう一度やってみて! メッセージは30分後消される @@ -93,19 +90,12 @@ キャッシュ:%s 空いてる:%s 現用:%s - 記憶番地選択 - (%s 空いてる) - 記憶番地 - キャッシュを消す - 記憶番地を変えるならキャッシュが消される。その後地図を見たら再ロードが必要。 スクリーン設定 ロックスクリーンで見せる 携帯をロックしても、アプリを使える スクリーンが消さない スクリーンがアプリを使い中いつでも自動的に消されない 地図設定 - 回転 - 地図を指で回転できる たった今 @@ -142,9 +132,6 @@ キャンセル 必要な許可を与える? 設定を開ける - 内部収納 - 外部SDメモリーカード - エミュレートのSDメモリーカード このクイックスタートを読んでください diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 660f75e5..af0840bc 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -3,7 +3,6 @@ Kaart Regels - Twitter Over Chat Instellingen @@ -70,8 +69,6 @@ Met afbeeldingen van criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Alle tweets met als onderwerp ‘CriticalMaps’ - Probeer het opnieuw! Berichten worden na 30 minuten verwijderd. @@ -99,25 +96,16 @@ Cache: %s Vrije ruimte: %s In gebruik: %s - Kies een opslaglocatie - (%s vrije ruimte) - Opslaglocatie - De huidige cache wordt gewist - Door het wijzigen van de opslaglocatie wordt de huidige cache gewist. Kaarttegels moeten daardoor opnieuw worden opgehaald. Scherminstellingen Tonen op vergrendelschermen Houd de app actief, ook als je de telefoon vergrendeld Scherm ingeschakeld houden Voorkom dat het scherm wordt uitgeschakeld zolang de app geopend is Kaartinstellingen - Draaien - Sta toe dat de kaart gedraaid wordt GPX-bestand tonen Toon een gpx-bestand op de kaart Kies een gpx-bestand Geen - Hoge kwaliteit - Mooier en scherper, maar verbruikt meer mb\'s en opslagruimte Zojuist @@ -163,9 +151,6 @@ Annuleren Wil je dit recht verlenen? Instellingen openen - Interne opslagruimte - Externe sd-kaart - Geëmuleerde sd-kaart Neem deze introductie door voordat je aan de slag gaat. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 6c7f50a3..04784695 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -3,7 +3,6 @@ Mapa Zasady - Twitter Informacje Czat Ustawienia @@ -61,8 +60,6 @@ Inni użytkownicy nie zobaczą Twojej lokalizacji, ale nadal możesz śledzić M Obrazki od criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Wszystkie twitty o \"CriticalMaps\" - Spróbuj ponownie! Wiadomość zostanie usunięta po 30 minutach. @@ -90,19 +87,12 @@ Inni użytkownicy nie zobaczą Twojej lokalizacji, ale nadal możesz śledzić M Pamięć podręczna: %s Wolne: %s Aktualne wykorzystanie %s - Wybór miejsca zapisu danych - (%s wolne) - Miejsce zapisu danych - Obecna pamięć podręczna zostanie wyczyszczona - Zmiana miejsca zapisu danych wyczyści pamięć podręczną. Obszary mapy będą musiały zostać ponownie pobrane w celu wyświetlania. Ustawienia ekranu Pokaż na zablokowanym ekranie Wyświetlaj aplikację nawet po zablokowaniu ekranu Zablokuj ekran Chroni przed automatycznym wygaszeniem ekranu kiedy aplikacja jest wyłączona Ustawienia map - Obracanie ekranu - Pozwól na obracanie ekranu map właśnie teraz @@ -139,8 +129,6 @@ D Anuluj Czy przyznać wymagane pozwolenia? Otwórz ustawienia - Pamięć telefonu - Zewnętrzna karta SD Zapoznaj się z tą krótką instrukcją. To Twój wygląd:\u0020 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9241a000..aeeac090 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -3,7 +3,6 @@ Карта Правила - Twitter О программе Чат Настройки @@ -68,8 +67,6 @@ Изображения criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Все твиты содержащие \"CriticalMaps\" - Попробовать еще раз! Сообщения будут удалены после 30 минут. @@ -97,19 +94,12 @@ Кэш %s Свободно %s Использовано %s - Выберите место хранения - (%s свободно) - Место хранения - Кэш будет очищен - Изменение места хранения очистит текущий кэш. Карта будет загружена снова при просмотре. Настройки экрана Показывать на экране блокировки Держать приложение на переднем плане даже при блокировке телефона Держать экран включенным Предотвратить автоматическое отключение экрана во время использования приложения Настройки карты - Поворот - Разрешить поворот карты только что @@ -150,9 +140,6 @@ Отмена Предоставить необходимое разрешение? Открыть настройки - Внутреннее хранилище - Внешнее хранилище - Эмулированная SD-карта Пожалуйста, найдите время, чтобы прочитать это краткое введение. diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 8689e30a..2cb3ef97 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -3,7 +3,6 @@ Mapa Pravidlá - Twitter info čet Nastavenia @@ -68,8 +67,6 @@ svoju polohu. Prosím, zvážte aktiváciu lokalizačných služieb v nastavenia Obrázky od criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - Všetky tweety obsahujú \"CriticalMaps\" - Skús opäť! Správy budú zmazané po 30 minútach. @@ -97,11 +94,6 @@ svoju polohu. Prosím, zvážte aktiváciu lokalizačných služieb v nastavenia Cache: %s Voľné: %s Práve použitých %s - Výber miesto pamäti - (%s voľných) - Adresa pamäte - Aktuálna cache bude vymazaná - Zmena umiestnenia úložného priestoru vymaže aktuálnu vyrovnávaciu pamäť. Mapové dlaždice sa budú musieť pri prezeraní znova stiahnuť. Nastavenia displeja Zobraz na uzamknutej obrazovke Aplikácia zostane bežať v pozadí aj keď bude zablokovaný telefón @@ -144,9 +136,6 @@ svoju polohu. Prosím, zvážte aktiváciu lokalizačných služieb v nastavenia Zruš Udeliť požadované oprávnenia? Otvor nastavenia - Interné úložisko - Externá SD karta - Emulovana SD karta Prosím výhrad si čas na prečítanie rýchleho úvodu. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 6951ad4c..ae394f4d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -3,7 +3,6 @@ Harita Kurallar - Twitter Hakkında Sohbet Ayarlar @@ -50,8 +49,6 @@ Resimler criticalmass-hh.de tarafından (CC BY-NC-ND 3.0 DE) lisanslı - miyav - Tekrar deneyin! Mesajlar 30 dakika sonra silinecek. @@ -95,7 +92,6 @@ Bir terslik oluştu Tamam İptal - Dahili Hafıza Lütfen hızlı tanıtıma biraz zaman ayırın. Böyle gözüküyorsun:\u0020 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 96ca6c6b..f53d5cd5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -33,11 +33,6 @@ @color/colorBackground - - @color/primaryDark_20pct - @color/colorPrimaryDark - @color/colorPrimaryDark - @color/colorOnBackground @color/colorOnBackground @@ -45,7 +40,6 @@ @color/primary_60pct @color/colorBackground - @color/colorBackground @color/material_red_900 @color/material_orange_600 @color/colorOnPrimary diff --git a/app/src/main/res/values/licenses.xml b/app/src/main/res/values/licenses.xml index 0258e73b..4c6af0f4 100644 --- a/app/src/main/res/values/licenses.xml +++ b/app/src/main/res/values/licenses.xml @@ -2,11 +2,11 @@ - AOSP Support Libraries + Android Jetpack https://android.googlesource.com/platform/frameworks/support - Copyright 2014 The Android Open Source Project + Copyright 2019 The Android Open Source Project - Copyright (C) 2014 The Android Open Source Project\n + Copyright (C) 2019 The Android Open Source Project\n \n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n @@ -22,12 +22,12 @@ - - AXT - https://github.com/ligi/AXT - Copyright 2013 ligi - - Copyright 2013 ligi\n + + Material Components for Android + https://github.com/material-components/material-components-android + Copyright 2019 The Android Open Source Project + + Copyright (C) 2019 The Android Open Source Project\n \n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n @@ -43,12 +43,12 @@ - - Butterknife - https://github.com/JakeWharton/butterknife - Copyright 2013 Jake Wharton - - Copyright 2013 Jake Wharton\n + + AXT + https://github.com/ligi/AXT + Copyright 2013 ligi + + Copyright 2013 ligi\n \n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n @@ -67,9 +67,9 @@ Dagger 2 https://github.com/google/dagger - Copyright 2012 The Dagger Authors + Copyright 2017 The Dagger Authors - Copyright 2012 The Dagger Authors\n + Copyright 2017 The Dagger Authors\n \n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n @@ -109,9 +109,9 @@ OkHttp https://github.com/square/okhttp - Copyright 2014 Square, Inc. + Copyright 2019 Square, Inc. - Copyright 2014 Square, Inc.\n + Copyright 2019 Square, Inc.\n \n Licensed under the Apache License, Version 2.0 (the "License");\n you may not use this file except in compliance with the License.\n @@ -127,25 +127,22 @@ - - osmdroid - https://github.com/osmdroid/osmdroid - Copyright osmdroid - - Licensed under the Apache License, Version 2.0 - - - - - OSMBonusPack - https://github.com/MKergall/osmbonuspack - Copyright OSMBonusPack - - The components inside this GitHub project are under LGPL licence, with an important simplification: The constraints described in Section 5.d and 5.e of the LGPL LICENCE are DISCARDED.\n + + MabLibre Native + https://github.com/maplibre/maplibre-native + Copyright (c) 2021 MapLibre contributors\nCopyright (c) 2018-2021 MapTiler.com\nCopyright (c) 2014-2020 Mapbox + + BSD 2-Clause License\n + \n + Copyright (c) 2021 MapLibre contributors\n + Copyright (c) 2018-2021 MapTiler.com\n + Copyright (c) 2014-2020 Mapbox\n \n - This means that you are allowed to convey a Combined Work without providing the user any way to recombine or relink the application, and without providing any shared library mechanism.\n + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n \n - In other terms, you are allowed to include the OSMBonusPack library in your Android application, without making your application open source.\n + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/app/src/main/res/values/strings-notranslate.xml b/app/src/main/res/values/strings-notranslate.xml index d8b3cc69..a9d2a4ba 100644 --- a/app/src/main/res/values/strings-notranslate.xml +++ b/app/src/main/res/values/strings-notranslate.xml @@ -2,8 +2,7 @@ Critical Maps - - \u00a9 OpenStreetMap contributors + MapLibre | \u00a9 OpenStreetMap contributors criticalmaps.net Gitti la Mar (Old Logo) \nJan Rabe (Code) \nChristian Balster (Code) \nLigi (Code) \nCaner Başaran (Translations) \nTobias Preuss (Code) \nLuca Gemini (Translations) \nLena Osswald (Translations) \nRodrigo Aguilera (Translations) \nHelen Sawyer (Translations)\nPeter Amende (Logo \u0026 Design)\nAaron Lau (Translations)\ntherasius (Translations)\nAlban Sagouis (Translations)\nAskar Syzdykov (Translations \u0026 Code)\nAlexander Mai (Translations)\nAndrei Guliaikin (Translations)\nIgor (Translations)\nStefan Kinzel (Code)\nwatchingJu (Translations)\ntrendspotter (Translations)\nHeimen Stoffels (Translations) stephanlindauer@posteo.de @@ -18,6 +17,6 @@ Facebook - Twitter + Instagram diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4d8e7942..14d52b44 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,6 @@ Map Rules - Twitter About Chat Settings @@ -69,10 +68,6 @@ Enjoy reclaimed streets. Go checkout the Sound Bikes. Chat with motorists, pedestrian and let them know what\'s going on. Most importantly: Have fun! Images by criticalmass-hh.de (CC BY-NC-ND 3.0 DE) - - All Tweets containing \"CriticalMaps\" - Try again! - Messages will be deleted after 30 minutes. Send @@ -99,25 +94,16 @@ Cache: %s Free: %s Currently using %s - Choose storage location - (%s free) - Storage location - Current cache will be cleared - Changing the storage location will clear the current cache. Map tiles will have to be downloaded again when viewed. Screen settings Show on Lockscreen Keep the app in the foreground even when locking the phone Keep screen on Prevent the display from turning off automatically while the app is open Map settings - Rotation - Allow the map to be rotated Show GPX-file Show GPX-file on the map Choose GPX-file None - High quality - Looks way better but also uses more bandwidth and storage just now @@ -163,9 +149,6 @@ Cancel Grant required permission? Open Settings - Internal Storage - External SD card - Emulated SD card Please take some time to read this quick introduction. diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index de84c208..191a37fe 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -3,9 +3,8 @@ @@ -23,13 +22,9 @@ @color/colorOnSurface @color/colorError @color/colorOnError - - @color/main_statusbarcolor_map - - @color/main_navbarcolor - - - @color/colorBackground + always + @android:color/transparent + @android:color/transparent @@ -55,7 +50,7 @@ 16dp wrap_content wrap_content - viewStart + viewStart start|top @@ -65,7 +60,7 @@ center_horizontal web 16dp - viewStart + viewStart start @style/TextAppearance.MaterialComponents.Caption @@ -77,7 +72,7 @@ 10dp match_parent wrap_content - viewStart + viewStart start @color/about_heading_background @@ -90,7 +85,7 @@ 20dp match_parent wrap_content - viewStart + viewStart start @@ -111,7 +106,7 @@ 20dp 8dp true - viewStart + viewStart start @@ -120,7 +115,7 @@ wrap_content 10dp @style/TextAppearance.MaterialComponents.Body2 - viewStart + viewStart start @@ -144,7 +139,7 @@ 12dp 12dp @style/TextAppearance.MaterialComponents.Body2 - viewStart + viewStart start @@ -154,7 +149,7 @@ 12dp @style/TextAppearance.MaterialComponents.Body2 ?android:textColorSecondary - viewStart + viewStart start @@ -163,7 +158,7 @@ wrap_content 16dp @style/TextAppearance.MaterialComponents.Body2 - viewStart + viewStart start diff --git a/app/src/test/java/de/stephanlindauer/criticalmaps/model/OwnLocationModelTest.java b/app/src/test/java/de/stephanlindauer/criticalmaps/model/OwnLocationModelTest.java index 5a8cffdd..164a4f33 100644 --- a/app/src/test/java/de/stephanlindauer/criticalmaps/model/OwnLocationModelTest.java +++ b/app/src/test/java/de/stephanlindauer/criticalmaps/model/OwnLocationModelTest.java @@ -1,7 +1,8 @@ package de.stephanlindauer.criticalmaps.model; import org.junit.Test; -import org.osmdroid.util.GeoPoint; +import org.maplibre.android.geometry.LatLng; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; @@ -11,7 +12,7 @@ public class OwnLocationModelTest { public void hasPreciseLocation_impreciseLocationIsReportedAsImprecise() { OwnLocationModel tested = new OwnLocationModel(); - tested.setLocation(new GeoPoint(0d, 0d), 50.0f); + tested.setLocation(new LatLng(0d, 0d), 50.0f); assertThat(tested.hasPreciseLocation()).isFalse(); } @@ -20,7 +21,7 @@ public void hasPreciseLocation_impreciseLocationIsReportedAsImprecise() { public void hasPreciseLocation_preciseLocationIsReportedAsPrecise() { OwnLocationModel tested = new OwnLocationModel(); - tested.setLocation(new GeoPoint(0d, 0d), 49.9f); + tested.setLocation(new LatLng(0d, 0d), 49.9f); assertThat(tested.hasPreciseLocation()).isTrue(); } @@ -37,7 +38,7 @@ public void getLocationJson_returnsCorrectJson() { OwnLocationModel tested = new OwnLocationModel(); String expected = "{\"latitude\":\"40741895\",\"longitude\":\"-73989308\"}"; - tested.setLocation(new GeoPoint(40.741895d, -73.989308d), 1.1f); + tested.setLocation(new LatLng(40.741895d, -73.989308d), 1.1f); assertThat(tested.getLocationJson().toString()).isEqualTo(expected); } } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 295774b1..00000000 --- a/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -buildscript { - ext { - dagger_version = "2.52" - } - - repositories { - google() - gradlePluginPortal() // gradle-errorprone-plugin - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.11.2' - classpath 'com.github.bjoernq:unmockplugin:0.7.9' - classpath 'net.ltgt.gradle:gradle-errorprone-plugin:3.1.0' - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..ae04fa97 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,4 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.unmock) apply false +} diff --git a/gradle.properties b/gradle.properties index 0d6a5ff1..0f9cc19b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,21 +1,27 @@ # 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. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -android.nonTransitiveRClass=false -android.useAndroidX=true -org.gradle.jvmargs=-Xmx1536M +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. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# 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 + +# Kotlin code style for this project: "official" or "obsolete": +# kotlin.code.style=official + +# 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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..50cb9b4e --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,52 @@ +[versions] +otto = "1.3.8" +mapLibre = "12.1.2" +picasso = "2.8" +timber = "5.0.1" +okhttp = "5.3.1" +typedPreferences = "2.1.0" +material = "1.13.0" +core = "1.17.0" +appcompat = "1.7.1" +annotation = "1.9.1" +exifinterface = "1.4.1" +constraintLayout = "2.2.1" +dagger = "2.57.2" +leakcanary = "2.14" +junit = "4.13.2" +truth = "1.4.5" +mockito = "5.20.0" +junitVersion = "1.3.0" +androidTest = "1.7.0" +espressoCore = "3.7.0" +agp = "8.13.1" +unmock = "0.9.0" + +[libraries] +otto = { group = "com.squareup", name = "otto", version.ref = "otto" } +maplibre = { group = "org.maplibre.gl", name = "android-sdk", version.ref = "mapLibre" } +picasso = { group = "com.squareup.picasso", name = "picasso", version.ref = "picasso" } +timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +typed-preferences = { group = "info.metadude.android", name = "typed-preferences", version.ref = "typedPreferences" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +androidx-core = { group = "androidx.core", name = "core", version.ref = "core" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" } +androidx-exifinterface = { group = "androidx.exifinterface", name = "exifinterface", version.ref = "exifinterface" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintLayout" } +dagger = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" } +dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" } +leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakcanary" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +com-google-truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } +org-mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-test-core = { group = "androidx.test", name = "core", version.ref = "androidTest" } +androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidTest" } +androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidTest" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +unmock = {id = "de.mobilej.unmock", version.ref= "unmock"} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8c8d5c18..a6472631 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,8 @@ #Sun Nov 08 23:45:32 CET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e7b4def4..00000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..7c541eeb --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,34 @@ +pluginManagement { + // Workaround for unmockplugin not being on gradle plugin portal + resolutionStrategy { + eachPlugin { + if (requested.id.id == "de.mobilej.unmock") { + useModule("com.github.bjoernq:unmockplugin:${requested.version}") + } + } + } + + repositories { + + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "criticalmaps-android" +include(":app")