diff --git a/OsmAnd-api/build.gradle b/OsmAnd-api/build.gradle index e2b703b4177..7d92b5842bd 100644 --- a/OsmAnd-api/build.gradle +++ b/OsmAnd-api/build.gradle @@ -2,8 +2,8 @@ apply plugin: 'com.android.library' apply plugin: 'ivy-publish' android { - compileSdk 34 - buildToolsVersion = "34.0.0" + compileSdk 35 + buildToolsVersion = "35.0.0" defaultConfig { minSdkVersion 24 @@ -27,12 +27,10 @@ android { } publishing { singleVariant('release') { - withSourcesJar() withJavadocJar() } singleVariant('debug') { - withSourcesJar() withJavadocJar() } } diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapDataObject.java b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapDataObject.java index 1a795ebc4d1..f61e4b47e28 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapDataObject.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/BinaryMapDataObject.java @@ -371,8 +371,8 @@ public int getLabelX() { for(int i = 0; i < len; i++) { sum += coordinates[2 * i]; } - int average = ((int) (sum >> BinaryMapIndexReader.SHIFT_COORDINATES)/ len) - << (BinaryMapIndexReader.SHIFT_COORDINATES - LABEL_SHIFT); + int l = (int) ((sum >> BinaryMapIndexReader.SHIFT_COORDINATES)/ len); + int average = l << (BinaryMapIndexReader.SHIFT_COORDINATES - LABEL_SHIFT); int label31X = (average + this.labelX) << LABEL_SHIFT; return label31X; } @@ -384,8 +384,8 @@ public int getLabelY() { for(int i = 0; i < len; i++) { sum += coordinates[2 * i + 1]; } - int average = ((int) (sum >> BinaryMapIndexReader.SHIFT_COORDINATES)/ len) - << (BinaryMapIndexReader.SHIFT_COORDINATES - LABEL_SHIFT); + int l = (int) ((sum >> BinaryMapIndexReader.SHIFT_COORDINATES)/ len); + int average = l << (BinaryMapIndexReader.SHIFT_COORDINATES - LABEL_SHIFT); int label31Y = (average + this.labelY) << LABEL_SHIFT; return label31Y; } diff --git a/OsmAnd-java/src/main/java/net/osmand/data/MultipolygonBuilder.java b/OsmAnd-java/src/main/java/net/osmand/data/MultipolygonBuilder.java index 19dd79393f4..3ee9c6af38b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/data/MultipolygonBuilder.java +++ b/OsmAnd-java/src/main/java/net/osmand/data/MultipolygonBuilder.java @@ -2,6 +2,7 @@ import gnu.trove.map.hash.TLongObjectHashMap; import net.osmand.osm.edit.*; +import net.osmand.osm.io.OsmBaseStorage; import net.osmand.util.JarvisAlgorithm; import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; @@ -124,19 +125,19 @@ public ArrayList combineToRings(List ways) { do { newWay = merge(multilineStartPoint, getLastId(changedWay), changedWay, multilineEndPoint, getFirstId(changedWay)); - if(newWay == null) { - newWay = merge(multilineEndPoint, getFirstId(changedWay), changedWay, - multilineStartPoint, getLastId(changedWay)); + if (newWay == null) { + newWay = merge(multilineEndPoint, getFirstId(changedWay), changedWay, multilineStartPoint, + getLastId(changedWay)); } - if(newWay == null) { - newWay = merge(multilineStartPoint, getFirstId(changedWay), changedWay, - multilineEndPoint, getLastId(changedWay)); + if (newWay == null) { + newWay = merge(multilineStartPoint, getFirstId(changedWay), changedWay, multilineEndPoint, + getLastId(changedWay)); } - if(newWay == null) { - newWay = merge(multilineEndPoint, getLastId(changedWay), changedWay, - multilineStartPoint, getFirstId(changedWay)); + if (newWay == null) { + newWay = merge(multilineEndPoint, getLastId(changedWay), changedWay, multilineStartPoint, + getFirstId(changedWay)); } - if(newWay != null) { + if (newWay != null) { changedWay = newWay; } } while (newWay != null); @@ -147,8 +148,11 @@ public ArrayList combineToRings(List ways) { } List multiLines = new ArrayList(); - for(List lst : multilineStartPoint.valueCollection()) { - multiLines.addAll(lst); + for (List lst : multilineStartPoint.valueCollection()) { + if(lst.size() > 0) { + multiLines.addAll(lst); + + } } ArrayList result = new ArrayList(); for (Way multiLine : multiLines) { @@ -253,6 +257,7 @@ private Way combineTwoWaysIfHasPoints(Way w1, Way w2) { } if (combine) { Way newWay = new Way(nextRandId()); +// Way newWay = new Way(-Math.abs(w1.getId())); boolean nodePresent = w1.getNodes() != null || w1.getNodes().size() != 0; int w1size = nodePresent ? w1.getNodes().size() : w1.getNodeIds().size(); for (int i = 0; i < w1size; i++) { diff --git a/OsmAnd-java/src/main/java/net/osmand/data/Ring.java b/OsmAnd-java/src/main/java/net/osmand/data/Ring.java index 148f1f05d90..4a49d18c222 100644 --- a/OsmAnd-java/src/main/java/net/osmand/data/Ring.java +++ b/OsmAnd-java/src/main/java/net/osmand/data/Ring.java @@ -129,6 +129,10 @@ public boolean isClosed() { public List getBorder() { return border.getNodes(); } + + public Way getBorderWay() { + return border; + } /** diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/edit/Relation.java b/OsmAnd-java/src/main/java/net/osmand/osm/edit/Relation.java index 008b903e68c..29ccf51f0d2 100644 --- a/OsmAnd-java/src/main/java/net/osmand/osm/edit/Relation.java +++ b/OsmAnd-java/src/main/java/net/osmand/osm/edit/Relation.java @@ -108,8 +108,8 @@ public List getMembers() { @Override public void initializeLinks(Map entities){ if (members != null) { - for(RelationMember rm : members) { - if(rm.entityId != null && entities.containsKey(rm.entityId)) { + for (RelationMember rm : members) { + if (rm.entityId != null && entities.containsKey(rm.entityId)) { rm.entity = entities.get(rm.entityId); } } diff --git a/OsmAnd-shared/build.gradle.kts b/OsmAnd-shared/build.gradle.kts index 8ed7c9582c9..99e4d1cb29a 100644 --- a/OsmAnd-shared/build.gradle.kts +++ b/OsmAnd-shared/build.gradle.kts @@ -51,6 +51,7 @@ kotlin { val commonLoggingVersion = "1.2" val coroutinesVersion = "1.8.1" val statelyVersion = "2.1.0" + val coilVersion = "3.1.0" sourceSets { commonMain.dependencies { @@ -73,6 +74,8 @@ kotlin { implementation("androidx.sqlite:sqlite:$sqliteVersion") implementation("androidx.sqlite:sqlite-framework:$sqliteVersion") implementation("net.sf.kxml:kxml2:$kxml2Version") + implementation("io.coil-kt.coil3:coil-core:$coilVersion") + implementation("io.coil-kt.coil3:coil-network-okhttp:$coilVersion") } iosMain.dependencies { implementation("co.touchlab:sqliter-driver:$sqliterVersion") @@ -86,7 +89,7 @@ kotlin { android { namespace = "net.osmand.shared" - compileSdk = 34 + compileSdk = 35 compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 diff --git a/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/util/NetworkImageLoader.kt b/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/util/NetworkImageLoader.kt new file mode 100644 index 00000000000..b507c97b344 --- /dev/null +++ b/OsmAnd-shared/src/androidMain/kotlin/net/osmand/shared/util/NetworkImageLoader.kt @@ -0,0 +1,76 @@ +package net.osmand.shared.util + +import android.content.Context +import coil3.Bitmap +import coil3.ImageLoader +import coil3.disk.DiskCache +import coil3.disk.directory +import coil3.memory.MemoryCache +import coil3.request.Disposable +import coil3.request.ImageRequest +import coil3.request.allowHardware +import coil3.toBitmap + +class NetworkImageLoader(private val context: Context, useDiskCache: Boolean = false) { + + companion object { + private const val DISK_CACHE_SIZE = 1024 * 1024 * 100L // 100MB + private const val DISK_IMAGES_CACHE_DIR = "net_images_cache" + } + + private var imageLoader: ImageLoader = ImageLoader.Builder(context) + .allowHardware(false) + .memoryCache { + MemoryCache.Builder() + .maxSizePercent(context, 0.25) + .build() + } + .apply { + if (useDiskCache) { + diskCache { + DiskCache.Builder() + .directory(context.cacheDir.resolve(DISK_IMAGES_CACHE_DIR)) + .maxSizeBytes(DISK_CACHE_SIZE) + .build() + } + } + } + .build() + + fun loadImage( + url: String, callback: ImageLoaderCallback, handlePlaceholder: Boolean = false + ): LoadingImage { + val request = ImageRequest.Builder(context) + .data(url) + .target( + onStart = { placeholder -> + callback.onStart(placeholder?.takeIf { handlePlaceholder }?.toBitmap()) + }, + onSuccess = { result -> + callback.onSuccess(result.toBitmap()) + }, + onError = { _ -> + callback.onError() + }) + .build() + + return LoadingImage(url, imageLoader.enqueue(request)) + } +} + +interface ImageLoaderCallback { + + fun onStart(bitmap: Bitmap?) + + fun onSuccess(bitmap: Bitmap) + + fun onError() +} + +class LoadingImage(val url: String, private val disposable: Disposable) { + + fun cancel(): Boolean { + disposable.dispose() + return true + } +} \ No newline at end of file diff --git a/OsmAnd-telegram/res/values-et/strings.xml b/OsmAnd-telegram/res/values-et/strings.xml index f9a9709bf01..861d1408575 100644 --- a/OsmAnd-telegram/res/values-et/strings.xml +++ b/OsmAnd-telegram/res/values-et/strings.xml @@ -64,7 +64,7 @@ Tühista Seaded Taustarežiim - yd + jrd jalga mi km @@ -73,8 +73,8 @@ min/m min/km m/s - km/h - mph + km/t + mi/t Kilomeetrit tunnis Miili tunnis Meetrit sekundis diff --git a/OsmAnd/build-common.gradle b/OsmAnd/build-common.gradle index 81cb48fa97d..81cf69ff32b 100644 --- a/OsmAnd/build-common.gradle +++ b/OsmAnd/build-common.gradle @@ -3,8 +3,8 @@ tasks.register('printc') { } android { - compileSdk 34 - buildToolsVersion = "34.0.0" + compileSdk 35 + buildToolsVersion = "35.0.0" // compileNdkVersion "android-ndk-r17b" namespace = "net.osmand.plus" defaultConfig { @@ -404,6 +404,9 @@ dependencies { // turn off for now //implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0' implementation 'com.squareup.picasso:picasso:2.71828' + //implementation("io.coil-kt.coil3:coil-core:3.1.0") + //implementation("io.coil-kt.coil3:coil-network-okhttp:3.1.0") + implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' implementation "net.osmand:antpluginlib:3.8.0@aar" // JS core diff --git a/OsmAnd/build-library.gradle b/OsmAnd/build-library.gradle index 45bd0b81393..403759aec4f 100644 --- a/OsmAnd/build-library.gradle +++ b/OsmAnd/build-library.gradle @@ -70,6 +70,13 @@ android { osmandTask.dependsOn(copyMapPOIIcons) osmandTask.dependsOn(copyLargePOIIcons) } + def generateResources= "generate${taskName}Resources" + tasks.named(generateResources).configure { osmandTask -> + println(osmandTask.getName() + " generate resources") + osmandTask.dependsOn(copyMapShaderIcons) + osmandTask.dependsOn(copyMapPOIIcons) + osmandTask.dependsOn(copyLargePOIIcons) + } } } diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle index 55eb4b708dd..9867294ba3e 100644 --- a/OsmAnd/build.gradle +++ b/OsmAnd/build.gradle @@ -211,6 +211,11 @@ android { println(osmandTask.getName() + " merge resources") osmandTask.dependsOn(collectExternalResources) } + def generateResources= "generate${taskName}Resources" + tasks.named(generateResources).configure { osmandTask -> + println(osmandTask.getName() + " generate resources") + osmandTask.dependsOn(collectExternalResources) + } } } diff --git a/OsmAnd/res/values-b+sr+Latn/phrases.xml b/OsmAnd/res/values-b+sr+Latn/phrases.xml index a397d538e83..0d5add2a0d4 100644 --- a/OsmAnd/res/values-b+sr+Latn/phrases.xml +++ b/OsmAnd/res/values-b+sr+Latn/phrases.xml @@ -4600,7 +4600,7 @@ Art Šetnja planetama Panoramski pogled - Obrazovanje + Područje obrazovne ustanove Beskontaktni MasterCard Beskontaktna Girocard Beskontaktni Girocard se ne prihvata diff --git a/OsmAnd/res/values-b+sr+Latn/strings.xml b/OsmAnd/res/values-b+sr+Latn/strings.xml index bbeeef4197d..35cd941aab4 100644 --- a/OsmAnd/res/values-b+sr+Latn/strings.xml +++ b/OsmAnd/res/values-b+sr+Latn/strings.xml @@ -1906,7 +1906,7 @@ Memorijska kartica Otvoreno 24/7 Traži - Sused + Kvart Distrikt iz Poštanski broj @@ -2619,7 +2619,7 @@ Snimljeno #Putovanje Pauzirano - &Pauziraj + Pauza Nastavi Nastavi Obaveštenja @@ -5515,7 +5515,7 @@ Putanja ne sadrži podatke za čuvanje. Dugme za čuvanje GPX staze i završetak snimanja putovanja. Prvo započni snimanje putovanja. - Snimljeno putovanje i nastavi + Snimi putovanje i nastavi Šeme boja Dugme za pokretanje novog segmenta u tekućem GPX snimanju staze. Počelo je snimanje novog segmenta putanje. diff --git a/OsmAnd/res/values-cs/phrases.xml b/OsmAnd/res/values-cs/phrases.xml index 914b7e9f18b..e99ef831427 100644 --- a/OsmAnd/res/values-cs/phrases.xml +++ b/OsmAnd/res/values-cs/phrases.xml @@ -4243,7 +4243,7 @@ Krém: ano Krém: ne Obchod s dlaždicemi - Vzdělávání + Oblast vzdělávání Umění Sport Dezinfekce rukou: ano diff --git a/OsmAnd/res/values-cs/strings.xml b/OsmAnd/res/values-cs/strings.xml index e1011528935..0019f003524 100644 --- a/OsmAnd/res/values-cs/strings.xml +++ b/OsmAnd/res/values-cs/strings.xml @@ -5473,7 +5473,7 @@ K této lokalitě zatím nebyly přidány žádné uživatelské fotografie Nejsou dostupné žádné fotografie Tlačítko pro uložení GPX stopy a ukončení záznamu cesty. - Zaznamenaná cesta a pokračování + Zaznamenaný výlet a pokračovat Stopa neobsahuje data, která by bylo možné uložit. Nejprve spusťte záznam cesty. Zahájení nahrávání nového segmentu stopy. @@ -5495,7 +5495,7 @@ Podpora OBD Teplota okolí Napětí baterie - Nový úsek cesty + Nový segment výletu Spustit / Pozastavit Barevná schémata Seznam filmů diff --git a/OsmAnd/res/values-de/phrases.xml b/OsmAnd/res/values-de/phrases.xml index 336a0156748..f26b0d724f0 100644 --- a/OsmAnd/res/values-de/phrases.xml +++ b/OsmAnd/res/values-de/phrases.xml @@ -4290,7 +4290,7 @@ Bietet eingeschränkte Dienstleistungen im Auftrag des Postdienstleisters an Name des Postdienstleisters Markenname der Postdienstleistungen - Bildung + Schulischer Bereich Begrünung Wäscheservice Friseurbedarf diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index 3883dc650bb..87f7ee52a8e 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -5727,4 +5727,8 @@ Jeder Punkt würde seine eigene Form behalten. Mercator statt WGS84 oder UTM verwenden Gitter in Mercator km statt WGS84 oder UTM anzeigen + Verwende Dezimeter statt Grad + Verwende Dezimeter statt Grad oder Dezimeter pro Meter + Zeige Gitter in Grad und Minuten statt in Grad oder DMS + Gitter in Grad, Minuten, Sekunden anzeigen statt in Grad diff --git a/OsmAnd/res/values-es-rAR/phrases.xml b/OsmAnd/res/values-es-rAR/phrases.xml index 6d30b4bf4c5..d5011865dc1 100644 --- a/OsmAnd/res/values-es-rAR/phrases.xml +++ b/OsmAnd/res/values-es-rAR/phrases.xml @@ -4290,7 +4290,7 @@ Cartel de bienvenida Deporte Arte - Educación + Área educativa Vegetación (decorativa);Follaje;Verdor Suministros de peluquería Cambiador de pañales diff --git a/OsmAnd/res/values-es-rAR/strings.xml b/OsmAnd/res/values-es-rAR/strings.xml index da105263494..6db76191769 100644 --- a/OsmAnd/res/values-es-rAR/strings.xml +++ b/OsmAnd/res/values-es-rAR/strings.xml @@ -3433,7 +3433,7 @@ Agregar punto de referencia de la traza Grabación de viaje Guardar como archivo de traza - Seguir traza + Navegar traza Elegí el archivo de la traza a seguir Elegí el archivo de la traza a seguir o importalo desde el dispositivo. Elegí otra traza diff --git a/OsmAnd/res/values-es-rUS/strings.xml b/OsmAnd/res/values-es-rUS/strings.xml index 86c3f3214e7..4a7a3cfbfb1 100644 --- a/OsmAnd/res/values-es-rUS/strings.xml +++ b/OsmAnd/res/values-es-rUS/strings.xml @@ -3508,7 +3508,7 @@ Pausar grabación de viaje Reanudar grabación de viaje Elige el archivo de la traza a seguir - Seguir traza + Navegar traza Importa o graba archivos de trazas Añadir archivos de traza La grabación de la traza se pausará al cerrar la aplicación (mediante aplicaciones recientes). (La indicación de fondo de OsmAnd, desaparecerá de la barra de notificaciones de Android.) diff --git a/OsmAnd/res/values-es/strings.xml b/OsmAnd/res/values-es/strings.xml index 8ee9d4becbb..b3e027efecb 100644 --- a/OsmAnd/res/values-es/strings.xml +++ b/OsmAnd/res/values-es/strings.xml @@ -3694,7 +3694,7 @@ Añadir punto de referencia de la traza Grabación de viaje Guardar como archivo de traza - Seguir traza + Navegar traza Elige el archivo de la traza a seguir Elige el archivo de la traza a seguir o impórtala desde el dispositivo. Elegir otra traza diff --git a/OsmAnd/res/values-et/phrases.xml b/OsmAnd/res/values-et/phrases.xml index 6d46d21a4d9..abd92d11f99 100644 --- a/OsmAnd/res/values-et/phrases.xml +++ b/OsmAnd/res/values-et/phrases.xml @@ -4256,20 +4256,20 @@ Kätepesu: ei Kätepesu: jah Täiskasvanud - Kätepesu pasta: jah - Kätepesu pasta: ei + Kätepuhastusvahend väga määrdunud kätele: jah + Kätepuhastusvahend väga määrdunud kätele: ei Soe vesi: ei - Büroo - Posti partner - Posti lisa + Täismahuline postkontor + Postiteenused partneri juures + Postiteenuste allhankija Postkontori bränd Postkontori ametlikud korjeajad Postkontori lahtioleku ajad Koguja Puhumisauk Uisupood - Kreem: jah - Kreem: ei + Kätehoolduskreem: jah + Kätehoolduskreem: ei Soe vesi: jah Tualettide tühjendamine: kuivkäimla Tualettide asend: istuv @@ -4326,7 +4326,7 @@ Purskkaevude väli Kang Tegeluspaneel - Pakihoidla + Pakiautomaat Laviiniohvrite detektor;AVD;Laviinimajakas Jalgrattaklubi Mängumaja @@ -4345,7 +4345,7 @@ Jalutuskäik planeetide vahel Sport ja treeninguvõimalused Tervitustahvel - Haridusasutus + Haridusasutuse maa-ala Kunstiobjekti kirjeldus Roheala Juuksuritarvete pood diff --git a/OsmAnd/res/values-et/strings.xml b/OsmAnd/res/values-et/strings.xml index 6b356fd5615..b243035ba4b 100644 --- a/OsmAnd/res/values-et/strings.xml +++ b/OsmAnd/res/values-et/strings.xml @@ -318,8 +318,8 @@ Vaata ainult pilte, mille on lisanud Paanide puhver Raadiuse joonlaud - Peata/jätka navigeerimist - Käivita/lõpeta navigeerimine + Peata/jätka tee juhatamine + Käivita/lõpeta tee juhatamine Navigeerimise alustamise või lõpetamise nupp. Mõõda vahemaa Sirvi kaarti ja lisa punkte @@ -375,7 +375,7 @@ Koordinaatide sisestamine Teisalda ajalukku Markerid - Koordinaatide formaat + Koordinaatide vorming Kasuta süsteemi klaviatuuri Vali koordinaatide sisestusformaat. Selle muutmiseks puuduta valikut \"Valikud\". Kiire koordinaatide sisestamine @@ -749,7 +749,7 @@ Vali rakenduses nähtaval olevad profiilid. Rakenduse profiilid OsmAnd allalaadimisteenus - Fuksiinpunane + Fuksiapunane Ikoon Kogutud andmed Puuduta uuesti kaardi orientatsiooni muutmiseks @@ -1259,7 +1259,7 @@ Määra oma vahendusserveri pordi number (nt. 8118). Matka salvestamine Määra kuidas oma matku salvestada. - h + t Kestus Kaugus Ringkäik @@ -1806,7 +1806,7 @@ Helkivad ülekatted Võrguühenduseta muutmine Kui võrguühenduseta muutmine on kasutusel, siis muudatused salvestatakse esmalt kohalikus nutiseadmes ning laaditakse üles eraldi päringuga. Muul juhul laaditakse muudatused üles koheselt. - Üles laadimine… + Üleslaadimine… {0} huvipunkti/märget üles laaditud Laadi kõik üles Laadi muudatus OSM-i üles @@ -1949,9 +1949,9 @@ Pikkusühikud Miilid/jardid Kilomeetrid/meetrid - yd + jrd jalga - mph + mi/t mi Jaga asukohta kasutades Asukoht: %1$s @@ -1986,7 +1986,7 @@ Huvipunkti indekseerimine… Transpordi indekseerimine… km - km/h + km/t m Lähimad huvipunktid Kohandatud filter @@ -2573,7 +2573,7 @@ \n \nSelle vaate saad tagasi lülitada, aktiveerides selle siin uuesti või muutes vastavalt vajadusele jaotises „Kaardi seadistamine“ „Kaardistiil“. See lisamoodul rikastab OsmAndi kaardirakendust meresõiduks vajaliku teabega, nagu laevateed, meremärgid, ohutsoonid, sildumisjuhendid ja muu oluline. Kasutamiseks lülita alajaotuses „Seadista kaarti“ sisse valik „Merekaardid“ ning laadi alla soovitud piirkonna kaart. \n \nLisateave: %1$s. - See OsmAnd laiendus toob sõrmeulatusse üksikasjad globaalsete mäesuusatamise nõlvade, murdmaasuusaradade, mäesuusaradade, köisraudteede ja suusaliftide kohta. Teekonnad ja suusaradade raskusastmed on tähistatud värvikoodidega ning kujutatud spetsiaalses talvises kaardistiilis, mis sulab ühte lumivalge talvemaastikuga. \n \nSelle vaate aktiveerimine muudab kaardi stiili väärtuseks \'Talv ja suusk\', mis näitab kõiki maastikuomadusi talvetingimustes. Selle vaate saab tagasi lülitada, aktiveerides selle siin uuesti või muutes vastavalt vajadusele jaotises \'Kaardi seadistamine\' \'Kaardistiil\'. + Mõeldud liikumiseks talipordipiirkonnas: vaata mäesuusatamise nõlvade, murdmaasuusaradade, mäesuusaradade ja suusaliftide teavet, sealhulgas värviliste joontega märgitud radade raskusastmeid. Kasutamiseks lülita lisamoodul sisse, ava „Kaardi seadistamine“ ja vali kaardi stiiliks „Talv ja suusk“. Tee reisi ajal heli-, pildi- või videomärkmeid, kasutades kas nuppu kaardil või asukoha kontekstimenüüd. Jäta meelde oma auto parkimiskoht ja teavita oma kalendrirakendust, kui parkimise aeg hakkab lõppema. Parkimismarkeri lisamiseks vali vajalik koht kaardil, ava „Tegevused“ ja klõpsi „Lisa parkimine“. Muuda vahemaa mõõtmiseks kasutatud ühikut. @@ -3924,7 +3924,7 @@ Võta ühendust tugiteenusega Veaotsing Ostudega seotud probleemide korral palun järgi seda linki. - OsmAnd Live + OsmAnd Reaalajas Aastatellimus Igakuine tellimus Kolme kuu tellimus @@ -4191,7 +4191,7 @@ Vikipeedia ja reisikaardid Ilmaennustus, mis ei vaja võrguühendust Ilmateade - Kaardimootori version 2 (OpenGL) on kiire ning sisaldab ka 2.5-mõõtmelise vaate. Kaardimootori versioon 1 oli esmase valikuna kasutusel kuni OsmAnd\'i versioonini 4.3 ning on jätkuvalt mõistlik eelistus vanemates seadmetes. + Kaardimootori versioon 2 (OpenGL) on kiire ning sisaldab ka 2.5-mõõtmelise vaate. Kaardimootori versioon 1 oli esmase valikuna kasutusel kuni OsmAndi versioonini 4.3 ning on jätkuvalt mõistlik eelistus vanemates seadmetes. Esitusviisi stiilid Sordi alamkaustad Valitud ilmateate andmete kuvamiseks kaardil lülita see valik sisse. @@ -4951,13 +4951,13 @@ Bensiinimootoriga hübriid Internetiühendus puudub Järjepidev sissesuumimine - Teekonna uus lõik + Reisi uus lõik Diiselmootoriga hübriid Esmalt väiksem suurus Kaart on uuendatud: %1$s. Näitab temperatuuri sensori aluselt Nupp GPX-raja salvestamisel uue lõigu alguse märkimiseks. - Käivita / Peata + Alusta / peata Vikimeedia Riigi nimi: Z – A Vaikimisi vaade @@ -5042,4 +5042,103 @@ Südame keskmine löögisagedus Jalgratta maksimaalne võimsus Jalgratta keskmine väntamissagedus + Tuule andmekiht + Salvesta lõik ja jätka + Pilvede andmekiht + Õhurõhu andmekiht + Temperatuuri andmekiht + Sademete andmekiht + Sügavuste samakõrgusjooned + Kahe sõrme vajutusega kaardil saad teda kaardi kalde muutmiseks nihutada üles-alla. + Pika vajutusega nupul saad tema asukohta muuta. + Merenduse samakõrguspunktid + Koordinaadid: kaardi keskpaik + Sügavuse samakõrgusjooned + kg + Koordinaadid: praegune asukoht + Katikuheli + Bluetooth on väljalülitatud + Kaamerarakendus + Bluetooth pole toetatud + Kontrolli uuendusi + Kas kustutame „%1$s“ OsmAnd Cloudist? + Esmalt lühim vahemaa + Esmalt pikim vahemaa + Otsi uuesti + Esmalt varaseim kuupäev + Andureid ei õnnestu leida + Esmalt hiliseim kuupäev + Kustuta pilves asuv variant + Esmalt pikim kestus + Vaheta kausta + Teata kõrvalekaldest teekonnal + Valitud väärtus + Esmalt lühim kestus + Lisateave andurite kohta. + Umbkaudne kurss + Liikumise kiirus + Tuleta kurss järgitavast tee juhatamise teekonnast. + Ilmaennustus on aegunud. + Y-telg + X-telg + Viimati sünkroniseeritud + Jaga failina + Jaga linki + Teadmata + Tuulekiiruse samajooned + Rahvusvaheline Mägirattasõidu Liit + Segmendi klassifikatsioon + Näita radu vastavalt nende MTB raskusastmele. + Näitab järgmise päikeseloojangu kellaaega või aega päikeseloojanguni. + Mõõtühikud + Puhverdatud ilmaennustus + MTB raskusaste + IMBA + Näita MTB raskusastet + Need vidinad näitavad järgmise päikesetõusu ja -loojangu teavet. + Nupp, mis võimaldab kaardil lülitada sisse/välja õhurõhu andmekihti. + Nupp, mis võimaldab kaardil lülitada sisse/välja tuule andmekihti. + Näitab järgmise päikesetõusu kellaaega või aega päikesetõusuni. + Nupp, mis võimaldab kaardil lülitada sisse/välja sademete andmekihti. + Nupp, mis võimaldab kaardil lülitada sisse/välja pilvisuse andmekihti. + Sademete samajooned + Nupp, mis võimaldab kaardil lülitada sisse/välja temperatuuri andmekihti. + Temperatuuri andmekihi kuvamiseks kaardil lülita see valik sisse. + Tolli + Millimeetrit + Õhurõhu andmekihi kuvamiseks kaardil lülita see valik sisse. + mi/t + Miili tunnis + Joonte värvid + Meresügavuste andmekihi kuvamiseks kaardil lülita see valik sisse. + Joone laius + tl + mm + Sademete andmekihi kuvamiseks kaardil lülita see valik sisse. + Sõlme + slm + Pilvisuse andmekihi kuvamiseks kaardil lülita see valik sisse. + Tuulte andmekihi kuvamiseks kaardil lülita see valik sisse. + Meetrit sekundis + Koordinaadid: praegune asukoht + Lisamooduli võimalused:\n- viie andmekihiga 24 tunni ja 7 päeva ennustus\n- asukohapõhised vidinad\n- temperatuuri / õhurõhu samajooned\n\nAndmeallikas on Global Forecast System (GFS, %1$s). + tolli elavhõbeda sammast + torri + Näitab praeguse asukoha geograafilisi koordinaate + hektopaskalit + Koordinaadid: kaardi keskpaik + 24 tunni ja 7 päeva ennustus, mida uuendatakse iga kolme tunni järel + mmHg + Valitud kaardistiilis pole see tegevus võimalik. + inHg + Celsius + Fahrenheit + Välised andurid + km/t + m/s + hPa + Versioon 1 + Versioon 2 (OpenGL) + Näita allalaaditud kaartide piirjooni + Näitab kaardivaate keskpunkti geograafilisi koordinaate diff --git a/OsmAnd/res/values-ga/phrases.xml b/OsmAnd/res/values-ga/phrases.xml index 0b8e7f69b6c..d477efd15f8 100644 --- a/OsmAnd/res/values-ga/phrases.xml +++ b/OsmAnd/res/values-ga/phrases.xml @@ -4696,7 +4696,7 @@ Siúlóid pláinéad Spórt Comhartha fáilte - Oideachas + Réimse oideachais Greenery Siopa soláthair gruagaire American Express gan teagmháil (AMEX) diff --git a/OsmAnd/res/values-ga/strings.xml b/OsmAnd/res/values-ga/strings.xml index 835b5c89996..c2271d74003 100644 --- a/OsmAnd/res/values-ga/strings.xml +++ b/OsmAnd/res/values-ga/strings.xml @@ -5499,7 +5499,7 @@ Am rabhaidh chun an Pointe Cur Chuige Is gaire (CPA) a bhaint amach Má tá an TCPA (am chun an CPA a bhaint amach le soitheach eile) níos lú ná an luach seo, tá an soitheach marcáilte le dath dearg. Taispeáin greille léarscáil - Taispeáin an eangach i méadair UTM in ionad céimeanna WGS84 + Taispeáin an eangach i méadair UTM in ionad WGS84 Greillí léarscáileanna Ceadaigh greille a thaispeáint ar an léarscáil Úsáid UTM in ionad WGS84 @@ -5508,4 +5508,15 @@ Promo HMD ar feadh %1$s mí Rochtain saor in aisce ar ghnéithe lena n-áirítear íoslódálacha neamhtheoranta léarscáileanna, faoiseamh 3D srl. ar feadh %1$s mí Scoir + Bain úsáid as Mercator in ionad WGS84 nó UTM + Taispeáin an eangach i Mercator km in ionad WGS84 nó UTM + Úsáid DMS in ionad céimeanna + Taispeáin an eangach i gcéimeanna, nóiméid, soicindí in ionad céimeanna + Úsáid DM in ionad céimeanna nó DMS + Taispeáin an eangach i gcéimeanna agus i nóiméid in ionad céimeanna nó DMS + Cuir i bhfeidhm ar gach pointe + Choimeádfadh gach pointe a dhath féin. + Choimeádfadh gach pointe a dheilbhín féin. + Choimeádfadh gach pointe a chruth féin. + An bhfuil fonn ort athruithe a chur i bhfeidhm ar na pointí reatha san fhillteán nó ar na pointí nua amháin? diff --git a/OsmAnd/res/values-gd/strings.xml b/OsmAnd/res/values-gd/strings.xml index 50789436acf..a8fbb031cfb 100644 --- a/OsmAnd/res/values-gd/strings.xml +++ b/OsmAnd/res/values-gd/strings.xml @@ -77,4 +77,109 @@ Fosgail WunderLINQ Datagrid Sreath %1$s Sreathan + Mapaichean àbhaisteach + RAM ri làimh + Àirde as motha + Teòthachd + %s - %s + %1$s : %2$s + Puingean air a\' mhapa + CarPlay + Tasgadan + Uicipeid agus mapaichean siubhail + %s - %s, %s + Dubh às mapa %1$s? + Dubh às mapa + An dàta agam + Steach-ghluais / Mach-ghluais + Lorg uile + Tòisich air OsmAnd + Seatadh + %1$s • %2$s • %3$s + Stuthan-spreadhaidh + Gasan + Measgaichte + Bathar cunnartach + Dubhadh às + Caol-dùirn + Corrag + Broilleach + Làmh + Cas + Dubh às \"%1$s\"? + Co-cheangailte + Dìochuimhnich + Luaths + Astar + Astar iomlan + Bataraidh + Reat-cridhe + Reat bhuillean-cuisle + Teòthachd + Ceangal + Bataraidh + Luaths + Astar iomlan + Astar + Ceangal + Geàrr ceangal + A\' sreap + Puinnd + lbs + Nas fhaisge + òirlich + cileagram + slat + Air a\' mhapa + Y-axis + X-axis + Co-thímich… %1$s + Sgòth + Faidhle ùr + Co-thìmich an-dràsta + Còmhstri + Còmhstrithean + Luchdaich suas uile + Steach-ghluais/mach-ghluais + Fosgail + Fosgail aimsir + Èiridh / dol fodha na grèine + Filleadh teòthachd + Filleadh bruthaidh + Filleadh gaoithe + Filleadh sgòthan + Filleadh silidh-uisge + Dol fodha na grèine + Ùine air fhàgail + Èirigh na grèine + Tuairmse far-loidhne + Tasgadan air-loidhne + Bruthadh-èadhair + Gaoth + Sgòth + Sileadh-uisge + Sìde + Loidhnichean-àirde + Fillidhean + in + mm + Òirleach + Milimeatair + kn + msu + km/u + Teòthachd + m/d + Mìltean-mara san uair + Mìltean san uair + Cilemeatairan san uair + Meatairan/diog + hPa + inHg + mmHg + Celsius + Fahrenheit + Ath-thòisich an-dràsta + Dreach 1 + Dreach 2 (OpenGL) diff --git a/OsmAnd/res/values-is/phrases.xml b/OsmAnd/res/values-is/phrases.xml index 61ee33fdfd9..0231dac6e3f 100644 --- a/OsmAnd/res/values-is/phrases.xml +++ b/OsmAnd/res/values-is/phrases.xml @@ -4220,7 +4220,7 @@ Tegund Íþróttir Skiptiborð - Menntun + Kennslusvæði Líknarsel Steingervingar Heilsutengt diff --git a/OsmAnd/res/values-is/strings.xml b/OsmAnd/res/values-is/strings.xml index 1e224d07ce9..36550f911a7 100644 --- a/OsmAnd/res/values-is/strings.xml +++ b/OsmAnd/res/values-is/strings.xml @@ -5683,11 +5683,22 @@ Leyfa birtingu hnitanets yfir landakortinu Nota UTM í stað WGS84 Hnitanet korts - Birta hnitanet í UTM-metum í staðinn fyrir WGS84-gráður + Birta hnitanet í UTM-metum í staðinn fyrir WGS84 Birta hnitanet á korti Engir staðir tiltækir Engum notendamyndum hefur ennþá verið bætt við þessa staðsetningu Ókeypis aðgangur að eiginleikum á borð við ótakmörkuð niðurhöl korta, þrívíddarlandslag, o.fl. fyrir %1$s á mánuði Útkeyrsla HMD-kynning í %1$s mánuði + Hver punktur myndi halda sinni lögun. + Beita á alla punkta + Hver punktur myndi halda sínum lit. + Hver punktur myndi halda sinni táknmynd. + Virkja breytingar á fyrirliggjandi punkta í möppunni eða aðeins á nýja punkta? + Nota Mercator í staðinn fyrir WGS84 eða UTM + Nota DMS í staðinn fyrir gráður + Birta hnitanet í gráðum og mínútum í staðinn fyrir gráður eða DMS + Birta hnitanet í Mercator-km í staðinn fyrir WGS84 eða UTM + Birta hnitanet í gráður, mínútur, sekúndur í staðinn fyrir gráður + Nota DM í staðinn fyrir gráður eða DMS diff --git a/OsmAnd/res/values-it/phrases.xml b/OsmAnd/res/values-it/phrases.xml index 29275e4192f..3844b2ecbcc 100644 --- a/OsmAnd/res/values-it/phrases.xml +++ b/OsmAnd/res/values-it/phrases.xml @@ -3101,7 +3101,7 @@ Scooter: no Presa: NEMA 5-20 Tram - Educazione + Area educativa No Biologia Chimica @@ -4432,4 +4432,7 @@ ATV: sì ATV: no Note di accesso + Sospeso + Misuratore di ispezione + Maar diff --git a/OsmAnd/res/values-it/strings.xml b/OsmAnd/res/values-it/strings.xml index e62cfe3991f..7927dad2754 100644 --- a/OsmAnd/res/values-it/strings.xml +++ b/OsmAnd/res/values-it/strings.xml @@ -2120,7 +2120,7 @@ Colore Seleziona cartella dei file GPX Il file non può essere spostato. - Muovi + Sposta Tracce Velocità media In movimento @@ -4011,13 +4011,13 @@ Cronologia della versione Memoria occupata Eliminare il registro delle modifiche per i tipi di dati deprecati da OsmAnd Cloud\? - Invia registro di log + Invia registro logcat Cancella la cronologia delle versioni Evita i tunnel Evita i tunnel Codice promozionale Invia rapporto errori - Linee di contorno del terreno, ombreggiatura in scala di grigi e indicazione della pendenza in scala di colori, per mostrare picchi e pianure. + Linee isoipse, ombreggiatura dei rilievi in scala di grigi e indicazione della pendenza in scala di colori, per mostrare picchi e pianure. Esplora Wikivoyage offline. Articoli divisi per nazione e regione e disponibili in tutte le lingue. Fornisce offline tutti gli articoli di Wikipedia relativi ai luoghi, aiutandoti a conoscere i luoghi che visiti durante il tuo viaggio con semplici tocchi sulla mappa. Non dimenticare di scaricare i file cartografici di Wikipedia per le rispettive regioni. Esplora ovunque gli articoli Wikipedia, senza una connessione a internet. I dati offline sono divisi per nazione e disponibili in tutte le lingue. @@ -4068,7 +4068,7 @@ Permetti l\'utilizzo dei cancelli Preferisci pavimentazione tattile Cambiamenti delle regole di acceso alla memorizzazione - Porta le mappe offline di OsmAnd nello schermo del tuo veicolo e integralo con i comandi del tuo veicolo. + Porta mappe e navigazione offline di OsmAnd sul display del tuo veicolo e le integra con i comandi di bordo. Nautico Strade esplicitamente permesse Utilizza solo le strade esplicitamente permesse @@ -5044,7 +5044,7 @@ Guida utente Scarica e installa la versione gratuita di OsmAnd Unisciti a una delle nostre chat Telegram locali. - Problema aperto su GitHub + Segnala un problema su GitHub Segnala un problema Copia la versione di compilazione I più visti @@ -5645,10 +5645,10 @@ Supporto OBD Efficienza Carburante (%) Abilita o disabilita il touch screen per evitare tocchi accidentali - Nuovo tratto del percorso + Nuovo segmento del percorso Un pulsante per avviare, mettere in pausa o riprendere la registrazione del percorso GPX. - Percorso registrato e proseguimento - Avvio / Pausa + Registra viaggio e continua + Inizio / Pausa Codice VIN tramite OBD Azzeramento velocità media Dispositivo sconosciuto diff --git a/OsmAnd/res/values-ru/phrases.xml b/OsmAnd/res/values-ru/phrases.xml index 733b709c066..117767cfe02 100644 --- a/OsmAnd/res/values-ru/phrases.xml +++ b/OsmAnd/res/values-ru/phrases.xml @@ -4433,4 +4433,88 @@ Парашютный спорт (прыжки с парашютом) Роликовые коньки Гольф + Анкерный болт + Подходит для хайкинга + Среднее + Низкое + Высокое + Высокое + Высокое + Среднее + Высокое + Место для скалолазания: базальт + Низкое + Среднее + Тип зоны для кемпинга + Высокое + Среднее + Среднее + Низкое + Высокое + Низкое + Высокое + Низкое + Среднее + Вода + Сложнейший маршрут (по французской шкале) + Сложнейший маршрут (по шкале Saxon) + Средний маршрут (по французской шкале) + Средний маршрут (по шкале UIAA) + Шкала скалолазания UIAA + Среднее + Статус доступа зоны отдыха + Общецелевой магазин + Низкое + Среднее + Высокое + Среднее + Зона отдыха + Место для скалолазания: гравелит + Сложнейший маршрут (по шкале UIAA) + Низкое + Автоматические раздатчики топлива; Топливный автомат + Кафе + Низкое + Высокое + Низкое + Место для скалолазания: конгломерат + Водная площадка + Средний маршрут (по шкале Saxon) + Элита + Супер элита + Кофейные капсулы + Другое + Поддоны + Да + Нефть + Аэрозольные баллончики + Спасатель + Да + Вышка спасателя + Ремни + Лодки + Электроприборы + Только + Ручки + Пакеты + Еда + Начинающий + Продолжающий + Эксперт + Новичок + Продвинутый + Супер эксперт + Шкала скалолазания Saxon + Стеклянные банки + Морские отходы + Металлическая упаковка + Французская шкала скалолазания + PET + Крюк + Да + Нет + Электроника + Газовые баллоны + Цветные стеклянные бутылки + Самостоятельный выход: нет diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index b65c9e54d5c..30a130dc125 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -5940,7 +5940,7 @@ Иконки каждой точки сохранятся. Цвет каждой точки сохранится. Применить для всех точек - HMD Промо за %1$s месяцев - Полный доступ к таким возможностям как безлимитная загрузка карт, 3D рельеф и т.д. за %1$s месяц + HMD Промо на %1$s месяцев + Полный доступ к таким возможностям как безлимитная загрузка карт, 3D-рельеф и прочим на %1$s месяцев Применить изменения к существующим точкам в папке или только к новым? diff --git a/OsmAnd/res/values-sr/phrases.xml b/OsmAnd/res/values-sr/phrases.xml index 9e5085f2a30..d18bb1e4291 100644 --- a/OsmAnd/res/values-sr/phrases.xml +++ b/OsmAnd/res/values-sr/phrases.xml @@ -4290,7 +4290,7 @@ Знак добродошлице Уметност Шетња по планети - Образовање + Образовна област Зеленило Продавница фризерског прибора Промена стола diff --git a/OsmAnd/res/values-sr/strings.xml b/OsmAnd/res/values-sr/strings.xml index 43b190fe8d7..aa73b6fd03c 100644 --- a/OsmAnd/res/values-sr/strings.xml +++ b/OsmAnd/res/values-sr/strings.xml @@ -955,7 +955,7 @@ Приказуј обавештење које омогућава покретање снимања путовања. Обавештења Настави - Паузирај + Пауза Путовање Снимљено Снимај @@ -5520,14 +5520,14 @@ Почело је снимање новог дела путање. Нови део путовања Дугме за покретање, застанак или наставак снимања стазе ГПКС-а. - Покрени / застани + Покрени / Паузирај Шеме боја Траг не садржи податке за чување. Дугме за чување стазе ГПКС-а и завршетак снимања путовања. Прво започните снимање путовања. Дугме за покретање новог дела у текућем снимању стазе ГПКС-а. Дугме за чување тренутно снимљеног путовања као датотеке ГПКС-а и наставак непрекидног снимања новог трага. - Снимљено путовање и наставите + Сними путовање и настави Списак филмова Остале везе Закључај екран diff --git a/OsmAnd/res/values-th/strings.xml b/OsmAnd/res/values-th/strings.xml index 7fef04fabe4..105da632118 100644 --- a/OsmAnd/res/values-th/strings.xml +++ b/OsmAnd/res/values-th/strings.xml @@ -482,7 +482,7 @@ ธีมสว่าง ภาษาตากาล็อค ภาษาละติน - ออกวงเวียนทางออกที่ %1$d แล้วไปยัง + ออกวงเวียนทางออกที่ %1$d แล้วไปต่อ บันทึกแล้ว ใช้ไป %1$s เมกะไบต์ มองเห็นได้ @@ -784,4 +784,15 @@ ส่งออกเป็นไฟล์ นำเข้าจากไฟล์ นำเข้า / ส่งออก + BRouter + ประเภทเส้นทาง + เส้นทาง + ชิดซ้ายและไปต่อ + กิโลเมตรต่อชั่วโมง + เลี้ยวซ้ายหักศอกและไปต่อ + เลี้ยวซ้ายและไปต่อ + เบี่ยงซ้ายและไปต่อ + ข้อมูลเส้นทาง + ชิดขวาและไปต่อ + เปิดเพื่อดูเส้นทางขนส่งสาธารณะบนแผนที่ diff --git a/OsmAnd/res/values-tr/strings.xml b/OsmAnd/res/values-tr/strings.xml index fa9afa7f22d..39e65318025 100644 --- a/OsmAnd/res/values-tr/strings.xml +++ b/OsmAnd/res/values-tr/strings.xml @@ -5415,4 +5415,328 @@ Pencere öğesi, harita işaretçileri listesindeki ilk iki işaretçi için mesafeyi veya tahmini varış zamanını (TVZ) gösterir. Web adresini parametre sözdizimi ile belirtin: enlem={0}, boylam={1}, zaman damgası={2}, hdop={3}, rakım={4}, hız={5}, yön={6}. Avrupa Orta Vadeli Hava Tahminleri Merkezi (ECMWF) + AIS verisini dosyadan yükleyin + IP adresi ayarları + Son ziyaret edilenler + Bütün noktalara uygula + Her nokta kendi renginde kalacak. + Her nokta kendi simgesiyle kalacak. + Her nokta kendi şekliyle kalacak. + %1$s aylığına sınırsız harita indirme, 3B kabartma vb. dahil ücretsiz erişim + Çıkış + Yakınlardaki popüler mekanlar + Değişiklikler klasördeki mevcut noktalara mı kaydolsun veya yeni oluşturulsun mu? + Sinyal alınmadığında gemi görünürlüğü zaman aşımı + Rota bilgisi + Sonraki durak için önce zamanı ve mesafeyi gösterir. Varış noktası ayrıntılarını sürekli görmek için kapatın. + Yeni tarayıcı bağla + Ses örnek hızını seçin. + Motorun çalıştırıldığından beri ne kadar süredir çalıştığını gösterir. + Hesaplanan Motor Yükü + Araç Hız Sensöründen (VSS) gelen hız verisini gösterir. + 3B otomatik yakınlaştırma açısı + Yakıt sistemindeki basıncı gösterir + Araç Verileri (OBD-II) + GPX dosyasına kaydedilecek parametreleri seçin. + Hesaplanıyor… + Aracın akü voltaj seviyesini gösterir + Motor suyu sıcaklığını gösterir + UYARI\n\nBu eklenti bir hobi projesidir, güvenilirlik ve doğruluk için tasarlanmamıştır. Can güvenliği ve/veya yön tarifi dahil hiçbir yönlendirmeye GÜVENMEYİN. + Bu konuma henüz hiç kullanıcı fotoğrafı eklenmemiş + Varsayılan görüntüleme + Her buton kendi arka plan opaklığında kalacak. + Uzunluk + Ort. yükseklik + Min. hız + Her buton kendi köşe ayarında kalacak. + + Saat + Gaz Kelebeği Konumu + Motorun anlık kullanılabilir gücünü yüzde olarak gösterir. + Tırmanma rotalarını göster + Tırmanma rotaları + \"%s\" profili seçildi + Boyutu hesapla + Her buton kendi boyutunda kalacak. + Ses örnek hızı + OBD-II protokolü verilerini kullanarak aracın önemli verilerini izleyin. Hız, motor devri, yakıt tüketimi ve diğer verileri takip edin. + %2$s başına %1$s + CPA ile ilgili ayarlar + Sonraki durak için rota ayrıntılarını göster + Ortalama değeri sıfırla + Anlık sıcaklık + NMEA veri kaynağının TCP port numarasını tanımlayın + Yerel NMEA veri alıcısının UDP portu + Ortalama değer ölçümü için zaman aralığını seçin. + Ortalama sıcaklık ölçümü için zaman aralığını seçin. + Ortalama sıcaklık + Yakıt tüketimi + Kalan yakıt + Aracın deposunda kalan yakıt miktarını gösterir + NMEA veri kaynağının IP adresi + NMEA veri kaynağının IP adresini tanımlayın (TCP kullanılıyorsa) + OsmAnd\'ın NMEA verisini çekeceği UDP portunu tanımlayın + Araç dışı sıcaklığı gösterir. + Emme manifoldundan motora giren havanın sıcaklığını gösterir. + Motorun yakıt kullanımını, kalan yakıtı, depo kapasitesini ve GPS\'den gelen veriye göre katedilen mesafeyi gösterir. + NMEA veri kaynağının TCP portu + Nesneler kaybolduğunda görünürlük zaman aşımı + Tahmini varış süresini, kalan yolculuk süresini ve mevcut yol tarifinin mesafesini gösterir. + Motor yağı sıcaklığını gösterir. + Motor Yağı Sıcaklığı + Araç ölçümlerini kaydet + %/sa + Yakıt seviyesi (%) + Yakıt tüketim oranı (obd) + Yakıt tüketim oranı + Yakıt tüketim oranı (L/sa) + İsabetli yakıt seviyesi ve yakıt tüketimi takibi yapmak için depo kapasitenizi girin + Yakıt deposu kapasitesi + Ebatlar + Litre + İngiliz galonu + L/100km + Yakıt tüketim oranı (L/100 km) + Yakıt tüketim oranı %/sa + %s bağlantısı kuruluyor + Galon + Amerikan galonu + + Maksimum + %s bağlantısı kesildi + %s bağlantısı kuruldu + Şeritler, kavşaklarda sesli yönergeler açık olsa da gösterilecek + Yakıt basıncı + Yakıt seviyesi (l) + Kalan yakıt (km) + Dinamik + Aygıtla eşleştirme başlatılamadı + Yakıt tüketim oranı (sensör) + Kalan yakıt (litre) + Aracın yakıt tüketim oranını OBD ve konuma göre gösterir + Köşe yarıçapı + Metanol + Artış + Harita yakınlaştırmayı değiştir. + Araç Ölçümleri + OBD desteği + Yükselti katmanlarını değiştir + Aramayı açar. + Harita eğimini değiştir. + Ana menüyü açar. + Aktivite türü + Benzin + Etanol + OBD + Araç Ölçümleri ayaları + devir + Aracın devir sayacını OBD sensörü üzerinden gösterir + Aracın yakıt tipini OBD sensörü üzerinden gösterir + Giren hava sıcaklığı + Akü voltajı + Motor suyu sıcaklığı + Yakıt tüketim oranı + Navigasyon görünümünü açıp kapatma butonu. + Haritayı konumunuza göre ortalar. + Yakıt tipi girilmedi + Bilinmeyen Yakıt Tipi + Hidrojen + Elektrik + Araç Ölçümleri + Arama görünümü + Kaynak + Yan menü + Yan menüyü gösterip gizleme butonu. + Tarama katmanlarını değiştir + Arayüz + Gezin + Navigasyon görünümü + Bu konuma henüz kullanıcı fotoğrafı eklenmemiş + Harita stilini, katmanları veya diğer ayarları değiştir. + Aracın yakıt seviyesini OBD sensörü üzerinden gösterir + Aracın kalan yakıtla ne kadar mesafe gidebileceğini ODB sensörü üzerinden gösterir + Ortam sıcaklığı + Yakıt tipi + Arka plan opaklığı + Önceki ekrana geçiş butonu. + Önceki ekran + İnternet bağlantısı yok + CNG + Lütfen bağlantınızı kontrol edip tekrar deneyin. + Aktiviteyi değiştir + Tarayıcıda aç + Düşüş + Tüp gazı + Yakıt Verimliliği (%) + Arama görünümünü açıp kapatma butonu. + Harita yönünü değiştirme butonu. + Arazi motoru yollarını göster + Arazi motoru yolları + Dizel + LPG + % + Grafik ekseni + Yukarıya widget ekle + Y ekseni için iki seçenek seçin. + Sağa widget ekle + Sola widget ekle + Yollar + Rotalar + Yönlendirme modunu değiştirmek için tıklayın ve basılı tutun + Haritadaki %1$s\'ı gösterip gizleme butonu. + OsmAnd yakınlarınızdaki yolları geliştirilmiş adım adım yol rehberi için eşleştirecek. + Birleşik Krallık ve benzeri + Otomatik + Bu widget silinecek. Yapılandırma ekranından geri getirebilirsiniz. + Aşağıya widget ekle + Widget silinsin mi? + %1$d çıkışı kullanın + SUV + Her zaman sor + Ayrıntılı yol rehberi + Sağa dön + Hindistan + Solda tut + Sağda tut + Navigasyon pozisyonu + Sola dönüş + Dinlenme & navigasyon pozisyonu + Dinlenme pozisyonu + Harita yönünü seçin + Sola hafif viraj + Soluk + Sola keskin viraj + U dönüşü yapın + Görüntüleme açısı + Mevcut konum doğruluğunuzu belirten dairesel alanı gösterir + Sağa hafif viraj + Pil istatistikleri (ortalama 1 / 5 / 15 dakika) + Sağa keskin viraj + Konum yarıçapı + Görüntü işleme istatistikleri (ortalama 1 / 5 / 15 dakika) + Dakika başına pil seviyesi: %1$s\nPil tüketimi (mAh): %2$s + Sesli not + Bütün simgeler + Sonraki varılacak nokta + Yeni rota + Yüzey renklendirme tipi + Varış noktası + Oluştur + Göster / Gizle + Aç / Kapat + Başlat / Durdur + Ayarla + GPX konumu + Video not + Harita stili + Fotoğraflı not + Konumuma + Son 1000 karedeki FPS: %1$s\nİşlemci (çekirdek): %2$s\nİşlemci (boşta):%3$s\nİşlemci (GPU\'yu bekleyen): %4$s + + Mevcut konumu her zaman ortada göster + Yüzey renk düzeni + Başlangıç noktası + Park yeri + Duraklat / Devam ettir + Hava durumu ekranı + Navigasyon pozisyonu simgesi + ECMWF + Dinlenme pozisyonu simgesi + GFS + Haritanın görünümü uygulama temasına uyum sağlar — gündüz modunda açık tema, gece modunda koyu tema + Gezinirken ya da hareket ederken simge görünür. + Hareketsizken simge görünür. + Profil simgesi + Harita kılavuzları + Harita kılavuzunu göster + Haritanın üzerinde kılavuz göstermeye izin ver + WGS84 yerine UTM kullan + Kuzey kutbunu yukarı sabitle + Kuzey kutbu yukarı sabitken haritayı parmak hareketleriyle döndürme + Kamu arazilerini gösterme modu + Filtrele + Filtrele: %d + Kamu arazisi sınırlarını gizle + Delta kanat sporu + Kamu arazisi bölgelerini göster sınırlarını gizle + Bisiklet Temposu, maksimum + Yamaç paraşütü + Bisiklet Temposu, ortalama + Süzülme ortalaması için zaman aralığı belirtin. + Süzülme hızı + Direkt noktaya rota (Tekne) + Tren rotası + Koordinat girişi + Rota planla + Kayak rotası + OsmAnd rota oluşturma hakkında + Rota parametreleri + Rota Hazırlığı + Bisiklet rotası (MTB) + Çevrimiçi rota + Toplu Taşıma rotası + Rota Ayrıntıları + Yaya rotası + Tekne rotası + Araç rotası (Kamyon, Motorsiklet) + Ortalama süzülme hızı + Haritaları tara (Çevrimiçi / Çevrimdışı) + Hedefe varmak için gerekli olan süzülme hızını gösterir. + Teker çevresi + Yollar ve Rotalar + Rota çiz + %1$s\'i değiştirir + Haritada bütün yolları göster + Yeni yol + nabız + Yol dosyasınız bulunmamaktadır. + Başlat / Duraklat + Rota rehberi + Kalp ritmi + Bilinmeyen aygıt + VIN + OBD\'den gelen VIN kodu + V + Navigasyonu açar. + Bazı yollarda ve tünellerde tehlikeli materyal taşınması yasaktır. + Rota tiplerinin zorluk sınıflandırması. + Küçük tansiyon + Hava durumunu aç + Nabız + Sensörler hakkında daha fazla bilgi edinin. + Dokunmatik ekran aktif edildi. + %1$s\'a dokunun ve listeden tarayıcınızı seçin. + Tarayıcıyı aracınızın OBD-II portuna bağlayın. + Yanlışlıkla dokunmaları önlemek için dokunmatik ekranı açıp kapatır + Yürüyüş yolu zorluk derecesi + Bütün yolları göster + L/sa + Ada göre yol ara + %1$s yol + OsmAnd ile yol dosyalarınızı içe aktarabilir, oluşturabilir veya kaydedebilirsiniz. + Lütfen önce seyahat kaydını başlatın. + Büyük tansiyon + Yolu yeniden hesaplayınca bildir + Film listesi + OsmAnd OBD-II tarayıcılarının Bluetooth bağlantılarını destekler. + Bu klasörde henüz hiç yol yok. + Serbest sürüş + Bluetooth + Yoldan sapınca uyar + Pil tasarrufu modu + Maksimum port değeri %1$s + Araç hızı + Haritada gösterilecek yolları seçin. + Araç bilgisi + Nasıl bağlantı kurulur: + Aracınızın motorunu çalıştırın + Cihazınızda Bluetooth\'u açın + Dokunmatik ekran devre dışı bırakıldı. Açmak için %1$s butonuna dokunun veya ekrandaki butona dokunun. + Dokunmatik ekran devre dışı bırakıldı. Aktif etmek için açma tuşuna dokunun. + Renk Şeması + Ortalama hızı sıfırla + Wikimedia + Bu işlem %1$s klasörünü ve bütün %2$s içeren yolları silecek. + Yol kaydedilecek veri içermiyor. + Bilgi diff --git a/OsmAnd/res/values-uk/phrases.xml b/OsmAnd/res/values-uk/phrases.xml index b4d91be4916..08a4df1c755 100644 --- a/OsmAnd/res/values-uk/phrases.xml +++ b/OsmAnd/res/values-uk/phrases.xml @@ -4295,7 +4295,7 @@ Вітання Визначні місця Теплиця - Освіта + Навчальний район Магазин перукарських товарів Сповивальний стіл Паливосховище diff --git a/OsmAnd/res/values-uk/strings.xml b/OsmAnd/res/values-uk/strings.xml index 91905517dd3..c23434ae46b 100644 --- a/OsmAnd/res/values-uk/strings.xml +++ b/OsmAnd/res/values-uk/strings.xml @@ -5539,7 +5539,7 @@ Віджет показує рівень пального в машині за датчиком OBD Віджет показує споживання пального машиною на основі даних OBD про розташування Екран блокування - Старт / Пауза + Пуск / Пауза Кольорові схеми Кнопка для збереження GPX-треку і завершення запису подорожі. Будь ласка, спочатку почніть запис треку. diff --git a/OsmAnd/res/values-vi/strings.xml b/OsmAnd/res/values-vi/strings.xml index 5457e42f670..4dcba593764 100644 --- a/OsmAnd/res/values-vi/strings.xml +++ b/OsmAnd/res/values-vi/strings.xml @@ -1917,7 +1917,7 @@ Hiện Chạm vào bản đồ để xem khoảng cách giữa vị trí hiện tại của bạn và điểm đã chạm.\nChạm 2 ngón vào bản đồ để xem khoảng cách giữa các điểm đó Góc giữa hướng bắc chuẩn và điểm đích được lấy từ vị trí của bạn. - Sửa chính xác độ cao + Sửa độ cao Sức mạnh xe đạp Chạm vào widget sẽ chuyển các chế độ. Cảm biến bên ngoài @@ -3396,4 +3396,82 @@ Trống Hiện chi tiết tuyến đường cho điểm dừng tiếp theo Tuyến đường du lịch + Nhập hoặc ghi các tệp cung đường + Thêm tệp cung đường + Điểm của cung đường để điều hướng + Đi theo cung đường + Cắt bỏ trước + Cắt bỏ sau + Điểm gần nhất + Nhập địa chỉ + Cung đường đơn giản hoá + Gắn với các con đường + Thay đổi loại tuyến đường trước + Chỉ có tuyến đường sẽ được lưu lại, các điểm dừng sẽ bị xóa. + Xoá địa chỉ + Điểm bắt đầu của cung đường + Chọn tệp cung đường để đi theo hoặc nhập nó từ thiết bị của bạn. + Chọn tệp cung đường để đi theo + Thay đổi loại tuyến đường sau + Thêm điểm dừng cung đường + Thêm địa chỉ + Lưu dưới dạng tệp cung đường + Cung đường đi + Huỷ bỏ tất cả thay đổi trong tuyến đường đã lập kế hoạch? + Ghi cung đường thành tệp GPX + Thêm vào một tệp cung đường + Chọn một tệp cung đường để mở. + Tạo tuyến đường mới + Chọn cách chia tách mong muốn: bởi thời gian hoặc bởi khoảng cách. + Hồ sơ điều hướng + Đảo ngược tuyến đường + Toàn bộ cung đường + Khoảng cách ngưỡng + Phân đoạn tiếp theo + Ghi đè cung đường + Chọn cách kết nối các điểm, bằng một đường thẳng, hoặc tính toán một tuyến đường giữa chúng như chỉ định ở dưới. + Chỉnh sửa lần cuối + Toàn bộ cung đường sẽ được tính lại sử dụng hồ sơ đã chọn. + Chỉ phân đoạn tiếp theo sẽ được tính lại sử dụng hồ sơ đã chọn. + Lưu dưới dạng cung đường mới + Chọn một tệp cung đường để thêm đoạn mới vào. + Mở cung đường đã có sẵn + Nhập cung đường + Chọn khoảng thời gian mà các dấu mốc với khoảng cách hoặc thời gian trên cung đường sẽ được hiển thị. + Chọn chiều rộng + Xe mô tô địa hình + Điểm đã thêm có thể được tìm thấy trong \"%s\". Bỏ ẩn nhóm đã chọn để hiện nó trên bản đồ. + Vui lòng cung cấp tên cho điểm + Điều khiển mức thu phóng bản đồ bằng nút âm lượng của thiết bị. + Tải bản đồ Wikipedia + Nút âm lượng để thu phóng + Xe lăn + Lấy thông tin về các điểm quan tâm từ Wikipedia, một hướng dẫn bỏ túi ngoại tuyến có chứa các bài viết về các địa điểm và điểm đến. + Xe lăn về phía trước + Ghi chú OSM đã bị đóng + Xe tay ga + Thêm vào một cung đường + Xoá đích đến kế tiếp trên tuyến đường của bạn. Nếu đó là đích đến cuối cùng, việc điều hướng sẽ dừng lại. + Tuyến đường giữa các điểm + Đặt ngày làm việc để tiếp tục + Xe đua nhỏ + Giày trượt patin bánh xe 1 hàng dọc + Gỡ cài đặt và Khởi động lại + Đặt chiều cao của tàu để tránh những cây cầu thấp. Nếu cây cầu có thể chuyển động, chiều cao khi mở được sử dụng. + mét + tấn + Hiện hoặc ẩn thêm chi tiết bổ sung của bản đồ + Việc cảnh báo camera tốc độ ở một số quốc gia bị cấm bởi luật pháp. + Đặt chiều rộng của tàu để tránh những cây cầu hẹp + Thêm nguồn trực tuyến + Giữ hoạt động + Đặt chiều cao của tàu để tránh những cây cầu thấp. Nhớ rằng, nếu cây cầu có thể chuyển động, chúng tôi sẽ dùng chiều cao của nó ở trạng thái mở. + Gỡ cài đặt + Một công tắc để hiện hoặc ẩn lớp phủ Mapillary trên bản đồ. + Bản đồ tối + Đặt chiều cao của tàu + Chỉ rõ chiều dài phương tiện được phép lưu thông trên đường. + Khởi động lại ứng dụng để xoá tất cả dữ liệu camera tốc độ. + Chiều dài + Áp dụng những thay đổi này sẽ xoá dữ liệu đã lưu vào bộ nhớ đệm cho nguồn của mảng này diff --git a/OsmAnd/res/values-zh-rTW/phrases.xml b/OsmAnd/res/values-zh-rTW/phrases.xml index 65f62b9d9e0..2ed9edf79f2 100644 --- a/OsmAnd/res/values-zh-rTW/phrases.xml +++ b/OsmAnd/res/values-zh-rTW/phrases.xml @@ -4290,7 +4290,7 @@ 景點 體育 歡迎符號 - 教育 + 教育區域 綠化 美髮用品店 尿布桌 diff --git a/OsmAnd/src/net/osmand/plus/AppVersionUpgradeOnInit.java b/OsmAnd/src/net/osmand/plus/AppVersionUpgradeOnInit.java index 662a2d26f06..38c4816a533 100644 --- a/OsmAnd/src/net/osmand/plus/AppVersionUpgradeOnInit.java +++ b/OsmAnd/src/net/osmand/plus/AppVersionUpgradeOnInit.java @@ -19,6 +19,7 @@ import static net.osmand.plus.views.mapwidgets.WidgetsPanel.PAGE_SEPARATOR; import static net.osmand.plus.views.mapwidgets.WidgetsPanel.WIDGET_SEPARATOR; import static net.osmand.plus.views.mapwidgets.configure.buttons.QuickActionButtonState.DEFAULT_BUTTON_ID; +import static net.osmand.plus.views.mapwidgets.widgetstates.ResizableWidgetState.SIMPLE_WIDGET_SIZE_ID; import static net.osmand.router.GeneralRouter.VEHICLE_HEIGHT; import static net.osmand.router.GeneralRouter.VEHICLE_LENGTH; import static net.osmand.router.GeneralRouter.VEHICLE_WEIGHT; @@ -58,6 +59,7 @@ import net.osmand.plus.settings.backend.preferences.*; import net.osmand.plus.settings.enums.CompassMode; import net.osmand.plus.settings.enums.LocalSortMode; +import net.osmand.plus.settings.enums.WidgetSize; import net.osmand.plus.views.layers.RadiusRulerControlLayer.RadiusRulerMode; import net.osmand.plus.views.mapwidgets.WidgetGroup; import net.osmand.plus.views.mapwidgets.WidgetType; @@ -140,8 +142,9 @@ public class AppVersionUpgradeOnInit { // 4803 - 4.8-03 (Merge asset files versions) public static final int VERSION_4_8_03 = 4803; public static final int VERSION_5_0_00 = 5000; + public static final int VERSION_5_0_01 = 5001; - public static final int LAST_APP_VERSION = VERSION_5_0_00; + public static final int LAST_APP_VERSION = VERSION_5_0_01; private static final String VERSION_INSTALLED = "VERSION_INSTALLED"; @@ -277,6 +280,9 @@ void upgradeVersion(@NonNull SharedPreferences startPrefs, int lastVersion) { init -> MergeAssetFilesVersionAlgorithm.execute(app) ); } + if (prevAppVersion < VERSION_5_0_01) { + migrateSideWidgetsSizePrefToSmall(settings); + } startPrefs.edit().putInt(VERSION_INSTALLED_NUMBER, lastVersion).commit(); startPrefs.edit().putString(VERSION_INSTALLED, Version.getFullVersion(app)).commit(); startPrefs.edit().putLong(UPDATE_TIME_MS, System.currentTimeMillis()).commit(); @@ -953,4 +959,37 @@ private void migrateTerrainModeDefaultPreferences(@NonNull OsmandSettings settin } } } + + private void migrateSideWidgetsSizePrefToSmall(@NonNull OsmandSettings settings) { + + for (ApplicationMode mode : ApplicationMode.allPossibleValues()) { + List leftPages = settings.LEFT_WIDGET_PANEL_ORDER.getStringsListForProfile(mode); + migrateSidePanelSizes(settings, mode, leftPages); + + List rightPages = settings.RIGHT_WIDGET_PANEL_ORDER.getStringsListForProfile(mode); + migrateSidePanelSizes(settings, mode, rightPages); + } + } + + private void migrateSidePanelSizes(@NonNull OsmandSettings settings, @NonNull ApplicationMode mode, @Nullable List pages) { + if (pages == null) { + return; + } + for (String page : pages) { + String[] widgetIds = page.split(WIDGET_SEPARATOR); + for (String widgetId : widgetIds) { + String sizePrefId; + if (WidgetType.isOriginalWidget(widgetId)) { + sizePrefId = SIMPLE_WIDGET_SIZE_ID + widgetId; + } else { + sizePrefId = SIMPLE_WIDGET_SIZE_ID + WidgetType.getDefaultWidgetId(widgetId) + widgetId; + } + if (settings.isSet(mode, sizePrefId)) { + CommonPreference pref = settings.registerEnumStringPreference(sizePrefId, WidgetSize.SMALL, WidgetSize.values(), WidgetSize.class) + .makeProfile(); + pref.resetModeToDefault(mode); + } + } + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/auto/screens/RoutePreviewScreen.java b/OsmAnd/src/net/osmand/plus/auto/screens/RoutePreviewScreen.java index 7e925a35de5..3e767102321 100644 --- a/OsmAnd/src/net/osmand/plus/auto/screens/RoutePreviewScreen.java +++ b/OsmAnd/src/net/osmand/plus/auto/screens/RoutePreviewScreen.java @@ -141,7 +141,7 @@ private void updateRoute(boolean newRoute) { description.setSpan(DurationSpan.create(leftTimeSec), 4, 5, 0); TargetPoint finish = targetPointsHelper.getPointToNavigate(); - String title = finish != null ? finish.getRoutePointDescription(app) : null; + String title = finish != null ? finish.getRoutePointDescription(app, true) : null; if (Algorithms.isEmpty(title)) { String name = QuickSearchListItem.getName(app, searchResult); diff --git a/OsmAnd/src/net/osmand/plus/card/base/multistate/BaseMultiStateCardController.java b/OsmAnd/src/net/osmand/plus/card/base/multistate/BaseMultiStateCardController.java index 0e632a67b22..5ff8428b4a9 100644 --- a/OsmAnd/src/net/osmand/plus/card/base/multistate/BaseMultiStateCardController.java +++ b/OsmAnd/src/net/osmand/plus/card/base/multistate/BaseMultiStateCardController.java @@ -10,6 +10,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.widgets.popup.PopUpMenu; import net.osmand.plus.widgets.popup.PopUpMenuDisplayData; +import net.osmand.plus.widgets.popup.PopUpMenuDisplayData.CustomDropDown; import net.osmand.plus.widgets.popup.PopUpMenuItem; import java.util.ArrayList; @@ -24,6 +25,9 @@ public abstract class BaseMultiStateCardController implements IMultiStateCardCon protected List states; protected CardState selectedState; + protected CustomDropDown customDropDownSelectorPopup; + protected Boolean limitHeightSelectorPopup; + public BaseMultiStateCardController(@NonNull OsmandApplication app) { this.app = app; } @@ -49,6 +53,12 @@ public void onSelectorButtonClicked(@NonNull View view) { } } PopUpMenuDisplayData data = new PopUpMenuDisplayData(); + if (customDropDownSelectorPopup != null) { + data.customDropDown = customDropDownSelectorPopup; + } + if (limitHeightSelectorPopup != null) { + data.limitHeight = limitHeightSelectorPopup; + } data.anchorView = view; data.menuItems = items; data.nightMode = nightMode; @@ -74,6 +84,14 @@ protected CardState findCardState(@Nullable Object tag) { return states.get(0); } + public void setCustomDropDownSelectorPopup(@NonNull CustomDropDown customDropDownSelectorPopup) { + this.customDropDownSelectorPopup = customDropDownSelectorPopup; + } + + public void setLimitHeightSelectorPopup(@Nullable Boolean limitHeightSelectorPopup) { + this.limitHeightSelectorPopup = limitHeightSelectorPopup; + } + protected boolean isCardStateAvailable(@NonNull CardState cardState) { return true; } diff --git a/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapUtils.java b/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapUtils.java index c30adc629b0..9c40e84b12e 100644 --- a/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapUtils.java +++ b/OsmAnd/src/net/osmand/plus/configmap/ConfigureMapUtils.java @@ -33,7 +33,7 @@ public class ConfigureMapUtils { - public static final String[] MAP_LANGUAGES_IDS = {"", "en", "af", "als", "ar", "az", "be", "ber", "bg", "bn", "bpy", "br", "bs", "ca", "ceb", "ckb", "cs", "cy", "da", "de", "el", "eo", "es", "et", "eu", "fa", "fi", "fr", "fy", "ga", "gl", "he", "hi", "hsb", "hr", "ht", "hu", "hy", "id", "is", "it", "ja", "ka", "kab", "kk", "kn", "ko", "ku", "la", "lb", "lo", "lt", "lv", "mk", "ml", "mr", "ms", "nds", "new", "nl", "nn", "no", "nv", "oc", "os", "pl", "pms", "pt", "ro", "ru", "sat", "sc", "sh", "sk", "sl", "sq", "sr", "sr-latn", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "vi", "vo", "zh", "zh-Hans", "zh-Hant"}; + public static final String[] MAP_LANGUAGES_IDS = {"", "en", "af", "als", "ar", "az", "be", "ber", "bg", "bn", "bpy", "br", "bs", "ca", "ceb", "ckb", "cs", "cy", "da", "de", "el", "eo", "es", "et", "eu", "fa", "fi", "fr", "fy", "ga", "gl", "he", "hi", "hsb", "hr", "ht", "hu", "hy", "id", "is", "it", "ja", "ka", "kab", "kk", "kn", "ko", "ku", "la", "lb", "lo", "lt", "lv", "mk", "ml", "mr", "ms", "nds", "new", "nl", "nn", "no", "nv", "oc", "os", "pl", "pms", "pt", "ro", "ru", "sat", "sc", "sh", "sk", "sl", "sq", "sr", "sr-Latn", "sv", "sw", "ta", "te", "th", "tl", "tr", "uk", "vi", "vo", "zh", "zh-Hans", "zh-Hant"}; @NonNull public static Map getSorterMapLanguages(@NonNull OsmandApplication app) { diff --git a/OsmAnd/src/net/osmand/plus/configmap/tracks/appearance/favorite/FavoriteAppearanceController.java b/OsmAnd/src/net/osmand/plus/configmap/tracks/appearance/favorite/FavoriteAppearanceController.java index 94d32d27ef0..78d3293ac04 100644 --- a/OsmAnd/src/net/osmand/plus/configmap/tracks/appearance/favorite/FavoriteAppearanceController.java +++ b/OsmAnd/src/net/osmand/plus/configmap/tracks/appearance/favorite/FavoriteAppearanceController.java @@ -22,6 +22,7 @@ import net.osmand.plus.myplaces.favorites.FavoriteGroup; import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.BaseCard.CardListener; +import net.osmand.plus.widgets.popup.PopUpMenuDisplayData.CustomDropDown; import net.osmand.shared.routing.ColoringType; public class FavoriteAppearanceController implements IDialogController, IColorCardControllerListener, CardListener, OnIconsPaletteListener { @@ -61,6 +62,8 @@ public FavoriteAppearanceController(@NonNull OsmandApplication app, @NonNull Fav } editorIconController.init(); editorIconController.setIconsPaletteListener(this); + editorIconController.getCardController().setCustomDropDownSelectorPopup(CustomDropDown.TOP_DROPDOWN); + editorIconController.getCardController().setLimitHeightSelectorPopup(true); shapesCardController = new FavoriteShapesCardController(app, this, selectedBackgroundType != null ? selectedBackgroundType : null); } diff --git a/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProvider.java b/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProvider.java index d1847f96a7b..eea853dfdfb 100644 --- a/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProvider.java +++ b/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProvider.java @@ -1,5 +1,7 @@ package net.osmand.plus.exploreplaces; +import androidx.annotation.NonNull; + import net.osmand.data.Amenity; import net.osmand.data.LatLon; import net.osmand.data.ExploreTopPlacePoint; @@ -17,7 +19,7 @@ public interface ExplorePlacesProvider { @NotNull List getDataCollection(QuadRect mapRect, int limit); - void showPointInContextMenu(@NotNull MapActivity it, @NotNull ExploreTopPlacePoint item); + void showPointInContextMenu(@NotNull MapActivity mapActivity, @NotNull ExploreTopPlacePoint item); void addListener(ExplorePlacesListener listener); @@ -30,6 +32,8 @@ public interface ExplorePlacesProvider { // data version is increased once new data is downloaded int getDataVersion(); + boolean isLoadingRect(@NonNull QuadRect rect); + interface ExplorePlacesListener { // once new data is downloaded data version is increased void onNewExplorePlacesDownloaded(); diff --git a/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProviderJava.java b/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProviderJava.java index abe53b5b85a..7e286ac2917 100644 --- a/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProviderJava.java +++ b/OsmAnd/src/net/osmand/plus/exploreplaces/ExplorePlacesProviderJava.java @@ -23,8 +23,10 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; // TODO use gzip in loading @@ -41,18 +43,18 @@ // Extra: display new categories from web public class ExplorePlacesProviderJava implements ExplorePlacesProvider { - private static final int DEFAULT_LIMIT_POINTS = 200; + public static final int DEFAULT_LIMIT_POINTS = 200; private static final int NEARBY_MIN_RADIUS = 50; private static final int MAX_TILES_PER_QUAD_RECT = 12; private static final double LOAD_ALL_TINY_RECT = 0.5; - private OsmandApplication app; + private final OsmandApplication app; private volatile int startedTasks = 0; private volatile int finishedTasks = 0; - private final Set loadingTiles = new HashSet<>(); // Track tiles being loaded + private final Map loadingTiles = new HashMap<>(); // Track tiles being loaded public ExplorePlacesProviderJava(OsmandApplication app) { this.app = app; @@ -98,11 +100,13 @@ private String getLang() { return preferredLang; } + @NonNull public List getDataCollection(QuadRect rect) { return getDataCollection(rect, DEFAULT_LIMIT_POINTS); } - public List getDataCollection(QuadRect rect, int limit) { + @NonNull + public List getDataCollection(QuadRect rect, int limit) { if (rect == null) { return Collections.emptyList(); } @@ -170,17 +174,22 @@ public List getDataCollection(QuadRect rect, int limit) { @SuppressLint("DefaultLocale") private void loadTile(int zoom, int tileX, int tileY, String queryLang, PlacesDatabaseHelper dbHelper) { + double left; + double right; + double top; + double bottom; + synchronized (loadingTiles) { String tileKey = zoom + "_" + tileX + "_" + tileY; - if (loadingTiles.contains(tileKey)) { + if (loadingTiles.containsKey(tileKey)) { return; } - loadingTiles.add(tileKey); + left = MapUtils.getLongitudeFromTile(zoom, tileX); + right = MapUtils.getLongitudeFromTile(zoom, tileX + 1); + top = MapUtils.getLatitudeFromTile(zoom, tileY); + bottom = MapUtils.getLatitudeFromTile(zoom, tileY + 1); + loadingTiles.put(tileKey, new QuadRect(left, top, right, bottom)); } - double left = MapUtils.getLongitudeFromTile(zoom, tileX); - double right = MapUtils.getLongitudeFromTile(zoom, tileX + 1); - double top = MapUtils.getLatitudeFromTile(zoom, tileY); - double bottom = MapUtils.getLatitudeFromTile(zoom, tileY + 1); KQuadRect tileRect = new KQuadRect(left, top, right, bottom); // Increment the task counter @@ -204,11 +213,9 @@ public void onFinish(@NonNull List result) { finishedTasks++; // Increment the finished task counter notifyListeners(startedTasks != finishedTasks); } - if (result != null) { - // Store the data in the database for the current tile - dbHelper.insertPlaces(zoom, ftileX, ftileY, queryLang, result); - } - // Remove the tile from the loading set + // Store the data in the database for the current tile + dbHelper.insertPlaces(zoom, ftileX, ftileY, queryLang, result); + // Remove the tile from the loading set String tileKey = zoom + "_" + ftileX + "_" + ftileY; synchronized (loadingTiles) { loadingTiles.remove(tileKey); @@ -217,7 +224,7 @@ public void onFinish(@NonNull List result) { }).execute(); } - public void showPointInContextMenu(MapActivity mapActivity, ExploreTopPlacePoint point) { + public void showPointInContextMenu(@NonNull MapActivity mapActivity, @NonNull ExploreTopPlacePoint point) { double latitude = point.getLatitude(); double longitude = point.getLongitude(); app.getSettings().setMapLocationToShow( @@ -267,4 +274,15 @@ public int getDataVersion() { // data version is increased once new data is downloaded return finishedTasks; } + + public boolean isLoadingRect(@NonNull QuadRect rect) { + synchronized (loadingTiles) { + for (QuadRect loadingRect : loadingTiles.values()) { + if (loadingRect.contains(rect)) { + return true; + } + } + return false; + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java b/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java index d8bcbab8671..9ab730071e0 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/IntentHelper.java @@ -527,18 +527,6 @@ public void parseContentIntent() { } clearIntent(intent); } - if (intent.hasExtra(EditFavoriteGroupDialogFragment.GROUP_NAME_KEY)) { - String groupName = intent.getStringExtra(EditFavoriteGroupDialogFragment.GROUP_NAME_KEY); - FavoriteGroup favoriteGroup = app.getFavoritesHelper().getGroup(FavoriteGroup.convertDisplayNameToGroupIdName(app, groupName)); - - PointsGroup pointsGroup = favoriteGroup != null ? favoriteGroup.toPointsGroup(app) : null; - FragmentManager manager = mapActivity.getSupportFragmentManager(); - if (pointsGroup != null) { - FavoriteAppearanceFragment.showInstance(manager, pointsGroup, true); - } - - clearIntent(intent); - } if (intent.hasExtra(BaseSettingsFragment.OPEN_CONFIG_ON_MAP)) { switch (intent.getStringExtra(BaseSettingsFragment.OPEN_CONFIG_ON_MAP)) { case BaseSettingsFragment.MAP_CONFIG: diff --git a/OsmAnd/src/net/osmand/plus/helpers/LocaleHelper.java b/OsmAnd/src/net/osmand/plus/helpers/LocaleHelper.java index ae5f7a19c7b..7e1692a7118 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/LocaleHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/LocaleHelper.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.TreeMap; public class LocaleHelper { @@ -41,10 +42,10 @@ public class LocaleHelper { public LocaleHelper(@NonNull OsmandApplication app) { this.app = app; this.defaultLocale = Locale.getDefault(); - localeListener = change -> preferredLocaleChanged(); + localeListener = change -> onPreferredLocaleChanged(); } - private void preferredLocaleChanged() { + private void onPreferredLocaleChanged() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { String preferredLocale = app.getSettings().PREFERRED_LOCALE.get(); if (!Algorithms.isEmpty(preferredLocale)) { @@ -58,8 +59,9 @@ private void preferredLocaleChanged() { public void checkPreferredLocale() { OsmandSettings settings = app.getSettings(); String locale = settings.PREFERRED_LOCALE.get(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - String currentLocale = Locale.getDefault().toString(); + String currentLocale = Locale.getDefault().toLanguageTag(); if (!Algorithms.stringsEqual(currentLocale, locale)) { locale = currentLocale; settings.PREFERRED_LOCALE.set(locale); @@ -67,54 +69,74 @@ public void checkPreferredLocale() { } settings.PREFERRED_LOCALE.addListener(localeListener); - String[] splitScript = locale.split("\\+"); - String script = (splitScript.length > 1) ? splitScript[1] : ""; - String[] splitCountry = splitScript[0].split("_"); - String lang = splitCountry[0]; - String country = (splitCountry.length > 1) ? splitCountry[1] : ""; - - if (!Algorithms.isEmpty(lang)) { - Locale.Builder builder = new Locale.Builder(); - lang = backwardCompatibleNonIsoCodes(lang); - String langLowerCase = lang.toLowerCase(); - for (String isoLang : Locale.getISOLanguages()) { - if (isoLang.toLowerCase().equals(langLowerCase)) { - builder.setLanguage(isoLang); - break; - } - } - if (!Algorithms.isEmpty(country)) { - builder.setRegion(country); - } - if (!Algorithms.isEmpty(script)) { - builder.setScript(script); + boolean useSystemDefault = Algorithms.isEmpty(locale); + if (!useSystemDefault) { + Locale modernLocale = Locale.forLanguageTag(locale); + if (!Algorithms.isEmpty(modernLocale.toString())) { + preferredLocale = modernLocale; + } else { + preferredLocale = parseLegacyLanguageTag(locale, preferredLocale); } - preferredLocale = builder.build(); } Locale selectedLocale = null; Configuration config = app.getBaseContext().getResources().getConfiguration(); - if (!Algorithms.isEmpty(lang) && !config.locale.equals(preferredLocale)) { + + if (!useSystemDefault && !Objects.equals(config.getLocales().get(0), preferredLocale)) { selectedLocale = preferredLocale; - } else if (Algorithms.isEmpty(lang) && defaultLocale != null && Locale.getDefault() != defaultLocale) { + } else if (useSystemDefault && defaultLocale != null && !Objects.equals(Locale.getDefault(), defaultLocale)) { selectedLocale = defaultLocale; preferredLocale = null; } updateTimeFormatting(selectedLocale != null ? selectedLocale : Locale.getDefault()); + if (selectedLocale != null) { Locale.setDefault(selectedLocale); - config.locale = selectedLocale; - config.setLayoutDirection(selectedLocale); + Configuration newConfig = new Configuration(config); + + newConfig.setLocales(new android.os.LocaleList(selectedLocale)); + newConfig.setLayoutDirection(selectedLocale); Resources resources = app.getBaseContext().getResources(); - resources.updateConfiguration(config, resources.getDisplayMetrics()); - localizedConf = new Configuration(config); - localizedConf.locale = selectedLocale; + resources.updateConfiguration(newConfig, resources.getDisplayMetrics()); + localizedConf = new Configuration(newConfig); } } + @Nullable + private Locale parseLegacyLanguageTag(@NonNull String locale, @Nullable Locale defaultLocale) { + // Split locale into language, region, and script + String[] scriptSplit = locale.split("\\+"); + String baseLocale = scriptSplit[0]; + String script = (scriptSplit.length > 1) ? scriptSplit[1] : ""; + + String[] localeSplit = baseLocale.split("_"); + String lang = localeSplit[0]; + String country = (localeSplit.length > 1) ? localeSplit[1] : ""; + + // Construct Locale using Builder + if (!Algorithms.isEmpty(lang)) { + Locale.Builder builder = new Locale.Builder(); + lang = backwardCompatibleNonIsoCodes(lang); + for (String isoLang : Locale.getISOLanguages()) { + if (isoLang.equalsIgnoreCase(lang)) { + builder.setLanguage(isoLang); + break; + } + } + if (!Algorithms.isEmpty(country)) { + builder.setRegion(country); + } + if (!Algorithms.isEmpty(script)) { + builder.setScript(script); + } + return builder.build(); + } + return defaultLocale; + } + private String backwardCompatibleNonIsoCodes(String lang) { if (lang.equalsIgnoreCase("iw")) { return "he"; diff --git a/OsmAnd/src/net/osmand/plus/helpers/TargetPoint.java b/OsmAnd/src/net/osmand/plus/helpers/TargetPoint.java index eeaf22c5b37..31c9a3665fe 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/TargetPoint.java +++ b/OsmAnd/src/net/osmand/plus/helpers/TargetPoint.java @@ -57,10 +57,18 @@ public PointDescription getPointDescription(@NonNull Context ctx) { } } - public String getRoutePointDescription(@NonNull Context ctx) { - String name = getOnlyName(); - if (!Algorithms.isEmpty(name)) { - return name.replace(':', ' '); + @NonNull + public String getRoutePointDescription(@NonNull Context ctx, boolean includeAddress) { + if (pointDescription != null) { + String name = pointDescription.getName(); + String typeName = pointDescription.getTypeName(); + + if (!Algorithms.isEmpty(name)) { + if (includeAddress && pointDescription.isAddress() && !Algorithms.isEmpty(typeName)) { + name = ctx.getString(R.string.ltr_or_rtl_combine_via_comma, name, typeName); + } + return name.replace(':', ' '); + } } return PointDescription.getLocationNamePlain(ctx, latLon.getLatitude(), latLon.getLongitude()); } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java index 2e9cdd71712..83ee2168548 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java @@ -72,6 +72,7 @@ import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.controls.HorizontalSwipeConfirm; import net.osmand.plus.views.controls.SingleTapConfirm; +import net.osmand.plus.views.controls.maphudbuttons.MapButton; import net.osmand.plus.views.layers.MapControlsLayer; import net.osmand.plus.views.layers.TransportStopsLayer; import net.osmand.plus.widgets.ctxmenu.ContextMenuAdapter; @@ -505,8 +506,12 @@ private void recycleVelocityTracker() { MapLayers mapLayers = mapActivity.getMapLayers(); MapControlsLayer layer = mapLayers.getMapControlsLayer(); - layer.addCustomMapButton(view.findViewById(R.id.map_zoom_in_button)); - layer.addCustomMapButton(view.findViewById(R.id.map_zoom_out_button)); + MapButton zoomInButton = view.findViewById(R.id.map_zoom_in_button); + MapButton zoomOutButton = view.findViewById(R.id.map_zoom_out_button); + layer.addCustomMapButton(zoomInButton); + layer.addCustomMapButton(zoomOutButton); + zoomInButton.setUseDefaultAppearance(false); + zoomOutButton.setUseDefaultAppearance(false); } AndroidUiHelper.updateVisibility(zoomButtonsView, zoomButtonsVisible); diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/DefaultFavoriteAppearanceSaveBottomSheet.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/DefaultFavoriteAppearanceSaveBottomSheet.java index 06db6c32c3a..ef328584011 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/DefaultFavoriteAppearanceSaveBottomSheet.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/DefaultFavoriteAppearanceSaveBottomSheet.java @@ -102,11 +102,9 @@ public int getSecondDividerHeight() { return getResources().getDimensionPixelSize(R.dimen.horizontal_divider_height); } - public static void showInstance(@NonNull FragmentManager manager, @Nullable Fragment target, - @NonNull String editorTag, int pointsSize) { + public static void showInstance(@NonNull FragmentManager manager, @Nullable Fragment target, int pointsSize) { if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { Bundle bundle = new Bundle(); - bundle.putString(EDITOR_TAG_KEY, editorTag); bundle.putInt(POINTS_SIZE_KEY, pointsSize); DefaultFavoriteAppearanceSaveBottomSheet fragment = new DefaultFavoriteAppearanceSaveBottomSheet(); diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteAppearanceFragment.java index 3e825f1b859..9d93afba3eb 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteAppearanceFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteAppearanceFragment.java @@ -5,24 +5,30 @@ import static net.osmand.plus.configmap.tracks.appearance.favorite.FavoriteAppearanceController.PROCESS_ID; import static net.osmand.shared.gpx.GpxUtilities.DEFAULT_ICON_NAME; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import androidx.core.view.ViewCompat; +import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import net.osmand.data.BackgroundType; import net.osmand.plus.R; -import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.base.BaseOsmAndFragment; +import net.osmand.plus.base.BaseOsmAndDialogFragment; import net.osmand.plus.base.dialog.DialogManager; import net.osmand.plus.card.base.multistate.IMultiStateCardController; import net.osmand.plus.card.base.multistate.MultiStateCard; @@ -32,15 +38,16 @@ import net.osmand.plus.myplaces.favorites.FavoriteGroup; import net.osmand.plus.myplaces.favorites.FavouritesHelper; import net.osmand.plus.myplaces.favorites.FavouritesHelper.SaveOption; +import net.osmand.plus.myplaces.favorites.dialogs.FavoritesTreeFragment; import net.osmand.plus.render.RenderingIcons; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; +import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.widgets.dialogbutton.DialogButton; import net.osmand.plus.widgets.dialogbutton.DialogButtonType; import net.osmand.shared.gpx.GpxUtilities.PointsGroup; -import net.osmand.util.Algorithms; -public class FavoriteAppearanceFragment extends BaseOsmAndFragment { +public class FavoriteAppearanceFragment extends BaseOsmAndDialogFragment { public static final String TAG = FavoriteAppearanceFragment.class.getName(); @@ -57,8 +64,6 @@ public class FavoriteAppearanceFragment extends BaseOsmAndFragment { private String iconName = DEFAULT_ICON_NAME; private BackgroundType backgroundType = DEFAULT_BACKGROUND_TYPE; - private boolean launchPrevIntent; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -78,6 +83,34 @@ public void onCreate(Bundle savedInstanceState) { registerFavoriteAppearanceController(); } + @ColorRes + public int getStatusBarColorId() { + AndroidUiHelper.setStatusBarContentColor(getView(), nightMode); + return ColorUtilities.getStatusBarColorId(nightMode); + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + updateNightMode(); + Activity activity = requireActivity(); + int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar; + Dialog dialog = new Dialog(activity, themeId) { + @Override + public void onBackPressed() { + dismiss(); + } + }; + Window window = dialog.getWindow(); + if (window != null) { + if (!settings.DO_NOT_USE_ANIMATIONS.get()) { + window.getAttributes().windowAnimations = R.style.Animations_Alpha; + } + window.setStatusBarColor(ColorUtilities.getColor(app, getStatusBarColorId())); + } + return dialog; + } + private void registerFavoriteAppearanceController() { dialogManager.register(PROCESS_ID, new FavoriteAppearanceController(app, favoriteGroup, new DefaultFavoriteListener() { @Override @@ -106,7 +139,6 @@ public BackgroundType getOriginalShape() { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { updateNightMode(); view = themedInflater.inflate(R.layout.favorite_default_appearance_fragment, container, false); - AndroidUtils.addStatusBarPadding21v(requireMyActivity(), view); setupToolbar(); setupButtons(); @@ -170,31 +202,6 @@ public void setBackgroundType(@NonNull BackgroundType backgroundType) { this.backgroundType = backgroundType; } - @Override - public int getStatusBarColorId() { - return ColorUtilities.getStatusBarColorId(nightMode); - } - - @Nullable - protected PointEditor getEditor() { - return requireMapActivity().getContextMenu().getFavoritePointEditor(); - } - - public void dismiss() { - hideKeyboard(); - FragmentActivity activity = getActivity(); - if (activity != null) { - activity.getSupportFragmentManager().popBackStack(); - } - } - - protected void hideKeyboard() { - FragmentActivity activity = getActivity(); - if (activity != null) { - AndroidUtils.hideSoftKeyboard(activity, activity.getCurrentFocus()); - } - } - private void setupToolbar() { View appbar = view.findViewById(R.id.appbar); ViewCompat.setElevation(appbar, 5.0f); @@ -219,12 +226,38 @@ protected void setupButtons() { } protected void savePressed() { - PointEditor editor = getEditor(); FragmentActivity activity = getActivity(); - if (editor != null && activity != null) { - String tag = editor.getFragmentTag(); + if (activity != null) { FragmentManager manager = activity.getSupportFragmentManager(); - DefaultFavoriteAppearanceSaveBottomSheet.showInstance(manager, this, tag, pointsGroup.getPoints().size()); + DefaultFavoriteAppearanceSaveBottomSheet.showInstance(manager, this, pointsGroup.getPoints().size()); + } + } + + @Override + public void dismiss() { + boolean hasChanges = false; + if (favoriteGroup != null) { + if (controller.getColor() != null && controller.getColor() != color) { + hasChanges = true; + } + if (controller.getIcon() != null && !controller.getIcon().equals(iconName)) { + hasChanges = true; + } + if (controller.getShape() != null && controller.getShape() != backgroundType) { + hasChanges = true; + } + } + + if (hasChanges) { + Context themedContext = UiUtilities.getThemedContext(requireActivity(), nightMode); + AlertDialog.Builder dismissDialog = new AlertDialog.Builder(themedContext); + dismissDialog.setTitle(getString(R.string.exit_without_saving)); + dismissDialog.setMessage(getString(R.string.dismiss_changes_descr)); + dismissDialog.setNegativeButton(R.string.shared_string_cancel, null); + dismissDialog.setPositiveButton(R.string.shared_string_exit, (dialog, which) -> super.dismiss()); + dismissDialog.show(); + } else { + super.dismiss(); } } @@ -250,16 +283,16 @@ public void editPointsGroup(@NonNull SaveOption saveOption) { favouritesHelper.saveCurrentPointsIntoFile(true); } } + + Fragment targetFragment = getTargetFragment(); + if (targetFragment instanceof FavoritesTreeFragment treeFragment) { + treeFragment.reloadData(); + } dismiss(); } @Override public void onDestroy() { - MapActivity mapActivity = getMapActivity(); - if (launchPrevIntent && mapActivity != null && !mapActivity.isChangingConfigurations()) { - mapActivity.launchPrevActivityIntent(); - } - FragmentActivity activity = getActivity(); if (activity != null && !activity.isChangingConfigurations()) { dialogManager.unregister(FavoriteAppearanceController.PROCESS_ID); @@ -268,28 +301,14 @@ public void onDestroy() { super.onDestroy(); } - @Nullable - protected MapActivity getMapActivity() { - return (MapActivity) getActivity(); - } - - @NonNull - protected MapActivity requireMapActivity() { - return (MapActivity) requireActivity(); - } - public static void showInstance(@NonNull FragmentManager manager, @NonNull PointsGroup pointsGroup, - boolean launchPrevIntent) { + @NonNull Fragment treeFragment) { if (AndroidUtils.isFragmentCanBeAdded(manager, TAG)) { FavoriteAppearanceFragment fragment = new FavoriteAppearanceFragment(); fragment.pointsGroup = pointsGroup; - fragment.launchPrevIntent = launchPrevIntent; - fragment.setRetainInstance(true); - manager.beginTransaction() - .add(R.id.fragmentContainer, fragment, TAG) - .addToBackStack(TAG) - .commitAllowingStateLoss(); + fragment.setTargetFragment(treeFragment, 0); + fragment.show(manager, TAG); } } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteShapesCardController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteShapesCardController.java index 9856d4e6385..6026490ae37 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteShapesCardController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/FavoriteShapesCardController.java @@ -96,8 +96,7 @@ public void onBindCardContent(@NonNull FragmentActivity activity, @NonNull ViewG } else { BackgroundType type = (BackgroundType) selectedState.getTag(); if (type != null) { - MapActivity mapActivity = (MapActivity) activity; - shapesCard = new ShapesCard(mapActivity, type, centralController.requireColor()){ + shapesCard = new ShapesCard(activity, type, centralController.requireColor()){ @Override protected Drawable getOutlineDrawable(@DrawableRes int shapeIconId) { diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/ShapesCard.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/ShapesCard.java index 0305d59baa8..78cf66e154b 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/ShapesCard.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/editors/ShapesCard.java @@ -9,23 +9,25 @@ import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import net.osmand.data.BackgroundType; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.plus.routepreparationmenu.cards.MapBaseCard; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.widgets.FlowLayout; -public class ShapesCard extends MapBaseCard { +public class ShapesCard extends BaseCard { @NonNull private BackgroundType selectedShape; @ColorInt protected int selectedColor; - public ShapesCard(@NonNull MapActivity mapActivity, @NonNull BackgroundType shape, @ColorInt int color) { - super(mapActivity); + public ShapesCard(@NonNull FragmentActivity fragmentActivity, @NonNull BackgroundType shape, @ColorInt int color) { + super(fragmentActivity); this.selectedShape = shape; this.selectedColor = color; } diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/ItineraryDataHelperKt.kt b/OsmAnd/src/net/osmand/plus/mapmarkers/ItineraryDataHelperKt.kt index 43038cbade4..a279b297345 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/ItineraryDataHelperKt.kt +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/ItineraryDataHelperKt.kt @@ -10,6 +10,7 @@ import net.osmand.shared.xml.XmlParserException import net.osmand.shared.xml.XmlPullParser import net.osmand.shared.xml.XmlSerializer import java.io.IOException +import java.util.Locale object ItineraryDataHelperKt { @@ -51,7 +52,7 @@ object ItineraryDataHelperKt { var tok: Int while (parser.next().also { tok = it } != XmlPullParser.END_DOCUMENT) { if (tok == XmlPullParser.START_TAG) { - val tagName = parser.getName()!!.toLowerCase() + val tagName = parser.getName()!!.lowercase() if ("name" == tagName) { groupInfo.name = readText(parser, tagName) } else if ("type" == tagName) { diff --git a/OsmAnd/src/net/osmand/plus/myplaces/favorites/dialogs/EditFavoriteGroupDialogFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/favorites/dialogs/EditFavoriteGroupDialogFragment.java index 4917107535e..9b233b3b3e5 100644 --- a/OsmAnd/src/net/osmand/plus/myplaces/favorites/dialogs/EditFavoriteGroupDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/myplaces/favorites/dialogs/EditFavoriteGroupDialogFragment.java @@ -25,6 +25,7 @@ import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem; import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem; +import net.osmand.plus.mapcontextmenu.editors.FavoriteAppearanceFragment; import net.osmand.plus.mapmarkers.MapMarkersGroup; import net.osmand.plus.mapmarkers.MapMarkersHelper; import net.osmand.plus.myplaces.favorites.FavoriteGroup; @@ -32,6 +33,7 @@ import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.FontCache; import net.osmand.plus.utils.UiUtilities; +import net.osmand.shared.gpx.GpxUtilities.PointsGroup; import net.osmand.util.Algorithms; public class EditFavoriteGroupDialogFragment extends MenuBottomSheetDialogFragment { @@ -108,13 +110,15 @@ public void createMenuItems(Bundle savedInstanceState) { .setOnClickListener(v -> { FragmentActivity activity = getActivity(); if (activity != null) { - Bundle bundle = new Bundle(); - Bundle prevParams = new Bundle(); - - bundle.putString(GROUP_NAME_KEY, group.getName()); - prevParams.putInt(TAB_ID, FAV_TAB); - - MapActivity.launchMapActivityMoveToTop(activity, prevParams, null, bundle); + PointsGroup pointsGroup = group != null ? group.toPointsGroup(app) : null; + FragmentManager manager = activity.getSupportFragmentManager(); + if (pointsGroup != null) { + Fragment fragment = getParentFragment(); + if (fragment instanceof FavoritesTreeFragment) { + FavoriteAppearanceFragment.showInstance(manager, pointsGroup, fragment); + dismiss(); + } + } } }) .create(); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java index a337cfd9936..ee552188754 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java @@ -2218,7 +2218,7 @@ public String generateViaDescription() { } TargetPoint point = points.get(i); String description = point.getOnlyName(); - via.append(point.getRoutePointDescription(mapActivity)); + via.append(point.getRoutePointDescription(mapActivity, false)); boolean needAddress = new PointDescription(POINT_TYPE_LOCATION, description) .isSearchingAddress(mapActivity) && !intermediateRequestsLatLon.contains(point.getLatLon()); @@ -2278,7 +2278,7 @@ private void setupToText(View view) { TargetPointsHelper targets = app.getTargetPointsHelper(); TargetPoint finish = targets.getPointToNavigate(); if (finish != null) { - toText.setText(finish.getRoutePointDescription(mapActivity)); + toText.setText(finish.getRoutePointDescription(mapActivity, false)); PointDescription pointDescription = finish.getOriginalPointDescription(); boolean needAddress = pointDescription != null && pointDescription.isSearchingAddress(mapActivity); diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index 488a666866f..3a43cf30821 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -303,23 +303,20 @@ public boolean setPreference(String key, Object value, ApplicationMode mode) { return false; } if (preference == APPLICATION_MODE) { - if (value instanceof String) { - String appModeKey = (String) value; + if (value instanceof String appModeKey) { ApplicationMode appMode = ApplicationMode.valueOfStringKey(appModeKey, null); if (appMode != null) { return setApplicationMode(appMode); } } } else if (preference == DEFAULT_APPLICATION_MODE) { - if (value instanceof String) { - String appModeKey = (String) value; + if (value instanceof String appModeKey) { ApplicationMode appMode = ApplicationMode.valueOfStringKey(appModeKey, null); if (appMode != null) { return DEFAULT_APPLICATION_MODE.set(appMode); } } - } else if (preference instanceof EnumStringPreference) { - EnumStringPreference enumPref = (EnumStringPreference) preference; + } else if (preference instanceof EnumStringPreference enumPref) { if (value instanceof String) { Enum enumValue = enumPref.parseString((String) value); if (enumValue != null) { diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java index 26ba1fb9bb1..41b2b647d35 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/BaseSettingsFragment.java @@ -880,8 +880,8 @@ public Preference createDividerPref() { } @NonNull - protected Preference requirePreference(@NonNull CharSequence key) { - Preference preference = findPreference(key); + protected T requirePreference(@NonNull CharSequence key) { + T preference = findPreference(key); if (preference == null) { throw new IllegalArgumentException("Preference with key '" + key + "' not found."); } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java index bd942cea8ea..fe53510d628 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/GlobalSettingsFragment.java @@ -211,7 +211,7 @@ private void setupDefaultAppModePref() { private void setupPreferredLocalePref() { boolean visible = Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU; - ListPreferenceEx preference = findPreference(settings.PREFERRED_LOCALE.getId()); + ListPreferenceEx preference = requirePreference(settings.PREFERRED_LOCALE.getId()); preference.setVisible(visible); if (visible) { preference.setIcon(getContentIcon(R.drawable.ic_action_map_language)); @@ -224,7 +224,7 @@ private void setupPreferredLocalePref() { preference.setEntryValues(languagesIds); // Add " (Display language)" to menu title in Latin letters for all non-en languages - if (!getResources().getString(R.string.preferred_locale).equals(getResources().getString(R.string.preferred_locale_no_translate))) { + if (!getString(R.string.preferred_locale).equals(getString(R.string.preferred_locale_no_translate))) { preference.setTitle(getString(R.string.preferred_locale) + " (" + getString(R.string.preferred_locale_no_translate) + ")"); } } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/ExploreTopPlacesLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/ExploreTopPlacesLayer.java index 018b7814bc4..74f395d600f 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/ExploreTopPlacesLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/ExploreTopPlacesLayer.java @@ -1,23 +1,25 @@ package net.osmand.plus.views.layers; +import static net.osmand.plus.exploreplaces.ExplorePlacesProviderJava.DEFAULT_LIMIT_POINTS; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; -import android.graphics.drawable.Drawable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.squareup.picasso.Picasso; -import com.squareup.picasso.Target; - import net.osmand.PlatformUtil; import net.osmand.core.android.MapRendererView; +import net.osmand.core.jni.MapMarker; +import net.osmand.core.jni.MapMarkerBuilder; +import net.osmand.core.jni.MapMarkersCollection; import net.osmand.core.jni.PointI; -import net.osmand.data.LatLon; +import net.osmand.core.jni.QListMapMarker; import net.osmand.data.ExploreTopPlacePoint; +import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; @@ -30,12 +32,17 @@ import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProvider; import net.osmand.plus.views.layers.base.OsmandMapLayer; import net.osmand.plus.views.layers.core.ExploreTopPlacesTileProvider; +import net.osmand.shared.util.ImageLoaderCallback; +import net.osmand.shared.util.LoadingImage; +import net.osmand.shared.util.NetworkImageLoader; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class ExploreTopPlacesLayer extends OsmandMapLayer implements IContextMenuProvider, ExplorePlacesProvider.ExplorePlacesListener { @@ -44,6 +51,7 @@ public class ExploreTopPlacesLayer extends OsmandMapLayer implements IContextMen private boolean nightMode; private ExploreTopPlacePoint selectedObject; + private static final int SELECTED_MARKER_ID = -1; private Bitmap cachedSmallIconBitmap; @@ -51,26 +59,40 @@ public class ExploreTopPlacesLayer extends OsmandMapLayer implements IContextMen private int requestZoom = 0; // null means disabled private ExploreTopPlacesTileProvider topPlacesMapLayerProvider; - private ExploreTopPlacesTileProvider selectedTopPlacesMapLayerProvider; private ExplorePlacesProvider explorePlacesProvider; private int cachedExploreDataVersion; private List places; // To refresh images - public static final String LOAD_NEARBY_IMAGES_TAG = "load_nearby_images"; private static final int TOP_LOAD_PHOTOS = 25; - private static final long DEBOUNCE_IMAGE_REFRESH = 5000; - + private static final long DEBOUNCE_IMAGE_REFRESH = 1000; private RotatedTileBox imagesDisplayedBox = null; private int imagesUpdatedVersion; private int imagesCachedVersion; private long lastImageCacheRefreshed = 0; + private final NetworkImageLoader imageLoader; + private final List loadingImages = new ArrayList<>(); + + private static class MapPoint { + private final PointI position; + private final boolean alreadyExists; + @Nullable + private final Bitmap imageBitmap; + + public MapPoint(PointI position, @Nullable Bitmap imageBitmap, boolean alreadyExists) { + this.position = position; + this.imageBitmap = imageBitmap; + this.alreadyExists = alreadyExists; + } + } public ExploreTopPlacesLayer(@NonNull Context ctx) { super(ctx); + + imageLoader = new NetworkImageLoader(ctx, false); } @Override @@ -103,9 +125,7 @@ protected void updateResources() { protected void cleanupResources() { super.cleanupResources(); deleteProvider(topPlacesMapLayerProvider); - deleteProvider(selectedTopPlacesMapLayerProvider); topPlacesMapLayerProvider = null; - selectedTopPlacesMapLayerProvider = null; explorePlacesProvider.removeListener(this); } @@ -140,7 +160,7 @@ public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSett places = null; } } - placesUpdated = placesUpdated || scheduleImageRefreshes(places, tileBox); + placesUpdated = placesUpdated || scheduleImageRefreshes(places, tileBox, placesUpdated); ExploreTopPlacePoint selectedObject = getSelectedNearbyPlace(); long selectedObjectId = selectedObject == null ? 0 : selectedObject.getId(); @@ -148,9 +168,9 @@ public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSett boolean selectedObjectChanged = selectedObjectId != lastSelectedObjectId; this.selectedObject = selectedObject; if (hasMapRenderer()) { - if ((mapActivityInvalidated || mapRendererChanged - || nightModeChanged || placesUpdated)) { - initProviderWithPoints(places); + if ((mapActivityInvalidated || mapRendererChanged || nightModeChanged || placesUpdated)) { + updateTopPlacesTileProvider(places != null); + updateTopPlacesCollection(places, tileBox); mapRendererChanged = false; } if (selectedObjectChanged) { @@ -163,7 +183,7 @@ public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSett QuadRect latLonBounds = tileBox.getLatLonBounds(); List fullObjectsLatLon = new ArrayList<>(); List smallObjectsLatLon = new ArrayList<>(); - drawPoints(places, latLonBounds, false, tileBox, boundIntersections, iconSize, canvas, + drawPoints(places, latLonBounds, tileBox, boundIntersections, iconSize, canvas, fullObjectsLatLon, smallObjectsLatLon); this.fullObjectsLatLon = fullObjectsLatLon; this.smallObjectsLatLon = smallObjectsLatLon; @@ -172,7 +192,7 @@ public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSett mapActivityInvalidated = false; } - private void drawPoints(List pointsToDraw, QuadRect latLonBounds, boolean synced, RotatedTileBox tileBox, + private void drawPoints(List pointsToDraw, QuadRect latLonBounds, RotatedTileBox tileBox, QuadTree boundIntersections, float iconSize, Canvas canvas, List fullObjectsLatLon, List smallObjectsLatLon) { List fullObjects = new ArrayList<>(); @@ -202,7 +222,7 @@ private void drawPoints(List pointsToDraw, QuadRect latLon Bitmap bigBitmap = ExploreTopPlacesTileProvider.createBigBitmap(getApplication(), bitmap, point.getId() == getSelectedObjectId()); float x = tileBox.getPixXFromLatLon(point.getLatitude(), point.getLongitude()); float y = tileBox.getPixYFromLatLon(point.getLatitude(), point.getLongitude()); - canvas.drawBitmap(bigBitmap, x - bigBitmap.getWidth() / 2, y - bigBitmap.getHeight() / 2, pointPaint); + canvas.drawBitmap(bigBitmap, x - bigBitmap.getWidth() / 2f, y - bigBitmap.getHeight() / 2f, pointPaint); } } } @@ -211,24 +231,94 @@ private long getSelectedObjectId() { return selectedObject == null ? 0 : selectedObject.getId(); } - private void initProviderWithPoints(List points) { + private void updateTopPlacesTileProvider(boolean show) { MapRendererView mapRenderer = getMapRenderer(); if (mapRenderer == null) { return; } - deleteProvider(topPlacesMapLayerProvider); - if (points == null) { + if (show) { + if (topPlacesMapLayerProvider == null) { + topPlacesMapLayerProvider = new ExploreTopPlacesTileProvider(getApplication(), + getPointsOrder() + 100, DEFAULT_LIMIT_POINTS / 8); + topPlacesMapLayerProvider.initProvider(mapRenderer); + } + } else { + deleteProvider(topPlacesMapLayerProvider); topPlacesMapLayerProvider = null; + } + } + + private void updateTopPlacesCollection(@Nullable List points, @NonNull RotatedTileBox tileBox) { + MapRendererView mapRenderer = getMapRenderer(); + if (mapRenderer == null) { + return; + } + if (points == null) { + clearMapMarkersCollections(); return; } - topPlacesMapLayerProvider = new ExploreTopPlacesTileProvider(getApplication(), - getPointsOrder(), - view.getDensity(), - getSelectedObjectId()); - for (ExploreTopPlacePoint nearbyPlacePoint : points) { - topPlacesMapLayerProvider.addToData(nearbyPlacePoint); + if (mapMarkersCollection == null) { + mapMarkersCollection = new MapMarkersCollection(); + } + QListMapMarker existingMapPoints = mapMarkersCollection.getMarkers(); + int[] existingX = new int[(int)existingMapPoints.size()]; + int[] existingY = new int[(int)existingMapPoints.size()]; + for (int i = 0; i < existingMapPoints.size(); i++) { + MapMarker mapPoint = existingMapPoints.get(i); + PointI pos = mapPoint.getPosition(); + existingX[i] = pos.getX(); + existingY[i] = pos.getY(); } - topPlacesMapLayerProvider.initProvider(mapRenderer); + List newPoints = new ArrayList<>(); + float iconSize = ExploreTopPlacesTileProvider.getBigIconSize(view.getApplication()); + QuadTree boundIntersections = initBoundIntersections(tileBox); + for (int j = 0; j < Math.min(points.size(), TOP_LOAD_PHOTOS); j++) { + ExploreTopPlacePoint point = points.get(j); + double lat = point.getLatitude(); + double lon = point.getLongitude(); + + PointI position = NativeUtilities.getPoint31FromLatLon(lat, lon); + int x = position.getX(); + int y = position.getY(); + PointF pixel = NativeUtilities.getElevatedPixelFromLatLon(mapRenderer, tileBox, lat, lon); + if (intersects(boundIntersections, pixel.x, pixel.y, iconSize, iconSize)) { + continue; + } + boolean alreadyExists = false; + for (int i = 0; i < existingX.length; i++) { + if (x == existingX[i] && y == existingY[i]) { + existingX[i] = 0; + existingY[i] = 0; + alreadyExists = true; + break; + } + } + newPoints.add(new MapPoint(position, point.getImageBitmap(), alreadyExists)); + } + for (MapPoint point : newPoints) { + Bitmap imageBitmap = point.imageBitmap; + if (point.alreadyExists || imageBitmap == null) { + continue; + } + + Bitmap imageMapBitmap = ExploreTopPlacesTileProvider + .createBigBitmap(getApplication(), imageBitmap, false); + + MapMarkerBuilder mapMarkerBuilder = new MapMarkerBuilder(); + mapMarkerBuilder.setIsAccuracyCircleSupported(false) + .setBaseOrder(getPointsOrder()) + .setPinIcon(NativeUtilities.createSkImageFromBitmap(imageMapBitmap)) + .setPosition(point.position) + .setPinIconVerticalAlignment(MapMarker.PinIconVerticalAlignment.CenterVertical) + .setPinIconHorisontalAlignment(MapMarker.PinIconHorisontalAlignment.CenterHorizontal) + .buildAndAddToCollection(mapMarkersCollection); + } + for (int i = 0; i < existingX.length; i++) { + if (existingX[i] != 0 && existingY[i] != 0) { + mapMarkersCollection.removeMarker(existingMapPoints.get(i)); + } + } + mapRenderer.addSymbolsProvider(mapMarkersCollection); } public synchronized void showSelectedNearbyPoint() { @@ -236,18 +326,39 @@ public synchronized void showSelectedNearbyPoint() { if (mapRenderer == null) { return; } - deleteProvider(selectedTopPlacesMapLayerProvider); - if (selectedObject != null) { - selectedTopPlacesMapLayerProvider = new ExploreTopPlacesTileProvider(getApplication(), - getPointsOrder() - 1, - view.getDensity(), - getSelectedObjectId()); - - selectedTopPlacesMapLayerProvider.addToData(selectedObject); - selectedTopPlacesMapLayerProvider.initProvider(mapRenderer); + if (mapMarkersCollection == null) { + mapMarkersCollection = new MapMarkersCollection(); } - } + MapMarker previousSelectedMarker = null; + QListMapMarker existingMapPoints = mapMarkersCollection.getMarkers(); + for (int i = 0; i < existingMapPoints.size(); i++) { + MapMarker mapPoint = existingMapPoints.get(i); + if (mapPoint.getMarkerId() == SELECTED_MARKER_ID) { + previousSelectedMarker = mapPoint; + break; + } + } + Bitmap imageBitmap = selectedObject != null ? selectedObject.getImageBitmap() : null; + if (imageBitmap != null) { + Bitmap imageMapBitmap = ExploreTopPlacesTileProvider + .createBigBitmap(getApplication(), imageBitmap, true); + + MapMarkerBuilder mapMarkerBuilder = new MapMarkerBuilder(); + mapMarkerBuilder.setIsAccuracyCircleSupported(false) + .setMarkerId(SELECTED_MARKER_ID) + .setBaseOrder(getPointsOrder() - 1) + .setPinIcon(NativeUtilities.createSkImageFromBitmap(imageMapBitmap)) + .setPosition(NativeUtilities.getPoint31FromLatLon(selectedObject.getLatitude(), selectedObject.getLongitude())) + .setPinIconVerticalAlignment(MapMarker.PinIconVerticalAlignment.CenterVertical) + .setPinIconHorisontalAlignment(MapMarker.PinIconHorisontalAlignment.CenterHorizontal) + .buildAndAddToCollection(mapMarkersCollection); + mapRenderer.addSymbolsProvider(mapMarkersCollection); + } + if (previousSelectedMarker != null) { + mapMarkersCollection.removeMarker(previousSelectedMarker); + } + } public void deleteProvider(@Nullable ExploreTopPlacesTileProvider provider) { MapRendererView mapRenderer = getMapRenderer(); @@ -257,12 +368,7 @@ public void deleteProvider(@Nullable ExploreTopPlacesTileProvider provider) { provider.deleteProvider(mapRenderer); } - @Override - public boolean onLongPressEvent(@NonNull PointF point, @NonNull RotatedTileBox tileBox) { - return false; - } - - @Override + @Override public PointDescription getObjectName(Object o) { if (o instanceof ExploreTopPlacePoint) { return ((ExploreTopPlacePoint) o).getPointDescription(getContext()); @@ -323,17 +429,16 @@ public LatLon getObjectLocation(Object o) { return null; } - private boolean scheduleImageRefreshes(List nearbyPlacePoints, RotatedTileBox tileBox) { + private boolean scheduleImageRefreshes(List nearbyPlacePoints, RotatedTileBox tileBox, boolean forceRefresh) { if (places == null) { if (imagesDisplayedBox != null) { - LOG.info(String.format("Picasso cancel loading")); - Picasso.get().cancelTag(LOAD_NEARBY_IMAGES_TAG); + cancelLoadingImages(); imagesDisplayedBox = null; } return false; } - if (imagesDisplayedBox == null || imagesDisplayedBox.getZoom() != tileBox.getZoom() || - !imagesDisplayedBox.containsTileBox(tileBox)) { + if (forceRefresh || imagesDisplayedBox == null || imagesDisplayedBox.getZoom() != tileBox.getZoom() + || !imagesDisplayedBox.containsTileBox(tileBox)) { imagesDisplayedBox = tileBox.copy(); imagesDisplayedBox.increasePixelDimensions(tileBox.getPixWidth() / 2, tileBox.getPixHeight() / 2); imagesUpdatedVersion++; @@ -347,41 +452,35 @@ private boolean scheduleImageRefreshes(List nearbyPlacePoi if (point.getImageBitmap() == null) { missingPhoto = true; } - if (placesToDisplayWithPhotos.size() > TOP_LOAD_PHOTOS) { - break; - } } } if (missingPhoto) { - Picasso.get().cancelTag(LOAD_NEARBY_IMAGES_TAG); -// LOG.info(String.format("Picasso cancel loading")); + Set imagesToLoad = placesToDisplayWithPhotos.stream() + .map(ExploreTopPlacePoint::getIconUrl).collect(Collectors.toSet()); + loadingImages.removeIf(image -> !imagesToLoad.contains(image.getUrl()) && image.cancel()); for (ExploreTopPlacePoint point : placesToDisplayWithPhotos) { if (point.getImageBitmap() != null) { continue; } - Target imgLoadTarget = new Target() { + + String url = point.getIconUrl(); + loadingImages.add(imageLoader.loadImage(url, new ImageLoaderCallback() { @Override - public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { - point.setImageBitmap(bitmap); -// LOG.info(String.format("Picasso loaded %s", point.getIconUrl())); - imagesUpdatedVersion++; + public void onStart(@Nullable Bitmap bitmap) { } @Override - public void onBitmapFailed(Exception e, Drawable errorDrawable) { - LOG.error(String.format("Picasso failed to load %s", point.getIconUrl()), e); + public void onSuccess(@NonNull Bitmap bitmap) { + point.setImageBitmap(bitmap); + imagesUpdatedVersion++; } @Override - public void onPrepareLoad(Drawable placeHolderDrawable) { + public void onError() { + LOG.error(String.format("Coil failed to load %s", url)); } - }; -// LOG.info(String.format("Picasso schedule %s", point.getIconUrl())); - Picasso.get() - .load(point.getIconUrl()) - .tag(LOAD_NEARBY_IMAGES_TAG) - .into(imgLoadTarget); + }, false)); } } } @@ -392,13 +491,15 @@ public void onPrepareLoad(Drawable placeHolderDrawable) { return true; } return false; + } - + private void cancelLoadingImages() { + loadingImages.forEach(LoadingImage::cancel); + loadingImages.clear(); } public void enableLayer(boolean enable) { - requestQuadRect = enable ? - new QuadRect() : null; + requestQuadRect = enable ? new QuadRect() : null; } @Override diff --git a/OsmAnd/src/net/osmand/plus/views/layers/base/OsmandMapLayer.java b/OsmAnd/src/net/osmand/plus/views/layers/base/OsmandMapLayer.java index 12a8a0f4d8f..8029b7d2b99 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/base/OsmandMapLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/base/OsmandMapLayer.java @@ -527,6 +527,11 @@ protected void cancelMovableObject() { } } + /** OpenGL */ + public static boolean isMapRendererLost(@NonNull Context ctx) { + return !((OsmandApplication) ctx.getApplicationContext()).getOsmandMap().getMapView().hasMapRenderer(); + } + public static class TileBoxRequest { private final int left; private final int top; diff --git a/OsmAnd/src/net/osmand/plus/views/layers/core/ExploreTopPlacesTileProvider.java b/OsmAnd/src/net/osmand/plus/views/layers/core/ExploreTopPlacesTileProvider.java index 4b12fb9aba4..089fbd448a9 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/core/ExploreTopPlacesTileProvider.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/core/ExploreTopPlacesTileProvider.java @@ -13,6 +13,7 @@ import androidx.annotation.NonNull; import net.osmand.core.android.MapRendererView; +import net.osmand.core.jni.AreaI; import net.osmand.core.jni.MapMarker; import net.osmand.core.jni.MapTiledCollectionProvider; import net.osmand.core.jni.PointI; @@ -22,36 +23,32 @@ import net.osmand.core.jni.SwigUtilities; import net.osmand.core.jni.TextRasterizer; import net.osmand.core.jni.TileId; +import net.osmand.core.jni.Utilities; import net.osmand.core.jni.ZoomLevel; +import net.osmand.core.jni.interface_MapTiledCollectionPoint; import net.osmand.core.jni.interface_MapTiledCollectionProvider; import net.osmand.data.ExploreTopPlacePoint; -import net.osmand.data.PointDescription; +import net.osmand.data.QuadRect; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.plus.exploreplaces.ExplorePlacesProvider; import net.osmand.plus.render.RenderingIcons; import net.osmand.plus.utils.AndroidUtils; import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.NativeUtilities; +import net.osmand.plus.views.layers.base.OsmandMapLayer; import net.osmand.util.MapUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; import java.util.List; public class ExploreTopPlacesTileProvider extends interface_MapTiledCollectionProvider { - private static final Log log = LogFactory.getLog(ExploreTopPlacesTileProvider.class); - private final QListPointI points31 = new QListPointI(); - private final List mapLayerDataList = new ArrayList<>(); - private Bitmap cachedSmallBitmap; - private final OsmandApplication app; - private final float density; - private final PointI offset; + private final Context ctx; + private final ExplorePlacesProvider explorePlacesProvider; private MapTiledCollectionProvider providerInstance; - private int baseOrder; - private long selectedObjectId; + + private static final int TILE_LOADING_TIMEOUT = 5000; + private static final int SLEEP_INTERVAL = 100; private static final int SMALL_ICON_BORDER_DP = 1; private static final int BIG_ICON_BORDER_DP = 2; @@ -59,30 +56,49 @@ public class ExploreTopPlacesTileProvider extends interface_MapTiledCollectionPr private static final int BIG_ICON_SIZE_DP = 40; private static final int POINT_OUTER_COLOR = 0xffffffff; + private final int baseOrder; + private final int tilePointsLimit; + private Bitmap cachedSmallBitmap; + private final PointI pinIconOffset; private static Bitmap circleBitmap; - private static Bitmap getCircle(@NonNull Context ctx) { - if (circleBitmap == null) { - circleBitmap = RenderingIcons.getBitmapFromVectorDrawable(ctx, R.drawable.bg_point_circle); + private class TopPlaceCollectionPoint extends interface_MapTiledCollectionPoint { + + private final PointI point31; + + public TopPlaceCollectionPoint(@NonNull ExploreTopPlacePoint point) { + int x = MapUtils.get31TileNumberX(point.getLongitude()); + int y = MapUtils.get31TileNumberY(point.getLatitude()); + this.point31 = new PointI(x, y); } - return circleBitmap; - } - private static Paint createBitmapPaint() { - Paint bitmapPaint = new Paint(); - bitmapPaint.setAntiAlias(true); - bitmapPaint.setDither(true); - bitmapPaint.setFilterBitmap(true); - return bitmapPaint; - } + @Override + public PointI getPoint31() { + return point31; + } + + @Override + public SingleSkImage getImageBitmap(boolean isFullSize) { + Bitmap bitmap; + if (cachedSmallBitmap == null) { + cachedSmallBitmap = createSmallPointBitmap(ctx); + } + bitmap = cachedSmallBitmap; + return NativeUtilities.createSkImageFromBitmap(bitmap); + } + @Override + public String getCaption() { + return ""; + } + } - public ExploreTopPlacesTileProvider(@NonNull OsmandApplication context, int baseOrder, float density, long selectedObjectId) { - this.app = context; + public ExploreTopPlacesTileProvider(@NonNull Context ctx, int baseOrder, int tilePointsLimit) { + this.ctx = ctx; this.baseOrder = baseOrder; - this.density = density; - this.offset = new PointI(0, 0); - this.selectedObjectId = selectedObjectId; + this.tilePointsLimit = tilePointsLimit; + this.pinIconOffset = new PointI(0, 0); + this.explorePlacesProvider = ((OsmandApplication) ctx.getApplicationContext()).getExplorePlacesProvider(); } public void initProvider(@NonNull MapRendererView mapRenderer) { @@ -106,7 +122,7 @@ public int getBaseOrder() { @Override public QListPointI getPoints31() { - return points31; + return new QListPointI(); } @Override @@ -126,7 +142,7 @@ public TextRasterizer.Style getCaptionStyle() { @Override public double getCaptionTopSpace() { - return -4.0 * density; + return 0.0; } @Override @@ -139,33 +155,64 @@ public double getScale() { return 1.0d; } + private static Bitmap getCircle(@NonNull Context ctx) { + if (circleBitmap == null) { + circleBitmap = RenderingIcons.getBitmapFromVectorDrawable(ctx, R.drawable.bg_point_circle); + } + return circleBitmap; + } + + private static Paint createBitmapPaint() { + Paint bitmapPaint = new Paint(); + bitmapPaint.setAntiAlias(true); + bitmapPaint.setDither(true); + bitmapPaint.setFilterBitmap(true); + return bitmapPaint; + } + @Override public SingleSkImage getImageBitmap(int index, boolean isFullSize) { - ExploreTopPlacesTileProvider.MapLayerData data = index < mapLayerDataList.size() ? mapLayerDataList.get(index) : null; - if (data == null) { - return SwigUtilities.nullSkImage(); - } - Bitmap bitmap; - if ((isFullSize || data.nearbyPlace.getId() == selectedObjectId) && data.nearbyPlace.getImageBitmap() != null) { - bitmap = createBigBitmap(app, data.nearbyPlace.getImageBitmap(), data.nearbyPlace.getId() == selectedObjectId); - } else { - if (cachedSmallBitmap == null) { - cachedSmallBitmap = createSmallPointBitmap(app); - } - bitmap = cachedSmallBitmap; - } - return NativeUtilities.createSkImageFromBitmap(bitmap); + return SwigUtilities.nullSkImage(); } @Override public String getCaption(int index) { - MapLayerData data = index < mapLayerDataList.size() ? mapLayerDataList.get(index) : null; - return data != null ? PointDescription.getSimpleName(data.nearbyPlace, app) : ""; + return ""; } @Override public QListMapTiledCollectionPoint getTilePoints(TileId tileId, ZoomLevel zoom) { - return new QListMapTiledCollectionPoint(); + if (OsmandMapLayer.isMapRendererLost(ctx)) { + return new QListMapTiledCollectionPoint(); + } + + AreaI tileBBox31 = Utilities.tileBoundingBox31(tileId, zoom); + double l = MapUtils.get31LongitudeX(tileBBox31.getTopLeft().getX()); + double t = MapUtils.get31LatitudeY(tileBBox31.getTopLeft().getY()); + double r = MapUtils.get31LongitudeX(tileBBox31.getBottomRight().getX()); + double b = MapUtils.get31LatitudeY(tileBBox31.getBottomRight().getY()); + + QuadRect tileRect = new QuadRect(l, t, r, b); + List places = explorePlacesProvider.getDataCollection(tileRect, tilePointsLimit); + int i = 0; + while (explorePlacesProvider.isLoadingRect(tileRect) && i++ * SLEEP_INTERVAL < TILE_LOADING_TIMEOUT) { + try { + Thread.sleep(SLEEP_INTERVAL); + } catch (InterruptedException ignore) { + } + } + places = explorePlacesProvider.getDataCollection(tileRect, tilePointsLimit); + if (places.isEmpty() || OsmandMapLayer.isMapRendererLost(ctx)) { + return new QListMapTiledCollectionPoint(); + } + + QListMapTiledCollectionPoint res = new QListMapTiledCollectionPoint(); + for (ExploreTopPlacePoint place : places) { + TopPlaceCollectionPoint point = new TopPlaceCollectionPoint(place); + res.add(point.instantiateProxy(true)); + point.swigReleaseOwnership(); + } + return res; } @Override @@ -180,7 +227,7 @@ public ZoomLevel getMaxZoom() { @Override public boolean supportsNaturalObtainDataAsync() { - return false; + return true; } @Override @@ -195,25 +242,7 @@ public MapMarker.PinIconHorisontalAlignment getPinIconHorisontalAlignment() { @Override public PointI getPinIconOffset() { - return offset; - } - - public void addToData(@NonNull ExploreTopPlacePoint nearbyPlacePoint) throws IllegalStateException { - if (providerInstance != null) { - throw new IllegalStateException("Provider already instantiated. Data cannot be modified at this stage."); - } - int x31 = MapUtils.get31TileNumberX(nearbyPlacePoint.getLongitude()); - int y31 = MapUtils.get31TileNumberY(nearbyPlacePoint.getLatitude()); - points31.add(new PointI(x31, y31)); - mapLayerDataList.add(new MapLayerData(nearbyPlacePoint)); - } - - private static class MapLayerData { - ExploreTopPlacePoint nearbyPlace; - - MapLayerData(@NonNull ExploreTopPlacePoint nearbyPlace) { - this.nearbyPlace = nearbyPlace; - } + return pinIconOffset; } public static Bitmap createSmallPointBitmap(@NonNull Context ctx) { @@ -243,7 +272,7 @@ public static Bitmap createBigBitmap(@NonNull OsmandApplication app, Bitmap load boolean nightMode = app.getDaynightHelper().isNightModeForMapControls(); int borderWidth = AndroidUtils.dpToPxAuto(app, BIG_ICON_BORDER_DP); Bitmap circle = getCircle(app); - int bigIconSize = AndroidUtils.dpToPxAuto(app, BIG_ICON_SIZE_DP); + int bigIconSize = getBigIconSize(app); Bitmap bitmapResult = Bitmap.createBitmap(bigIconSize, bigIconSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmapResult); Paint bitmapPaint = createBitmapPaint(); @@ -266,5 +295,7 @@ public static Bitmap createBigBitmap(@NonNull OsmandApplication app, Bitmap load return bitmapResult; } - + public static int getBigIconSize(@NonNull OsmandApplication app) { + return AndroidUtils.dpToPxAuto(app, BIG_ICON_SIZE_DP); + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/core/OsmBugsTileProvider.java b/OsmAnd/src/net/osmand/plus/views/layers/core/OsmBugsTileProvider.java index 1a95002b034..46fa49c2e05 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/core/OsmBugsTileProvider.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/core/OsmBugsTileProvider.java @@ -80,7 +80,7 @@ public PointI getPoint31() { @Override public SingleSkImage getImageBitmap(boolean isFullSize) { - Bitmap bitmap = null; + Bitmap bitmap; if (!osmNote.isOpened() && !showClosed) { return SwigUtilities.nullSkImage(); } @@ -189,7 +189,7 @@ public double getScale() { @Override public QListMapTiledCollectionPoint getTilePoints(TileId tileId, ZoomLevel zoom) { - if (isMapRendererLost()) { + if (OsmandMapLayer.isMapRendererLost(ctx)) { return new QListMapTiledCollectionPoint(); } @@ -204,7 +204,7 @@ public QListMapTiledCollectionPoint getTilePoints(TileId tileId, ZoomLevel zoom) start[0] = System.currentTimeMillis(); }); while (System.currentTimeMillis() - start[0] < layerData.DATA_REQUEST_TIMEOUT) { - if (isMapRendererLost()) { + if (OsmandMapLayer.isMapRendererLost(ctx)) { return new QListMapTiledCollectionPoint(); } synchronized (dataReadyCallback.getSync()) { @@ -219,7 +219,7 @@ public QListMapTiledCollectionPoint getTilePoints(TileId tileId, ZoomLevel zoom) } layerData.removeDataReadyCallback(dataReadyCallback); - if (isMapRendererLost()) { + if (OsmandMapLayer.isMapRendererLost(ctx)) { return new QListMapTiledCollectionPoint(); } @@ -284,8 +284,4 @@ public MapMarker.PinIconHorisontalAlignment getPinIconHorisontalAlignment() { public PointI getPinIconOffset() { return offset; } - - private boolean isMapRendererLost() { - return !((OsmandApplication) ctx.getApplicationContext()).getOsmandMap().getMapView().hasMapRenderer(); - } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java index 9abeeec3ec2..9661d466308 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java @@ -394,20 +394,35 @@ public void drawPath(Canvas canvas, DrawPathData pathData) { public void drawPath(@NonNull VectorLinesCollection collection, int baseOrder, boolean shouldDrawArrows, @NonNull List pathsData) { - GeometryWayStyle prevStyle = null; + + if (pathsData.isEmpty()) { + return; + } + List dataArr = new ArrayList<>(); + dataArr.add(pathsData.get(0)); + + GeometryWayStyle prevStyle = pathsData.get(0).style; int lineId = LINE_ID; - for (DrawPathData31 data : pathsData) { - if (!dataArr.isEmpty() && prevStyle != null && (!Algorithms.objectEquals(data.style, prevStyle) || data.style.isUnique() - || prevStyle.hasPathLine() != data.style.hasPathLine())) { - drawVectorLine(collection, lineId++, baseOrder, shouldDrawArrows, true, prevStyle, dataArr); + + for (int i = 1; i < pathsData.size(); ++i) { + DrawPathData31 data = pathsData.get(i); + + if (!prevStyle.hasPathLine()) { + prevStyle = data.style; + } + + if (!prevStyle.equalsExceptColor(data.style)) { + drawVectorLine(collection, lineId, baseOrder, shouldDrawArrows, true, prevStyle, dataArr); + ++lineId; dataArr.clear(); + prevStyle = data.style; } - prevStyle = data.style; - data.lineId = lineId; + dataArr.add(data); } - if (!dataArr.isEmpty() && prevStyle != null) { + + if (!dataArr.isEmpty()) { drawVectorLine(collection, lineId, baseOrder, shouldDrawArrows, true, prevStyle, dataArr); } } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayStyle.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayStyle.java index 35b34620d63..bb063daaf49 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayStyle.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayStyle.java @@ -152,6 +152,22 @@ public boolean equals(Object other) { && o.elevationMeters == ((GeometryWayStyle) other).elevationMeters; } + public boolean equalsExceptColor(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof GeometryWayStyle)) { + return false; + } + GeometryWayStyle o = (GeometryWayStyle) other; + return Algorithms.objectEquals(width, o.width) + && Arrays.equals(dashPattern, o.dashPattern) + && o.trackVisualizationType == ((GeometryWayStyle) other).trackVisualizationType + && o.trackLinePositionType == ((GeometryWayStyle) other).trackLinePositionType + && o.additionalExaggeration == ((GeometryWayStyle) other).additionalExaggeration + && o.elevationMeters == ((GeometryWayStyle) other).elevationMeters; + } + public int getColorizationScheme() { return COLORIZATION_NONE; } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapWidgetsFactory.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapWidgetsFactory.java index 7a7ab07555b..aa00f510134 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapWidgetsFactory.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/MapWidgetsFactory.java @@ -1,7 +1,7 @@ package net.osmand.plus.views.mapwidgets; -import static net.osmand.plus.views.mapwidgets.WidgetType.ALTITUDE_MY_LOCATION; import static net.osmand.plus.views.mapwidgets.WidgetType.ALTITUDE_MAP_CENTER; +import static net.osmand.plus.views.mapwidgets.WidgetType.ALTITUDE_MY_LOCATION; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -9,33 +9,11 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.plugins.PluginsHelper; -import net.osmand.plus.views.mapwidgets.widgets.AltitudeWidget; -import net.osmand.plus.views.mapwidgets.widgets.AverageSpeedWidget; -import net.osmand.plus.views.mapwidgets.widgets.BatteryWidget; -import net.osmand.plus.views.mapwidgets.widgets.BearingWidget; +import net.osmand.plus.views.mapwidgets.widgets.*; import net.osmand.plus.views.mapwidgets.widgets.BearingWidget.BearingType; -import net.osmand.plus.views.mapwidgets.widgets.routeinfo.RouteInfoWidget; -import net.osmand.plus.views.mapwidgets.widgets.CoordinatesMapCenterWidget; -import net.osmand.plus.views.mapwidgets.widgets.CoordinatesCurrentLocationWidget; -import net.osmand.plus.views.mapwidgets.widgets.CurrentSpeedWidget; -import net.osmand.plus.views.mapwidgets.widgets.CurrentTimeWidget; import net.osmand.plus.views.mapwidgets.widgets.DistanceToPointWidget.DistanceToDestinationWidget; import net.osmand.plus.views.mapwidgets.widgets.DistanceToPointWidget.DistanceToIntermediateDestinationWidget; -import net.osmand.plus.views.mapwidgets.widgets.ElevationProfileWidget; -import net.osmand.plus.views.mapwidgets.widgets.GlideAverageWidget; -import net.osmand.plus.views.mapwidgets.widgets.GlideTargetWidget; -import net.osmand.plus.views.mapwidgets.widgets.GpsInfoWidget; -import net.osmand.plus.views.mapwidgets.widgets.LanesWidget; -import net.osmand.plus.views.mapwidgets.widgets.MapMarkerSideWidget; -import net.osmand.plus.views.mapwidgets.widgets.MapMarkersBarWidget; -import net.osmand.plus.views.mapwidgets.widgets.MapWidget; -import net.osmand.plus.views.mapwidgets.widgets.MaxSpeedWidget; -import net.osmand.plus.views.mapwidgets.widgets.NextTurnWidget; -import net.osmand.plus.views.mapwidgets.widgets.RadiusRulerWidget; -import net.osmand.plus.views.mapwidgets.widgets.SecondNextTurnWidget; -import net.osmand.plus.views.mapwidgets.widgets.StreetNameWidget; -import net.osmand.plus.views.mapwidgets.widgets.SunriseSunsetWidget; -import net.osmand.plus.views.mapwidgets.widgets.TimeToNavigationPointWidget; +import net.osmand.plus.views.mapwidgets.widgets.routeinfo.RouteInfoWidget; import net.osmand.plus.views.mapwidgets.widgetstates.GlideTargetWidgetState; import net.osmand.plus.views.mapwidgets.widgetstates.MapMarkerSideWidgetState; import net.osmand.plus.views.mapwidgets.widgetstates.SunriseSunsetWidgetState; @@ -56,26 +34,27 @@ public MapWidget createMapWidget(@NonNull WidgetType widgetType) { return createMapWidget(null, widgetType, null); } - public MapWidget createMapWidget(@Nullable String customId, @NonNull WidgetType widgetType, @Nullable WidgetsPanel panel) { + public MapWidget createMapWidget(@Nullable String customId, @NonNull WidgetType widgetType, + @Nullable WidgetsPanel panel) { switch (widgetType) { case NEXT_TURN: - return new NextTurnWidget(mapActivity, customId, false, panel); + return new NextTurnWidget(mapActivity, customId, panel, false); case SMALL_NEXT_TURN: - return new NextTurnWidget(mapActivity, customId, true , panel); + return new NextTurnWidget(mapActivity, customId, panel, true); case SECOND_NEXT_TURN: return new SecondNextTurnWidget(mapActivity, customId, panel); case COORDINATES_CURRENT_LOCATION: - return new CoordinatesCurrentLocationWidget(mapActivity); + return new CoordinatesCurrentLocationWidget(mapActivity, customId, panel); case COORDINATES_MAP_CENTER: - return new CoordinatesMapCenterWidget(mapActivity); + return new CoordinatesMapCenterWidget(mapActivity, customId, panel); case STREET_NAME: - return new StreetNameWidget(mapActivity); + return new StreetNameWidget(mapActivity, customId, panel); case MARKERS_TOP_BAR: - return new MapMarkersBarWidget(mapActivity, customId); + return new MapMarkersBarWidget(mapActivity, customId, panel); case LANES: - return new LanesWidget(mapActivity); + return new LanesWidget(mapActivity, customId, panel); case ROUTE_INFO: - return new RouteInfoWidget(mapActivity, customId); + return new RouteInfoWidget(mapActivity, customId, panel); case DISTANCE_TO_DESTINATION: return new DistanceToDestinationWidget(mapActivity, customId, panel); case INTERMEDIATE_DESTINATION: @@ -131,7 +110,7 @@ public MapWidget createMapWidget(@Nullable String customId, @NonNull WidgetType case GLIDE_AVERAGE: return new GlideAverageWidget(mapActivity, customId, panel); case ELEVATION_PROFILE: - return new ElevationProfileWidget(mapActivity, customId); + return new ElevationProfileWidget(mapActivity, customId, panel); case AIDL_WIDGET: return app.getAidlApi().askCreateExternalWidget(mapActivity, customId, panel); default: diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsContextMenu.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsContextMenu.java index 5feaa48f59b..413fb8031a3 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsContextMenu.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsContextMenu.java @@ -23,6 +23,7 @@ import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportMultiRow; import net.osmand.plus.widgets.popup.PopUpMenu; import net.osmand.plus.widgets.popup.PopUpMenuDisplayData; +import net.osmand.plus.widgets.popup.PopUpMenuDisplayData.CustomDropDown; import net.osmand.plus.widgets.popup.PopUpMenuItem; import net.osmand.plus.widgets.popup.PopUpMenuWidthMode; import net.osmand.util.Algorithms; @@ -103,7 +104,7 @@ static public void showMenu(@NonNull View view, @NonNull MapActivity mapActivity displayData.nightMode = nightMode; displayData.widthMode = PopUpMenuWidthMode.STANDARD; displayData.showCompound = false; - displayData.customDropDown = false; + displayData.customDropDown = CustomDropDown.NONE; displayData.layoutId = R.layout.popup_menu_item_full_divider; PopUpMenu.show(displayData); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsVisibilityHelper.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsVisibilityHelper.java index 1728b0d8047..6f33b51e559 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsVisibilityHelper.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/WidgetsVisibilityHelper.java @@ -1,17 +1,7 @@ package net.osmand.plus.views.mapwidgets; import static net.osmand.plus.views.mapwidgets.MapWidgetRegistry.ENABLED_MODE; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.BACK_TO_LOCATION_BUTTON; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.BOTTOM_MENU_BUTTONS; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.COMPASS; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.DOWNLOAD_MAP_WIDGET; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.ELEVATION_PROFILE_WIDGET; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.FAB_BUTTON; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.SPEEDOMETER; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.TOP_BUTTONS; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.TOP_COORDINATES_WIDGET; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.VERTICAL_WIDGETS; -import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.ZOOM_BUTTONS; +import static net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper.VisibleElements.*; import android.view.View; @@ -102,8 +92,8 @@ public boolean shouldHideVerticalWidgets() { || !shouldShowElementOnActiveScreen(VERTICAL_WIDGETS); } - public boolean shouldHideMapMarkersWidget() { - return shouldHideVerticalWidgets(); + public boolean shouldHideBottomWidgets() { + return shouldHideVerticalWidgets() || isContextMenuFragmentVisible(); } public boolean shouldShowBottomMenuButtons() { @@ -204,7 +194,8 @@ public boolean shouldShowSpeedometer() { return shouldShowElementOnActiveScreen(SPEEDOMETER); } - public static boolean isWidgetEnabled(@NonNull MapActivity activity, @NonNull WidgetsPanel panel, @NonNull String... widgetsIds) { + public static boolean isWidgetEnabled(@NonNull MapActivity activity, + @NonNull WidgetsPanel panel, @NonNull String... widgetsIds) { OsmandApplication app = activity.getMyApplication(); ApplicationMode appMode = app.getSettings().getApplicationMode(); @@ -357,7 +348,8 @@ public void showWidgets() { updateWidgetsVisibility(true); } - public void updateControlsVisibility(boolean topControlsVisible, boolean bottomControlsVisible) { + public void updateControlsVisibility(boolean topControlsVisible, + boolean bottomControlsVisible) { updateWidgetsVisibility(topControlsVisible); updateBottomControlsVisibility(bottomControlsVisible); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageGlideComputer.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageGlideComputer.java index 05f968f2cba..cb4c0b7f8e3 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageGlideComputer.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageGlideComputer.java @@ -1,12 +1,17 @@ package net.osmand.plus.views.mapwidgets.utils; -import static net.osmand.plus.views.mapwidgets.utils.GlideUtils.calculateFormattedRatio; + +import static java.lang.String.format; + +import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.Location; +import net.osmand.data.LatLon; import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.WidgetsAvailabilityHelper; import net.osmand.plus.views.mapwidgets.MapWidgetInfo; @@ -16,11 +21,20 @@ import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; public class AverageGlideComputer extends AverageValueComputer { + private static final NumberFormat GLIDE_RATIO_FORMATTER = new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.US)); + public static final float MAX_VALUE_TO_DISPLAY = 150.f; + public static final float MAX_VALUE_TO_FORMAT = 100.f; + public static final float MIN_ACCEPTABLE_VALUE = 0.1f; + public AverageGlideComputer(@NonNull OsmandApplication app) { super(app); } @@ -47,14 +61,21 @@ protected void saveLocation(@NonNull Location location, long time) { Location loc = new Location(location); loc.setTime(time); locations.add(loc); - clearExpiredLocations(locations, BIGGEST_MEASURED_INTERVAL); + clearExpiredLocations(BIGGEST_MEASURED_INTERVAL); } } @Nullable public String getFormattedAverageGlideRatio(long measuredInterval) { - List locationsToUse = new ArrayList<>(locations); - clearExpiredLocations(locationsToUse, measuredInterval); + List locationsToUse = new ArrayList<>(); + long now = System.currentTimeMillis(); + for (Location location : locations) { + long locationTime = location.getTime(); + // Check if the location is within the measured interval and after the start timestamp + if (now - locationTime <= measuredInterval) { + locationsToUse.add(location); + } + } if (!Algorithms.isEmpty(locationsToUse)) { double distance = calculateTotalDistance(locationsToUse); @@ -83,4 +104,48 @@ private double calculateAltitudeDifference(@NonNull List locations) { } return 0; } + + @NonNull + public static String calculateFormattedRatio(@NonNull Context ctx, LatLon l1, LatLon l2, double a1, double a2) { + double distance = MapUtils.getDistance(l1, l2); + return calculateFormattedRatio(ctx, distance, a1 - a2); + } + + @NonNull + public static String calculateFormattedRatio(@NonNull Context ctx, double distance, double altDif) { + int sign = altDif < 0 ? -1 : 1; + + // Round arguments to '0' if they are smaller + // in absolute value than the minimum acceptable value + if (Math.abs(distance) < MIN_ACCEPTABLE_VALUE) { + distance = 0; + } + if (Math.abs(altDif) < MIN_ACCEPTABLE_VALUE) { + altDif = 0; + } + + // Calculate and round glide ratio if needed + float absRatio = 0; + if (distance > 0) { + absRatio = altDif != 0 ? (float) Math.abs(distance / altDif) : 1; + } + if (absRatio < MIN_ACCEPTABLE_VALUE) { + absRatio = 0; + } + int divider = altDif != 0 ? 1 : 0; + + String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_colon_with_space); + if (absRatio > MAX_VALUE_TO_DISPLAY || (absRatio == 1 && divider == 0)) { + return format(pattern, "1", "0"); + } else if (absRatio > MAX_VALUE_TO_FORMAT) { + return format(pattern, "" + (int) absRatio * sign, "" + divider); + } else { + return format(pattern, GLIDE_RATIO_FORMATTER.format(absRatio * sign), "" + divider); + } + } + + public static boolean areAltitudesEqual(@Nullable Double a1, @Nullable Double a2) { + return a1 == null && a2 == null + || a1 != null && a2 != null && Math.abs(a1 - a2) > 0.01; + } } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageSpeedComputer.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageSpeedComputer.java index ec64805a880..1b0cbb8e4a8 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageSpeedComputer.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageSpeedComputer.java @@ -19,23 +19,16 @@ import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; -import java.util.ArrayList; -import java.util.List; +import java.util.Iterator; +import java.util.Queue; public class AverageSpeedComputer extends AverageValueComputer { - private static final boolean CALCULATE_UNIFORM_SPEED = true; - - private final SegmentsList segmentsList; - - private Location previousLocation; - private long previousTime; - public AverageSpeedComputer(@NonNull OsmandApplication app) { super(app); - this.segmentsList = new SegmentsList(); } + @Override protected boolean isEnabled() { ApplicationMode appMode = settings.getApplicationMode(); MapWidgetRegistry registry = app.getOsmandMap().getMapLayers().getMapWidgetRegistry(); @@ -52,21 +45,13 @@ protected boolean isEnabled() { return false; } + @Override protected void saveLocation(@NonNull Location location, long time) { - if (CALCULATE_UNIFORM_SPEED) { - if (location.hasSpeed()) { - Location loc = new Location(location); - loc.setTime(time); - locations.add(loc); - clearExpiredLocations(locations, BIGGEST_MEASURED_INTERVAL); - } - } else if (time - previousTime >= ADD_POINT_INTERVAL_MILLIS) { - if (previousLocation != null && previousTime > 0) { - double distance = MapUtils.getDistance(previousLocation, location); - segmentsList.addSegment(new Segment(distance, previousTime, time)); - } - previousLocation = location; - previousTime = time; + if (location.hasSpeed()) { + Location loc = new Location(location); + loc.setTime(time); + locations.add(loc); + clearExpiredLocations(BIGGEST_MEASURED_INTERVAL); } } @@ -83,54 +68,29 @@ private float getSpeedToSkipInMetersPerSecond() { }; } - /** - * @return average speed in meters/second or {@link Float#NaN} if average speed cannot be calculated - */ - public float getAverageSpeed(long measuredInterval, boolean skipLowSpeed) { - if (CALCULATE_UNIFORM_SPEED) { - return calculateUniformSpeed(measuredInterval, skipLowSpeed); - } else { - return calculateNonUniformSpeed(measuredInterval, skipLowSpeed); - } + public float getAverageSpeed(long startTimestamp, long measuredInterval, boolean skipLowSpeed) { + return calculateUniformSpeed(startTimestamp, measuredInterval, skipLowSpeed); } - private float calculateUniformSpeed(long measuredInterval, boolean skipLowSpeed) { - List locationsToUse = new ArrayList<>(locations); - clearExpiredLocations(locationsToUse, measuredInterval); + private float calculateUniformSpeed(long startTimestamp, long measuredInterval, boolean skipLowSpeed) { + long now = System.currentTimeMillis(); + float totalSpeed = 0; + int countedLocations = 0; + float speedToSkip = getSpeedToSkipInMetersPerSecond(); - if (!Algorithms.isEmpty(locationsToUse)) { - float totalSpeed = 0; - float speedToSkip = getSpeedToSkipInMetersPerSecond(); + // Iterate over the concurrent queue + for (Location location : locations) { + long locationTime = location.getTime(); - int countedLocations = 0; - for (Location location : locationsToUse) { + // Check if the location is within the measured interval and after the start timestamp + if (locationTime >= startTimestamp && now - locationTime <= measuredInterval) { if (!skipLowSpeed || location.getSpeed() >= speedToSkip) { totalSpeed += location.getSpeed(); countedLocations++; } } - return countedLocations != 0 ? totalSpeed / countedLocations : Float.NaN; - } - return Float.NaN; - } - - private float calculateNonUniformSpeed(long measuredInterval, boolean skipLowSpeed) { - long intervalStart = System.currentTimeMillis() - measuredInterval; - List segments = segmentsList.getSegments(intervalStart); - - double totalDistance = 0; - double totalTimeMillis = 0; - - float speedToSkip = getSpeedToSkipInMetersPerSecond(); - - for (Segment segment : segments) { - if (!skipLowSpeed || !segment.isLowSpeed(speedToSkip)) { - totalDistance += segment.distance; - totalTimeMillis += segment.endTime - segment.startTime; - } } - - return totalTimeMillis == 0 ? Float.NaN : (float) (totalDistance / totalTimeMillis * 1000); + return countedLocations != 0 ? totalSpeed / countedLocations : Float.NaN; } public static int getConvertedSpeedToSkip(@NonNull SpeedConstants speedSystem) { @@ -147,82 +107,4 @@ public static int getConvertedSpeedToSkip(@NonNull SpeedConstants speedSystem) { throw new IllegalStateException("Unsupported speed system"); } } - - public void resetLocations() { - locations.clear(); - } - - private static class SegmentsList { - - private final Segment[] segments; - - private int tailIndex; - private int headIndex; - - public SegmentsList() { - int size = (int) (BIGGEST_MEASURED_INTERVAL / ADD_POINT_INTERVAL_MILLIS) + 1; - segments = new Segment[size]; - } - - @NonNull - public List getSegments(long fromTimeInclusive) { - List filteredSegments = new ArrayList<>(); - for (int i = tailIndex; i != headIndex; i = nextIndex(i)) { - Segment segment = segments[i]; - if (segment != null && segment.startTime >= fromTimeInclusive) { - filteredSegments.add(segment); - } - } - return filteredSegments; - } - - public void removeSegments(long toTimeExclusive) { - for (int i = tailIndex; i != headIndex; i = nextIndex(i)) { - Segment segment = segments[i]; - if (segment != null && segment.startTime < toTimeExclusive) { - deleteFromTail(); - } - } - } - - public void addSegment(@NonNull Segment segment) { - cleanUpIfOverflowed(); - headIndex = nextIndex(headIndex); - segments[headIndex] = segment; - } - - private void cleanUpIfOverflowed() { - if (nextIndex(headIndex) == tailIndex) { - deleteFromTail(); - } - } - - private void deleteFromTail() { - segments[tailIndex] = null; - tailIndex = nextIndex(tailIndex); - } - - private int nextIndex(int index) { - return (index + 1) % segments.length; - } - } - - private static class Segment { - - public final double distance; - public final long startTime; - public final long endTime; - public final float speed; - - public Segment(double distance, long startTime, long endTime) { - this.distance = distance; - this.startTime = startTime; - this.endTime = endTime; - this.speed = (float) (distance / ((endTime - startTime) / 1000f)); - } - - public boolean isLowSpeed(float speedToSkip) { - return speed < speedToSkip; - } - } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageValueComputer.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageValueComputer.java index df83de17dd7..5b1d982a70e 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageValueComputer.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/AverageValueComputer.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; public abstract class AverageValueComputer { @@ -34,10 +35,8 @@ public abstract class AverageValueComputer { } protected final OsmandApplication app; - protected final OsmandSettings settings; - - protected final List locations = new LinkedList<>(); + protected final Queue locations = new ConcurrentLinkedQueue<>(); public AverageValueComputer(@NonNull OsmandApplication app) { this.app = app; @@ -54,9 +53,10 @@ public void updateLocation(@Nullable Location location) { } } - protected void clearExpiredLocations(@NonNull List locations, long measuredInterval) { + protected void clearExpiredLocations(long measuredInterval) { long expirationTime = System.currentTimeMillis() - measuredInterval; - for (Iterator iterator = locations.iterator(); iterator.hasNext(); ) { + Iterator iterator = locations.iterator(); + while (iterator.hasNext()) { Location location = iterator.next(); if (location.getTime() < expirationTime) { iterator.remove(); @@ -69,4 +69,4 @@ protected void clearExpiredLocations(@NonNull List locations, long mea protected abstract boolean isEnabled(); protected abstract void saveLocation(@NonNull Location location, long time); -} +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/GlideUtils.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/GlideUtils.java deleted file mode 100644 index fd14c4c78b7..00000000000 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/utils/GlideUtils.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.osmand.plus.views.mapwidgets.utils; - -import static java.lang.String.format; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import net.osmand.data.LatLon; -import net.osmand.plus.R; -import net.osmand.util.MapUtils; - -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.util.Locale; - -public class GlideUtils { - - private static final NumberFormat GLIDE_RATIO_FORMATTER = new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.US)); - - public static final float MAX_VALUE_TO_DISPLAY = 150.f; - public static final float MAX_VALUE_TO_FORMAT = 100.f; - public static final float MIN_ACCEPTABLE_VALUE = 0.1f; - - @NonNull - public static String calculateFormattedRatio(@NonNull Context ctx, LatLon l1, LatLon l2, double a1, double a2) { - double distance = MapUtils.getDistance(l1, l2); - return calculateFormattedRatio(ctx, distance, a1 - a2); - } - - @NonNull - public static String calculateFormattedRatio(@NonNull Context ctx, double distance, double altDif) { - int sign = altDif < 0 ? -1 : 1; - - // Round arguments to '0' if they are smaller - // in absolute value than the minimum acceptable value - if (Math.abs(distance) < MIN_ACCEPTABLE_VALUE) { - distance = 0; - } - if (Math.abs(altDif) < MIN_ACCEPTABLE_VALUE) { - altDif = 0; - } - - // Calculate and round glide ratio if needed - float absRatio = 0; - if (distance > 0) { - absRatio = altDif != 0 ? (float) Math.abs(distance / altDif) : 1; - } - if (absRatio < MIN_ACCEPTABLE_VALUE) { - absRatio = 0; - } - int divider = altDif != 0 ? 1 : 0; - - String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_colon_with_space); - if (absRatio > MAX_VALUE_TO_DISPLAY || (absRatio == 1 && divider == 0)) { - return format(pattern, "1", "0"); - } else if (absRatio > MAX_VALUE_TO_FORMAT) { - return format(pattern, "" + (int) absRatio * sign, "" + divider); - } else { - return format(pattern, GLIDE_RATIO_FORMATTER.format(absRatio * sign), "" + divider); - } - } - - public static boolean areAltitudesEqual(@Nullable Double a1, @Nullable Double a2) { - return a1 == null && a2 == null - || a1 != null && a2 != null && Math.abs(a1 - a2) > 0.01; - } -} diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/AverageSpeedWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/AverageSpeedWidget.java index f03f7adb1af..955df71f821 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/AverageSpeedWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/AverageSpeedWidget.java @@ -35,10 +35,13 @@ public class AverageSpeedWidget extends SimpleWidget { private final CommonPreference skipStopsPref; private long lastUpdateTime; + private long resetTimestamp; // Timestamp when the widget was last reset + public AverageSpeedWidget(@NonNull MapActivity mapActivity, @Nullable String customId, @Nullable WidgetsPanel widgetsPanel) { super(mapActivity, AVERAGE_SPEED, customId, widgetsPanel); averageSpeedComputer = app.getAverageSpeedComputer(); + resetTimestamp = System.currentTimeMillis(); setIcons(AVERAGE_SPEED); measuredIntervalPref = registerMeasuredIntervalPref(customId); skipStopsPref = registerSkipStopsPref(customId); @@ -74,7 +77,10 @@ protected void updateSimpleWidgetInfo(@Nullable DrawSettings drawSettings) { private void updateAverageSpeed() { long measuredInterval = measuredIntervalPref.get(); boolean skipLowSpeed = skipStopsPref.get(); - float averageSpeed = averageSpeedComputer.getAverageSpeed(measuredInterval, skipLowSpeed); + + // Calculate average speed only for locations after the reset timestamp + float averageSpeed = averageSpeedComputer.getAverageSpeed(resetTimestamp, measuredInterval, skipLowSpeed); + if (Float.isNaN(averageSpeed)) { setText(NO_VALUE, null); } else { @@ -100,7 +106,7 @@ protected List getWidgetActions() { } public void resetAverageSpeed() { - averageSpeedComputer.resetLocations(); + resetTimestamp = System.currentTimeMillis(); // Update reset timestamp setText(NO_VALUE, null); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesBaseWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesBaseWidget.java index 79833085149..08627f8cffe 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesBaseWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesBaseWidget.java @@ -64,8 +64,9 @@ protected int getLayoutId() { return R.layout.coordinates_widget; } - public CoordinatesBaseWidget(@NonNull MapActivity mapActivity, WidgetType widgetType) { - super(mapActivity, widgetType); + public CoordinatesBaseWidget(@NonNull MapActivity mapActivity, @NonNull WidgetType widgetType, + @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, widgetType, customId, panel); divider = view.findViewById(R.id.divider); updateViewIds(isLayoutRtl()); @@ -148,9 +149,9 @@ protected void showFormattedCoordinates(double lat, double lon) { showMgrsCoordinates(lat, lon); } else if (format == PointDescription.OLC_FORMAT) { showOlcCoordinates(lat, lon); - } else if(format == PointDescription.SWISS_GRID_FORMAT){ + } else if (format == PointDescription.SWISS_GRID_FORMAT) { showSwissGrid(lat, lon, false); - } else if (format == PointDescription.SWISS_GRID_PLUS_FORMAT){ + } else if (format == PointDescription.SWISS_GRID_PLUS_FORMAT) { showSwissGrid(lat, lon, true); } else { showStandardCoordinates(lat, lon, format); @@ -182,7 +183,7 @@ private void showOlcCoordinates(double lat, double lon) { setFirstCoordinateText(olcCoordinates); } - private void showSwissGrid(double lat, double lon, boolean swissGridPlus){ + private void showSwissGrid(double lat, double lon, boolean swissGridPlus) { LatLon latLon = new LatLon(lat, lon); double[] swissGrid = swissGridPlus ? SwissGridApproximation.convertWGS84ToLV95(latLon) @@ -249,7 +250,7 @@ protected void setCoordinateIcon(@NonNull ImageView imageView, @NonNull Drawable } @NonNull - protected Drawable getUtmIcon(){ + protected Drawable getUtmIcon() { int utmIconId = isNightMode() ? R.drawable.widget_coordinates_utm_night : R.drawable.widget_coordinates_utm_day; diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesCurrentLocationWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesCurrentLocationWidget.java index 6c724229452..0beafc15b52 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesCurrentLocationWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesCurrentLocationWidget.java @@ -11,17 +11,19 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.AndroidUiHelper; import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; +import net.osmand.plus.views.mapwidgets.WidgetsPanel; public class CoordinatesCurrentLocationWidget extends CoordinatesBaseWidget { - public CoordinatesCurrentLocationWidget(@NonNull MapActivity mapActivity) { - super(mapActivity, COORDINATES_CURRENT_LOCATION); + public CoordinatesCurrentLocationWidget(@NonNull MapActivity mapActivity, + @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, COORDINATES_CURRENT_LOCATION, customId, panel); } @Override public void updateInfo(@Nullable DrawSettings drawSettings) { super.updateInfo(drawSettings); - boolean visible = mapActivity.getWidgetsVisibilityHelper().shouldShowTopCoordinatesWidget(); + boolean visible = visibilityHelper.shouldShowTopCoordinatesWidget(); updateVisibility(visible); if (visible) { Location location = locationProvider.getLastKnownLocation(); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesMapCenterWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesMapCenterWidget.java index 335b428b1b9..f3426b21451 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesMapCenterWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/CoordinatesMapCenterWidget.java @@ -12,20 +12,21 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; +import net.osmand.plus.views.mapwidgets.WidgetsPanel; public class CoordinatesMapCenterWidget extends CoordinatesBaseWidget { private final OsmandMapTileView mapTileView; - public CoordinatesMapCenterWidget(@NonNull MapActivity mapActivity) { - super(mapActivity, COORDINATES_MAP_CENTER); + public CoordinatesMapCenterWidget(@NonNull MapActivity mapActivity, @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, COORDINATES_MAP_CENTER, customId, panel); mapTileView = app.getOsmandMap().getMapView(); } @Override public void updateInfo(@Nullable DrawSettings drawSettings) { super.updateInfo(drawSettings); - boolean visible = mapActivity.getWidgetsVisibilityHelper().shouldShowTopCoordinatesWidget(); + boolean visible = visibilityHelper.shouldShowTopCoordinatesWidget(); updateVisibility(visible); if (visible) { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/ElevationProfileWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/ElevationProfileWidget.java index e8b1f466e6f..2d5bfbd6d2c 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/ElevationProfileWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/ElevationProfileWidget.java @@ -33,21 +33,9 @@ import net.osmand.StateChangedListener; import net.osmand.data.LatLon; import net.osmand.gpx.ElevationDiffsCalculator; -import net.osmand.plus.charts.ElevationChartAppearance; -import net.osmand.plus.utils.ColorUtilities; -import net.osmand.plus.views.layers.MapInfoLayer.TextState; -import net.osmand.shared.gpx.GpxFile; -import net.osmand.shared.gpx.GpxTrackAnalysis; -import net.osmand.shared.gpx.primitives.TrkSegment; -import net.osmand.shared.gpx.primitives.WptPt; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.charts.ChartUtils; -import net.osmand.plus.charts.GPXDataSetAxisType; -import net.osmand.plus.charts.GPXDataSetType; -import net.osmand.plus.charts.GPXHighlight; -import net.osmand.plus.charts.OrderedLineDataSet; -import net.osmand.plus.charts.TrackChartPoints; +import net.osmand.plus.charts.*; import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu; import net.osmand.plus.measurementtool.graph.BaseCommonChartAdapter; import net.osmand.plus.routing.RouteCalculationResult; @@ -55,9 +43,16 @@ import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.track.helpers.GpxDisplayItem; import net.osmand.plus.track.helpers.GpxUiHelper; +import net.osmand.plus.utils.ColorUtilities; import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.plus.utils.UiUtilities; +import net.osmand.plus.views.layers.MapInfoLayer.TextState; import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; +import net.osmand.plus.views.mapwidgets.WidgetsPanel; +import net.osmand.shared.gpx.GpxFile; +import net.osmand.shared.gpx.GpxTrackAnalysis; +import net.osmand.shared.gpx.primitives.TrkSegment; +import net.osmand.shared.gpx.primitives.WptPt; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; @@ -106,8 +101,8 @@ public class ElevationProfileWidget extends MapWidget { } }; - public ElevationProfileWidget(@NonNull MapActivity mapActivity, @Nullable String customId) { - super(mapActivity, ELEVATION_PROFILE); + public ElevationProfileWidget(@NonNull MapActivity mapActivity, @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, ELEVATION_PROFILE, customId, panel); this.showSlopePreference = registerShowSlopePref(customId); settings.MAP_LINKED_TO_LOCATION.addListener(linkedToLocationListener); updateVisibility(false); @@ -186,7 +181,7 @@ private View setupStatisticBlock(int viewId, int textId, int iconId) { @Override public void updateInfo(@Nullable DrawSettings drawSettings) { - boolean visible = mapActivity.getWidgetsVisibilityHelper().shouldShowElevationProfileWidget(); + boolean visible = visibilityHelper.shouldShowElevationProfileWidget(); updateVisibility(visible); if (visible) { updateInfoImpl(); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/GlideTargetWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/GlideTargetWidget.java index f46ebb2d3a7..a7a190dddab 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/GlideTargetWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/GlideTargetWidget.java @@ -1,6 +1,5 @@ package net.osmand.plus.views.mapwidgets.widgets; -import static net.osmand.plus.views.mapwidgets.utils.GlideUtils.areAltitudesEqual; import android.view.View; @@ -20,7 +19,7 @@ import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.mapwidgets.WidgetType; import net.osmand.plus.views.mapwidgets.WidgetsPanel; -import net.osmand.plus.views.mapwidgets.utils.GlideUtils; +import net.osmand.plus.views.mapwidgets.utils.AverageGlideComputer; import net.osmand.plus.views.mapwidgets.widgetstates.GlideTargetWidgetState; import net.osmand.util.CollectionUtils; import net.osmand.util.MapUtils; @@ -96,7 +95,7 @@ private void updateTargetAltitude() { calculateAltitude(targetLocation, targetAltitude -> { markUpdated(); - if (forceUpdate || metricSystemChanged || !areAltitudesEqual(cachedTargetAltitude, targetAltitude)) { + if (forceUpdate || metricSystemChanged || !AverageGlideComputer.areAltitudesEqual(cachedTargetAltitude, targetAltitude)) { cachedTargetAltitude = targetAltitude; if (cachedTargetAltitude == null) { setText(NO_VALUE, null); @@ -120,7 +119,7 @@ private void updateRequiredRatioToTarget() { Double currentAltitude = currentLocation != null && currentLocation.hasAltitude() ? currentLocation.getAltitude() : null; - boolean currentAltitudeChanged = !areAltitudesEqual(currentAltitude, cachedCurrentAltitude); + boolean currentAltitudeChanged = !AverageGlideComputer.areAltitudesEqual(currentAltitude, cachedCurrentAltitude); LatLon targetLocation = getTargetLocation(); boolean targetLocationChanged = !MapUtils.areLatLonEqual(targetLocation, cachedTargetLocation); @@ -138,7 +137,7 @@ private void updateRequiredRatioToTarget() { calculateAltitude(targetLocation, targetAltitude -> { markUpdated(); - if (forceUpdate || anyChanged || !areAltitudesEqual(cachedTargetAltitude, targetAltitude)) { + if (forceUpdate || anyChanged || !AverageGlideComputer.areAltitudesEqual(cachedTargetAltitude, targetAltitude)) { cachedTargetAltitude = targetAltitude; String ratio = calculateFormattedRatio(currentLocation, currentAltitude, targetLocation, targetAltitude); if (forceUpdate || !Objects.equals(cachedFormattedRatio, ratio)) { @@ -182,7 +181,7 @@ private String calculateFormattedRatio(Location l1, Double a1, LatLon l2, Double return null; } LatLon l1LatLon = new LatLon(l1.getLatitude(), l1.getLongitude()); - return GlideUtils.calculateFormattedRatio(app, l1LatLon, l2, a1, a2); + return AverageGlideComputer.calculateFormattedRatio(app, l1LatLon, l2, a1, a2); } public boolean isInTargetAltitudeState() { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/LanesWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/LanesWidget.java index 8034a5df3a6..a6b58c8e79b 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/LanesWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/LanesWidget.java @@ -1,6 +1,7 @@ package net.osmand.plus.views.mapwidgets.widgets; import static net.osmand.plus.views.mapwidgets.WidgetType.LANES; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import android.view.ViewGroup; import android.widget.ImageView; @@ -49,8 +50,9 @@ public class LanesWidget extends MapWidget { private int shadowRadius; boolean specialPosition; - public LanesWidget(@NonNull MapActivity mapActivity) { - super(mapActivity, LANES); + public LanesWidget(@NonNull MapActivity mapActivity, @Nullable String customId, + @Nullable WidgetsPanel panel) { + super(mapActivity, LANES, customId, panel); routingHelper = mapActivity.getMyApplication().getRoutingHelper(); lanesImage = view.findViewById(R.id.map_lanes); @@ -108,11 +110,7 @@ public void updateInfo(@Nullable DrawSettings drawSettings) { } } - boolean visible = lanes != null && lanes.length > 0 - && !MapRouteInfoMenu.chooseRoutesVisible - && !MapRouteInfoMenu.waypointsVisible - && !MapRouteInfoMenu.followTrackVisible - && !mapActivity.getWidgetsVisibilityHelper().shouldHideVerticalWidgets(); + boolean visible = lanes != null && lanes.length > 0 && !shouldHide(); if (visible) { updateLanes(lanes, imminent, distance); } @@ -120,6 +118,12 @@ public void updateInfo(@Nullable DrawSettings drawSettings) { updateVisibility(visible); } + protected boolean shouldHide() { + return MapRouteInfoMenu.chooseRoutesVisible || MapRouteInfoMenu.waypointsVisible || + MapRouteInfoMenu.followTrackVisible || visibilityHelper.shouldHideVerticalWidgets() + || panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + @Override public boolean updateVisibility(boolean visible) { AndroidUiHelper.updateVisibility(lanesShadowText, visible && shadowRadius > 0); @@ -174,7 +178,8 @@ public void updateColors(@NonNull TextState textState) { } @Override - public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, @NonNull List followingWidgets) { + public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, + @NonNull List followingWidgets) { ViewGroup specialContainer = getSpecialContainer(); specialPosition = panel == WidgetsPanel.TOP && followingWidgets.isEmpty(); if (specialPosition) { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkerSideWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkerSideWidget.java index 9d0a8c9ac35..c377b0120c6 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkerSideWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkerSideWidget.java @@ -158,7 +158,7 @@ private void updateArrivalTime(int distance, long currentTime) { AverageSpeedComputer averageSpeedComputer = app.getAverageSpeedComputer(); long interval = widgetState.getAverageSpeedIntervalPref().get(); - float averageSpeed = averageSpeedComputer.getAverageSpeed(interval, false); + float averageSpeed = averageSpeedComputer.getAverageSpeed(0, interval, false); if (Float.isNaN(averageSpeed) || averageSpeed == 0) { setText(NO_VALUE, null); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkersBarWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkersBarWidget.java index 96f04f1e9ed..cedb5a20476 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkersBarWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapMarkersBarWidget.java @@ -1,6 +1,7 @@ package net.osmand.plus.views.mapwidgets.widgets; import static net.osmand.plus.views.mapwidgets.WidgetType.MARKERS_TOP_BAR; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import android.view.View; import android.view.ViewGroup; @@ -26,7 +27,6 @@ import net.osmand.plus.views.mapwidgets.MarkersWidgetsHelper; import net.osmand.plus.views.mapwidgets.MarkersWidgetsHelper.CustomLatLonListener; import net.osmand.plus.views.mapwidgets.WidgetsPanel; -import net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; @@ -39,7 +39,6 @@ public class MapMarkersBarWidget extends MapWidget implements CustomLatLonListen private final MapMarkersHelper markersHelper; private final boolean portraitMode; - private final String customId; private final View markerContainer2nd; private final ImageView arrowImg; @@ -58,9 +57,9 @@ protected int getLayoutId() { return R.layout.map_markers_widget; } - public MapMarkersBarWidget(@NonNull MapActivity mapActivity, String customId) { - super(mapActivity, MARKERS_TOP_BAR); - this.customId = customId; + public MapMarkersBarWidget(@NonNull MapActivity mapActivity, String customId, + @Nullable WidgetsPanel panel) { + super(mapActivity, MARKERS_TOP_BAR, customId, panel); markersHelper = app.getMapMarkersHelper(); portraitMode = AndroidUiHelper.isOrientationPortrait(mapActivity); @@ -132,8 +131,7 @@ public void setCustomLatLon(@Nullable LatLon customLatLon) { public void updateInfo(@Nullable DrawSettings drawSettings) { List markers = markersHelper.getMapMarkers(); int zoom = mapActivity.getMapView().getZoom(); - WidgetsVisibilityHelper widgetsVisibilityHelper = mapActivity.getWidgetsVisibilityHelper(); - if (markers.size() == 0 || zoom < 3 || widgetsVisibilityHelper.shouldHideMapMarkersWidget()) { + if (markers.size() == 0 || zoom < 3 || shouldHide()) { updateVisibility(false); return; } @@ -141,6 +139,11 @@ public void updateInfo(@Nullable DrawSettings drawSettings) { showMarkers(markers); } + protected boolean shouldHide() { + return visibilityHelper.shouldHideVerticalWidgets() + || panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + public void showMarkers(@NonNull List markers) { LatLon latLon = customLatLon != null ? customLatLon : app.getMapViewTrackingUtilities().getDefaultLocation(); boolean defaultLatLon = customLatLon == null; @@ -152,12 +155,12 @@ public void showMarkers(@NonNull List markers) { } public void updateFirstMarker(@NonNull LatLon center, @NonNull MapMarker marker, - @Nullable Float heading, boolean customLocation) { + @Nullable Float heading, boolean customLocation) { updateMarker(center, heading, marker, arrowImg, distText, okButton, addressText, true, customLocation); } public void updateSecondMarker(@NonNull LatLon center, @NonNull List markers, - @Nullable Float heading, boolean customLocation) { + @Nullable Float heading, boolean customLocation) { if (markers.size() > 1 && settings.DISPLAYED_MARKERS_WIDGETS_COUNT.get() == 2) { MapMarker secondMarker = markers.get(1); if (!customLocation) { @@ -177,10 +180,11 @@ public void updateSecondMarker(@NonNull LatLon center, @NonNull List } } - private void updateMarker(@NonNull LatLon latlon, @Nullable Float heading, @NonNull MapMarker marker, - @NonNull ImageView arrowImg, @NonNull TextView distText, - @NonNull ImageButton okButton, @NonNull TextView addressText, - boolean firstMarker, boolean customLocation) { + private void updateMarker(@NonNull LatLon latlon, @Nullable Float heading, + @NonNull MapMarker marker, + @NonNull ImageView arrowImg, @NonNull TextView distText, + @NonNull ImageButton okButton, @NonNull TextView addressText, + boolean firstMarker, boolean customLocation) { float[] distInfo = new float[2]; if (marker.point != null) { Location.distanceBetween(marker.getLatitude(), marker.getLongitude(), @@ -234,7 +238,7 @@ protected boolean updateVisibility(boolean visible) { @Override public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, - @NonNull List followingWidgets) { + @NonNull List followingWidgets) { super.attachView(container, panel, followingWidgets); View bottomShadow = view.findViewById(R.id.bottom_shadow); AndroidUiHelper.updateVisibility(bottomShadow, followingWidgets.isEmpty()); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapWidget.java index b41be67c4b8..c390e5e6e9c 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/MapWidget.java @@ -26,6 +26,7 @@ import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.mapwidgets.WidgetType; import net.osmand.plus.views.mapwidgets.WidgetsPanel; +import net.osmand.plus.views.mapwidgets.WidgetsVisibilityHelper; import net.osmand.plus.views.mapwidgets.widgetstates.WidgetState; import java.util.List; @@ -38,22 +39,34 @@ public abstract class MapWidget { protected final UiUtilities iconsCache; protected final OsmAndLocationProvider locationProvider; protected final RoutingHelper routingHelper; + protected final WidgetsVisibilityHelper visibilityHelper; protected final WidgetType widgetType; protected boolean nightMode; + protected WidgetsPanel panel; + @Nullable + protected String customId; + protected final View view; - public MapWidget(@NonNull MapActivity mapActivity, @Nullable WidgetType widgetType) { + public MapWidget(@NonNull MapActivity mapActivity, @Nullable WidgetType widgetType, + @Nullable String customId, @Nullable WidgetsPanel panel) { this.app = mapActivity.getMyApplication(); this.settings = app.getSettings(); this.mapActivity = mapActivity; + this.customId = customId; this.widgetType = widgetType; this.iconsCache = app.getUIUtilities(); this.locationProvider = app.getLocationProvider(); this.routingHelper = app.getRoutingHelper(); this.nightMode = app.getDaynightHelper().isNightMode(); + this.visibilityHelper = mapActivity.getWidgetsVisibilityHelper(); this.view = UiUtilities.getInflater(mapActivity, nightMode).inflate(getLayoutId(), null); + + String id = customId != null ? customId : widgetType.id; + WidgetsPanel selectedPanel = panel != null ? panel : widgetType.getPanel(id, settings); + setPanel(selectedPanel); } @LayoutRes @@ -79,10 +92,12 @@ public void copySettings(@NonNull ApplicationMode appMode, @Nullable String cust } } - public void copySettingsFromMode(@NonNull ApplicationMode sourceAppMode, @NonNull ApplicationMode appMode, @Nullable String customId) { + public void copySettingsFromMode(@NonNull ApplicationMode sourceAppMode, + @NonNull ApplicationMode appMode, @Nullable String customId) { } - public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, @NonNull List followingWidgets) { + public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, + @NonNull List followingWidgets) { container.addView(view); } @@ -127,9 +142,17 @@ public boolean isViewVisible() { return view.getVisibility() == View.VISIBLE; } + protected void setPanel(@NonNull WidgetsPanel panel) { + this.panel = panel; + } + + public boolean isVerticalWidget() { + return panel.isPanelVertical(); + } + public static void updateTextColor(@NonNull TextView text, @Nullable TextView textShadow, - @ColorInt int textColor, @ColorInt int textShadowColor, - boolean boldText, int shadowRadius) { + @ColorInt int textColor, @ColorInt int textShadowColor, + boolean boldText, int shadowRadius) { int typefaceStyle = boldText ? Typeface.BOLD : Typeface.NORMAL; if (textShadow != null) { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnBaseWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnBaseWidget.java index baaebf87cec..ddd7075dc17 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnBaseWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnBaseWidget.java @@ -1,5 +1,6 @@ package net.osmand.plus.views.mapwidgets.widgets; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import static net.osmand.plus.views.mapwidgets.widgets.StreetNameWidget.MAX_SHIELDS_QUANTITY; import static net.osmand.plus.views.mapwidgets.widgets.StreetNameWidget.setShieldImage; import static java.lang.Math.min; @@ -75,9 +76,6 @@ public class NextTurnBaseWidget extends TextInfoWidget implements IComplexWidget private LinearLayout shieldImagesContainer; private LinearLayout bg; - - @Nullable - protected String customId; private List cachedRoadShields; private final ResizableWidgetState widgetState; protected TextState textState; @@ -85,10 +83,10 @@ public class NextTurnBaseWidget extends TextInfoWidget implements IComplexWidget protected boolean verticalWidget; public NextTurnBaseWidget(@NonNull MapActivity mapActivity, @Nullable String customId, - @NonNull WidgetType widgetType, @Nullable WidgetsPanel panel, boolean horizontalMini) { - super(mapActivity, widgetType); + @NonNull WidgetType widgetType, @Nullable WidgetsPanel panel, + boolean horizontalMini) { + super(mapActivity, widgetType, customId, panel); this.horizontalMini = horizontalMini; - this.customId = customId; widgetState = new ResizableWidgetState(app, customId, widgetType, WidgetSize.MEDIUM); WidgetsPanel selectedPanel = panel != null ? panel : widgetType.getPanel(customId != null ? customId : widgetType.id, settings); @@ -415,16 +413,21 @@ public final void updateInfo(@Nullable DrawSettings drawSettings) { return; } - boolean shouldHideTopWidgets = mapActivity.getWidgetsVisibilityHelper().shouldHideVerticalWidgets(); + boolean shouldHide = shouldHide(); boolean typeAllowed = widgetType != null && widgetType.isAllowed(); boolean hasInfoToDisplay = (turnDrawable.getTurnType() != null || turnType != null || nextTurnDistance != 0); - boolean visible = typeAllowed && !shouldHideTopWidgets && hasInfoToDisplay; + boolean visible = typeAllowed && !shouldHide && hasInfoToDisplay; updateVisibility(visible); - if (typeAllowed && !shouldHideTopWidgets) { + if (typeAllowed && !shouldHide) { updateNavigationInfo(drawSettings); } } + protected boolean shouldHide() { + return visibilityHelper.shouldHideVerticalWidgets() + || panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + void updateNavigationInfo(@Nullable DrawSettings drawSettings) { } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnWidget.java index 22f541be3c9..2a74d14b942 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/NextTurnWidget.java @@ -22,7 +22,8 @@ public class NextTurnWidget extends NextTurnBaseWidget { private final NextDirectionInfo nextDirectionInfo = new NextDirectionInfo(); - public NextTurnWidget(@NonNull MapActivity mapActivity, @Nullable String customId, boolean horizontalMini, @Nullable WidgetsPanel panel) { + public NextTurnWidget(@NonNull MapActivity mapActivity, @Nullable String customId, + @Nullable WidgetsPanel panel, boolean horizontalMini) { super(mapActivity, customId, horizontalMini ? SMALL_NEXT_TURN : NEXT_TURN, panel, horizontalMini); setOnClickListener(getOnClickListener()); } diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/SimpleWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/SimpleWidget.java index 5df1ceecaab..aa7a6b104b9 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/SimpleWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/SimpleWidget.java @@ -1,6 +1,7 @@ package net.osmand.plus.views.mapwidgets.widgets; import static net.osmand.plus.utils.AndroidUtils.dpToPx; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; @@ -22,8 +23,10 @@ import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.preferences.CommonPreference; import net.osmand.plus.settings.backend.preferences.OsmandPreference; +import net.osmand.plus.settings.enums.WidgetSize; import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.views.layers.MapInfoLayer; +import net.osmand.plus.views.layers.MapInfoLayer.TextState; import net.osmand.plus.views.layers.base.OsmandMapLayer; import net.osmand.plus.views.mapwidgets.WidgetType; import net.osmand.plus.views.mapwidgets.WidgetsContextMenu; @@ -31,7 +34,6 @@ import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportMultiRow; import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportWidgetResizing; import net.osmand.plus.views.mapwidgets.widgetstates.SimpleWidgetState; -import net.osmand.plus.settings.enums.WidgetSize; import net.osmand.plus.widgets.popup.PopUpMenuItem; import net.osmand.util.Algorithms; @@ -41,19 +43,13 @@ public abstract class SimpleWidget extends TextInfoWidget implements ISupportWid private final SimpleWidgetState widgetState; - private TextView widgetNameTextView; - private boolean verticalWidget; + protected TextView widgetName; + protected TextState textState; private boolean isFullRow; - protected MapInfoLayer.TextState textState; - @Nullable - protected String customId; - public SimpleWidget(@NonNull MapActivity mapActivity, @NonNull WidgetType widgetType, @Nullable String customId, @Nullable WidgetsPanel panel) { - super(mapActivity, widgetType); - this.customId = customId; - - WidgetsPanel selectedPanel = panel != null ? panel : widgetType.getPanel(customId != null ? customId : widgetType.id, settings); - setVerticalWidget(selectedPanel); + public SimpleWidget(@NonNull MapActivity mapActivity, @NonNull WidgetType widgetType, + @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, widgetType, customId, panel); widgetState = new SimpleWidgetState(app, customId, widgetType, getDefaultWidgetSize()); setupViews(); @@ -68,17 +64,18 @@ private void setupViews() { UiUtilities.getInflater(mapActivity, nightMode).inflate(layoutId, container); findViews(); view.setOnLongClickListener(v -> { - WidgetsContextMenu.showMenu(v, mapActivity, widgetType, customId, getWidgetActions(), verticalWidget, nightMode); + WidgetsContextMenu.showMenu(v, mapActivity, widgetType, customId, getWidgetActions(), isVerticalWidget(), nightMode); return true; }); } @LayoutRes protected int getContentLayoutId() { - return verticalWidget ? getProperVerticalLayoutId(widgetState) : getProperSideLayoutId(widgetState); + return isVerticalWidget() ? getProperVerticalLayoutId(widgetState) : getProperSideLayoutId(widgetState); } - protected WidgetSize getDefaultWidgetSize(){ + @NonNull + protected WidgetSize getDefaultWidgetSize() { return isVerticalWidget() ? WidgetSize.MEDIUM : WidgetSize.SMALL; } @@ -102,7 +99,7 @@ private void findViews() { textViewShadow = view.findViewById(R.id.widget_text_shadow); smallTextViewShadow = view.findViewById(R.id.widget_text_small_shadow); smallTextView = view.findViewById(R.id.widget_text_small); - widgetNameTextView = view.findViewById(R.id.widget_name); + widgetName = view.findViewById(R.id.widget_name); bottomDivider = view.findViewById(R.id.bottom_divider); } @@ -130,25 +127,17 @@ private int getProperVerticalLayoutId(@NonNull SimpleWidgetState simpleWidgetSta }; } - public void setVerticalWidget(@NonNull WidgetsPanel panel) { - verticalWidget = panel.isPanelVertical(); - } - - public boolean isVerticalWidget() { - return verticalWidget; - } - public void updateWidgetView() { boolean showIcon = shouldShowIcon(); AndroidUiHelper.updateVisibility(imageView, showIcon); updateWidgetName(); - if (verticalWidget) { + if (isVerticalWidget()) { app.getOsmandMap().getMapLayers().getMapInfoLayer().updateRow(this); } } public boolean shouldShowIcon() { - boolean hideIcon = !verticalWidget && getWidgetSizePref().get() != WidgetSize.SMALL; + boolean hideIcon = !isVerticalWidget() && getWidgetSizePref().get() != WidgetSize.SMALL; return widgetState.getShowIconPref().get() && !hideIcon; } @@ -168,9 +157,9 @@ public OsmandPreference getWidgetSizePref() { } public void recreateViewIfNeeded(@NonNull WidgetsPanel panel) { - boolean oldWidgetOrientation = verticalWidget; - setVerticalWidget(panel); - if (oldWidgetOrientation != verticalWidget) { + boolean oldWidgetOrientation = isVerticalWidget(); + setPanel(panel); + if (oldWidgetOrientation != isVerticalWidget()) { recreateView(); } } @@ -211,24 +200,29 @@ protected List getWidgetActions() { @Override public final void updateInfo(@Nullable OsmandMapLayer.DrawSettings drawSettings) { - boolean shouldHideTopWidgets = (verticalWidget && mapActivity.getWidgetsVisibilityHelper().shouldHideVerticalWidgets()); + boolean shouldHide = shouldHide(); boolean emptyValueTextView = Algorithms.isEmpty(textView.getText()); boolean typeAllowed = widgetType != null && widgetType.isAllowed(); - boolean visible = typeAllowed && !(shouldHideTopWidgets || emptyValueTextView); + boolean visible = typeAllowed && !(shouldHide || emptyValueTextView); updateVisibility(visible); - if (typeAllowed && (!shouldHideTopWidgets || emptyValueTextView)) { + if (typeAllowed && (!shouldHide || emptyValueTextView)) { updateSimpleWidgetInfo(drawSettings); } } + protected boolean shouldHide() { + return isVerticalWidget() && visibilityHelper.shouldHideVerticalWidgets() || + panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + protected void updateSimpleWidgetInfo(@Nullable OsmandMapLayer.DrawSettings drawSettings) { } @Override public boolean updateVisibility(boolean visible) { boolean updatedVisibility = super.updateVisibility(visible); - if (verticalWidget && updatedVisibility) { + if (isVerticalWidget() && updatedVisibility) { app.getOsmandMap().getMapLayers().getMapInfoLayer().updateRow(this); } return updatedVisibility; @@ -236,12 +230,12 @@ public boolean updateVisibility(boolean visible) { protected void updateWidgetName() { String widgetName = getWidgetName(); - if (widgetName != null && widgetNameTextView != null) { + if (widgetName != null && this.widgetName != null) { String additionalName = getAdditionalWidgetName(); if (additionalName != null) { widgetName = widgetName + ", " + additionalName; } - widgetNameTextView.setText(widgetName); + this.widgetName.setText(widgetName); } } @@ -251,7 +245,8 @@ protected String getWidgetName() { } @Override - public void copySettingsFromMode(@NonNull ApplicationMode sourceAppMode, @NonNull ApplicationMode appMode, @Nullable String customId) { + public void copySettingsFromMode(@NonNull ApplicationMode sourceAppMode, + @NonNull ApplicationMode appMode, @Nullable String customId) { if (widgetState != null) { widgetState.copyPrefsFromMode(sourceAppMode, appMode, customId); } @@ -310,7 +305,7 @@ public void setImageDrawable(int res) { @Override public void updateColors(@NonNull MapInfoLayer.TextState textState) { this.textState = textState; - if (verticalWidget || widgetState.getWidgetSizePref().get() != WidgetSize.SMALL) { + if (isVerticalWidget() || widgetState.getWidgetSizePref().get() != WidgetSize.SMALL) { updateVerticalWidgetColors(textState); } else { super.updateColors(textState); @@ -321,7 +316,7 @@ protected void updateVerticalWidgetColors(@NonNull MapInfoLayer.TextState textSt nightMode = textState.night; textView.setTextColor(textState.textColor); smallTextView.setTextColor(textState.secondaryTextColor); - widgetNameTextView.setTextColor(textState.secondaryTextColor); + widgetName.setTextColor(textState.secondaryTextColor); int iconId = getIconId(); if (iconId != 0) { setImageDrawable(iconId); @@ -335,7 +330,7 @@ protected void updateVerticalWidgetColors(@NonNull MapInfoLayer.TextState textSt @Override protected View getContentView() { - return verticalWidget ? view : container; + return isVerticalWidget() ? view : container; } public void updateFullRowState(boolean fullRow) { diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/StreetNameWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/StreetNameWidget.java index 830e28c4118..04be761d465 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/StreetNameWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/StreetNameWidget.java @@ -2,6 +2,7 @@ import static net.osmand.plus.render.OsmandRenderer.RenderingContext; import static net.osmand.plus.views.mapwidgets.WidgetType.STREET_NAME; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import static net.osmand.plus.views.mapwidgets.widgets.NextTurnBaseWidget.SHIELD_HEIGHT_DP; import static java.lang.Math.min; @@ -43,8 +44,8 @@ import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu; import net.osmand.plus.routepreparationmenu.ShowAlongTheRouteBottomSheet; import net.osmand.plus.routing.CurrentStreetName; -import net.osmand.plus.routing.RoadShield; import net.osmand.plus.routing.NextDirectionInfo; +import net.osmand.plus.routing.RoadShield; import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.routing.RoutingHelperUtils; import net.osmand.plus.settings.backend.OsmandSettings; @@ -87,8 +88,9 @@ protected int getLayoutId() { return R.layout.street_name_widget; } - public StreetNameWidget(@NonNull MapActivity mapActivity) { - super(mapActivity, STREET_NAME); + public StreetNameWidget(@NonNull MapActivity mapActivity, @Nullable String customId, + @Nullable WidgetsPanel panel) { + super(mapActivity, STREET_NAME, customId, panel); waypointHelper = app.getWaypointHelper(); rendererRegistry = app.getRendererRegistry(); @@ -116,10 +118,8 @@ public void updateInfo(@Nullable DrawSettings drawSettings) { turnDrawable.setRouteDirectionColor(turnArrowColorId); } - boolean hideStreetName = MapRouteInfoMenu.chooseRoutesVisible - || MapRouteInfoMenu.waypointsVisible - || mapActivity.getWidgetsVisibilityHelper().shouldHideVerticalWidgets(); - if (hideStreetName) { + boolean shouldHide = shouldHide(); + if (shouldHide) { updateVisibility(false); } else if (showClosestWaypointFirstInAddress && updateWaypoint()) { updateVisibility(true); @@ -184,6 +184,12 @@ public void updateInfo(@Nullable DrawSettings drawSettings) { } } + protected boolean shouldHide() { + return MapRouteInfoMenu.chooseRoutesVisible || MapRouteInfoMenu.waypointsVisible + || visibilityHelper.shouldHideVerticalWidgets() + || panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + public boolean updateWaypoint() { LocationPointWrapper point = waypointHelper.getMostImportantLocationPoint(null); boolean changed = lastPoint != point; @@ -234,8 +240,9 @@ private boolean setRoadShield(@NonNull List shields) { return false; } - public static boolean setShieldImage(@NonNull RoadShield shield, @NonNull MapActivity mapActivity, - @NonNull LinearLayout shieldImagesContainer, boolean nightMode) { + public static boolean setShieldImage(@NonNull RoadShield shield, + @NonNull MapActivity mapActivity, + @NonNull LinearLayout shieldImagesContainer, boolean nightMode) { OsmandApplication app = mapActivity.getMyApplication(); RouteDataObject object = shield.getRdo(); StringBuilder additional = shield.getAdditional(); @@ -290,7 +297,8 @@ public static boolean setShieldImage(@NonNull RoadShield shield, @NonNull MapAct int viewHeightPx = AndroidUtils.dpToPx(app, SHIELD_HEIGHT_DP); int viewWidthPx = (int) (viewHeightPx * xyRatio); - float scaleCoefficient = viewWidthPx / xSize;; + float scaleCoefficient = viewWidthPx / xSize; + ; Bitmap bitmap = Bitmap.createBitmap(viewWidthPx, viewHeightPx, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); @@ -319,7 +327,7 @@ public static boolean setShieldImage(@NonNull RoadShield shield, @NonNull MapAct @NonNull public static Paint setupTextPaint(@NonNull OsmandApplication app, @NonNull Paint paint, - @NonNull RenderingRuleSearchRequest request) { + @NonNull RenderingRuleSearchRequest request) { paint.setTypeface(Typeface.create(TextRenderer.DROID_SERIF, Typeface.BOLD)); if (request.isSpecified(request.ALL.R_TEXT_COLOR)) { @@ -378,13 +386,14 @@ protected boolean updateVisibility(boolean visible) { } @Override - public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, @NonNull List followingWidgets) { + public void attachView(@NonNull ViewGroup container, @NonNull WidgetsPanel panel, + @NonNull List followingWidgets) { ViewGroup specialContainer = getSpecialContainer(); boolean useSpecialPosition = panel == WidgetsPanel.TOP && specialContainer != null; if (useSpecialPosition) { specialContainer.removeAllViews(); - boolean showTopCoordinates = mapActivity.getWidgetsVisibilityHelper().shouldShowTopCoordinatesWidget(); + boolean showTopCoordinates = visibilityHelper.shouldShowTopCoordinatesWidget(); if (!followingWidgets.isEmpty() && showTopCoordinates) { useSpecialPosition = false; } @@ -464,7 +473,7 @@ private void computeParams() { } private void updateParamsByLastKnown(@NonNull RouteDataObject lastKnownSegment, - @NonNull Location lastKnownLocation) { + @NonNull Location lastKnownLocation) { String preferredLocale = settings.MAP_PREFERRED_LOCALE.get(); boolean transliterateNames = settings.MAP_TRANSLITERATE_NAMES.get(); boolean direction = lastKnownSegment.bearingVsRouteDirection(lastKnownLocation); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/TextInfoWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/TextInfoWidget.java index 57db4e3e94e..195731f3ccf 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/TextInfoWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/TextInfoWidget.java @@ -19,6 +19,7 @@ import net.osmand.plus.utils.OsmAndFormatter; import net.osmand.plus.views.layers.MapInfoLayer.TextState; import net.osmand.plus.views.mapwidgets.WidgetType; +import net.osmand.plus.views.mapwidgets.WidgetsPanel; import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportSidePanel; public class TextInfoWidget extends MapWidget implements ISupportSidePanel { @@ -45,8 +46,9 @@ public class TextInfoWidget extends MapWidget implements ISupportSidePanel { private Integer cachedAngularUnits; - public TextInfoWidget(@NonNull MapActivity mapActivity, @Nullable WidgetType widgetType) { - super(mapActivity, widgetType); + public TextInfoWidget(@NonNull MapActivity mapActivity, @Nullable WidgetType widgetType, + @Nullable String customId, @Nullable WidgetsPanel panel) { + super(mapActivity, widgetType, customId, panel); container = view.findViewById(R.id.container); emptyBanner = view.findViewById(R.id.empty_banner); imageView = view.findViewById(R.id.widget_icon); diff --git a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/routeinfo/RouteInfoWidget.java b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/routeinfo/RouteInfoWidget.java index de068c49d06..3e0bf6c9c07 100644 --- a/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/routeinfo/RouteInfoWidget.java +++ b/OsmAnd/src/net/osmand/plus/views/mapwidgets/widgets/routeinfo/RouteInfoWidget.java @@ -1,5 +1,7 @@ package net.osmand.plus.views.mapwidgets.widgets.routeinfo; +import static net.osmand.plus.views.mapwidgets.WidgetType.ROUTE_INFO; +import static net.osmand.plus.views.mapwidgets.WidgetsPanel.BOTTOM; import static net.osmand.plus.views.mapwidgets.widgets.DistanceToPointWidget.DISTANCE_CHANGE_THRESHOLD; import static net.osmand.plus.views.mapwidgets.widgets.TimeToNavigationPointWidget.UPDATE_INTERVAL_SECONDS; @@ -30,8 +32,8 @@ import net.osmand.plus.utils.UiUtilities; import net.osmand.plus.views.layers.MapInfoLayer.TextState; import net.osmand.plus.views.layers.base.OsmandMapLayer.DrawSettings; -import net.osmand.plus.views.mapwidgets.WidgetType; import net.osmand.plus.views.mapwidgets.WidgetsContextMenu; +import net.osmand.plus.views.mapwidgets.WidgetsPanel; import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportMultiRow; import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportVerticalPanel; import net.osmand.plus.views.mapwidgets.widgetinterfaces.ISupportWidgetResizing; @@ -49,8 +51,6 @@ public class RouteInfoWidget extends MapWidget implements ISupportVerticalPanel, private final RouteInfoWidgetState widgetState; - @Nullable - protected String customId; private boolean isFullRow; private TextState textState; private final RouteInfoCalculator calculator; @@ -72,9 +72,9 @@ public class RouteInfoWidget extends MapWidget implements ISupportVerticalPanel, private TextView tvTertiaryValue2; private View blocksDivider; - public RouteInfoWidget(@NonNull MapActivity mapActivity, @Nullable String customId) { - super(mapActivity, WidgetType.ROUTE_INFO); - this.customId = customId; + public RouteInfoWidget(@NonNull MapActivity mapActivity, @Nullable String customId, + @Nullable WidgetsPanel panel) { + super(mapActivity, ROUTE_INFO, customId, panel); widgetState = new RouteInfoWidgetState(app, customId); calculator = new RouteInfoCalculator(mapActivity); @@ -93,8 +93,8 @@ protected int getContentLayoutId() { return switch (selectedSize) { case SMALL -> isFullRow ? isSecondaryDataAvailable() - ? R.layout.widget_route_information_small_duo - : R.layout.widget_route_information_small + ? R.layout.widget_route_information_small_duo + : R.layout.widget_route_information_small : R.layout.widget_route_information_small_half; case MEDIUM -> isFullRow ? R.layout.widget_route_information_medium @@ -181,15 +181,20 @@ private void updateInfoInternal() { recreateView(); return; } - boolean shouldHideTopWidgets = mapActivity.getWidgetsVisibilityHelper().shouldHideVerticalWidgets(); + boolean shouldHide = shouldHide(); boolean typeAllowed = widgetType != null && widgetType.isAllowed(); - if (typeAllowed && !shouldHideTopWidgets) { + if (typeAllowed && !shouldHide) { updateRouteInformation(); } else { updateVisibility(false); } } + protected boolean shouldHide() { + return visibilityHelper.shouldHideVerticalWidgets() + || panel == BOTTOM && visibilityHelper.shouldHideBottomWidgets(); + } + private void updateRouteInformation() { List calculatedRouteInfo = calculator.calculateRouteInformation(); if (Algorithms.isEmpty(calculatedRouteInfo)) { @@ -220,7 +225,7 @@ private void updateRouteInformation() { } private void updatePrimaryBlock(@NonNull DestinationInfo destinationInfo, - @NonNull RouteInfoDisplayMode[] modes) { + @NonNull RouteInfoDisplayMode[] modes) { Map displayData = prepareDisplayData(destinationInfo); tvPrimaryValue1.setText(displayData.get(modes[0])); @@ -229,7 +234,7 @@ private void updatePrimaryBlock(@NonNull DestinationInfo destinationInfo, } private void updateSecondaryBlock(@NonNull DestinationInfo destinationInfo, - @NonNull RouteInfoDisplayMode[] modes) { + @NonNull RouteInfoDisplayMode[] modes) { Map displayData = prepareDisplayData(destinationInfo); tvPrimaryValue2.setText(displayData.get(modes[0])); @@ -317,7 +322,8 @@ public RouteInfoDisplayMode getDisplayMode(@NonNull ApplicationMode appMode) { return widgetState.getDisplayMode(appMode); } - public void setDisplayMode(@NonNull ApplicationMode appMode, @NonNull RouteInfoDisplayMode displayMode) { + public void setDisplayMode(@NonNull ApplicationMode appMode, + @NonNull RouteInfoDisplayMode displayMode) { widgetState.setDisplayMode(appMode, displayMode); } diff --git a/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenu.java b/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenu.java index 544b1699c09..8c0702f9103 100644 --- a/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenu.java +++ b/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenu.java @@ -10,8 +10,8 @@ import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.view.menu.MenuBuilder; -import androidx.appcompat.view.menu.MenuPopupHelper; import androidx.appcompat.widget.ListPopupWindow; import androidx.appcompat.widget.PopupMenu; import androidx.core.view.MenuCompat; @@ -73,15 +73,15 @@ private ListPopupWindow createCustomListPopUpWindow() { listPopupWindow.setContentWidth(totalWidth); listPopupWindow.setModal(true); listPopupWindow.setAdapter(adapter); - if (displayData.customDropDown) { - if (shouldShowAsDropDown(ctx)) { - listPopupWindow.setDropDownGravity(Gravity.START | Gravity.TOP); - listPopupWindow.setVerticalOffset(-anchorView.getHeight() + contentPaddingHalf); - } else { - listPopupWindow.setDropDownGravity(Gravity.START | Gravity.BOTTOM); - listPopupWindow.setVerticalOffset(anchorView.getHeight() - contentPaddingHalf); + + setDropDown(listPopupWindow, anchorView, ctx); + if (displayData.limitHeight) { + Integer maxHeight = calculatePopupMaxHeight(anchorView, ctx); + if (maxHeight != null) { + listPopupWindow.setHeight(maxHeight); } } + if (displayData.bgColor != 0) { listPopupWindow.setBackgroundDrawable(new ColorDrawable(displayData.bgColor)); } @@ -94,6 +94,47 @@ private ListPopupWindow createCustomListPopUpWindow() { return listPopupWindow; } + private void setDropDown(@NonNull ListPopupWindow listPopupWindow, @NonNull View anchorView, @NonNull Context ctx){ + int contentPaddingHalf = getDimension(ctx, R.dimen.content_padding_half); + + switch (displayData.customDropDown) { + case AUTO_DROP_DOWN -> { + if (shouldShowAsDropDown(ctx)) { + listPopupWindow.setDropDownGravity(Gravity.START | Gravity.TOP); + listPopupWindow.setVerticalOffset(-anchorView.getHeight() + contentPaddingHalf); + } else { + listPopupWindow.setDropDownGravity(Gravity.START | Gravity.BOTTOM); + listPopupWindow.setVerticalOffset(anchorView.getHeight() - contentPaddingHalf); + } + } + case TOP_DROPDOWN -> { + listPopupWindow.setDropDownGravity(Gravity.START | Gravity.TOP); + listPopupWindow.setVerticalOffset(-anchorView.getHeight() + contentPaddingHalf); + } + case BOTTOM_DROPDOWN -> { + listPopupWindow.setDropDownGravity(Gravity.START | Gravity.BOTTOM); + listPopupWindow.setVerticalOffset(anchorView.getHeight() - contentPaddingHalf); + } + } + } + + @Nullable + private Integer calculatePopupMaxHeight(View anchorView, Context context) { + int totalHeightNeeded = calculateApproxPopupWindowHeight(context); + int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + int[] location = new int[2]; + anchorView.getLocationOnScreen(location); + int availableSpaceBelow = screenHeight - location[1] - anchorView.getHeight(); + + + if (totalHeightNeeded <= availableSpaceBelow) { + return null; + } + + int contentPaddingHalf = context.getResources().getDimensionPixelSize(R.dimen.content_padding_half); + return availableSpaceBelow - contentPaddingHalf; + } + private boolean shouldShowAsDropDown(@NonNull Context ctx) { int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels; int anchorViewTopY = AndroidUtils.getViewOnScreenY(displayData.anchorView); diff --git a/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenuDisplayData.java b/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenuDisplayData.java index a2014bde614..a7df47fda60 100644 --- a/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenuDisplayData.java +++ b/OsmAnd/src/net/osmand/plus/widgets/popup/PopUpMenuDisplayData.java @@ -20,8 +20,9 @@ public class PopUpMenuDisplayData { public PopUpMenuWidthMode widthMode = PopUpMenuWidthMode.AS_ANCHOR_VIEW; public List menuItems; public OnPopUpMenuItemClickListener onItemClickListener; - public boolean customDropDown = true; + public CustomDropDown customDropDown = CustomDropDown.AUTO_DROP_DOWN; public boolean showCompound = true; + public boolean limitHeight = false; public boolean hasCustomizations() { if (layoutId != DEFAULT_LAYOUT_ID) { @@ -35,4 +36,10 @@ public boolean hasCustomizations() { return false; } + public enum CustomDropDown { + AUTO_DROP_DOWN, + TOP_DROPDOWN, + BOTTOM_DROPDOWN, + NONE + } } diff --git a/build.gradle b/build.gradle index ff286975d8f..8afc9456e5c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '2.0.0' + ext.kotlin_version = '2.1.10' repositories { google() mavenCentral() @@ -8,7 +8,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:8.2.1' + classpath 'com.android.tools.build:gradle:8.7.3' classpath 'com.google.gms:google-services:4.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a10a1b58323..baf031e6e99 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Jul 15 15:30:46 EEST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists