Compare commits
75 Commits
release/20
...
2025.06.30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fe3526bf4 | ||
|
|
b31819fcfb | ||
|
|
fdc05a2a6c | ||
|
|
1584adc4cb | ||
|
|
4623291461 | ||
|
|
b409d805cc | ||
|
|
ac30139432 | ||
|
|
df3850b86c | ||
|
|
70c3f725f9 | ||
|
|
a830e4b444 | ||
|
|
142759c4d0 | ||
|
|
5ee1c2a2a0 | ||
|
|
a21f2125bc | ||
|
|
5346193f80 | ||
|
|
a94cb3531d | ||
|
|
ceb94232a6 | ||
|
|
5ea4bfef34 | ||
|
|
6014a899d1 | ||
|
|
c4d8ac0426 | ||
|
|
b6b02ba9d7 | ||
|
|
a274ed927e | ||
|
|
bbadd3f338 | ||
|
|
0e9bc6f960 | ||
|
|
a448422ad6 | ||
|
|
e3d8454b6c | ||
|
|
99be248ec8 | ||
|
|
cd0ffab996 | ||
|
|
2dca80cd0f | ||
|
|
d01de6ade7 | ||
|
|
f7f73f04b1 | ||
|
|
eee299f6cd | ||
|
|
5b43e4ec9b | ||
|
|
733c0ae8a8 | ||
|
|
30ee5c30e1 | ||
|
|
d562f23256 | ||
|
|
ecb44b5ae9 | ||
|
|
c49cf48575 | ||
|
|
4581907f00 | ||
|
|
423d45a1bb | ||
|
|
4d8e7c39fd | ||
|
|
273eeed9f3 | ||
|
|
754748123c | ||
|
|
b58bacddf1 | ||
|
|
a985bf8349 | ||
|
|
b4f115a8fa | ||
|
|
df89761eba | ||
|
|
25e49b0fe1 | ||
|
|
6a10cffe51 | ||
|
|
495167c11f | ||
|
|
d44d671550 | ||
|
|
d44d575368 | ||
|
|
fbddff009e | ||
|
|
58bab61890 | ||
|
|
464b3cf59a | ||
|
|
4a48d43240 | ||
|
|
d68544de13 | ||
|
|
ae1c975627 | ||
|
|
090b7c21fc | ||
|
|
126d4f6373 | ||
|
|
78b54acad4 | ||
|
|
35cda6d342 | ||
|
|
1ad5975790 | ||
|
|
275695b85e | ||
|
|
d8d93bc0cb | ||
|
|
2ecdf10fde | ||
|
|
40164a01d7 | ||
|
|
d6478a0b4d | ||
|
|
c04c3b7783 | ||
|
|
e960e8240c | ||
|
|
ef18d2dee8 | ||
|
|
0cb1372075 | ||
|
|
d74f7c1594 | ||
|
|
32eefec665 | ||
|
|
25ff7aaf97 | ||
|
|
abf19976f6 |
@@ -7,6 +7,10 @@ CoMaps contributors:
|
||||
(in alphabetic order)
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
clover sage
|
||||
Harry Bond <me@hbond.xyz>
|
||||
vikiawv
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Organic Maps (formerly OMaps) contributors:
|
||||
(in alphabetic order)
|
||||
|
||||
32
README.md
@@ -13,16 +13,16 @@
|
||||
# [CoMaps](https://comaps.app) – Hike, Bike, Drive Offline – Easy Map Navigation with Privacy
|
||||
|
||||
[
|
||||

|
||||

|
||||
](https://github.com/comaps/comaps/actions/workflows/android-check.yaml)
|
||||
[
|
||||

|
||||

|
||||
](https://github.com/comaps/comaps/actions/workflows/ios-check.yaml)
|
||||
[
|
||||

|
||||

|
||||
](https://opencollective.com/comaps)
|
||||
[
|
||||

|
||||

|
||||
](https://liberapay.com/CoMaps)
|
||||
|
||||
|
||||
@@ -32,20 +32,16 @@ A community-led free & open source maps app based on [OpenStreetMap](https://www
|
||||
There are apps for Android and iOS (and ARM MacOS).
|
||||
An alpha Linux / MacOS Qt desktop version, which is also suitable for Linux phones.
|
||||
|
||||
The June app release is available on Google Play, F-Droid and as an APK to download now! We are working on publishing in the iOS App Store as well, please stay tuned!
|
||||
|
||||
<!--
|
||||
[<img src="docs/badges/apple-appstore.png" alt="App Store" width="160">](https://apps.apple.com/app/comaps/id1567437057)
|
||||
-->
|
||||
[<img src="docs/badges/apple-appstore.png" alt="App Store" width="160">](https://apps.apple.com/app/comaps/id6747180809)
|
||||
[<img src="docs/badges/google-play.png" alt="Google Play" width="160">](https://play.google.com/store/apps/details?id=app.comaps.google)
|
||||
[<img src="docs/badges/fdroid.png" alt="F-Droid" width="160">](https://f-droid.org/en/packages/app.comaps.fdroid/)
|
||||
[<img src="docs/badges/codeberg.png" alt="Codeberg" width="160">](https://codeberg.org/comaps/comaps/releases)
|
||||
|
||||
<p float="left">
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/1.jpg" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/2.jpg" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/3.jpg" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/4.jpg" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/1.png" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/2.png" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/3.png" width="180" />
|
||||
<img src="android/app/src/fdroid/play/listings/en-US/graphics/phone-screenshots/4.png" width="180" />
|
||||
</p>
|
||||
|
||||
**Offline-focused**: Plan and navigate your trip abroad without the need for cellular service, search waypoints while on a distant hike, etc. All app functions are designed to work offline.
|
||||
@@ -105,9 +101,9 @@ There is a dedicated Zulip chat for active contributors: [comaps.zulipchat.com](
|
||||
|
||||
### Feedback
|
||||
|
||||
<!-- uncomment when linked resources are ready
|
||||
- **Rate us on the [App Store](https://apps.apple.com/app/comaps/id1567437057)
|
||||
and [Google Play](https://play.google.com/store/apps/details?id=app.comaps)**. -->
|
||||
|
||||
- **Rate us on the [App Store](https://apps.apple.com/app/comaps/id6747180809)
|
||||
and [Google Play](https://play.google.com/store/apps/details?id=app.comaps.google)**.
|
||||
- Star our repos on Codeberg
|
||||
- Report bugs and discuss features at [the issue tracker](https://codeberg.org/comaps/comaps/issues)
|
||||
|
||||
@@ -117,6 +113,10 @@ The app is free for everyone, so we rely on donations. Please [donate](https://o
|
||||
|
||||
The project's financial information is completely open and transparent at [our Open Collective](https://opencollective.com/comaps).
|
||||
|
||||
## Privacy
|
||||
|
||||
The Android application was analysed by the [Exodus platform](https://reports.exodus-privacy.eu.org/fr/reports/app.comaps.google/latest/)
|
||||
|
||||
## License and Copyright
|
||||
|
||||
Licensed under the Apache License, Version 2.0. See
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
To build, install and run e.g. a Web Debug version on your device/emulator: './gradlew runWebDebug'
|
||||
|
||||
Or to compile a redistributable Fdroid Beta apk for testing: './gradlew assembleFdroidBeta'
|
||||
Or to compile a redistributable Fdroid Test apk for testing: './gradlew assembleFdroidBeta'
|
||||
|
||||
Or to build beta apks for all flavors: './gradlew assembleBeta'
|
||||
Or to build test apks for all flavors: './gradlew assembleBeta'
|
||||
|
||||
To see all available build targets './gradlew tasks'
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ buildscript {
|
||||
// Detect flavors from the task name.
|
||||
def taskName = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase()
|
||||
def isFdroid = taskName.contains('fdroid')
|
||||
def isBeta = taskName.contains('beta')
|
||||
|
||||
dependencies {
|
||||
classpath libs.android.tools
|
||||
@@ -297,7 +296,6 @@ android {
|
||||
ndk.debugSymbolLevel = 'symbol_table'
|
||||
}
|
||||
|
||||
// TODO(@pastk): rename to "test" everywhere in code
|
||||
beta {
|
||||
applicationIdSuffix '.test'
|
||||
versionNameSuffix '-test'
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
• Kartenfarben aufgefrischt – heller, wärmer, freundlicher!
|
||||
• OSM-Editor: „Stockwerk“ Feld hinzugefügt
|
||||
• Symbole für Tankstellen und Ladestationen aktualisiert
|
||||
• Farben einiger UI Elemente überarbeitet
|
||||
• Funktionierende Links zum Teilen von Orten
|
||||
• Falsch angezeigte Kartengröße nach Downloadfehlern korrigiert
|
||||
• Kleine Sprünge des Standortpfeils in bestimmten Fällen behoben
|
||||
• Bugfixes für Android 5 & 6
|
||||
• OpenStreetMap-Daten vom 22. Juni
|
||||
• Optionale automatische Backups von Lesezeichen & Tracks
|
||||
• Neue 100m-Höhenlinien für Regionen die vorher gröbere/keine Isolinien hatten
|
||||
• Vegetation & Spielplätze werden früher angezeigt, neue Farben für Campingplätze & andere Einrichtungen
|
||||
• Pfade & Tracks werden standardmäßig bei höherem Zoom angezeigt, Outdoor-Stil für Detailübersicht
|
||||
• Aktion des linken Button nichtm mehr im Hamburger-Menü, stattdessen werden "Über & Hilfe" dort angezeigt
|
||||
|
||||
|
Before Width: | Height: | Size: 747 KiB |
|
After Width: | Height: | Size: 628 KiB |
|
Before Width: | Height: | Size: 749 KiB |
|
After Width: | Height: | Size: 532 KiB |
|
Before Width: | Height: | Size: 730 KiB |
|
After Width: | Height: | Size: 391 KiB |
|
Before Width: | Height: | Size: 590 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 268 KiB |
|
After Width: | Height: | Size: 263 KiB |
@@ -1,8 +1,7 @@
|
||||
• refresh map colors - lighter, warmer, friendlier!
|
||||
• OSM editor: add a "level" field
|
||||
• update gas and charging stations icons
|
||||
• update colors of some UI elements
|
||||
• fix location sharing links
|
||||
• fix wrong displayed map size after download errors
|
||||
• fix small location arrow jumps in some cases
|
||||
• android 5&6 bugfixes
|
||||
• OpenStreetMap data as of June 22
|
||||
• a setting for automatic bookmarks and tracks backup
|
||||
• added 100m-step altitude isolines to all regions that had worse or no isolines
|
||||
• display vegetation and playground color fills earlier, add fills to camp sites and some amenities
|
||||
• paths & tracks appear on the map later by default - still appear earlier in the outdoor style
|
||||
• hide active custom button action from the hamburger menu, move there About & Help from the settings
|
||||
• update map transport icons
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
• colores del mapa renovados - más claros, cálidos y amigables!
|
||||
• editor OSM: campo "nivel" agregado
|
||||
• actualización de íconos de carga de combustible y electricidad
|
||||
• actualización de colores de algunos elementos de IU
|
||||
• corrección de links para compartir ubicación
|
||||
• corrección de tamaño incorrecto del mapa luego de errores de descarga
|
||||
• corrección de pequeños saltos de flechas de posición en algunos casos
|
||||
• corrección de bugs en Android 5 y 6
|
||||
• datos de OpenStreetMap a 22 de junio
|
||||
• añadido ajuste para la copia de seguridad automática de marcadores y trazas
|
||||
• añadidas isolíneas de 100 m a las regiones que tenían isolíneas peores o no tenían isolíneas
|
||||
• se muestra antes la vegetación y zonas de juego, añadidas áreas a campings y otros servicios
|
||||
• los senderos y pistas aparecen más tarde - siguen igual en estilo de outdoors
|
||||
• se oculta botón personalizado del menú y se mueve allí Acerca de y Ayuda desde los ajustes
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
Komunitateko doako eta iturburu irekiko aplikazioa OpenStreetMap datuetan oinarrituta eta gardentasuna, pribatutasuna eta irabazi asmorik gabeko konpromisoarekin indartua. Comaps Organic Maps-en fork edo aldaera bat da, eta hori, aldi berean, maps.me-ren forka da.
|
||||
|
||||
Irakurri proiektuaren zergatia eta haren norabidea <b> <i> codeberg.org/comaps </ i> </ b>.
|
||||
Sartu komunitatean eta lagundu maparik onena aplikatzen
|
||||
• Erabili aplikazioa eta horren berri eman
|
||||
• Eman feedbacka eta txostenetako gaiak
|
||||
• Eguneratu maparen datuak aplikazioan edo OpenStreetMap webgunean
|
||||
|
||||
‣ <b> Konexiorik gabe fokatuta </ b> Planifikatu eta nabigatu atzerrira bidaiatzea, telefono zerbitzu beharrik gabe, bilaketa-biderapenak urruneko ibilaldian eta abar. Aplikazio funtzio guztiak lineaz kanpo lan egiteko diseinatuta daude.
|
||||
‣ <b> Pribatutasuna errespetatzea </ b> errespetatzea: aplikazioa pribatutasunarekin diseinatuta dago, ez du pertsonak identifikatzen, ez du jarraipena egiten, eta ez du informazio pertsonala biltzen. Iragarkirik ez.
|
||||
‣ <b> Sinplea eta leundua </ b>: Ezinbestekoa da funtzionatzen duten ezaugarriak erabiltzeko.
|
||||
‣ <b> Zure bateria eta espazioa gordetzen ditu </ b>: ez du bateria xahutzen beste nabigazio aplikazioak bezala. Mapa trinkoak. Gorde espazio preziatua zure telefonoan.
|
||||
‣ <b> Librea eta komunitateak eraikitakoa: Jendeak aplikazioa eraikitzen lagundu zuen aplikazioa eraikitzen lagunduz OpenStreetMap, probatu eta funtzioei buruzko iritzia emanez eta garapen trebetasunak eta dirua lagunduz.
|
||||
‣ <b> Erabakiak eta finantza irekiak eta gardena, irabazi asmorik gabeko eta guztiz irekitako iturria. </ B>
|
||||
|
||||
<b> Ezaugarri nagusiak </ b>:
|
||||
• Deskargatu mapa zehatzak Google Maps-ekin eskuragarri ez dauden lekuekin
|
||||
• Mendiko modua nabarmendutako mendi ibilbideak, kanpinak, ur iturriak, gailurrak, sestra-lerroak, etab
|
||||
• Bideak eta bidegorriak
|
||||
• Jatetxe, gas geltokiak, hotelak, dendak, bisitak eta bestelako interesguneak
|
||||
• Bilatu izenaren edo helbide baten arabera edo interes-kategoriaren arabera
|
||||
• Oinez, txirrinduaz edo gidatzeko ahots-oharrekin nabigazioa
|
||||
• Markatu zure gogoko lekuak sakatze bakarrarekin
|
||||
• Lineaz kanpoko Wikipedia artikuluak
|
||||
• Metroaren garraio geruza eta jarraibideak
|
||||
• Arrastoen grabazioa
|
||||
• Laster-markak eta ibilbideak esportatu eta inportatu KML, KMZ, GPX formatuetan
|
||||
• Gauean erabiltzeko modu iluna
|
||||
• Hobetu mapako datuak guztiontzat oinarrizko editore integratua erabiliz
|
||||
|
||||
<b> Askatasuna hemen </ b> da
|
||||
Ezagutu zure bidaia, nabigatu munduan pribatutasunarekin eta komunitatez abangoardian!
|
||||
@@ -1 +1 @@
|
||||
CoMaps- Mendia, bizikleta, autoa. Dena offline eta pribatutasunearekin
|
||||
CoMaps- Mendia, bizikleta, autoa, dena offline
|
||||
|
||||
|
Before Width: | Height: | Size: 737 KiB |
|
After Width: | Height: | Size: 655 KiB |
|
Before Width: | Height: | Size: 765 KiB |
|
After Width: | Height: | Size: 532 KiB |
|
Before Width: | Height: | Size: 735 KiB |
|
After Width: | Height: | Size: 391 KiB |
|
Before Width: | Height: | Size: 594 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 263 KiB |
@@ -1,8 +1,6 @@
|
||||
• Mise à jour des couleurs de la carte, plus claires, plus chaudes et plus conviviales
|
||||
• Editeur OSM: ajout du champ "level"
|
||||
• Mise à jour des icônes des stations-service et bornes de recharge
|
||||
• Mise à jour des couleurs de certains éléments d'interface
|
||||
• Correction de lien de partage
|
||||
• Correction de la taille d'une carte suite à une erreur de téléchargement
|
||||
• Correction de saut de la localisation dans certaines situations
|
||||
• Corrections de bug sur Android 5&6
|
||||
• Données OpenStreetMap du 22 juin
|
||||
• Sauvegarde automatique des signets et traces GPS en local
|
||||
• Ajout des courbes d'altitude avec un précision de 100 mètres dans toutes les régions qui avaient peu de courbes ou aucune
|
||||
• Ajustements des styles notamment sur la végétation, les aires de jeu et les chemins
|
||||
• Masque l’action active du bouton personnalisé dans le menu hamburger
|
||||
• Correction de certains plantages et bugs
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Navegación doada - Descubre máis sobre o teu camiño - Creada pola comunidade
|
||||
1
android/app/src/fdroid/play/listings/gl-ES/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - Aplicación de mapas privada, sen conexión
|
||||
1
android/app/src/fdroid/play/listings/nl-NL/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
CoMaps - Wandel, fiets, rijdt offline met privacy
|
||||
@@ -1,8 +0,0 @@
|
||||
• Atualizadas as cores do mapa - mais claras, quentes e amigáveis!
|
||||
• Editor OSM: adicionado um campo de "andar"
|
||||
• Atualizados ícones de postos de gasolina e recarga
|
||||
• Atualizadas cores de alguns elementos da interface do usuário
|
||||
• Correção de links de compartilhamento de localização
|
||||
• Correção de erros de tamanho de mapa exibidos incorretamente após download
|
||||
• Correção de pequenos saltos na seta de localização em alguns casos
|
||||
• Correções de bugs do Android 5 e 6
|
||||
@@ -1 +1 @@
|
||||
Navegação fácil nos mapas - Descobre mais sobre o teu percurso - Feito por todos
|
||||
Navegação fácil nos mapas - Descubra mais sobre o seu percurso - Feito por todos
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
• обновлены цвета карты — теперь они светлее, теплее и дружелюбнее
|
||||
• редактор OSM: добавлено поле «этаж»
|
||||
• обновлены иконки заправок и зарядных станций
|
||||
• обновлены цвета некоторых элементов интерфейса
|
||||
• исправлена ссылка на карту при попытке поделиться местоположением
|
||||
• исправлено неверное отображение размера карты после ошибок загрузки
|
||||
• исправлены мелкие скачки стрелки местоположения в некоторых случаях
|
||||
• исправления ошибок для Android 5 и 6
|
||||
• карты OpenStreetMap от 22 июня
|
||||
• автоматическое резервное копирование меток и треков
|
||||
• линии высот с шагом 100м для всех регионов, где линии с этим шагом отсутствовали
|
||||
• цветная заливка растительности и игровых площадок отображается раньше, добавлена заливка для кемпингов и других объектов
|
||||
• тропы и грунтовки отображаются позже в стиле по умолчанию - используйте стиль «Активный отдых» для обзора троп
|
||||
• выбранная функция настраиваемой кнопки больше не дублируется в пунктах меню
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
• освежене су боје мапе – светлије, топлије, пријатније!
|
||||
• у OSM едитору је додато поље „спрат“
|
||||
• ажуриране су иконице бензинских пумпи и станица за пуњење
|
||||
• ажуриране су боје неких елемената корисничког интерфејса
|
||||
• поправљени су линкови за дељење локације
|
||||
• поправљена је погрешно приказана величина мапе након грешака при преузимању
|
||||
• исправљена су мала поскакивања стрелице локације у неким случајевима
|
||||
• исправљене су грешке за Android 5 и 6
|
||||
@@ -1,8 +0,0 @@
|
||||
• 刷新地图颜色-更浅、更暖、更友好!
|
||||
• OSM 编辑器:添加“楼层”字段
|
||||
• 更新加油站和充电站图标
|
||||
• 更新部分用户界面组件的颜色
|
||||
• 修复位置共享的链接
|
||||
• 修复下载后错误显示地图大小的问题
|
||||
• 修复定位箭头偶尔轻微跳动的问题
|
||||
• Android 5&6 错误修复
|
||||
@@ -1,8 +0,0 @@
|
||||
• 刷新地圖顏色-更淺、更暖、更友好!
|
||||
• OSM 編輯器:新增「樓層」欄位
|
||||
• 更新加油站和充電站圖示
|
||||
• 更新某些使用者介面元件的顏色
|
||||
• 修正位置分享的連結
|
||||
• 修正下載後錯誤顯示地圖尺寸的問題
|
||||
• 修正定位箭頭偶爾輕微跳動的問題
|
||||
• Android 5&6 錯誤修正
|
||||
@@ -1 +1 @@
|
||||
version: 2025.03.02-7-FDroid+25030207
|
||||
version: 2025.06.30-22-FDroid+25063022
|
||||
|
||||
@@ -1 +1 @@
|
||||
CoMaps
|
||||
CoMaps - Navi mit Datenschutz
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Navegación doada - Descubre máis sobre o teu camiño - Creada pola comunidade
|
||||
@@ -0,0 +1 @@
|
||||
Navegação fácil nos mapas - Descubra mais sobre o seu percurso - Feito por todos
|
||||
@@ -0,0 +1,36 @@
|
||||
OpenStreetMap verilerine dayanan ve şeffaflık, gizlilik ve kar amacı gütmeyen olma taahhüdüyle güçlendirilen, topluluk tarafından yönetilen ücretsiz ve açık kaynaklı bir harita uygulaması.
|
||||
|
||||
Topluluğa katılın ve en iyi harita uygulamasını oluşturmaya yardımcı olun
|
||||
• Uygulamayı kullanın ve bunu herkese duyurun
|
||||
• Geri bildirimde bulunun ve sorunları bildirin
|
||||
• Harita verilerini uygulamada veya OpenStreetMap web sitesinde güncelleyin
|
||||
|
||||
<i>Geri bildirimleriniz ve 5 yıldızlı yorumlarınız bizim için en iyi destektir!</i>
|
||||
|
||||
‣ <b>Basit ve Cilalı</b>: sadece işe yarayan, kullanımı kolay temel özellikler.
|
||||
‣ <b>Çevrim dışı odaklı</b>: Cep telefonu hizmetine ihtiyaç duymadan yurtdışı seyahatinizi planlayın ve gezinin, uzun bir yürüyüş sırasında rota noktalarını arayın, vb. Tüm uygulama işlevleri çevrimdışı çalışmak üzere tasarlanmıştır.
|
||||
‣ <b>Gizliliğe Saygı</b>: Uygulama gizlilik düşünülerek tasarlanmıştır; kişileri tanımlamaz, takip etmez ve kişisel bilgi toplamaz. Reklamsız.
|
||||
‣ <b>Pilinizden ve Alanınızdan Tasarruf Edin</b>: Diğer navigasyon uygulamaları gibi pilinizi tüketmez. Kompakt haritalar telefonunuzda değerli alan tasarrufu sağlar.
|
||||
‣ <b>Ücretsiz ve Topluluk Tarafından Oluşturuldu</b>: Sizin gibi insanlar, OpenStreetMap'e yerler ekleyerek, özellikleri test ederek ve geri bildirimde bulunarak ve geliştirme becerilerinizi ve paranızı katkıda bulunarak uygulamanın oluşturulmasına yardımcı oldunuz..
|
||||
‣ <b>Açık ve Şeffaf Karar Alma ve Finansman, Kar Amacı Gütmeyen ve Tamamen Açık Kaynak.</b>
|
||||
|
||||
<b>Ana Özellikleri</b>:
|
||||
• Google Haritalar'da bulunmayan yerleri içeren indirilebilir detaylı haritalar
|
||||
• Vurgulanan yürüyüş parkurları, kamp alanları, su kaynakları, zirveler, kontur çizgileriyle açık hava modu gibi
|
||||
• Yürüyüş yolları ve bisiklet yolları
|
||||
• Restoranlar, benzin istasyonları, oteller, mağazalar, turistik yerler gibi ilgi çekici noktalar ve daha fazlası
|
||||
• İsme veya adrese göre veya ilgi noktası kategorisine göre arama yapın
|
||||
• Yürüyerek, bisikletle veya araçla seyahat edenler için sesli duyurularla navigasyon
|
||||
• Favori yerlerinizi tek bir dokunuşla yer imlerine ekleyin
|
||||
• Çevrim dışı Wikipedia makaleleri
|
||||
• Metro geçiş katmanı ve yönleri
|
||||
• Rota kaydı
|
||||
• Yer imlerini ve parkurları KML, KMZ, GPX formatlarında dışa ve içe aktarın
|
||||
• Geceleri kullanmak için karanlık mod
|
||||
• Temel bir yerleşik düzenleyici kullanarak herkes için harita verilerini iyileştirin
|
||||
• Android Auto desteği
|
||||
|
||||
Lütfen uygulama sorunlarını bildirin, fikir önerin ve <b><i>comaps.app</i></b> web sitesinde topluluğumuza katılın.
|
||||
|
||||
<b>Özgürlük Burada</b>
|
||||
Yolculuğunuzu keşfedin, gizlilik ve topluluk ön planda tutularak dünyayı keşfedin!
|
||||
@@ -44,6 +44,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import app.organicmaps.api.Const;
|
||||
import app.organicmaps.backup.PeriodicBackupRunner;
|
||||
import app.organicmaps.base.BaseMwmFragmentActivity;
|
||||
import app.organicmaps.base.OnBackPressListener;
|
||||
import app.organicmaps.bookmarks.BookmarkCategoriesActivity;
|
||||
@@ -139,6 +140,7 @@ import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
|
||||
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_RECORD_TRACK_CODE;
|
||||
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_SETTINGS_CODE;
|
||||
import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG;
|
||||
import static app.organicmaps.util.concurrency.UiThread.runLater;
|
||||
|
||||
public class MwmActivity extends BaseMwmFragmentActivity
|
||||
implements PlacePageActivationListener,
|
||||
@@ -253,6 +255,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
@NonNull
|
||||
private DisplayManager mDisplayManager;
|
||||
|
||||
private PeriodicBackupRunner backupRunner;
|
||||
|
||||
ManageRouteBottomSheet mManageRouteBottomSheet;
|
||||
|
||||
private boolean mRemoveDisplayListener = true;
|
||||
@@ -607,6 +611,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
*/
|
||||
if (Map.isEngineCreated())
|
||||
onRenderingInitializationFinished();
|
||||
|
||||
backupRunner = new PeriodicBackupRunner(this);
|
||||
}
|
||||
|
||||
private void onSettingsResult(ActivityResult activityResult)
|
||||
@@ -838,7 +844,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
@Override
|
||||
public String getPrefsName()
|
||||
{
|
||||
return getString(R.string.help);
|
||||
return getString(R.string.about_help);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1352,6 +1358,11 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
final String backUrl = Framework.nativeGetParsedBackUrl();
|
||||
if (!TextUtils.isEmpty(backUrl))
|
||||
Utils.openUri(this, Uri.parse(backUrl), null);
|
||||
|
||||
if (backupRunner != null && !backupRunner.isAlreadyChecked() && backupRunner.isTimeToBackup())
|
||||
{
|
||||
backupRunner.doBackup();
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@@ -2584,20 +2595,28 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
{
|
||||
if (id.equals(MAIN_MENU_ID))
|
||||
{
|
||||
final String activeLeftButton = buttonsHolder.getActiveButtonCode();
|
||||
ArrayList<MenuBottomSheetItem> items = new ArrayList<>();
|
||||
items.add(new MenuBottomSheetItem(R.string.placepage_add_place_button, R.drawable.ic_plus, this::onAddPlaceOptionSelected));
|
||||
items.add(new MenuBottomSheetItem(
|
||||
R.string.download_maps,
|
||||
R.drawable.ic_download,
|
||||
getDownloadMapsCounter(),
|
||||
this::onDownloadMapsOptionSelected
|
||||
));
|
||||
mDonatesUrl = Config.getDonateUrl(getApplicationContext());
|
||||
if (!TextUtils.isEmpty(mDonatesUrl))
|
||||
|
||||
if (!BUTTON_ADD_PLACE_CODE.equals(activeLeftButton))
|
||||
items.add(new MenuBottomSheetItem(R.string.placepage_add_place_button, R.drawable.ic_plus, this::onAddPlaceOptionSelected));
|
||||
|
||||
items.add(new MenuBottomSheetItem(R.string.download_maps, R.drawable.ic_download, getDownloadMapsCounter(), this::onDownloadMapsOptionSelected));
|
||||
|
||||
if (!Config.getDonateUrl(getApplicationContext()).isEmpty())
|
||||
items.add(new MenuBottomSheetItem(R.string.donate, R.drawable.ic_donate, this::onDonateOptionSelected));
|
||||
items.add(new MenuBottomSheetItem(R.string.settings, R.drawable.ic_settings, this::onSettingsOptionSelected));
|
||||
items.add(new MenuBottomSheetItem(R.string.start_track_recording, R.drawable.ic_track_recording_off, -1, this::onTrackRecordingOptionSelected));
|
||||
|
||||
if (!BUTTON_SETTINGS_CODE.equals(activeLeftButton))
|
||||
items.add(new MenuBottomSheetItem(R.string.settings, R.drawable.ic_settings, this::onSettingsOptionSelected));
|
||||
|
||||
if (!BUTTON_RECORD_TRACK_CODE.equals(activeLeftButton))
|
||||
items.add(new MenuBottomSheetItem(R.string.start_track_recording, R.drawable.ic_track_recording_off, -1, this::onTrackRecordingOptionSelected));
|
||||
|
||||
items.add(new MenuBottomSheetItem(R.string.share_my_location, R.drawable.ic_share, this::onShareLocationOptionSelected));
|
||||
|
||||
if (!BUTTON_HELP_CODE.equals(activeLeftButton))
|
||||
items.add(new MenuBottomSheetItem(R.string.about_help, R.drawable.ic_question_mark, this::showHelp));
|
||||
|
||||
return items;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_DEFAULT_COUNT;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.MAX_BACKUPS_KEY;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.util.UiUtils;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class BackupUtils
|
||||
{
|
||||
private static final String BACKUP_PREFIX = "backup_";
|
||||
private static final String BACKUP_EXTENSION = ".kmz";
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").withLocale(Locale.US);
|
||||
private static final String TAG = BackupUtils.class.getSimpleName();
|
||||
|
||||
public static CharSequence formatReadableFolderPath(Context context, @NonNull Uri uri)
|
||||
{
|
||||
String docId = DocumentsContract.getTreeDocumentId(uri);
|
||||
String volumeId;
|
||||
String subPath = "";
|
||||
|
||||
int colonIndex = docId.indexOf(':');
|
||||
if (colonIndex >= 0)
|
||||
{
|
||||
volumeId = docId.substring(0, colonIndex);
|
||||
subPath = docId.substring(colonIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
volumeId = docId;
|
||||
}
|
||||
|
||||
String volumeName;
|
||||
if ("primary".equalsIgnoreCase(volumeId))
|
||||
volumeName = context.getString(R.string.maps_storage_shared);
|
||||
else
|
||||
volumeName = context.getString(R.string.maps_storage_removable);
|
||||
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
sb.append(volumeName + ": \n", new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_3)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
sb.append("/" + subPath, new AbsoluteSizeSpan(UiUtils.dimen(context, R.dimen.text_size_body_4)), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static int getMaxBackups(SharedPreferences prefs)
|
||||
{
|
||||
String rawValue = prefs.getString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT));
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(rawValue);
|
||||
} catch (NumberFormatException e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to parse max backups count, raw value: " + rawValue + " set to default: " + MAX_BACKUPS_DEFAULT_COUNT, e);
|
||||
prefs.edit()
|
||||
.putString(MAX_BACKUPS_KEY, String.valueOf(MAX_BACKUPS_DEFAULT_COUNT))
|
||||
.apply();
|
||||
return MAX_BACKUPS_DEFAULT_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentFile createUniqueBackupFolder(@NonNull DocumentFile parentDir, LocalDateTime backupTime)
|
||||
{
|
||||
String folderName = BACKUP_PREFIX + backupTime.format(DATE_FORMATTER);
|
||||
return parentDir.createDirectory(folderName);
|
||||
}
|
||||
|
||||
public static String getBackupName(LocalDateTime backupTime)
|
||||
{
|
||||
String formattedBackupTime = backupTime.format(DATE_FORMATTER);
|
||||
return BACKUP_PREFIX + formattedBackupTime + BACKUP_EXTENSION;
|
||||
}
|
||||
|
||||
public static DocumentFile[] getBackupFolders(DocumentFile parentDir)
|
||||
{
|
||||
List<DocumentFile> backupFolders = new ArrayList<>();
|
||||
for (DocumentFile file : parentDir.listFiles())
|
||||
{
|
||||
if (file.isDirectory() && file.getName() != null && file.getName().startsWith(BACKUP_PREFIX))
|
||||
backupFolders.add(file);
|
||||
}
|
||||
return backupFolders.toArray(new DocumentFile[0]);
|
||||
}
|
||||
|
||||
public static boolean isBackupFolderAvailable(Context context, String storedFolderPath)
|
||||
{
|
||||
return !TextUtils.isEmpty(storedFolderPath) && isFolderWritable(context, storedFolderPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupName;
|
||||
import static app.organicmaps.backup.BackupUtils.getBackupFolders;
|
||||
import static app.organicmaps.util.StorageUtils.copyFileToDocumentFile;
|
||||
import static app.organicmaps.util.StorageUtils.deleteDirectoryRecursive;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import app.organicmaps.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.bookmarks.data.BookmarkSharingResult;
|
||||
import app.organicmaps.bookmarks.data.KmlFileType;
|
||||
import app.organicmaps.util.concurrency.ThreadPool;
|
||||
import app.organicmaps.util.concurrency.UiThread;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class LocalBackupManager implements BookmarkManager.BookmarksSharingListener
|
||||
{
|
||||
public static final String TAG = LocalBackupManager.class.getSimpleName();
|
||||
|
||||
private final Activity activity;
|
||||
private final String backupFolderPath;
|
||||
private final int maxBackups;
|
||||
private Listener listener;
|
||||
|
||||
public LocalBackupManager(@NonNull Activity activity, @NonNull String backupFolderPath, int maxBackups)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.backupFolderPath = backupFolderPath;
|
||||
this.maxBackups = maxBackups;
|
||||
}
|
||||
|
||||
public void doBackup()
|
||||
{
|
||||
BookmarkManager.INSTANCE.addSharingListener(this);
|
||||
|
||||
prepareBookmarkCategoriesForSharing();
|
||||
|
||||
if (listener != null)
|
||||
listener.onBackupStarted();
|
||||
}
|
||||
|
||||
public void setListener(@NonNull Listener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreparedFileForSharing(@NonNull BookmarkSharingResult result)
|
||||
{
|
||||
BookmarkManager.INSTANCE.removeSharingListener(this);
|
||||
|
||||
ThreadPool.getWorker().execute(() -> {
|
||||
ErrorCode errorCode = null;
|
||||
switch (result.getCode())
|
||||
{
|
||||
case BookmarkSharingResult.SUCCESS ->
|
||||
{
|
||||
if (!saveBackup(result))
|
||||
{
|
||||
Logger.e(TAG, "Failed to save backup. See system log above");
|
||||
errorCode = ErrorCode.FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.i(TAG, "Backup was created and saved successfully");
|
||||
}
|
||||
}
|
||||
case BookmarkSharingResult.EMPTY_CATEGORY ->
|
||||
{
|
||||
errorCode = ErrorCode.EMPTY_CATEGORY;
|
||||
Logger.e(TAG, "Failed to create backup. Category is empty");
|
||||
}
|
||||
case BookmarkSharingResult.ARCHIVE_ERROR ->
|
||||
{
|
||||
errorCode = ErrorCode.ARCHIVE_ERROR;
|
||||
Logger.e(TAG, "Failed to create archive of bookmarks");
|
||||
}
|
||||
case BookmarkSharingResult.FILE_ERROR ->
|
||||
{
|
||||
errorCode = ErrorCode.FILE_ERROR;
|
||||
Logger.e(TAG, "Failed create file for archive");
|
||||
}
|
||||
default ->
|
||||
{
|
||||
errorCode = ErrorCode.UNSUPPORTED;
|
||||
Logger.e(TAG, "Failed to create backup. Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode finalErrorCode = errorCode;
|
||||
UiThread.run(() -> {
|
||||
if (listener != null)
|
||||
{
|
||||
if (finalErrorCode == null)
|
||||
listener.onBackupFinished();
|
||||
else
|
||||
listener.onBackupFailed(finalErrorCode);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private boolean saveBackup(@NonNull BookmarkSharingResult result)
|
||||
{
|
||||
boolean isSuccess = false;
|
||||
Uri folderUri = Uri.parse(backupFolderPath);
|
||||
try
|
||||
{
|
||||
DocumentFile parentFolder = DocumentFile.fromTreeUri(activity, folderUri);
|
||||
if (parentFolder != null && parentFolder.canWrite())
|
||||
{
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
DocumentFile backupFolder = BackupUtils.createUniqueBackupFolder(parentFolder, now);
|
||||
if (backupFolder != null)
|
||||
{
|
||||
String backupName = getBackupName(now);
|
||||
DocumentFile backupFile = backupFolder.createFile(result.getMimeType(), backupName);
|
||||
if (backupFile != null && copyFileToDocumentFile(activity, new File(result.getSharingPath()), backupFile))
|
||||
{
|
||||
Logger.i(TAG, "Backup saved to " + backupFile.getUri());
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Failed to create backup folder");
|
||||
}
|
||||
}
|
||||
cleanOldBackups(parentFolder);
|
||||
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to save backup", e);
|
||||
}
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
public void cleanOldBackups(DocumentFile parentDir)
|
||||
{
|
||||
DocumentFile[] backupFolders = getBackupFolders(parentDir);
|
||||
if (backupFolders.length > maxBackups)
|
||||
{
|
||||
Arrays.sort(backupFolders, Comparator.comparing(DocumentFile::getName));
|
||||
for (int i = 0; i < backupFolders.length - maxBackups; i++)
|
||||
{
|
||||
Logger.i(TAG, "Delete old backup " + backupFolders[i].getUri());
|
||||
deleteDirectoryRecursive(backupFolders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareBookmarkCategoriesForSharing()
|
||||
{
|
||||
List<BookmarkCategory> categories = BookmarkManager.INSTANCE.getCategories();
|
||||
long[] categoryIds = new long[categories.size()];
|
||||
for (int i = 0; i < categories.size(); i++)
|
||||
categoryIds[i] = categories.get(i).getId();
|
||||
BookmarkManager.INSTANCE.prepareCategoriesForSharing(categoryIds, KmlFileType.Text);
|
||||
}
|
||||
|
||||
public interface Listener
|
||||
{
|
||||
void onBackupStarted();
|
||||
|
||||
void onBackupFinished();
|
||||
|
||||
void onBackupFailed(ErrorCode errorCode);
|
||||
}
|
||||
|
||||
public enum ErrorCode
|
||||
{
|
||||
EMPTY_CATEGORY,
|
||||
ARCHIVE_ERROR,
|
||||
FILE_ERROR,
|
||||
UNSUPPORTED,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package app.organicmaps.backup;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.getMaxBackups;
|
||||
import static app.organicmaps.backup.BackupUtils.isBackupFolderAvailable;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_FOLDER_PATH_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.BACKUP_INTERVAL_KEY;
|
||||
import static app.organicmaps.settings.BackupSettingsFragment.LAST_BACKUP_TIME_KEY;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
public class PeriodicBackupRunner
|
||||
{
|
||||
private final Activity activity;
|
||||
private static final String TAG = PeriodicBackupRunner.class.getSimpleName();
|
||||
private final SharedPreferences prefs;
|
||||
private boolean alreadyChecked = false;
|
||||
|
||||
public PeriodicBackupRunner(Activity activity)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
}
|
||||
|
||||
public boolean isAlreadyChecked()
|
||||
{
|
||||
return alreadyChecked;
|
||||
}
|
||||
|
||||
public boolean isTimeToBackup()
|
||||
{
|
||||
long intervalMs = getBackupIntervalMs();
|
||||
|
||||
if (intervalMs <= 0)
|
||||
return false;
|
||||
|
||||
long lastBackupTime = prefs.getLong(LAST_BACKUP_TIME_KEY, 0);
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
alreadyChecked = true;
|
||||
|
||||
return (now - lastBackupTime) >= intervalMs;
|
||||
}
|
||||
|
||||
public void doBackup()
|
||||
{
|
||||
String storedFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
|
||||
if (isBackupFolderAvailable(activity, storedFolderPath))
|
||||
{
|
||||
Logger.i(TAG, "Performing periodic backup");
|
||||
performBackup(storedFolderPath, getMaxBackups(prefs));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.w(TAG, "Backup folder is not writable, passed path: " + storedFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
private long getBackupIntervalMs()
|
||||
{
|
||||
String defaultValue = "0";
|
||||
try
|
||||
{
|
||||
return Long.parseLong(prefs.getString(BACKUP_INTERVAL_KEY, defaultValue));
|
||||
} catch (NumberFormatException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void performBackup(String backupFolderPath, int maxBackups)
|
||||
{
|
||||
LocalBackupManager backupManager = new LocalBackupManager(activity, backupFolderPath, maxBackups);
|
||||
backupManager.setListener(new LocalBackupManager.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onBackupStarted()
|
||||
{
|
||||
Logger.i(TAG, "Periodic backup started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFinished()
|
||||
{
|
||||
prefs.edit().putLong(LAST_BACKUP_TIME_KEY, System.currentTimeMillis()).apply();
|
||||
Logger.i(TAG, "Periodic backup finished");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFailed(LocalBackupManager.ErrorCode errorCode)
|
||||
{
|
||||
Logger.e(TAG, "Periodic backup was failed with code: " + errorCode);
|
||||
}
|
||||
});
|
||||
|
||||
backupManager.doBackup();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package app.organicmaps.bookmarks;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -21,6 +20,9 @@ import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.adapter.OnItemClickListener;
|
||||
@@ -279,7 +281,7 @@ public class BookmarkCategoriesFragment extends BaseMwmRecyclerFragment<Bookmark
|
||||
}
|
||||
|
||||
private void showNoFileManagerError() {
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(R.string.error_no_file_manager_app)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
|
||||
@@ -69,7 +69,8 @@ public class Metadata implements Parcelable
|
||||
FMD_OUTDOOR_SEATING(48),
|
||||
FMD_NETWORK(49),
|
||||
FMD_CONTACT_FEDIVERSE(50),
|
||||
FMD_CONTACT_BLUESKY(51);
|
||||
FMD_CONTACT_BLUESKY(51),
|
||||
FMD_PANORAMAX(52);
|
||||
private final int mMetaType;
|
||||
|
||||
MetadataType(int metadataType)
|
||||
|
||||
@@ -41,7 +41,7 @@ public class HelpScreen extends BaseMapScreen
|
||||
{
|
||||
final Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
builder.setTitle(getCarContext().getString(R.string.help));
|
||||
builder.setTitle(getCarContext().getString(R.string.about_help));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ public class SettingsScreen extends BaseMapScreen
|
||||
private Item createHelpItem()
|
||||
{
|
||||
final Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.help));
|
||||
builder.setTitle(getCarContext().getString(R.string.about_help));
|
||||
builder.setOnClickListener(() -> getScreenManager().push(new HelpScreen(getCarContext(), getSurfaceRenderer())));
|
||||
builder.setBrowsable(true);
|
||||
return builder.build();
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.text.style.StyleSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -28,6 +27,7 @@ import app.organicmaps.util.UiUtils;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
|
||||
import app.organicmaps.util.bottomsheet.MenuBottomSheetItem;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -362,10 +362,10 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
|
||||
private class ItemViewHolder extends BaseInnerViewHolder<CountryItem>
|
||||
{
|
||||
private final DownloaderStatusIcon mStatusIcon;
|
||||
private final TextView mName;
|
||||
private final TextView mSubtitle;
|
||||
private final TextView mFoundName;
|
||||
private final TextView mSize;
|
||||
private final MaterialTextView mName;
|
||||
private final MaterialTextView mSubtitle;
|
||||
private final MaterialTextView mFoundName;
|
||||
private final MaterialTextView mSize;
|
||||
|
||||
private void processClick(boolean clickOnStatus)
|
||||
{
|
||||
@@ -510,7 +510,7 @@ class DownloaderAdapter extends RecyclerView.Adapter<DownloaderAdapter.ViewHolde
|
||||
static class HeaderViewHolder extends BaseInnerViewHolder<String>
|
||||
{
|
||||
@NonNull
|
||||
private final TextView mTitle;
|
||||
private final MaterialTextView mTitle;
|
||||
|
||||
HeaderViewHolder(@NonNull View frame)
|
||||
{
|
||||
|
||||
@@ -3,13 +3,14 @@ package app.organicmaps.downloader;
|
||||
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import android.app.ForegroundServiceStartNotAllowedException;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ServiceCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.List;
|
||||
@@ -40,19 +41,11 @@ public class DownloaderService extends Service implements MapManager.StorageCall
|
||||
Logger.i(TAG, "Downloading: " + MapManager.nativeIsDownloading());
|
||||
|
||||
var notification = mNotifier.buildProgressNotification();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
{
|
||||
try
|
||||
{
|
||||
startForeground(DownloaderNotifier.NOTIFICATION_ID, notification);
|
||||
} catch (ForegroundServiceStartNotAllowedException e)
|
||||
{
|
||||
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
|
||||
}
|
||||
} else
|
||||
{
|
||||
startForeground(DownloaderNotifier.NOTIFICATION_ID, notification);
|
||||
}
|
||||
Logger.i(TAG, "Starting Downloader Foreground Service");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
ServiceCompat.startForeground(this, DownloaderNotifier.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
|
||||
else
|
||||
ServiceCompat.startForeground(this, DownloaderNotifier.NOTIFICATION_ID, notification, 0);
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package app.organicmaps.downloader;
|
||||
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
import com.google.android.material.imageview.ShapeableImageView;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.widget.WheelProgressView;
|
||||
import app.organicmaps.util.ThemeUtils;
|
||||
@@ -15,7 +16,7 @@ import app.organicmaps.util.UiUtils;
|
||||
public class DownloaderStatusIcon
|
||||
{
|
||||
private final View mFrame;
|
||||
protected final ImageView mIcon;
|
||||
protected final ShapeableImageView mIcon;
|
||||
private final WheelProgressView mProgress;
|
||||
|
||||
private static final SparseIntArray sIconsCache = new SparseIntArray();
|
||||
|
||||
@@ -43,7 +43,7 @@ public class CopyrightFragment extends BaseMwmFragment
|
||||
{
|
||||
if (!mDelegate.onBackPressed())
|
||||
{
|
||||
((HelpActivity) requireActivity()).stackFragment(HelpFragment.class, getString(R.string.help), null);
|
||||
((HelpActivity) requireActivity()).stackFragment(HelpFragment.class, getString(R.string.about_help), null);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -43,15 +43,21 @@ public class LeftButtonsHolder
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LeftButton getActiveButton()
|
||||
public String getActiveButtonCode()
|
||||
{
|
||||
String activeButtonCode = prefs.getString(leftButtonPreferenceKey, DEFAULT_BUTTON_CODE);
|
||||
if (!TextUtils.isEmpty(activeButtonCode))
|
||||
return availableButtons.get(activeButtonCode);
|
||||
return activeButtonCode;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LeftButton getActiveButton()
|
||||
{
|
||||
return availableButtons.get(getActiveButtonCode());
|
||||
}
|
||||
|
||||
public Collection<LeftButton> getAllButtons()
|
||||
{
|
||||
return availableButtons.values();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package app.organicmaps.location;
|
||||
|
||||
import android.app.ForegroundServiceStartNotAllowedException;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.location.Location;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
@@ -17,6 +17,7 @@ import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationChannelCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.app.ServiceCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import app.organicmaps.MwmActivity;
|
||||
import app.organicmaps.MwmApplication;
|
||||
@@ -158,21 +159,11 @@ public class TrackRecordingService extends Service implements LocationListener
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Starting foreground service");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
{
|
||||
try
|
||||
{
|
||||
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
} catch (ForegroundServiceStartNotAllowedException e)
|
||||
{
|
||||
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
|
||||
}
|
||||
}
|
||||
Logger.i(TAG, "Starting Track Recording Foreground service");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
ServiceCompat.startForeground(this, TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
|
||||
else
|
||||
{
|
||||
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
}
|
||||
ServiceCompat.startForeground(this, TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build(), 0);
|
||||
|
||||
final LocationHelper locationHelper = LocationHelper.from(this);
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ public class LayerBottomSheetItem
|
||||
case SUBWAY:
|
||||
disabledResource = R.attr.subwayMenuDisabled;
|
||||
enabledResource = R.attr.subwayMenuEnabled;
|
||||
buttonTextResource = R.string.button_layer_subway;
|
||||
buttonTextResource = R.string.subway;
|
||||
break;
|
||||
case ISOLINES:
|
||||
disabledResource = R.attr.isoLinesMenuDisabled;
|
||||
|
||||
@@ -43,6 +43,7 @@ public class LayersAdapter extends RecyclerView.Adapter<LayerHolder>
|
||||
boolean isEnabled = item.getMode().isEnabled(context);
|
||||
|
||||
holder.mButton.setSelected(isEnabled);
|
||||
holder.mButton.setContentDescription(context.getString(item.getTitle()));
|
||||
holder.mTitle.setSelected(isEnabled);
|
||||
holder.mTitle.setText(item.getTitle());
|
||||
boolean isNewLayer = SharedPropertiesUtils.shouldShowNewMarkerForLayerMode(context,
|
||||
|
||||
@@ -213,11 +213,13 @@ public class MapButtonsController extends Fragment
|
||||
)
|
||||
{
|
||||
leftButtonView.setImageResource(R.drawable.ic_christmas_tree);
|
||||
leftButtonView.setContentDescription(getString(R.string.about_help));
|
||||
leftButtonView.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
|
||||
}
|
||||
else
|
||||
{
|
||||
mLeftButton.drawIcon(leftButtonView);
|
||||
leftButtonView.setContentDescription(mLeftButton.getPrefsName());
|
||||
leftButtonView.setOnClickListener((v) -> mLeftButton.onClick(leftButtonView));
|
||||
}
|
||||
// else
|
||||
|
||||
@@ -266,7 +266,8 @@ public class NavigationController implements TrafficManager.TrafficCallback,
|
||||
mSpeedLimit.setSpeedLimit(0, false);
|
||||
return;
|
||||
}
|
||||
final boolean speedLimitExceeded = info.speedLimitMps < location.getSpeed();
|
||||
mSpeedLimit.setSpeedLimit(StringUtils.nativeFormatSpeed(info.speedLimitMps), speedLimitExceeded);
|
||||
final int fSpeedLimit = StringUtils.nativeFormatSpeed(info.speedLimitMps);
|
||||
final boolean speedLimitExceeded = fSpeedLimit < StringUtils.nativeFormatSpeed(location.getSpeed());
|
||||
mSpeedLimit.setSpeedLimit(fSpeedLimit, speedLimitExceeded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static app.organicmaps.util.Constants.Vendor.XIAOMI;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ForegroundServiceStartNotAllowedException;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.location.Location;
|
||||
@@ -27,6 +27,7 @@ import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationChannelCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.app.ServiceCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import app.organicmaps.Framework;
|
||||
@@ -224,21 +225,11 @@ public class NavigationService extends Service implements LocationListener
|
||||
return START_NOT_STICKY; // The service will be stopped by stopSelf().
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Starting foreground");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
{
|
||||
try
|
||||
{
|
||||
startForeground(NavigationService.NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
} catch (ForegroundServiceStartNotAllowedException e)
|
||||
{
|
||||
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
|
||||
}
|
||||
}
|
||||
Logger.i(TAG, "Starting Navigation Foreground service");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
ServiceCompat.startForeground(this, NavigationService.NOTIFICATION_ID, getNotificationBuilder(this).build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
|
||||
else
|
||||
{
|
||||
startForeground(NavigationService.NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
}
|
||||
ServiceCompat.startForeground(this, NavigationService.NOTIFICATION_ID, getNotificationBuilder(this).build(), 0);
|
||||
|
||||
final LocationHelper locationHelper = LocationHelper.from(this);
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.imageview.ShapeableImageView;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
|
||||
import app.organicmaps.Framework;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.bookmarks.data.DistanceAndAzimut;
|
||||
@@ -67,21 +70,21 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
||||
@NonNull
|
||||
private final ImageView mAltitudeChart;
|
||||
@NonNull
|
||||
private final TextView mTime;
|
||||
private final MaterialTextView mTime;
|
||||
@NonNull
|
||||
private final TextView mAltitudeDifference;
|
||||
private final MaterialTextView mAltitudeDifference;
|
||||
@NonNull
|
||||
private final TextView mTimeVehicle;
|
||||
@Nullable
|
||||
private final TextView mArrival;
|
||||
private final MaterialTextView mArrival;
|
||||
@NonNull
|
||||
private final View mActionFrame;
|
||||
@NonNull
|
||||
private final TextView mActionMessage;
|
||||
private final MaterialTextView mActionMessage;
|
||||
@NonNull
|
||||
private final View mActionButton;
|
||||
@NonNull
|
||||
private final ImageView mActionIcon;
|
||||
private final ShapeableImageView mActionIcon;
|
||||
@NonNull
|
||||
private final DotDividerItemDecoration mTransitViewDecorator;
|
||||
|
||||
@@ -98,10 +101,10 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
||||
TextView error = (TextView) getViewById(activity, frame, R.id.error);
|
||||
Button start = (Button) getViewById(activity, frame, R.id.start);
|
||||
ImageView altitudeChart = (ImageView) getViewById(activity, frame, R.id.altitude_chart);
|
||||
TextView time = (TextView) getViewById(activity, frame, R.id.time);
|
||||
MaterialTextView time = (MaterialTextView) getViewById(activity, frame, R.id.time);
|
||||
TextView timeVehicle = (TextView) getViewById(activity, frame, R.id.time_vehicle);
|
||||
TextView altitudeDifference = (TextView) getViewById(activity, frame, R.id.altitude_difference);
|
||||
TextView arrival = (TextView) getViewById(activity, frame, R.id.arrival);
|
||||
MaterialTextView altitudeDifference = (MaterialTextView) getViewById(activity, frame, R.id.altitude_difference);
|
||||
MaterialTextView arrival = (MaterialTextView) getViewById(activity, frame, R.id.arrival);
|
||||
View actionFrame = getViewById(activity, frame, R.id.routing_action_frame);
|
||||
|
||||
return new RoutingBottomMenuController(activity, altitudeChartFrame, timeElevationLine, transitFrame,
|
||||
@@ -124,10 +127,10 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
||||
@NonNull TextView error,
|
||||
@NonNull Button start,
|
||||
@NonNull ImageView altitudeChart,
|
||||
@NonNull TextView time,
|
||||
@NonNull TextView altitudeDifference,
|
||||
@NonNull MaterialTextView time,
|
||||
@NonNull MaterialTextView altitudeDifference,
|
||||
@NonNull TextView timeVehicle,
|
||||
@Nullable TextView arrival,
|
||||
@Nullable MaterialTextView arrival,
|
||||
@NonNull View actionFrame,
|
||||
@Nullable RoutingBottomMenuListener listener)
|
||||
{
|
||||
@@ -198,12 +201,12 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
||||
|
||||
scrollToBottom(rv);
|
||||
|
||||
TextView totalTimeView = mTransitFrame.findViewById(R.id.total_time);
|
||||
MaterialTextView totalTimeView = mTransitFrame.findViewById(R.id.total_time);
|
||||
totalTimeView.setText(RoutingController.formatRoutingTime(mContext, info.getTotalTime(),
|
||||
R.dimen.text_size_routing_number));
|
||||
View dotView = mTransitFrame.findViewById(R.id.dot);
|
||||
View pedestrianIcon = mTransitFrame.findViewById(R.id.pedestrian_icon);
|
||||
TextView distanceView = mTransitFrame.findViewById(R.id.total_distance);
|
||||
MaterialTextView distanceView = mTransitFrame.findViewById(R.id.total_distance);
|
||||
UiUtils.showIf(info.getTotalPedestrianTimeInSec() > 0, dotView, pedestrianIcon, distanceView);
|
||||
distanceView.setText(info.getTotalPedestrianDistance() + " " + info.getTotalPedestrianDistanceUnits());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
package app.organicmaps.settings;
|
||||
|
||||
import static app.organicmaps.backup.BackupUtils.formatReadableFolderPath;
|
||||
import static app.organicmaps.backup.BackupUtils.getMaxBackups;
|
||||
import static app.organicmaps.backup.BackupUtils.isBackupFolderAvailable;
|
||||
import static app.organicmaps.util.StorageUtils.isFolderWritable;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.backup.LocalBackupManager;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
|
||||
public class BackupSettingsFragment
|
||||
extends BaseXmlSettingsFragment
|
||||
{
|
||||
private ActivityResultLauncher<Intent> folderPickerLauncher;
|
||||
|
||||
private static final String TAG = LocalBackupManager.class.getSimpleName();
|
||||
public static final String BACKUP_FOLDER_PATH_KEY = "backup_location";
|
||||
public static final String LAST_BACKUP_TIME_KEY = "last_backup_time";
|
||||
private static final String BACKUP_NOW_KEY = "backup_now";
|
||||
public static final String BACKUP_INTERVAL_KEY = "backup_history_interval";
|
||||
public static final String MAX_BACKUPS_KEY = "backup_history_count";
|
||||
public static final int MAX_BACKUPS_DEFAULT_COUNT = 10;
|
||||
public static final String DEFAULT_BACKUP_INTERVAL = "86400000"; // 24 hours in ms
|
||||
|
||||
private LocalBackupManager mBackupManager;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
@Override
|
||||
protected int getXmlResources()
|
||||
{
|
||||
return R.xml.prefs_backup;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference backupLocationOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
ListPreference backupIntervalOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference maxBackupsOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference backupNowOption;
|
||||
@NonNull
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
Preference advancedCategory;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
folderPickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
boolean isSuccess = false;
|
||||
|
||||
String lastFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
|
||||
if (result.getResultCode() == Activity.RESULT_OK)
|
||||
{
|
||||
Intent data = result.getData();
|
||||
Logger.i(TAG, "Folder selection result: " + data);
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
Uri uri = data.getData();
|
||||
if (uri != null)
|
||||
{
|
||||
takePersistableUriPermission(uri);
|
||||
Logger.i(TAG, "Backup location changed to " + uri);
|
||||
prefs.edit().putString(BACKUP_FOLDER_PATH_KEY, uri.toString()).apply();
|
||||
setFormattedBackupPath(uri);
|
||||
|
||||
runBackup();
|
||||
|
||||
isSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.w(TAG, "Folder selection result is null");
|
||||
}
|
||||
}
|
||||
else if (result.getResultCode() == Activity.RESULT_CANCELED)
|
||||
{
|
||||
Logger.w(TAG, "User canceled folder selection");
|
||||
if (TextUtils.isEmpty(lastFolderPath))
|
||||
{
|
||||
prefs.edit().putString(BACKUP_FOLDER_PATH_KEY, null).apply();
|
||||
Logger.i(TAG, "Backup settings reset");
|
||||
initBackupLocationOption();
|
||||
}
|
||||
else if (isFolderWritable(requireActivity(), lastFolderPath))
|
||||
{
|
||||
Logger.i(TAG, "Backup location not changed, using previous value " + lastFolderPath);
|
||||
isSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Backup location not changed, but last folder is not writable: " + lastFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
resetLastBackupTime();
|
||||
updateStatusSummaryOption();
|
||||
|
||||
Logger.i(TAG, "Folder selection result: " + isSuccess);
|
||||
applyAdvancedSettings(isSuccess);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
|
||||
{
|
||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||
backupLocationOption = findPreference(BACKUP_FOLDER_PATH_KEY);
|
||||
backupIntervalOption = findPreference(BACKUP_INTERVAL_KEY);
|
||||
maxBackupsOption = findPreference(MAX_BACKUPS_KEY);
|
||||
backupNowOption = findPreference(BACKUP_NOW_KEY);
|
||||
|
||||
initBackupLocationOption();
|
||||
initBackupIntervalOption();
|
||||
initMaxBackupsOption();
|
||||
initBackupNowOption();
|
||||
}
|
||||
|
||||
|
||||
private void initBackupLocationOption()
|
||||
{
|
||||
String storedFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
boolean isEnabled = false;
|
||||
if (!TextUtils.isEmpty(storedFolderPath))
|
||||
{
|
||||
if (isFolderWritable(requireContext(), storedFolderPath))
|
||||
{
|
||||
setFormattedBackupPath(Uri.parse(storedFolderPath));
|
||||
isEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.e(TAG, "Backup location is not available, path: " + storedFolderPath);
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_missing_folder));
|
||||
backupLocationOption.setSummary(requireContext().getString(R.string.pref_backup_now_summary_folder_unavailable));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupLocationOption.setSummary(requireContext().getString(R.string.pref_backup_location_summary_initial));
|
||||
}
|
||||
|
||||
applyAdvancedSettings(isEnabled);
|
||||
|
||||
backupLocationOption.setOnPreferenceClickListener(preference -> {
|
||||
launchFolderPicker();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setFormattedBackupPath(@NonNull Uri uri)
|
||||
{
|
||||
backupLocationOption.setSummary(formatReadableFolderPath(requireContext(), uri));
|
||||
}
|
||||
|
||||
private void initBackupIntervalOption()
|
||||
{
|
||||
String backupInterval = prefs.getString(BACKUP_INTERVAL_KEY, DEFAULT_BACKUP_INTERVAL);
|
||||
|
||||
CharSequence entry = getEntryForValue(backupIntervalOption, backupInterval);
|
||||
if (entry != null)
|
||||
backupIntervalOption.setSummary(entry);
|
||||
|
||||
backupIntervalOption.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
CharSequence newEntry = getEntryForValue(backupIntervalOption, newValue.toString());
|
||||
Logger.i(TAG, "auto backup interval changed to " + newEntry);
|
||||
if (newEntry != null)
|
||||
backupIntervalOption.setSummary(newEntry);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initMaxBackupsOption()
|
||||
{
|
||||
maxBackupsOption.setSummary(String.valueOf(getMaxBackups(prefs)));
|
||||
|
||||
maxBackupsOption.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
maxBackupsOption.setSummary(newValue.toString());
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initBackupNowOption()
|
||||
{
|
||||
updateStatusSummaryOption();
|
||||
backupNowOption.setOnPreferenceClickListener(preference -> {
|
||||
runBackup();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateStatusSummaryOption()
|
||||
{
|
||||
long lastBackupTime = prefs.getLong(LAST_BACKUP_TIME_KEY, 0L);
|
||||
|
||||
String summary;
|
||||
if (lastBackupTime > 0)
|
||||
{
|
||||
String time = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(lastBackupTime);
|
||||
summary = requireContext().getString(R.string.pref_backup_status_summary_success) + ": " + time;
|
||||
}
|
||||
else
|
||||
{
|
||||
summary = requireContext().getString(R.string.pref_backup_now_summary);
|
||||
}
|
||||
|
||||
backupNowOption.setSummary(summary);
|
||||
}
|
||||
|
||||
private void resetLastBackupTime()
|
||||
{
|
||||
prefs.edit().remove(LAST_BACKUP_TIME_KEY).apply();
|
||||
}
|
||||
|
||||
private void applyAdvancedSettings(boolean isBackupEnabled)
|
||||
{
|
||||
backupIntervalOption.setVisible(isBackupEnabled);
|
||||
maxBackupsOption.setVisible(isBackupEnabled);
|
||||
backupNowOption.setVisible(isBackupEnabled);
|
||||
}
|
||||
|
||||
|
||||
private void runBackup()
|
||||
{
|
||||
String currentFolderPath = prefs.getString(BACKUP_FOLDER_PATH_KEY, null);
|
||||
if (!TextUtils.isEmpty(currentFolderPath))
|
||||
{
|
||||
if (isFolderWritable(requireContext(), currentFolderPath))
|
||||
{
|
||||
mBackupManager = new LocalBackupManager(requireActivity(), currentFolderPath, getMaxBackups(prefs));
|
||||
mBackupManager.setListener(new LocalBackupManager.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onBackupStarted()
|
||||
{
|
||||
Logger.i(TAG, "Manual backup started");
|
||||
|
||||
backupNowOption.setEnabled(false);
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFinished()
|
||||
{
|
||||
Logger.i(TAG, "Manual backup successful");
|
||||
|
||||
backupNowOption.setEnabled(true);
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_ok);
|
||||
|
||||
prefs.edit().putLong(LAST_BACKUP_TIME_KEY, System.currentTimeMillis()).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackupFailed(LocalBackupManager.ErrorCode errorCode)
|
||||
{
|
||||
String errorMessage;
|
||||
if (errorCode == LocalBackupManager.ErrorCode.EMPTY_CATEGORY)
|
||||
{
|
||||
errorMessage = requireContext().getString(R.string.pref_backup_now_summary_empty_lists);
|
||||
Logger.i(TAG, "Nothing to backup");
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = requireContext().getString(R.string.pref_backup_now_summary_failed);
|
||||
Logger.e(TAG, "Manual backup has failed: " + errorCode);
|
||||
}
|
||||
|
||||
backupNowOption.setEnabled(true);
|
||||
backupNowOption.setSummary(errorMessage);
|
||||
|
||||
if (errorCode != LocalBackupManager.ErrorCode.EMPTY_CATEGORY)
|
||||
{
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_with_logs));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mBackupManager.doBackup();
|
||||
}
|
||||
else
|
||||
{
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_folder_unavailable);
|
||||
showBackupErrorAlertDialog(requireContext().getString(R.string.dialog_report_error_missing_folder));
|
||||
Logger.e(TAG, "Manual backup error: folder " + currentFolderPath + " unavailable");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupNowOption.setSummary(R.string.pref_backup_now_summary_folder_unavailable);
|
||||
Logger.e(TAG, "Manual backup error: no folder selected");
|
||||
}
|
||||
}
|
||||
|
||||
private void launchFolderPicker()
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
|
||||
|
||||
PackageManager packageManager = requireActivity().getPackageManager();
|
||||
if (intent.resolveActivity(packageManager) != null)
|
||||
folderPickerLauncher.launch(intent);
|
||||
else
|
||||
showNoFileManagerError();
|
||||
}
|
||||
|
||||
private void showNoFileManagerError()
|
||||
{
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(R.string.error_no_file_manager_app)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showBackupErrorAlertDialog(String message)
|
||||
{
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.pref_backup_now_summary_failed)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
private void takePersistableUriPermission(Uri uri)
|
||||
{
|
||||
requireContext().getContentResolver().takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CharSequence getEntryForValue(@NonNull ListPreference listPref, @NonNull CharSequence value)
|
||||
{
|
||||
CharSequence[] entryValues = listPref.getEntryValues();
|
||||
CharSequence[] entries = listPref.getEntries();
|
||||
|
||||
if (entryValues == null || entries == null)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < entryValues.length; i++)
|
||||
{
|
||||
if (entryValues[i].equals(value))
|
||||
return entries[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -184,15 +184,15 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
|
||||
{
|
||||
getSettingsActivity().stackFragment(VoiceInstructionsSettingsFragment.class, getString(R.string.pref_tts_enable_title), null);
|
||||
}
|
||||
else if (key.equals(getString(R.string.pref_help)))
|
||||
{
|
||||
startActivity(new Intent(requireActivity(), HelpActivity.class));
|
||||
}
|
||||
else if (key.equals(getString(R.string.pref_map_locale)))
|
||||
{
|
||||
LanguagesFragment langFragment = (LanguagesFragment)getSettingsActivity().stackFragment(LanguagesFragment.class, getString(R.string.change_map_locale), null);
|
||||
langFragment.setListener(this);
|
||||
}
|
||||
else if (key.equals(getString(R.string.pref_backup)))
|
||||
{
|
||||
getSettingsActivity().stackFragment(BackupSettingsFragment.class, getString(R.string.pref_backup_title), null);
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.organicmaps.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -10,10 +11,13 @@ import android.provider.DocumentsContract;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import app.organicmaps.BuildConfig;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
@@ -323,4 +327,76 @@ public class StorageUtils
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copyFileToDocumentFile(
|
||||
@NonNull Activity activity,
|
||||
@NonNull File sourceFile,
|
||||
@NonNull DocumentFile targetFile
|
||||
)
|
||||
{
|
||||
try (
|
||||
InputStream in = new FileInputStream(sourceFile);
|
||||
OutputStream out = activity.getContentResolver().openOutputStream(targetFile.getUri())
|
||||
)
|
||||
{
|
||||
if (out == null)
|
||||
{
|
||||
Logger.e(TAG, "Failed to open output stream for " + targetFile.getUri());
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
|
||||
while ((length = in.read(buffer)) > 0)
|
||||
out.write(buffer, 0, length);
|
||||
|
||||
out.flush();
|
||||
return true;
|
||||
} catch (IOException e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to copy file from " + sourceFile.getAbsolutePath() + " to " + targetFile.getUri(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteDirectoryRecursive(@NonNull DocumentFile dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (DocumentFile file : dir.listFiles())
|
||||
{
|
||||
if (file.isDirectory())
|
||||
deleteDirectoryRecursive(file);
|
||||
else
|
||||
file.delete();
|
||||
}
|
||||
dir.delete();
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to delete directory: " + dir.getUri(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFolderWritable(Context context, String folderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri folderUri = Uri.parse(folderPath);
|
||||
DocumentFile folder = DocumentFile.fromTreeUri(context, folderUri);
|
||||
if (folder != null && folder.canWrite())
|
||||
{
|
||||
DocumentFile tempFile = folder.createFile("application/octet-stream", "temp_file");
|
||||
if (tempFile != null)
|
||||
{
|
||||
tempFile.delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.e(TAG, "Failed to check if folder is writable: " + folderPath, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ public final class PlacePageButtons extends Fragment implements Observer<List<Pl
|
||||
TextView title = parent.findViewById(R.id.title);
|
||||
|
||||
title.setText(current.getTitle());
|
||||
parent.setContentDescription(getString(current.getTitle()));
|
||||
@AttrRes final int tint = current.getType() == ButtonType.BOOKMARK_DELETE
|
||||
? R.attr.iconTintActive
|
||||
: R.attr.iconTint;
|
||||
|
||||
@@ -56,6 +56,9 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
|
||||
private View mWikimedia;
|
||||
private TextView mTvWikimedia;
|
||||
|
||||
private View mPanoramax;
|
||||
private TextView mTvPanoramax;
|
||||
|
||||
private PlacePageViewModel mViewModel;
|
||||
private MapObject mMapObject;
|
||||
|
||||
@@ -163,6 +166,11 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
|
||||
mTvLinePage = mFrame.findViewById(R.id.tv__place_line_page);
|
||||
mLinePage.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_CONTACT_LINE));
|
||||
mLinePage.setOnLongClickListener((v) -> copyUrl(mLinePage, Metadata.MetadataType.FMD_CONTACT_LINE));
|
||||
|
||||
mPanoramax = mFrame.findViewById(R.id.ll__place_panoramax);
|
||||
mTvPanoramax = mFrame.findViewById(R.id.tv__place_panoramax);
|
||||
mPanoramax.setOnClickListener((v) -> openUrl(Metadata.MetadataType.FMD_PANORAMAX));
|
||||
mTvPanoramax.setOnLongClickListener((v) -> copyUrl(mPanoramax, Metadata.MetadataType.FMD_PANORAMAX));
|
||||
}
|
||||
|
||||
private void openUrl(Metadata.MetadataType type)
|
||||
@@ -226,6 +234,9 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
|
||||
|
||||
final String line = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_LINE);
|
||||
refreshMetadataOrHide(line, mLinePage, mTvLinePage);
|
||||
|
||||
final String panoramax = mMapObject.getMetadata(Metadata.MetadataType.FMD_PANORAMAX);
|
||||
refreshMetadataOrHide(panoramax, mPanoramax, mTvPanoramax);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="144dp"
|
||||
android:height="144dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
android:viewportWidth="144"
|
||||
android:viewportHeight="144">
|
||||
<path
|
||||
android:pathData="M28.2,58.5q-1.6,0 -2.87,-0.74 -1.26,-0.73 -1.98,-2.09t-0.72,-3.21q0,-1.87 0.72,-3.23t1.98,-2.1q1.27,-0.72 2.87,-0.72 1.03,0 1.91,0.3 0.88,0.31 1.56,0.88 0.68,0.56 1.11,1.36 0.44,0.79 0.58,1.77L30.9,50.72q-0.1,-0.52 -0.34,-0.92 -0.23,-0.4 -0.58,-0.68t-0.8,-0.43q-0.43,-0.15 -0.96,-0.15 -1,0 -1.7,0.48t-1.08,1.36 -0.38,2.08 0.37,2.07 1.09,1.35 1.7,0.48q0.53,0 0.97,-0.14t0.78,-0.43 0.59,-0.68 0.35,-0.91h2.44q-0.14,0.97 -0.58,1.76 -0.43,0.8 -1.11,1.36t-1.57,0.88q-0.87,0.3 -1.9,0.3m10.56,0q-1.25,0 -2.2,-0.55 -0.95,-0.54 -1.48,-1.51 -0.53,-0.98 -0.53,-2.28t0.53,-2.27 1.48,-1.52 2.2,-0.55q1.27,0 2.21,0.55 0.95,0.54 1.48,1.52 0.54,0.97 0.54,2.27t-0.54,2.28 -1.48,1.51 -2.2,0.55m0,-1.88q0.57,0 1,-0.3 0.42,-0.3 0.65,-0.84 0.24,-0.55 0.24,-1.32t-0.24,-1.32q-0.23,-0.55 -0.66,-0.84 -0.42,-0.3 -0.99,-0.3 -0.55,0 -0.98,0.3 -0.42,0.29 -0.66,0.84 -0.23,0.55 -0.23,1.32 0,0.78 0.23,1.33 0.24,0.54 0.66,0.84t0.98,0.29m5.82,1.69L44.58,46.6h3.53l1.93,5.45 0.29,0.91 0.33,1.13q0.18,0.58 0.32,1.11l0.24,0.9h-0.6l0.23,-0.9 0.32,-1.11 0.34,-1.13 0.27,-0.9 1.91,-5.46h3.53v11.7h-2.37v-5.56l0.01,-0.93 0.03,-1.16 0.03,-1.25 0.03,-1.2h0.29l-0.38,1.27 -0.37,1.27 -0.34,1.13 -0.28,0.87 -1.98,5.57h-1.96l-2,-5.57 -0.3,-0.87 -0.35,-1.13 -0.38,-1.27 -0.39,-1.27h0.35l0.02,1.2 0.03,1.25 0.03,1.16 0.01,0.93v5.57zM61.72,58.45q-0.82,0 -1.47,-0.28 -0.64,-0.27 -1.01,-0.82 -0.37,-0.56 -0.37,-1.39 0,-0.7 0.26,-1.16 0.26,-0.47 0.7,-0.75 0.46,-0.3 1.04,-0.44 0.6,-0.15 1.24,-0.2 0.76,-0.09 1.2,-0.16 0.46,-0.07 0.65,-0.2 0.2,-0.14 0.2,-0.4v-0.06q0,-0.3 -0.17,-0.53 -0.16,-0.24 -0.47,-0.37 -0.3,-0.14 -0.72,-0.14t-0.75,0.14 -0.52,0.38q-0.18,0.24 -0.22,0.56h-2.17q0.05,-0.85 0.5,-1.48 0.46,-0.63 1.27,-0.97 0.82,-0.35 1.96,-0.35 0.85,0 1.52,0.2 0.67,0.19 1.12,0.56 0.47,0.37 0.7,0.9 0.24,0.52 0.24,1.19v5.63h-2.27v-1.17h-0.03q-0.22,0.4 -0.54,0.7t-0.79,0.45 -1.1,0.16m0.65,-1.61q0.56,0 0.96,-0.2t0.63,-0.57 0.22,-0.8v-0.83l-0.27,0.11 -0.39,0.1 -0.48,0.08 -0.53,0.09q-0.4,0.06 -0.72,0.2 -0.33,0.12 -0.52,0.34 -0.18,0.21 -0.18,0.54 0,0.3 0.15,0.5 0.16,0.22 0.45,0.33t0.68,0.1m5.98,4.75L68.35,50.01h2.29v1.12h0.02q0.26,-0.43 0.62,-0.72 0.37,-0.29 0.83,-0.43 0.48,-0.15 1.01,-0.15 1.06,0 1.86,0.55 0.81,0.55 1.26,1.52 0.46,0.97 0.46,2.25 0,1.3 -0.45,2.27 -0.45,0.98 -1.25,1.52t-1.9,0.54q-0.54,0 -1,-0.16 -0.46,-0.15 -0.82,-0.47t-0.59,-0.79h-0.02v4.53zM72.51,56.58q0.56,0 0.97,-0.28 0.42,-0.29 0.65,-0.83 0.23,-0.55 0.23,-1.33t-0.23,-1.32 -0.65,-0.83q-0.4,-0.3 -0.97,-0.3 -0.59,0 -1.03,0.31 -0.44,0.3 -0.69,0.85 -0.23,0.54 -0.23,1.29 0,0.74 0.23,1.29 0.25,0.55 0.69,0.85 0.45,0.3 1.03,0.3m9.18,1.92q-1.08,0 -1.92,-0.33 -0.84,-0.34 -1.35,-0.97 -0.5,-0.62 -0.58,-1.51h2.28q0.07,0.54 0.46,0.85 0.4,0.3 1.07,0.3 0.64,0 1,-0.24 0.37,-0.24 0.37,-0.63 0,-0.33 -0.28,-0.53 -0.27,-0.2 -0.79,-0.3l-1.45,-0.29q-1.21,-0.23 -1.84,-0.84 -0.63,-0.62 -0.63,-1.58 0,-0.78 0.43,-1.37t1.21,-0.91q0.8,-0.33 1.88,-0.33t1.88,0.35 1.25,0.97q0.46,0.63 0.48,1.49h-2.14q-0.01,-0.5 -0.4,-0.83 -0.38,-0.33 -1,-0.33 -0.6,0 -0.94,0.26 -0.34,0.25 -0.34,0.62 0,0.32 0.27,0.52t0.74,0.31l1.57,0.3q1.26,0.25 1.85,0.8 0.6,0.56 0.6,1.48 0,0.82 -0.48,1.44 -0.46,0.62 -1.3,0.96 -0.82,0.34 -1.9,0.34"
|
||||
android:pathData="M40.34 29.42a41.6 41.6 0 0 0-19.66 5.03q-8.77 4.85-13.8 14.42-5.05 9.57-5.05 23.18 0 13.4 5.04 22.88a36 36 0 0 0 13.71 14.51q8.67 5.04 19.76 5.04 7.95 0 14.2-2.42A33.6 33.6 0 0 0 72.8 96.24a33 33 0 0 0 3.43-11.09l-17.64-0.1q-0.6 3.33-2.22 5.95a12 12 0 0 1-3.83 4.33 19 19 0 0 1-5.44 2.73q-2.93 0.9-6.45 0.9-6.15 0-10.99-3.02-4.82-3.03-7.46-9.07-2.61-6.05-2.62-14.82 0-8.56 2.62-14.61 2.63-6.06 7.46-9.28 4.64-3.22 11.09-3.22 3.53 0 6.55 1 3.13 1.01 5.44 3.03a14.5 14.5 0 0 1 3.83 4.63q1.51 2.63 2.02 6.05h17.64a37 37 0 0 0-3.83-12.8 30 30 0 0 0-7.76-9.47 34 34 0 0 0-10.99-5.95 43 43 0 0 0-13.3-2.01m71.29 21.16q-9.37 0-16.23 4.03a26.6 26.6 0 0 0-10.59 11.2q-3.62 7.14-3.62 16.82 0 9.48 3.62 16.73a28 28 0 0 0 10.69 11.2q6.84 4.01 16.28 4.02 9.24 0 16.07-4.03a27.4 27.4 0 0 0 10.59-11.19q3.72-7.25 3.73-16.73 0-9.87-3.73-16.93a27.6 27.6 0 0 0-10.59-11.09q-6.86-4.03-16.22-4.03m0.2 13.1a9.8 9.8 0 0 1 7.05 2.42 16 16 0 0 1 4.34 6.76q1.5 4.23 1.5 9.57a33 33 0 0 1-1.5 9.68 14 14 0 0 1-4.44 6.65q-2.72 2.52-7.05 2.52-4.24 0-7.26-2.52a15 15 0 0 1-4.44-6.65 31 31 0 0 1-1.4-9.68q0-5.34 1.4-9.57 1.52-4.24 4.44-6.76 2.92-2.41 7.36-2.42"
|
||||
android:fillColor="#fff"/>
|
||||
</vector>
|
||||
|
||||
15
android/app/src/main/res/drawable/ic_panoramax.xml
Normal file
@@ -23,7 +23,7 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_marginEnd="@dimen/margin_base"
|
||||
android:layout_gravity="center_vertical" >
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -33,7 +33,7 @@
|
||||
tools:text="5 h 55 min • 1555km"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="5 h 55 min • 1555km"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/altitude_chart_time_distance_height"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_marginEnd="@dimen/margin_base"
|
||||
android:layout_gravity="center_vertical" >
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -33,7 +33,7 @@
|
||||
tools:text="5 h 55 min • 1555km"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -64,7 +64,7 @@
|
||||
tools:text="5 h 55 min • 1555km"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/arrival"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:id="@+id/numbers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -13,7 +13,7 @@
|
||||
android:ellipsize="end"
|
||||
android:layout_marginBottom="4dp"
|
||||
tools:text="5 h 55 min • 1555km"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/arrival"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -23,7 +23,7 @@
|
||||
tools:text="Arrival 13:03"
|
||||
style="@style/MwmWidget.TextView.PlanDetail.Number.Secondary"
|
||||
android:textSize="@dimen/text_size_routing_plan_detail_arrival"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<include
|
||||
layout="@layout/toolbar_extended"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="@dimen/settings_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?actionBarSize"
|
||||
@@ -18,6 +18,6 @@
|
||||
style="@style/MwmWidget.FrameLayout.Elevation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="@dimen/margin_half"
|
||||
android:layout_marginBottom="@dimen/margin_half">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -31,7 +31,7 @@
|
||||
tools:text="5 h 55 min • 1555km"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/altitude_chart_time_distance_height"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
android:layout_marginEnd="@dimen/margin_base"
|
||||
android:layout_centerVertical="true"/>
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -37,7 +37,7 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/downloader_status_frame"
|
||||
android:layout_toStartOf="@id/size">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/found_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -46,7 +46,7 @@
|
||||
tools:text="Крымск"
|
||||
tools:background="#60FF00FF"/>
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -54,7 +54,7 @@
|
||||
tools:text="Донецкая область"
|
||||
tools:background="#40FF0000"/>
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:background="#400000FF">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
wheel:wheelSecondaryColor="?dividerHorizontal"
|
||||
wheel:wheelThickness="@dimen/margin_eighth"/>
|
||||
|
||||
<ImageView
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/downloader_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:textColorHint="?android:textColorSecondary"
|
||||
app:endIconMode="custom"
|
||||
app:endIconCheckable="false"
|
||||
app:endIconContentDescription="@string/clear"
|
||||
app:endIconDrawable="@drawable/ic_clear_rounded"
|
||||
app:endIconTint="?android:textColorSecondary">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
@@ -79,6 +81,7 @@
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignEnd="@id/divideerrr"
|
||||
android:background="?clickableBackground"
|
||||
android:contentDescription="@string/bookmark_color"
|
||||
android:padding="@dimen/margin_half"
|
||||
tools:src="@drawable/ic_bookmark_none" />
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:textAppearance"
|
||||
android:text="@string/elevation_profile_time" />
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/help_button"
|
||||
style="@style/MwmWidget.MapButton.Square"
|
||||
android:contentDescription="@string/help"
|
||||
android:tint="@null"
|
||||
app:shapeAppearanceOverlay="@style/MwmWidget.MapButton.Square"
|
||||
app:srcCompat="@drawable/ic_question_mark" />
|
||||
@@ -21,4 +21,5 @@
|
||||
<include layout="@layout/place_page_line" />
|
||||
<include layout="@layout/place_page_bluesky" />
|
||||
<include layout="@layout/place_page_wikimedia" />
|
||||
<include layout="@layout/place_page_panoramax" />
|
||||
</LinearLayout>
|
||||
25
android/app/src/main/res/layout/place_page_panoramax.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/ll__place_panoramax"
|
||||
style="@style/PlacePageItemFrame"
|
||||
android:tag="website"
|
||||
tools:background="#20FF0000"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv__place_panoramax"
|
||||
style="@style/PlacePageMetadataIcon"
|
||||
app:srcCompat="@drawable/ic_panoramax"
|
||||
app:tint="?colorAccent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv__place_panoramax"
|
||||
android:textAlignment="viewStart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
|
||||
tools:text="@string/panoramax"/>
|
||||
</LinearLayout>
|
||||
@@ -15,14 +15,14 @@
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?clickableBackground">
|
||||
<ImageView
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_search"
|
||||
app:tint="?colorAccent"
|
||||
android:layout_marginStart="@dimen/margin_base"
|
||||
android:layout_marginEnd="@dimen/margin_base"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tv__message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -49,7 +49,7 @@
|
||||
android:layout_marginBottom="@dimen/margin_half"
|
||||
android:layout_marginTop="@dimen/margin_half"
|
||||
android:background="?dividerHorizontal"/>
|
||||
<ImageView
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/iv__icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
android:paddingEnd="@dimen/margin_base"
|
||||
android:paddingBottom="@dimen/margin_half"
|
||||
android:paddingTop="@dimen/margin_half_plus">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/total_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -18,7 +18,7 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
style="@style/MwmWidget.TextView.PlanDetail.Number.Time"
|
||||
tools:text="40 min"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/dot"
|
||||
style="@style/MwmWidget.TextView.PlanDetail.Number.Secondary"
|
||||
android:layout_marginStart="@dimen/margin_quarter_plus"
|
||||
@@ -28,7 +28,7 @@
|
||||
app:layout_constraintStart_toEndOf="@id/total_time"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="HardcodedText"/>
|
||||
<ImageView
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/pedestrian_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -37,7 +37,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="@id/total_time"
|
||||
app:layout_constraintStart_toEndOf="@id/dot"
|
||||
app:tint="?iconTint"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/total_distance"
|
||||
style="@style/MwmWidget.TextView.PlanDetail.Number.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/altitude_chart_time_distance_margin_bottom">
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/altitude_difference"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/altitude_chart_time_distance_height"
|
||||
@@ -19,7 +19,7 @@
|
||||
android:visibility="gone"
|
||||
tools:text="43 m"
|
||||
tools:visibility="visible"/>
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:maxLines="2"
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
android:contentDescription="@string/route_type"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<app.organicmaps.widget.RoutingToolbarButton
|
||||
@@ -45,6 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/routing_selector_wheel_margin"
|
||||
android:contentDescription="@string/vehicle"
|
||||
tools:button="@drawable/ic_car"
|
||||
tools:buttonTint="?colorAccent" />
|
||||
|
||||
@@ -54,6 +56,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:contentDescription="@string/pedestrian"
|
||||
tools:button="@drawable/ic_pedestrian"
|
||||
tools:buttonTint="?iconTintLight" />
|
||||
|
||||
@@ -62,6 +65,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/margin_half_plus"
|
||||
android:contentDescription="@string/subway"
|
||||
tools:button="@drawable/ic_transit"
|
||||
tools:buttonTint="?iconTintLight" />
|
||||
|
||||
@@ -70,6 +74,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:contentDescription="@string/bicycle"
|
||||
tools:button="@drawable/ic_bike"
|
||||
tools:buttonTint="?iconTintLight" />
|
||||
|
||||
@@ -78,6 +83,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:contentDescription="@string/ruler"
|
||||
tools:button="@drawable/ic_ruler_route"
|
||||
tools:buttonTint="?iconTintLight" />
|
||||
</RadioGroup>
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
<!-- Title for OSM note section in the editor -->
|
||||
<string name="editor_other_info">Nota aan OpenStreetMap-vrywilligers (opsioneel)</string>
|
||||
<!-- Hint of the input field in the OSM note section of the editor -->
|
||||
<string name="editor_note_hint">Beskryf foute in die kaart of wat nie met Organiese Kaarte geredigeer kan word nie</string>
|
||||
<string name="editor_note_hint">Beskryf foute in die kaart of wat nie met CoMaps geredigeer kan word nie</string>
|
||||
<!-- Information about OSM at the top of the editing page -->
|
||||
<string name="editor_about_osm">Jou wysigings word opgelaai na die publieke <a href="https://wiki.openstreetmap.org/wiki/About_OpenStreetMap">OpenStreetMap</a>-databasis. Moet asseblief nie persoonlike of kopiereginligting byvoeg nie.</string>
|
||||
<string name="editor_more_about_osm">Meer oor OpenStreetMap</string>
|
||||
@@ -503,7 +503,7 @@
|
||||
<!-- To indicate the operator of ATMs, bicycle rentals, electric vehicle charging stations... -->
|
||||
<string name="operator">Operateur: %s</string>
|
||||
<string name="editor_category_unsuitable_title">Kan u nie \'n geskikte kategorie vind nie?</string>
|
||||
<string name="editor_category_unsuitable_text">Organiese kaarte laat toe om slegs eenvoudige puntkategorieë by te voeg, dit beteken geen dorpe, paaie, mere, gebouomlynings, ens. Voeg asseblief sulke kategorieë direk by <a href="https://www.openstreetmap.org">OpenStreetMap.org</a>. Gaan ons <a href="https://www.comaps.app/support/advanced-map-editing/">gids</a> na vir gedetailleerde stap-vir-stap-instruksies.</string>
|
||||
<string name="editor_category_unsuitable_text">CoMaps laat toe om slegs eenvoudige puntkategorieë by te voeg, dit beteken geen dorpe, paaie, mere, gebouomlynings, ens. Voeg asseblief sulke kategorieë direk by <a href="https://www.openstreetmap.org">OpenStreetMap.org</a>. Gaan ons <a href="https://www.comaps.app/support/advanced-map-editing/">gids</a> na vir gedetailleerde stap-vir-stap-instruksies.</string>
|
||||
<string name="downloader_no_downloaded_maps_title">U het geen kaarte afgelaai nie</string>
|
||||
<string name="downloader_no_downloaded_maps_message">Laai kaarte af om die ligging te soek en vanlyn te navigeer.</string>
|
||||
<string name="current_location_unknown_error_title">Huidige ligging is onbekend.</string>
|
||||
@@ -546,7 +546,7 @@
|
||||
<string name="editor_share_to_all_dialog_title">Wil u dit na alle gebruikers stuur?</string>
|
||||
<!-- Dialog before publishing the modifications to the public map. -->
|
||||
<string name="editor_share_to_all_dialog_message_1">Maak seker u het geen privaat of persoonlike data ingevoer nie.</string>
|
||||
<string name="editor_share_to_all_dialog_message_2">OpenStraatMap-redigeerders sal die verandeirnge nagaan en u kontak indien hulle vrae het.</string>
|
||||
<string name="editor_share_to_all_dialog_message_2">OpenStreetMap-redigeerders sal die verandeirnge nagaan en u kontak indien hulle vrae het.</string>
|
||||
<!-- Shown as toast when starting the recent track recording -->
|
||||
<string name="track_recording">Opname van die spoor</string>
|
||||
<!-- For the first routing -->
|
||||
@@ -616,7 +616,7 @@
|
||||
<string name="privacy_policy">Privaatheidsbeleid</string>
|
||||
<string name="terms_of_use">Gebruiksvoorwaardes</string>
|
||||
<string name="button_layer_traffic">Verkeer</string>
|
||||
<string name="button_layer_subway">Moltrein</string>
|
||||
<string name="subway">Moltrein</string>
|
||||
<string name="layers_title">Kaartstyle en -lae</string>
|
||||
<string name="subway_data_unavailable">Moltreinkaart is onbeskikbaar</string>
|
||||
<string name="bookmarks_empty_list_title">Hierdie lys is leeg</string>
|
||||
@@ -797,4 +797,10 @@
|
||||
<string name="uri_open_location_failed">Geen toepassing geïnstalleer wat die ligging kan oopmaak nie</string>
|
||||
<!-- preference string for using auto theme only in navigation mode -->
|
||||
<string name="nav_auto">Outo in navigasie</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/About_OpenStreetMap</string>
|
||||
<string name="comma_separated_pair">%1$s, %2$s</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
|
||||
<string name="translated_om_site_url">https://comaps.app/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
</resources>
|
||||
|
||||
@@ -503,7 +503,7 @@
|
||||
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
|
||||
<string name="osm_presentation">بيانات OpenStreetMap التي أنشأها المجتمع اعتبارًا من %s. تعرف على المزيد حول كيفية تعديل الخريطة وتحديثها على OpenStreetMap.org</string>
|
||||
<!-- OSM explanation on Android login screen -->
|
||||
<string name="login_osm_presentation">OpenStreetMap.org (OSM) هو مشروع مجتمعي لبناء خريطة مجانية ومفتوحة. إنه المصدر الرئيسي لبيانات الخرائط في الخرائط العضوية ويعمل على غرار ويكيبيديا. يمكنك إضافة الأماكن أو تعديلها وتصبح متاحة لملايين المستخدمين في جميع أنحاء العالم. نضم إلى المجتمع وساعد في إنشاء خريطة أفضل للجميع!</string>
|
||||
<string name="login_osm_presentation">OpenStreetMap.org (OSM) هو مشروع مجتمعي لبناء خريطة مجانية ومفتوحة. إنه المصدر الرئيسي لبيانات الخرائط في CoMaps ويعمل على غرار ويكيبيديا. يمكنك إضافة الأماكن أو تعديلها وتصبح متاحة لملايين المستخدمين في جميع أنحاء العالم.\nنضم إلى المجتمع وساعد في إنشاء خريطة أفضل للجميع!</string>
|
||||
<string name="login_to_make_edits_visible">أنشئ حساباً على OpenStreetMap أو سجّل الدخول لنشر تعديلاتك على الخريطة للعالم.</string>
|
||||
<!-- Downloaded 10 **of** 20 <- it is that "of" -->
|
||||
<string name="downloader_of">%1$d من%2$d</string>
|
||||
@@ -519,7 +519,7 @@
|
||||
<!-- Title for OSM note section in the editor -->
|
||||
<string name="editor_other_info">ملاحظة لمتطوعي OpenStreetMap (اختياري)</string>
|
||||
<!-- Hint of the input field in the OSM note section of the editor -->
|
||||
<string name="editor_note_hint">وصف الأخطاء على الخريطة أو الأشياء التي لا يمكن تحريرها باستخدام الخرائط العضوية</string>
|
||||
<string name="editor_note_hint">وصف الأخطاء على الخريطة أو الأشياء التي لا يمكن تحريرها باستخدام CoMaps</string>
|
||||
<!-- Information about OSM at the top of the editing page -->
|
||||
<string name="editor_about_osm">يتم تحميل تعديلاتك على قاعدة البيانات العامة <a href="https://wiki.openstreetmap.org/wiki/Ar:About_OpenStreetMap">OpenStreetMap</a>. يرجى عدم إضافة معلومات شخصية أو محمية بحقوق الطبع والنشر.</string>
|
||||
<string name="editor_more_about_osm">المزيد عن خريطة الشارع المفتوحة</string>
|
||||
@@ -598,7 +598,7 @@
|
||||
<!-- Settings: "Send general feedback" button -->
|
||||
<string name="feedback_general">تعقيب عام</string>
|
||||
<string name="prefs_languages_information">نحن نستخدم نظام تحويل النص إلى كلام (TTS) للتعليمات الصوتية. تستخدم العديد من أجهزة أندرويد نظام Google TTS، يمكنك تنزيله من أو تحديثه من متجر Play (https://play.google.com/store/apps/details?id=com.google.android.tts)</string>
|
||||
<string name="prefs_languages_information_off">بالنسبة لبعض اللغات، ستحتاج إلى تنزيل تطبيق تحويل النص إلى كلام أو حزمة لغات إضافية من متجر التطبيقات(متجر Play، Galaxy Store، App Gallery، FDroid(. \nافتح إعدادات جهازك ثم اللغة والإدخال ثم تحويل النص إلى كلام. \nهنا يمكنك إدارة الإعدادات لأنظمة تحويل النص إلى كلا(على سبيل المثال، تنزيل حزمة اللغة للاستجدام دون اتصال انترنيت)</string>
|
||||
<string name="prefs_languages_information_off">بالنسبة لبعض اللغات، ستحتاج إلى تنزيل تطبيق تحويل النص إلى كلام أو حزمة لغات إضافية من متجر التطبيقات (متجر Play، متجر Galaxy، معرض التطبيقات، FDroid).\nافتح إعدادات جهازك، ثم اللغة والإدخال، ثم تحويل النص إلى كلام.\nهنا يمكنك إدارة إعدادات نظامي تحويل النص إلى كلام (على سبيل المثال، تنزيل حزمة لغات للاستخدام دون اتصال بالإنترنت).</string>
|
||||
<string name="prefs_languages_information_off_link">لمزيد من المعلومات الرجاء مراجعة هذا الدليل.</string>
|
||||
<string name="transliteration_title">كتابة جميع الاسماء بالحروف اللاتينية بشكل حرفي</string>
|
||||
<string name="learn_more">معرفة المزيد</string>
|
||||
@@ -667,7 +667,7 @@
|
||||
<string name="privacy_policy">سياسة الخصوصية</string>
|
||||
<string name="terms_of_use">شروط الاستخدام</string>
|
||||
<string name="button_layer_traffic">حركة مرور</string>
|
||||
<string name="button_layer_subway">مترو الانفاق</string>
|
||||
<string name="subway">مترو الانفاق</string>
|
||||
<string name="layers_title">أنماط الخريطة وطبقاتها</string>
|
||||
<string name="subway_data_unavailable">خريطة مترو الانفاق غير متوفرة</string>
|
||||
<string name="bookmarks_empty_list_title">هذه اللائحة فارغة</string>
|
||||
@@ -821,9 +821,9 @@
|
||||
<!-- App tip #09 -->
|
||||
<string name="app_tip_09">هدفنا الرئيسي هو إنشاء خرائط سريعة وسهلة الاستخدام تركز على الخصوصية والتي ستعجبك.</string>
|
||||
<!-- Text on the Android Auto or CarPlay placeholder screen that maps are displayed on the phone screen -->
|
||||
<string name="car_used_on_the_phone_screen">أنت الآن تستخدم الخرائط العضوية على شاشة الهاتف</string>
|
||||
<string name="car_used_on_the_phone_screen">أنت الآن تستخدم CoMaps على شاشة الهاتف</string>
|
||||
<!-- Text on the phone placeholder screen that maps are displayed on the car screen -->
|
||||
<string name="car_used_on_the_car_screen">أنت الآن تستخدم الخرائط العضوية على شاشة السيارة</string>
|
||||
<string name="car_used_on_the_car_screen">أنت الآن تستخدم CoMaps على شاشة السيارة</string>
|
||||
<!-- Displayed on the phone screen. Android Auto connected -->
|
||||
<string name="aa_connected_title">أنت متصل بـ Android Auto</string>
|
||||
<!-- Displayed on the phone screen. Button to display maps on the phone screen instead of a car -->
|
||||
@@ -831,11 +831,11 @@
|
||||
<!-- Displayed on the Android Auto or CarPlay screen. Button to display maps on the car screen instead of a phone. Must be no more than 18 symbols! -->
|
||||
<string name="car_continue_in_the_car">إلى شاشة السيارة</string>
|
||||
<!-- Ask user to grant location permissions -->
|
||||
<string name="aa_location_permissions_request">تحتاج الخرائط العضوية إلى الوصول إلى الموقع. عندما يكون الوضع آمنًا، تحقق من الإشعارات الموجودة على هاتفك.</string>
|
||||
<string name="aa_location_permissions_request">تحتاج CoMaps ة إلى الوصول إلى الموقع. عندما يكون الوضع آمنًا، تحقق من الإشعارات الموجودة على هاتفك.</string>
|
||||
<!-- Notification title for permission request from AA. -->
|
||||
<string name="aa_request_permission_notification">هذا التطبيق يحتاج إلى إذنك</string>
|
||||
<!-- The text in the activity for location permission request. -->
|
||||
<string name="aa_request_permission_activity_text">تحتاج الخرائط العضوية في Android Auto إلى إذن تحديد الموقع للعمل بفعالية</string>
|
||||
<string name="aa_request_permission_activity_text">تحتاج CoMaps في Android Auto إلى إذن تحديد الموقع للعمل بفعالية</string>
|
||||
<!-- Grant Permissions button. -->
|
||||
<string name="aa_grant_permissions">أذونات المنح</string>
|
||||
<!-- Outdoors/hiking map style (activity) name in the Styles and Layers dialog -->
|
||||
@@ -886,4 +886,9 @@
|
||||
<string name="uri_open_location_failed">لم يتم تثبيت أي تطبيق يمكنه فتح الموقع</string>
|
||||
<!-- preference string for using auto theme only in navigation mode -->
|
||||
<string name="nav_auto">تلقائي في التنقل</string>
|
||||
<string name="translated_om_site_url">https://comaps.app/ar</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app</string>
|
||||
<string name="wikimedia_commons">ويكيميديا كومنز</string>
|
||||
</resources>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<string name="privacy">Privacidá</string>
|
||||
<string name="layers_title">Estilos y capes del mapa</string>
|
||||
<string name="subway_data_unavailable">El mapa del metro nun ta disponible</string>
|
||||
<string name="button_layer_subway">Metro</string>
|
||||
<string name="subway">Metro</string>
|
||||
<string name="delete_list">Desaniciar llista</string>
|
||||
<string name="public_access">Accesu públicu</string>
|
||||
<string name="bookmarks_empty_list_title">Esta llista ta balera</string>
|
||||
@@ -176,4 +176,10 @@
|
||||
<string name="choose_street">Escueyi una cai</string>
|
||||
<string name="select_option">Esbilla una opción</string>
|
||||
<string name="choose_color">Escueyi un color</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="translated_om_site_url">https://comaps.app/</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/About_OpenStreetMap</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="wikimedia_commons">Wikimedia Commons</string>
|
||||
</resources>
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
|
||||
<string name="osm_presentation">%s tarixinə icma tərəfindən yaradılmış OpenStreetMap datası. OpenStreetMap.org saytında xəritəni necə redaktə etmək və yeniləmək haqqında ətraflı məlumat əldə edin</string>
|
||||
<!-- OSM explanation on Android login screen -->
|
||||
<string name="login_osm_presentation">OpenStreetMap.org (OSM) pulsuz və açıq xəritə yaratmaq üçün icma layihəsidir. O, Üzvi Xəritələrdə xəritə məlumatlarının əsas mənbəyidir və Vikipediyaya oxşar işləyir. Siz yerlər əlavə edə və ya redaktə edə bilərsiniz və onlar bütün dünyada milyonlarla istifadəçi üçün əlçatan olur. \nİcmaya qoşulun və hər kəs üçün daha yaxşı xəritə yaratmağa kömək edin!</string>
|
||||
<string name="login_osm_presentation">OpenStreetMap.org (OSM) pulsuz və açıq xəritə yaratmaq üçün icma layihəsidir. O, CoMaps xəritə məlumatlarının əsas mənbəyidir və Vikipediyaya oxşar işləyir. Siz yerlər əlavə edə və ya redaktə edə bilərsiniz və onlar bütün dünyada milyonlarla istifadəçi üçün əlçatan olur. \nİcmaya qoşulun və hər kəs üçün daha yaxşı xəritə yaratmağa kömək edin!</string>
|
||||
<string name="login_to_make_edits_visible">OpenStreetMap hesabı yaradın və ya xəritə redaktələrinizi dünyada dərc etmək üçün daxil olun.</string>
|
||||
<!-- Downloaded 10 **of** 20 <- it is that "of" -->
|
||||
<string name="downloader_of">%1$d/%2$d</string>
|
||||
@@ -508,7 +508,7 @@
|
||||
<!-- Title for OSM note section in the editor -->
|
||||
<string name="editor_other_info">OpenStreetMap könüllüləri üçün qeyd (isteğe bağlı)</string>
|
||||
<!-- Hint of the input field in the OSM note section of the editor -->
|
||||
<string name="editor_note_hint">Xəritədəki səhvləri və ya Üzvi Xəritələrdən istifadə edərək redaktə edilə bilməyənləri təsvir edin</string>
|
||||
<string name="editor_note_hint">Xəritədəki səhvləri və ya CoMaps istifadə edərək redaktə edilə bilməyənləri təsvir edin</string>
|
||||
<!-- Information about OSM at the top of the editing page -->
|
||||
<string name="editor_about_osm">Redaktələriniz ictimai <a href="https://wiki.openstreetmap.org/wiki/Tr:About">OpenStreetMap</a> verilənlər bazasına yüklənir. Zəhmət olmasa şəxsi və ya müəllif hüquqları ilə qorunan məlumatları əlavə etməyin.</string>
|
||||
<string name="editor_more_about_osm">OpenStreetMap haqqında əlavə məlumat</string>
|
||||
@@ -518,7 +518,7 @@
|
||||
<!-- To indicate the operator of ATMs, bicycle rentals, electric vehicle charging stations... -->
|
||||
<string name="operator">Operator: %s</string>
|
||||
<string name="editor_category_unsuitable_title">Uyğun kateqoriya tapa bilmirsiniz?</string>
|
||||
<string name="editor_category_unsuitable_text">Üzvi Xəritələr yalnız sadə nöqtə kateqoriyaları əlavə etməyə imkan verir, bu o deməkdir ki, şəhərlər, yollar, göllər, bina konturları və s. yoxdur. Lütfən, belə kateqoriyaları birbaşa <a href="https://www.openstreetmap.org">OpenStreetMap.org</a> saytına əlavə edin. Ətraflı addım-addım təlimatlar üçün <a href="https://www.comaps.app/support/advanced-map-editing/">bələdçimizi</a> yoxlayın.</string>
|
||||
<string name="editor_category_unsuitable_text">CoMaps yalnız sadə nöqtə kateqoriyaları əlavə etməyə imkan verir, bu o deməkdir ki, şəhərlər, yollar, göllər, bina konturları və s. yoxdur. Lütfən, belə kateqoriyaları birbaşa <a href="https://www.openstreetmap.org">OpenStreetMap.org</a> saytına əlavə edin. Ətraflı addım-addım təlimatlar üçün <a href="https://www.comaps.app/support/advanced-map-editing/">bələdçimizi</a> yoxlayın.</string>
|
||||
<string name="downloader_no_downloaded_maps_title">Siz heç bir xəritə endirməmisiniz</string>
|
||||
<string name="downloader_no_downloaded_maps_message">Ünvanları tapmaq və oflayn naviqasiya etmək üçün xəritələri endirin.</string>
|
||||
<string name="current_location_unknown_error_title">Cari yer məlum deyil.</string>
|
||||
@@ -644,7 +644,7 @@
|
||||
<string name="privacy_policy">Gizlilik Siyasəti</string>
|
||||
<string name="terms_of_use">İstifadə qaydaları</string>
|
||||
<string name="button_layer_traffic">Nəqliyyat</string>
|
||||
<string name="button_layer_subway">Metro</string>
|
||||
<string name="subway">Metro</string>
|
||||
<string name="layers_title">Xəritə Üslubları və Qatları</string>
|
||||
<string name="subway_data_unavailable">Metro xəritəsi mövcud deyil</string>
|
||||
<string name="bookmarks_empty_list_title">Bu siyahı boşdur</string>
|
||||
@@ -671,7 +671,7 @@
|
||||
<string name="power_managment_setting_never">Heç vaxt</string>
|
||||
<string name="power_managment_setting_auto">Avtomatik</string>
|
||||
<string name="power_managment_setting_manual_max">Maksimum enerji qənaəti</string>
|
||||
<string name="enable_logging_warning_message">Yardım dialoq qutusunda “Problemi bildir” istifadə etməklə probleminizlə bağlı ətraflı diaqnostik jurnalları qeyd etmək və bizə göndərmək üçün bu seçimi müvəqqəti aktivləşdirin. Qeydlərə məkan məlumatı daxil ola bilər</string>
|
||||
<string name="enable_logging_warning_message">Yardım dialoq qutusunda “Problemi bildir” istifadə etməklə probleminizlə bağlı ətraflı diaqnostik jurnalları qeyd etmək və bizə göndərmək üçün bu seçimi müvəqqəti aktivləşdirin. Qeydlərə məkan məlumatı daxil ola bilər.</string>
|
||||
<string name="access_rules_author_only">Onlayn redaktə</string>
|
||||
<string name="driving_options_title">Marşrutlaşdırma seçimləri</string>
|
||||
<!-- Recommended length for CarPlay and Android Auto is around 25-27 characters -->
|
||||
@@ -682,7 +682,7 @@
|
||||
<string name="avoid_ferry">Bərə keçidlərindən çəkinin</string>
|
||||
<string name="avoid_motorways">Magistral yoldan çəkinin</string>
|
||||
<string name="unable_to_calc_alert_title">Marşrutu hesablamaq mümkün deyil</string>
|
||||
<string name="unable_to_calc_alert_subtitle">Təəssüf ki, seçdiyiniz seçimlərə görə marşrut tapa bilmədik. Seçimləri dəyişdirin və yenidən cəhd edin</string>
|
||||
<string name="unable_to_calc_alert_subtitle">Təəssüf ki, seçdiyiniz seçimlərə görə marşrut tapa bilmədik. Seçimləri dəyişdirin və yenidən cəhd edin.</string>
|
||||
<string name="define_to_avoid_btn">Qarşısını almaq üçün yolları müəyyənləşdirin</string>
|
||||
<string name="change_driving_options_btn">Sürmə seçimləri aktiv edildi</string>
|
||||
<string name="toll_road">Ücrətli yol</string>
|
||||
@@ -777,7 +777,7 @@
|
||||
<!-- Translated CoMaps site, add new translations here: https://github.com/organicmaps/organicmaps.github.io/tree/master/content -->
|
||||
<string name="translated_om_site_url">https://comaps.app/tr/</string>
|
||||
<!-- Link to OSM wiki for Editor, Profile and About pages -->
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Tr:About</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Az:Layihə_haqqında</string>
|
||||
<!-- App Tip #00 -->
|
||||
<string name="app_tip_00">İcma tərəfindən yaradılmış xəritələrimizdən istifadə etdiyiniz üçün təşəkkür edirik!</string>
|
||||
<!-- App tip #04 -->
|
||||
@@ -840,4 +840,8 @@
|
||||
<string name="uri_open_location_failed">Məkanı aça biləcək proqram quraşdırılmayıb</string>
|
||||
<!-- preference string for using auto theme only in navigation mode -->
|
||||
<string name="nav_auto">Naviqasiyada avtomatik</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="wikimedia_commons">Vikianbar</string>
|
||||
</resources>
|
||||
|
||||
@@ -636,7 +636,7 @@
|
||||
<string name="privacy_policy">Палітыка прыватнасці</string>
|
||||
<string name="terms_of_use">Умовы выкарыстання</string>
|
||||
<string name="button_layer_traffic">Рух</string>
|
||||
<string name="button_layer_subway">Метро</string>
|
||||
<string name="subway">Метро</string>
|
||||
<string name="layers_title">Стылі і слаі карты</string>
|
||||
<string name="subway_data_unavailable">Карта метро недаступная</string>
|
||||
<string name="bookmarks_empty_list_title">Гэты спіс пусты</string>
|
||||
@@ -880,7 +880,8 @@
|
||||
<item quantity="other">Знойдзена %d файлаў. Вы можаце ўбачыць іх пасля пераўтварэння.</item>
|
||||
</plurals>
|
||||
<string name="error_enter_correct_vk_page">Увядзіце сапраўднае імя карыстальніка або спасылку VK</string>
|
||||
<string name="wikimedia_commons">Wikimedia Commons</string>
|
||||
<string name="wikimedia_commons">Вікісховішча</string>
|
||||
<string name="comma_separated_pair">%1$s, %2$s</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/About_OpenStreetMap</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/RU:О_проекте</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
</resources>
|
||||
|
||||
@@ -542,7 +542,7 @@
|
||||
<!-- Settings: "Send general feedback" button -->
|
||||
<string name="feedback_general">Обща обратна връзка</string>
|
||||
<string name="prefs_languages_information">Навигирането се озвучава от системен синтезатор на реч (TTS). Много устройства използват Google TTS, който може да бъде изтеглен или актуализиран от Google Play (https://play.google.com/store/apps/details?id=com.google.android.tts).</string>
|
||||
<string name="prefs_languages_information_off">За някои езици може да се наложи да инсталирате допълнителен синтезатор на реч (TTS) от магазина за приложения (Google Play Магазин, Galaxy Store). \nЗа да настроите синтезатора на реч, отидете в Настройки → Езици и въвеждане → Синтезиран говор. \nТук можете да инсталирате допълнителни езикови пакети или да изберете синтезатор на реч.</string>
|
||||
<string name="prefs_languages_information_off">За някои езици може да се наложи да инсталирате допълнителен синтезатор на реч (TTS) от магазина за приложения (Google Play, Samsung Galaxy Store, Huawei AppGallery, F-Droid). \nЗа да настроите синтезатора на реч, отидете в Настройки → Езици и въвеждане → Синтезиран говор. \nТук можете да инсталирате допълнителни езикови пакети или да изберете синтезатор на реч.</string>
|
||||
<string name="prefs_languages_information_off_link">За повече информация вижте това ръководство.</string>
|
||||
<string name="transliteration_title">Изпиши на латиница</string>
|
||||
<string name="learn_more">Научете повече</string>
|
||||
@@ -594,7 +594,7 @@
|
||||
<string name="privacy_policy">Политика за поверителност</string>
|
||||
<string name="terms_of_use">Условия за ползване</string>
|
||||
<string name="button_layer_traffic">Трафик</string>
|
||||
<string name="button_layer_subway">Метро</string>
|
||||
<string name="subway">Метро</string>
|
||||
<string name="layers_title">Стилове и слоеве на картата</string>
|
||||
<string name="subway_data_unavailable">Картата на метрото не е налична</string>
|
||||
<string name="bookmarks_empty_list_title">Този списък е празен</string>
|
||||
@@ -690,7 +690,7 @@
|
||||
<!-- OpenStreetMap text on splash screen -->
|
||||
<string name="splash_subtitle">Картографски данни от OpenStreetMap</string>
|
||||
<!-- Link to OSM wiki for Editor, Profile and About pages -->
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Bg:About</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Bg:About_OpenStreetMap</string>
|
||||
<!-- App Tip #00 -->
|
||||
<string name="app_tip_00">Благодарим ви, че използвате нашите карти, създадени от общността!</string>
|
||||
<!-- App tip #01 -->
|
||||
@@ -800,7 +800,7 @@
|
||||
<string name="parkings">Паркинги</string>
|
||||
<string name="fuel_places">Бензиностанции</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comapscommunity/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="moreyear_ago_sorttype">Преди повече от година</string>
|
||||
<string name="maps_storage_external">Външно споделено хранилище</string>
|
||||
<string name="deep_orange">Тъмно Оранжево</string>
|
||||
@@ -824,7 +824,7 @@
|
||||
<string name="miles_per_hour">мили/ч</string>
|
||||
<string name="animals">Животни</string>
|
||||
<string name="buildings">Сгради</string>
|
||||
<string name="translated_om_site_url">https://www.comaps.app/</string>
|
||||
<string name="translated_om_site_url">https://comaps.app/</string>
|
||||
<string name="hotels">Хотели</string>
|
||||
<string name="others_sorttype">Други</string>
|
||||
<string name="month_ago_sorttype">Преди месец</string>
|
||||
@@ -838,4 +838,5 @@
|
||||
<string name="trip_finished">Пристигнахте!</string>
|
||||
<string name="instagram">Instagram</string>
|
||||
<string name="downloader_loading_ios">Изтегляне</string>
|
||||
<string name="wikimedia_commons">Общомедия</string>
|
||||
</resources>
|
||||
|
||||
@@ -10,8 +10,30 @@
|
||||
<string name="search">অনুসন্ধান</string>
|
||||
<string name="download_has_failed">ডাউনলোড ব্যর্থ। আবার চেষ্টা করতে টিপ দাও।</string>
|
||||
<string name="mb">এমবি</string>
|
||||
<string name="search_map">মানচিত্র অনুসন্ধান</string>
|
||||
<string name="search_map">ম্যাপ অনুসন্ধান</string>
|
||||
<string name="gb">জিবি</string>
|
||||
<string name="kilometres">কিলোমিটার</string>
|
||||
<string name="downloading">ডাউনলোডরত…</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/About_OpenStreetMap</string>
|
||||
<string name="translated_om_site_url">https://comaps.app/</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="app_site_url">https://comaps.app/</string>
|
||||
<string name="location_is_disabled_long_text">আপনার ডিভাইস বা অ্যাপ এর সব লোকেশন পরিষেবা বন্ধ করা আছে। দয়া করে সেটিংস থেকে চালু করুন।</string>
|
||||
<string name="close">বন্ধ</string>
|
||||
<string name="download">ডাউনলোড</string>
|
||||
<string name="limited_accuracy">সীমিত সঠিকতা</string>
|
||||
<string name="precise_location_is_disabled_long_text">সঠিক ন্যাভিগেশনের জন্য সেটিংস থেকে নিখুঁত লোকেশন অন করুন।</string>
|
||||
<string name="zoom_to_country">ম্যাপে দেখান</string>
|
||||
<string name="country_status_download_failed">ডাউনলোড ব্যর্থ হল</string>
|
||||
<string name="try_again">আবার চেষ্টা করুন</string>
|
||||
<string name="about_menu_title">CoMaps এর ব্যাপারে</string>
|
||||
<string name="about_headline">উন্মুক্ত প্রকল্প, তার সমাজ দ্বারা চলিত</string>
|
||||
<string name="location_settings">লোকেশন সেটিংস</string>
|
||||
<string name="about_proposition_1">• ব্যবহার করা সহজ এবং দেখতে সুন্দর</string>
|
||||
<string name="about_proposition_2">• গোপনীয়তা বান্ধব এবং বিজ্ঞাপন মুক্ত</string>
|
||||
<string name="about_proposition_3">• অফলাইন, দ্রুত এবং ছোট সাইজ</string>
|
||||
<string name="about_developed_by_enthusiasts">পুরোপুরি ওপেন সোর্স, অলাভজনক, প্রকাশ্য সিদ্ধান্ত করণ এবং অর্থায়ন।</string>
|
||||
<string name="wikimedia_commons">উইকিমিডিয়া কমন্স</string>
|
||||
</resources>
|
||||
|
||||
2
android/app/src/main/res/values-bn/types_strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
@@ -507,7 +507,7 @@
|
||||
<!-- Title for OSM note section in the editor -->
|
||||
<string name="editor_other_info">Nota per als voluntaris d\'OpenStreetMap (opcional)</string>
|
||||
<!-- Hint of the input field in the OSM note section of the editor -->
|
||||
<string name="editor_note_hint">Descriu errors al mapa o què no es pot editar amb Mapes orgànics</string>
|
||||
<string name="editor_note_hint">Descriu errors al mapa o què no es pot editar amb CoMaps</string>
|
||||
<!-- Information about OSM at the top of the editing page -->
|
||||
<string name="editor_about_osm">Les vostres edicions es pengen a la base de dades pública <a href="https://wiki.openstreetmap.org/wiki/Ca:About">OpenStreetMap</a>. Si us plau, no afegiu informació personal o amb drets d\'autor.</string>
|
||||
<string name="editor_more_about_osm">Més sobre l\'OpenStreetMap</string>
|
||||
@@ -586,7 +586,7 @@
|
||||
<!-- Settings: "Send general feedback" button -->
|
||||
<string name="feedback_general">Opinió general</string>
|
||||
<string name="prefs_languages_information">Usem el sistema de síntesi de veu per a les instruccions de veu. Molts aparells Android use el motor de síntesi de veu de Google, podeu baixar o actualitzar-lo des del Google Play (https://play.google.com/store/apps/details?id=com.google.android.tts)</string>
|
||||
<string name="prefs_languages_information_off">Per a algunes llengües, haureu d\'instal·lar un sintetizador de veu o un paquet de llengua addicional des de la botiga d\'apliacions (Google Play, Galazy Store, FDroid). \nObriu la configuració de l\'aparell → Idioma i entrada → Veu → Sortidda de text a veu. \nAquí podeu gestionar la configuració de la síntesi de veu (per exemple, baixar un paquet de llengua per a ús sense connexió) i triar un altre motor de síntesi de veu.</string>
|
||||
<string name="prefs_languages_information_off">Per a algunes llengües, haureu d\'instal·lar un sintetizador de veu o un paquet de llengua addicional des de la botiga d\'apliacions (Google Play, Samsung Galaxy Store, Huawei AppGallery, F-Droid). \nObriu la configuració de l\'aparell → Idioma i entrada → Veu → Sortidda de text a veu. \nAquí podeu gestionar la configuració de la síntesi de veu (per exemple, baixar un paquet de llengua per a ús sense connexió) i triar un altre motor de síntesi de veu.</string>
|
||||
<string name="prefs_languages_information_off_link">Per a més informació, vegeu aquesta guia.</string>
|
||||
<string name="transliteration_title">Transliteració a l’alfabet llatí</string>
|
||||
<string name="learn_more">Més informació</string>
|
||||
@@ -646,7 +646,7 @@
|
||||
<string name="privacy_policy">Política de privadesa</string>
|
||||
<string name="terms_of_use">Condicions del servei</string>
|
||||
<string name="button_layer_traffic">Trànsit</string>
|
||||
<string name="button_layer_subway">Metro</string>
|
||||
<string name="subway">Metro</string>
|
||||
<string name="layers_title">Estils i capes del mapa</string>
|
||||
<string name="subway_data_unavailable">El mapa del metro no està disponible</string>
|
||||
<string name="bookmarks_empty_list_title">Aquesta llista és buida</string>
|
||||
@@ -780,7 +780,7 @@
|
||||
<!-- Translated CoMaps site -->
|
||||
<string name="translated_om_site_url">https://comaps.app/ca/</string>
|
||||
<!-- Link to OSM wiki for Editor, Profile and About pages -->
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Ca:About</string>
|
||||
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Ca:About_OpenStreetMap</string>
|
||||
<!-- App Tip #00 -->
|
||||
<string name="app_tip_00">Gràcies per utilitzar els nostres mapes creats per la comunitat!</string>
|
||||
<!-- App tip #01 -->
|
||||
@@ -882,7 +882,7 @@
|
||||
<string name="twitter">X (Twitter)</string>
|
||||
<string name="wikimedia_commons">Wikimedia Commons</string>
|
||||
<string name="matrix">[Matrix]</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comapscommunity/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="comma_separated_pair">%1$s, %2$s</string>
|
||||
|
||||
@@ -960,4 +960,6 @@
|
||||
<string name="type.place.suburb">Suburbi</string>
|
||||
<string name="type.place.state.USA">Estat</string>
|
||||
<string name="type.power.line">Línia elèctrica</string>
|
||||
<string name="type.amenity.studio">Estudi</string>
|
||||
<string name="type.barrier.guard_rail">Barrera de seguretat</string>
|
||||
</resources>
|
||||
|
||||
@@ -421,7 +421,7 @@
|
||||
<string name="closed">Zavřeno</string>
|
||||
<string name="edit_opening_hours">Upravit otevírací dobu</string>
|
||||
<string name="no_osm_account">Nemáte účet u OpenStreetMap?</string>
|
||||
<string name="register_at_openstreetmap">Registrace</string>
|
||||
<string name="register_at_openstreetmap">Zaregistrujte si účet na OpenStreetMap</string>
|
||||
<string name="login">Přihlásit se</string>
|
||||
<!-- Status message indicating that user did not login to OSM profile yet. -->
|
||||
<string name="not_signed_in">Nejste přihlášeni</string>
|
||||
@@ -498,7 +498,7 @@
|
||||
<!-- To indicate the operator of ATMs, bicycle rentals, electric vehicle charging stations... -->
|
||||
<string name="operator">Provozovatel: %s</string>
|
||||
<string name="editor_category_unsuitable_title">Nemůžete najít vhodnou kategorii?</string>
|
||||
<string name="editor_category_unsuitable_text">Organické mapy umožňují přidávat pouze jednoduché kategorie bodů, tedy žádná města, silnice, jezera, obrysy budov atd. Takové kategorie prosím přidávejte přímo na <a href="https://www.openstreetmap.org">OpenStreetMap.org</a>. Podrobné pokyny krok za krokem najdete v našem <a href="https://www.comaps.app/support/advanced-map-editing/">průvodci</a>.</string>
|
||||
<string name="editor_category_unsuitable_text">CoMaps umožňují přidávat pouze jednoduché kategorie bodů, tedy žádná města, silnice, jezera, obrysy budov atd. Takové kategorie prosím přidávejte přímo na <a href="https://www.openstreetmap.org">OpenStreetMap.org</a>. Podrobné pokyny krok za krokem najdete v našem <a href="https://www.comaps.app/support/advanced-map-editing/">průvodci</a>.</string>
|
||||
<string name="downloader_no_downloaded_maps_title">Nemáte stažené žádné mapy</string>
|
||||
<string name="downloader_no_downloaded_maps_message">Stáhněte si mapy a hledejte cestu a její cíl, i když jste offline.</string>
|
||||
<string name="current_location_unknown_error_title">Současná poloha nezjištěna.</string>
|
||||
@@ -619,7 +619,7 @@
|
||||
<string name="privacy_policy">Zásady ochrany osobních údajů</string>
|
||||
<string name="terms_of_use">Podmínky užívání</string>
|
||||
<string name="button_layer_traffic">Zácpy</string>
|
||||
<string name="button_layer_subway">Metro</string>
|
||||
<string name="subway">Metro</string>
|
||||
<string name="layers_title">Styly a vrstvy mapy</string>
|
||||
<string name="subway_data_unavailable">Mapa metra není dostupná</string>
|
||||
<string name="bookmarks_empty_list_title">Seznam je prázdný</string>
|
||||
@@ -871,7 +871,7 @@
|
||||
<string name="instagram">Instagram</string>
|
||||
<string name="editor_line_social_network">LINE</string>
|
||||
<string name="openstreetmap">OpenStreetMap</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comapscommunity/</string>
|
||||
<string name="instagram_url">https://www.instagram.com/comaps.app/</string>
|
||||
<string name="app_site_url">https://comaps.app/cs/</string>
|
||||
<string name="telegram_url">https://t.me/CoMapsApp/</string>
|
||||
<string name="codeberg">Codeberg</string>
|
||||
@@ -884,4 +884,13 @@
|
||||
<string name="error_enter_correct_level">Zadejte platné číslo podlaží</string>
|
||||
<string name="editor_building_levels">Podlaží (vč. přízemí, bez střechy)</string>
|
||||
<string name="editor_level">Podlaží (0 je přízemí)</string>
|
||||
<string name="route_type">Typ trasy</string>
|
||||
<string name="vehicle">Vozidlo</string>
|
||||
<string name="pedestrian">Pěší zóna</string>
|
||||
<string name="bicycle">Jízdní kolo</string>
|
||||
<string name="ruler">Pravítko</string>
|
||||
<string name="bookmark_color">Barva záložky</string>
|
||||
<string name="clear">Vymazat</string>
|
||||
<string name="panoramax">Obrázek Panoramax</string>
|
||||
<string name="about_help">O aplikaci a nápověda</string>
|
||||
</resources>
|
||||
|
||||