summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Guerra <fabian.guerra@mapbox.com>2017-09-27 12:08:24 -0400
committerFabian Guerra <fabian.guerra@mapbox.com>2017-09-27 12:08:24 -0400
commit6d1fdf2ca3a93839bc7dc0929599dd096ab00e33 (patch)
tree5436aefbab4abcba5caa5020c62c24de7d493616
parentfafe0928227ec8e944e1ec68ee1d2bbc1c52f6ae (diff)
parent3f52377543885170da6a27e1c24657cc4cbcf29c (diff)
downloadqtlocation-mapboxgl-6d1fdf2ca3a93839bc7dc0929599dd096ab00e33.tar.gz
Merge branch 'release-ios-v3.6.0-android-v5.1.0' into master.upstream/fabian-merge-release-ios-v3.6.0-final
# Conflicts: # circle.yml # platform/android/CHANGELOG.md # platform/android/MapboxGLAndroidSDK/gradle.properties # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java # platform/android/dependencies.gradle # platform/default/mbgl/storage/offline_database.cpp # platform/ios/CHANGELOG.md # platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec # platform/ios/Mapbox-iOS-SDK-symbols.podspec # platform/ios/Mapbox-iOS-SDK.podspec # platform/ios/app/Main.storyboard # platform/ios/src/MGLMapView.mm # src/mbgl/programs/attributes.hpp # src/mbgl/renderer/painter_fill.cpp # src/mbgl/tile/geometry_tile.hpp # src/mbgl/tile/geometry_tile_worker.cpp # src/mbgl/tile/raster_tile.cpp # src/mbgl/tile/raster_tile.hpp # src/mbgl/tile/raster_tile_worker.cpp # test/tile/annotation_tile.test.cpp # test/tile/geojson_tile.test.cpp # test/tile/raster_tile.test.cpp # test/tile/vector_tile.test.cpp
-rw-r--r--.tx/config7
-rw-r--r--platform/android/CHANGELOG.md1
-rw-r--r--platform/android/MapboxGLAndroidSDK/proguard-rules.pro7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties2
-rw-r--r--platform/darwin/resources/ca.lproj/Foundation.strings4
-rw-r--r--platform/darwin/resources/de.lproj/Foundation.stringsdict16
-rw-r--r--platform/darwin/resources/lt.lproj/Foundation.stringsdict6
-rw-r--r--platform/darwin/resources/ru.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/uk.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/uk.lproj/Foundation.stringsdict16
-rw-r--r--platform/darwin/resources/vi.lproj/Foundation.stringsdict48
-rw-r--r--platform/darwin/resources/zh-Hant.lproj/Foundation.strings42
-rw-r--r--platform/darwin/src/MGLStyle.h46
-rw-r--r--platform/darwin/src/MGLStyle.mm31
-rw-r--r--platform/darwin/test/MGLStyleTests.mm5
-rw-r--r--platform/ios/CHANGELOG.md16
-rw-r--r--platform/ios/app/Info.plist6
-rw-r--r--platform/ios/app/MBXViewController.m42
-rw-r--r--platform/ios/app/Main.storyboard32
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj44
-rw-r--r--platform/ios/resources/es.lproj/Localizable.strings22
-rw-r--r--platform/ios/resources/lt.lproj/Localizable.stringsdict12
-rw-r--r--platform/ios/resources/ru.lproj/Localizable.strings20
-rw-r--r--platform/ios/resources/sv.lproj/Localizable.strings6
-rw-r--r--platform/ios/resources/uk.lproj/Localizable.strings26
-rw-r--r--platform/ios/resources/uk.lproj/Localizable.stringsdict38
-rw-r--r--platform/ios/resources/zh-Hant.lproj/Localizable.strings39
-rw-r--r--platform/ios/resources/zh-Hant.lproj/Localizable.stringsdict30
-rwxr-xr-xplatform/ios/scripts/package.sh4
-rw-r--r--platform/ios/src/MGLFaux3DUserLocationAnnotationView.h10
-rw-r--r--platform/ios/src/MGLFaux3DUserLocationAnnotationView.m180
-rw-r--r--platform/ios/src/MGLMapView+IBAdditions.h1
-rw-r--r--platform/ios/src/MGLMapView.h46
-rw-r--r--platform/ios/src/MGLMapView.mm471
-rw-r--r--platform/ios/src/MGLUserLocation.h3
-rw-r--r--platform/ios/src/MGLUserLocation.m3
-rw-r--r--platform/ios/src/MGLUserLocationHeadingArrowLayer.h11
-rw-r--r--platform/ios/src/MGLUserLocationHeadingArrowLayer.m59
-rw-r--r--platform/ios/src/MGLUserLocationHeadingBeamLayer.h11
-rw-r--r--platform/ios/src/MGLUserLocationHeadingBeamLayer.m104
-rw-r--r--platform/ios/src/MGLUserLocationHeadingIndicator.h10
m---------platform/ios/uitest/KIF0
m---------platform/ios/uitest/OHHTTPStubs0
-rw-r--r--platform/macos/CHANGELOG.md6
-rw-r--r--platform/macos/Mapbox-macOS-SDK-symbols.podspec2
-rw-r--r--platform/macos/Mapbox-macOS-SDK.podspec2
-rw-r--r--platform/macos/app/MapDocument.m8
-rw-r--r--platform/macos/app/hu.lproj/Localizable.strings0
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj21
-rw-r--r--platform/macos/sdk/ca.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/es.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/hu.lproj/Localizable.strings27
-rw-r--r--platform/macos/sdk/ru.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/uk.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/vi.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/zh-Hant.lproj/Localizable.strings12
-rw-r--r--platform/macos/src/MGLMapView.h4
61 files changed, 1806 insertions, 449 deletions
diff --git a/.tx/config b/.tx/config
index b464acb01a..1de8f78303 100644
--- a/.tx/config
+++ b/.tx/config
@@ -9,6 +9,13 @@ source_file = platform/darwin/resources/Base.lproj/Foundation.strings
source_lang = en
type = STRINGS
+[mapbox-gl-native.foundationstringsdict-darwin]
+file_filter = platform/darwin/resources/<lang>.lproj/Foundation.stringsdict
+lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
+source_file = platform/darwin/resources/en.lproj/Foundation.stringsdict
+source_lang = en
+type = STRINGSDICT
+
[mapbox-gl-native.localizablestrings-ios]
file_filter = platform/ios/resources/<lang>.lproj/Localizable.strings
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 716dba18ea..8ce8b3d3c1 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -23,6 +23,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
* Avoid adding duplicate points to bounds [#9955](https://github.com/mapbox/mapbox-gl-native/pull/9955)
* Download is complete fix [#9913](https://github.com/mapbox/mapbox-gl-native/pull/9913)
* MAS 2.2.3 [#9901](https://github.com/mapbox/mapbox-gl-native/pull/9901)
+* Russian and Ukrainian localizations [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945)
## 5.1.3 - August 18, 2017
diff --git a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
index 68edc12f35..b5a1d82c81 100644
--- a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
@@ -7,4 +7,9 @@
-keep interface com.mapbox.mapboxsdk.** { *; }
-keep class com.mapbox.services.android.telemetry.** { *; }
-keep class com.mapbox.services.commons.** { *;}
--keep class com.google.gson.** { *; } \ No newline at end of file
+-keep class com.google.gson.** { *; }
+
+# config for okhttp 3.8.0, https://github.com/square/okhttp/pull/3354
+-dontwarn okio.**
+-dontwarn javax.annotation.Nullable
+-dontwarn javax.annotation.ParametersAreNonnullByDefault \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
index 34e9914e46..6ed788d1dc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="mapbox_compassContentDescription">Brúixola del mapa. Activa per restablir la rotació del mapa al Nord.</string>
- <string name="mapbox_attributionsIconContentDescription">Icona d\'atribució. Activa per mostrar el diàleg de l\'atribució.</string>
+ <string name="mapbox_attributionsIconContentDescription">Icona d’atribució. Activa per mostrar el diàleg de l’atribució.</string>
<string name="mapbox_myLocationViewContentDescription">Vista de posició. Mostra la teva posició al mapa.</string>
- <string name="mapbox_mapActionDescription">Mostrant un mapa creat amb Mapbox. Desplaça\'t arrossegant amb dos dits. Fes zoom pessigant amb dos dits.</string>
+ <string name="mapbox_mapActionDescription">Mostrant un mapa creat amb Mapbox. Desplaça’t arrossegant amb dos dits. Fes zoom pessigant amb dos dits.</string>
<string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
<string name="mapbox_attributionTelemetryTitle">Millora els mapes de Mapbox</string>
- <string name="mapbox_attributionTelemetryMessage">Estàs ajudant a millorar els mapes d\'OpenStreetMap i de Mapbox aportant dades d\'ús anònimes.</string>
- <string name="mapbox_attributionTelemetryPositive">D\'acord</string>
+ <string name="mapbox_attributionTelemetryMessage">Estàs ajudant a millorar els mapes d’OpenStreetMap i de Mapbox aportant dades d’ús anònimes.</string>
+ <string name="mapbox_attributionTelemetryPositive">D’acord</string>
<string name="mapbox_attributionTelemetryNegative">Disconforme</string>
<string name="mapbox_attributionTelemetryNeutral">Més informació</string>
<string name="mapbox_offline_error_region_definition_invalid">La OfflineRegionDefinition proporcionada no encaixa amb els límits del món: %s</string>
-</resources>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
index fef652c542..f1fcf837ea 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
@@ -11,4 +11,5 @@
<string name="mapbox_attributionTelemetryNegative">Intrekken</string>
<string name="mapbox_attributionTelemetryNeutral">Meer informatie</string>
<string name="mapbox_offline_error_region_definition_invalid">Aangeleverde OfflineRegionDefinition past niet in de wereld omtrek: %s</string>
-</resources>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000000..39880d56ba
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Компас. Активируйте, чтобы повернуть карту на Север.</string>
+ <string name="mapbox_attributionsIconContentDescription">Иконка атрибутов. Активируйте, чтобы показать диалог.</string>
+ <string name="mapbox_myLocationViewContentDescription">Местоположение. Отображает ваше местоположение на карте.</string>
+ <string name="mapbox_mapActionDescription">Отображает карту, созданную при помощи Mapbox. Протисните при помощи двух пальцев. Приблизьте, соединением пальцев. </string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Сделать карты Mapbox лучше</string>
+ <string name="mapbox_attributionTelemetryMessage">Вы помогаете сделать карты OpenStreetMap и Mapbox лучше путем предоставления анонимных данных об использовании.</string>
+ <string name="mapbox_attributionTelemetryPositive">Согласен</string>
+ <string name="mapbox_attributionTelemetryNegative">Не согласен</string>
+ <string name="mapbox_attributionTelemetryNeutral">Дополнительная информация</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Запрошенный OfflineRegionDefinition не входит в допустимые границы: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000000..64c7e3efcc
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Компас. Натисніть щоб зорієнтувати мапу на північ.</string>
+ <string name="mapbox_attributionsIconContentDescription">Значок атрибуції. Натисніть, щоб показати діалог атрибуції.</string>
+ <string name="mapbox_myLocationViewContentDescription">Визначення положення. Показує ваше місцеположення на мапі.</string>
+ <string name="mapbox_mapActionDescription">Показує мапи створені за допомоги Mapbox. Пересувайте мапу двома пальцями. Змінюйте масштаб стуляючи/розводячи два пальці.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Допоможіть зробити мапи Mapbox краще</string>
+ <string name="mapbox_attributionTelemetryMessage">Ви допомагаєте робити мапи OpenStreetMap та Mapbox краще пощирюючи анонімні дані про користування мапами.</string>
+ <string name="mapbox_attributionTelemetryPositive">Погоджуюсь</string>
+ <string name="mapbox_attributionTelemetryNegative">Не погоджуюсь</string>
+ <string name="mapbox_attributionTelemetryNeutral">Додаткова інформація</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Межі ділянки для оффлайнового користування даними за межами світу: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
index 3cfc7d5fdc..716f0ffe70 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
+++ b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
@@ -1,3 +1,3 @@
fabric-identifier=com.mapbox.mapboxsdk.mapbox-android-sdk
-fabric-version=5.1.2
+fabric-version=5.1.4
fabric-build-type=binary
diff --git a/platform/darwin/resources/ca.lproj/Foundation.strings b/platform/darwin/resources/ca.lproj/Foundation.strings
index e36ea9ed8a..f86442f26f 100644
--- a/platform/darwin/resources/ca.lproj/Foundation.strings
+++ b/platform/darwin/resources/ca.lproj/Foundation.strings
@@ -1,8 +1,8 @@
/* Clock position format, long: {hours} o’clock */
-"CLOCK_FMT_LONG" = "%@ en punt";
+"CLOCK_FMT_LONG" = "a les %@";
/* Clock position format, medium: {hours} o’clock */
-"CLOCK_FMT_MEDIUM" = "%@ en punt";
+"CLOCK_FMT_MEDIUM" = "a les %@";
/* Clock position format, short: {hours}:00 */
"CLOCK_FMT_SHORT" = "%@:00";
diff --git a/platform/darwin/resources/de.lproj/Foundation.stringsdict b/platform/darwin/resources/de.lproj/Foundation.stringsdict
index 776528a99c..fb9073fa96 100644
--- a/platform/darwin/resources/de.lproj/Foundation.stringsdict
+++ b/platform/darwin/resources/de.lproj/Foundation.stringsdict
@@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d Grad</string>
+ <key>other</key>
+ <string>%d Grad</string>
+ </dict>
+ </dict>
<key>COORD_MIN_LONG</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
diff --git a/platform/darwin/resources/lt.lproj/Foundation.stringsdict b/platform/darwin/resources/lt.lproj/Foundation.stringsdict
index e3bb31838a..4ab9d4a8bf 100644
--- a/platform/darwin/resources/lt.lproj/Foundation.stringsdict
+++ b/platform/darwin/resources/lt.lproj/Foundation.stringsdict
@@ -16,8 +16,6 @@
<string>%d laipsniai</string>
<key>few</key>
<string>%d laipsniai</string>
- <key>many</key>
- <string>%d laipsniai</string>
<key>other</key>
<string>%d laipsnių</string>
</dict>
@@ -36,8 +34,6 @@
<string>%d minutė</string>
<key>few</key>
<string>%d minutės</string>
- <key>many</key>
- <string>%d minutės</string>
<key>other</key>
<string>%d minučių</string>
</dict>
@@ -56,8 +52,6 @@
<string>%d sekundė</string>
<key>few</key>
<string>%d sekundės</string>
- <key>many</key>
- <string>%d sekundės</string>
<key>other</key>
<string>%d sekundžių</string>
</dict>
diff --git a/platform/darwin/resources/ru.lproj/Foundation.strings b/platform/darwin/resources/ru.lproj/Foundation.strings
new file mode 100644
index 0000000000..fd9eb04ada
--- /dev/null
+++ b/platform/darwin/resources/ru.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ часов";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ час.";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "восток";
+
+/* East, short */
+"COMPASS_E_SHORT" = "В";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "северо-восток";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "СВ";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "юго-восток";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "ЮВ";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "восток-северо-восток";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ВСВ";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "юго-юго-восток";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "ЮЮВ";
+
+/* North, long */
+"COMPASS_N_LONG" = "север";
+
+/* North, short */
+"COMPASS_N_SHORT" = "С";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "северо-восток";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "СВ";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "северо-запад";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "СЗ";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "северо-восток";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "СВ";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "восток-северо-восток";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "ВСВ";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "северо-северо-восток";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "ССВ";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "северо-северо-восток";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "ССВ";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "северо-северо-запад";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "ССЗ";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "северо-запад";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "СЗ";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "северо-северо-запад";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "ССЗ";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "запад-северо-запад";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "ЗСЗ";
+
+/* South, long */
+"COMPASS_S_LONG" = "юг";
+
+/* South, short */
+"COMPASS_S_SHORT" = "Ю";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "юго-восток";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "ЮВ";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "юго-запад";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "ЮЗ";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "юго-восток";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "ЮВ";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "восток-юго-восток";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "ВЮВ";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "юго-юго-восток";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "ЮЮВ";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "юго-юго-восток";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "ЮЮВ";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "юго-юго-запад";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "ЮЮЗ";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "юго-запад";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "ЮЗ";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "юго-юго-запад";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "ЮЮЗ";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "восток-юго-восток";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "ВЮВ";
+
+/* West, long */
+"COMPASS_W_LONG" = "запад";
+
+/* West, short */
+"COMPASS_W_SHORT" = "З";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "северо-запад";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "СЗ";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "юго-запад";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "ЮГ";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "запад-северо-запад";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "ЗСЗ";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "запад-юго-запад";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "ЗЮЗ";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d градус(ов)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ и %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@, и %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@восточной долготы";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@восточной долготы";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@E";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@,%2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d минут(а)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@северной широты";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@северной широты";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@южной широты";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@южной широты";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d секунд(а)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@западной долготы";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@западной долготы";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@W";
+
diff --git a/platform/darwin/resources/uk.lproj/Foundation.strings b/platform/darwin/resources/uk.lproj/Foundation.strings
new file mode 100644
index 0000000000..32a006829f
--- /dev/null
+++ b/platform/darwin/resources/uk.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@год.";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@г.";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "схід";
+
+/* East, short */
+"COMPASS_E_SHORT" = "Сх";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "північний схід";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "ПнСх";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "південний схід";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "ПдСх";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "схід - північний схід";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "Сх-ПнСх";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "схід - південний схід";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "Сх-ПдСх";
+
+/* North, long */
+"COMPASS_N_LONG" = "північ";
+
+/* North, short */
+"COMPASS_N_SHORT" = "Пн";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "північний схід";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "ПнСх";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "північний захід";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "ПнЗх";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "північний схід";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "ПнСх";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "північний схід - схід";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "ПнСх-Сх";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "північний счхід - північ";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "ПнСх-Пн";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "північ - північний схід";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "Пн-ПнСх";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "північ - північний захід";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "Пн-ПнЗх";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "північний захід";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "ПнЗх";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "північний захід - північ";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "ПнЗх-Пн";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "північний захід - захід";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "ПнЗх-Зх";
+
+/* South, long */
+"COMPASS_S_LONG" = "південь";
+
+/* South, short */
+"COMPASS_S_SHORT" = "Пд";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "південний схід";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "ПдСх";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "південний захід";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "ПдЗх";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "південний схід";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "ПдСх";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "південний схід - схід";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "ПдСх-Сх";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "південний схід - південь";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "ПдСх-Пд";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "південь - південний схід";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "Пд-ПдСх";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "південь - південний захід";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "Пд-ПдЗх";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "південний захід";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "ПдЗх";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "південний захід - південь";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "ПдЗх-Пд";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "південний захід - захід";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "ПдЗх-Зх";
+
+/* West, long */
+"COMPASS_W_LONG" = "захід";
+
+/* West, short */
+"COMPASS_W_SHORT" = "Зх";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "північний захід";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "ПнЗх";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "південний захід";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "ПдЗх";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "захід - північний захід";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "Зх-ПнЗх";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "захід - південний захід";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "Зх-ПдЗх";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d градус(ів)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ та %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@, та %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ східної довготи";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ східної довготи";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@Сх";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@, %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d хвилин(а)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ північної широти";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ північної широти";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@Пн";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ південної широти";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ південної широти";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@Пд";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d секунд(а)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ західної довготи";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ західної довготи";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@Зх";
+
diff --git a/platform/darwin/resources/uk.lproj/Foundation.stringsdict b/platform/darwin/resources/uk.lproj/Foundation.stringsdict
index f35f0516e1..fdad193d4d 100644
--- a/platform/darwin/resources/uk.lproj/Foundation.stringsdict
+++ b/platform/darwin/resources/uk.lproj/Foundation.stringsdict
@@ -16,10 +16,8 @@
<string>%d градус</string>
<key>few</key>
<string>%d градуси</string>
- <key>many</key>
- <string>%d градусів</string>
<key>other</key>
- <string>%d градуса</string>
+ <string>%d градусів</string>
</dict>
</dict>
<key>COORD_MIN_LONG</key>
@@ -33,13 +31,11 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
- <string>%d мінута</string>
+ <string>%d хвилина</string>
<key>few</key>
- <string>%d мінути</string>
- <key>many</key>
- <string>%d мінут</string>
+ <string>%d хвилини</string>
<key>other</key>
- <string>%d мінути</string>
+ <string>%d хвилин</string>
</dict>
</dict>
<key>COORD_SEC_LONG</key>
@@ -56,10 +52,8 @@
<string>%d секунда</string>
<key>few</key>
<string>%d секунди</string>
- <key>many</key>
- <string>%d секунд</string>
<key>other</key>
- <string>%d секунди</string>
+ <string>%d секунд</string>
</dict>
</dict>
</dict>
diff --git a/platform/darwin/resources/vi.lproj/Foundation.stringsdict b/platform/darwin/resources/vi.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..d85707f7ff
--- /dev/null
+++ b/platform/darwin/resources/vi.lproj/Foundation.stringsdict
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>other</key>
+ <string>%d độ</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>other</key>
+ <string>%d phút</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>other</key>
+ <string>%d giây</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/zh-Hant.lproj/Foundation.strings b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
index 41b1d2baae..8a02bcfac0 100644
--- a/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
+++ b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
@@ -1,4 +1,4 @@
-/* Clock position format, long: {hours} o’clock */
+/* Clock position format, long: {hours} o’clock */
"CLOCK_FMT_LONG" = "%@點";
/* Clock position format, medium: {hours} o’clock */
@@ -26,16 +26,16 @@
"COMPASS_EbS_SHORT" = "東微南";
/* East-northeast, long */
-"COMPASS_ENE_LONG" = "東北偏東";
+"COMPASS_ENE_LONG" = "東北東";
/* East-northeast, short */
-"COMPASS_ENE_SHORT" = "東北偏東";
+"COMPASS_ENE_SHORT" = "東北東";
/* East-southeast, long */
-"COMPASS_ESE_LONG" = "東南偏東";
+"COMPASS_ESE_LONG" = "東南東";
/* East-southeast, short */
-"COMPASS_ESE_SHORT" = "東南偏東";
+"COMPASS_ESE_SHORT" = "東南東";
/* North, long */
"COMPASS_N_LONG" = "北";
@@ -74,16 +74,16 @@
"COMPASS_NEbN_SHORT" = "東北微北";
/* North-northeast, long */
-"COMPASS_NNE_LONG" = "東北偏北";
+"COMPASS_NNE_LONG" = "北北東";
/* North-northeast, short */
-"COMPASS_NNE_SHORT" = "東北偏北";
+"COMPASS_NNE_SHORT" = "北北東";
/* North-northwest, long */
-"COMPASS_NNW_LONG" = "西北偏北";
+"COMPASS_NNW_LONG" = "北北西";
/* North-northwest, short */
-"COMPASS_NNW_SHORT" = "西北偏北";
+"COMPASS_NNW_SHORT" = "北北西";
/* Northwest, long */
"COMPASS_NW_LONG" = "西北";
@@ -140,16 +140,16 @@
"COMPASS_SEbS_SHORT" = "東南微南";
/* South-southeast, long */
-"COMPASS_SSE_LONG" = "東南偏南";
+"COMPASS_SSE_LONG" = "南南東";
/* South-southeast, short */
-"COMPASS_SSE_SHORT" = "東南偏南";
+"COMPASS_SSE_SHORT" = "南南東";
/* South-southwest, long */
-"COMPASS_SSW_LONG" = "西南偏南";
+"COMPASS_SSW_LONG" = "南南西";
/* South-southwest, short */
-"COMPASS_SSW_SHORT" = "西南偏南";
+"COMPASS_SSW_SHORT" = "南南西";
/* Southwest, long */
"COMPASS_SW_LONG" = "西南";
@@ -158,16 +158,16 @@
"COMPASS_SW_SHORT" = "西南";
/* Southwest by south, long */
-"COMPASS_SWbS_LONG" = "西南偏南";
+"COMPASS_SWbS_LONG" = "西南微南";
/* Southwest by south, short */
-"COMPASS_SWbS_SHORT" = "西南偏南";
+"COMPASS_SWbS_SHORT" = "西南微南";
/* Southwest by west, long */
-"COMPASS_SWbW_LONG" = "西南偏西";
+"COMPASS_SWbW_LONG" = "西南微西";
/* Southwest by west, short */
-"COMPASS_SWbW_SHORT" = "西南偏西";
+"COMPASS_SWbW_SHORT" = "西南微西";
/* West, long */
"COMPASS_W_LONG" = "西";
@@ -188,16 +188,16 @@
"COMPASS_WbS_SHORT" = "西微南";
/* West-northwest, long */
-"COMPASS_WNW_LONG" = "西北偏西";
+"COMPASS_WNW_LONG" = "西北西";
/* West-northwest, short */
-"COMPASS_WNW_SHORT" = "西北偏西";
+"COMPASS_WNW_SHORT" = "西北西";
/* West-southwest, long */
-"COMPASS_WSW_LONG" = "西南偏西";
+"COMPASS_WSW_LONG" = "西南西";
/* West-southwest, short */
-"COMPASS_WSW_SHORT" = "西南偏西";
+"COMPASS_WSW_SHORT" = "西南西";
/* Degrees format, long */
"COORD_DEG_LONG" = "%d度";
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 98be70be9c..0b360de8fc 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -233,66 +233,38 @@ MGL_EXPORT
+ (NSURL *)satelliteStreetsStyleURLWithVersion:(NSInteger)version;
/**
- Returns the URL to the current version of the
+ Returns the URL to version 2 of the
<a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
style.
- Traffic Day color-codes roads based on live traffic congestion data. Traffic
- data is currently available in
- <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
-
- @warning The return value may change in a future release of the SDK. If you use
- any feature that depends on a specific aspect of a default style – for
- instance, the minimum zoom level that includes roads – use the
- `-trafficDayStyleURLWithVersion:` method instead. Such details may change
- significantly from version to version.
*/
-+ (NSURL *)trafficDayStyleURL;
++ (NSURL *)trafficDayStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));
/**
Returns the URL to the given version of the
<a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
style as of publication.
-
- Traffic Day color-codes roads based on live traffic congestion data. Traffic
- data is currently available in
- <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
-
+
@param version A specific version of the style.
*/
-+ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version;
++ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));;
/**
- Returns the URL to the current version of the
+ Returns the URL to the version 2 of the
<a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
style.
- Traffic Night color-codes roads based on live traffic congestion data and is
- designed to maximize legibility in low-light situations. Traffic data is
- currently available in
- <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
-
- @warning The return value may change in a future release of the SDK. If you use
- any feature that depends on a specific aspect of a default style – for
- instance, the minimum zoom level that includes roads – use the
- `-trafficNightStyleURLWithVersion:` method instead. Such details may change
- significantly from version to version.
*/
-+ (NSURL *)trafficNightStyleURL;
++ (NSURL *)trafficNightStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
/**
- Returns the URL to the given version of the
+ Returns the URL to to the version 2 of the
<a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
style as of publication.
-
- Traffic Night color-codes roads based on live traffic congestion data and is
- designed to maximize legibility in low-light situations. Traffic data is
- currently available in
- <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
-
+
@param version A specific version of the style.
*/
-+ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version;
++ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
#pragma mark Accessing Metadata About the Style
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 94f199fd21..52efc7a85a 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -108,8 +108,6 @@ MGL_DEFINE_STYLE(light, light)
MGL_DEFINE_STYLE(dark, dark)
MGL_DEFINE_STYLE(satellite, satellite)
MGL_DEFINE_STYLE(satelliteStreets, satellite-streets)
-MGL_DEFINE_STYLE(trafficDay, traffic-day)
-MGL_DEFINE_STYLE(trafficNight, traffic-night)
// Make sure all the styles listed in mbgl::util::default_styles::orderedStyles
// are defined above and also declared in MGLStyle.h.
@@ -136,6 +134,35 @@ static NSURL *MGLStyleURL_emerald;
return MGLStyleURL_emerald;
}
+// Traffic Day is no longer getting new versions as a default style, so the current version is hard-coded here.
+static NSURL *MGLStyleURL_trafficDay;
++ (NSURL *)trafficDayStyleURL {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ MGLStyleURL_trafficDay = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-day-v2"];
+ });
+ return MGLStyleURL_trafficDay;
+}
+
++ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version {
+ return [NSURL URLWithString:[@"mapbox://styles/mapbox/traffic-day-v" stringByAppendingFormat:@"%li", (long)version]];
+}
+
+// Traffic Night is no longer getting new versions as a default style, so the current version is hard-coded here.
+static NSURL *MGLStyleURL_trafficNight;
++ (NSURL *)trafficNightStyleURL {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ MGLStyleURL_trafficNight = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-night-v2"];
+ });
+ return MGLStyleURL_trafficNight;
+}
+
++ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version {
+ return [NSURL URLWithString:[@"mapbox://styles/mapbox/traffic-night-v" stringByAppendingFormat:@"%li", (long)version]];
+}
+
+
#pragma mark -
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 608cfdfd2d..8f610e338c 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -99,6 +99,8 @@
@(mbgl::util::default_styles::satelliteStreets.url));
XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:99].absoluteString,
@"mapbox://styles/mapbox/satellite-streets-v99");
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:mbgl::util::default_styles::trafficDay.currentVersion].absoluteString,
@(mbgl::util::default_styles::trafficDay.url));
XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:99].absoluteString,
@@ -107,6 +109,7 @@
@(mbgl::util::default_styles::trafficNight.url));
XCTAssertEqualObjects([MGLStyle trafficNightStyleURLWithVersion:99].absoluteString,
@"mapbox://styles/mapbox/traffic-night-v99");
+#pragma clang diagnostic pop
static_assert(8 == mbgl::util::default_styles::numOrderedStyles,
"MGLStyleTests isn’t testing all the styles in mbgl::util::default_styles.");
@@ -140,7 +143,7 @@
NSString *styleHeader = self.stringWithContentsOfStyleHeader;
NSError *versionedMethodError;
- NSString *versionedMethodExpressionString = @(R"RE(^\+\s*\(NSURL\s*\*\s*\)\s*\w+StyleURLWithVersion\s*:\s*\(\s*NSInteger\s*\)\s*version\s*;)RE");
+ NSString *versionedMethodExpressionString = @(R"RE(^\+\s*\(NSURL\s*\*\s*\)\s*\w+StyleURLWithVersion\s*:\s*\(\s*NSInteger\s*\)\s*version\s*\b)RE");
NSRegularExpression *versionedMethodExpression = [NSRegularExpression regularExpressionWithPattern:versionedMethodExpressionString options:NSRegularExpressionAnchorsMatchLines error:&versionedMethodError];
XCTAssertNil(versionedMethodError, @"Error compiling regular expression to search for versioned methods.");
NSUInteger numVersionedMethodDeclarations = [versionedMethodExpression numberOfMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length)];
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 6d54e0a7e7..8dd1c5d8c7 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -34,7 +34,21 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed an issue that could cause line label rendering glitches when the line geometry is projected to a point behind the plane of the camera. ([#9865](https://github.com/mapbox/mapbox-gl-native/pull/9865))
* Fixed an issue that could cause a crash when using `-[MGLMapView flyToCamera:completionHandler:]` and related methods with zoom levels at or near the maximum value. ([#9381](https://github.com/mapbox/mapbox-gl-native/pull/9381))
-## 3.6.2
+## 3.6.4 - September 25, 2017
+
+* Fixed an issue where stale (but still valid) map data could be ignored in offline mode. ([#10012](https://github.com/mapbox/mapbox-gl-native/pull/10012))
+
+## 3.6.3 - September 15, 2017
+
+* Added the option to display an always-on heading indicator with the default user location annotation, controlled via the `MGLMapView.showsUserHeadingIndicator` property. ([#9886](https://github.com/mapbox/mapbox-gl-native/pull/9886))
+* Fixed an issue where user heading tracking mode would update too frequently. ([#9845](https://github.com/mapbox/mapbox-gl-native/pull/9845))
+* Added support for iOS 11 location usage descriptions. ([#9869](https://github.com/mapbox/mapbox-gl-native/pull/9869))
+* Fixed an issue where `MGLUserLocation.location` did not follow its documented initialization behavior. This property will now properly return `nil` until the user’s location has been determined. ([#9639](https://github.com/mapbox/mapbox-gl-native/pull/9639))
+* `MGLMapView`’s `minimumZoomLevel` and `maximumZoomLevel` properties are now available in Interface Builder’s Attributes inspector. ([#9729](https://github.com/mapbox/mapbox-gl-native/pull/9729))
+* Deprecated `+[MGLStyle trafficDayStyleURL]` and `+[MGLStyle trafficNightStyleURL]` with no replacement method. To use the Traffic Day and Traffic Night styles going forward, we recommend that you use the underlying URL. ([#9918](https://github.com/mapbox/mapbox-gl-native/pull/9918))
+* Fixed a crash that sometimes occurred when a map view's view controller was deallocated. ([#9995](https://github.com/mapbox/mapbox-gl-native/pull/9995))
+
+## 3.6.2 - August 18, 2017
* Added an `MGLStyle.localizesLabels` property, off by default, that localizes any Mapbox Streets–sourced symbol layer into the user’s preferred language. ([#9582](https://github.com/mapbox/mapbox-gl-native/pull/9582))
* Added an additional camera method to MGLMapView that accepts an edge padding parameter. ([#9651](https://github.com/mapbox/mapbox-gl-native/pull/9651))
diff --git a/platform/ios/app/Info.plist b/platform/ios/app/Info.plist
index 167e66fa09..a98a8c10c5 100644
--- a/platform/ios/app/Info.plist
+++ b/platform/ios/app/Info.plist
@@ -27,9 +27,11 @@
<key>NSHumanReadableCopyright</key>
<string>© 2014–2017 Mapbox</string>
<key>NSLocationAlwaysUsageDescription</key>
- <string>The map will ALWAYS display the user’s location.</string>
+ <string>The map will display your location. The map may also use your location when it isn’t visible in order to improve OpenStreetMap and Mapbox products.</string>
<key>NSLocationWhenInUseUsageDescription</key>
- <string>The map will display the user’s location.</string>
+ <string>The map will display your location.</string>
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
+ <string>The map will display your location. If you choose Always, the map may also use your location when it isn’t visible in order to improve OpenStreetMap and Mapbox products.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 8f7896ffee..07838bc6bd 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -115,7 +115,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@property (nonatomic) IBOutlet MGLMapView *mapView;
-@property (weak, nonatomic) IBOutlet UILabel *hudLabel;
+@property (weak, nonatomic) IBOutlet UIButton *hudLabel;
@property (nonatomic) NSInteger styleIndex;
@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) BOOL customUserLocationAnnnotationEnabled;
@@ -163,7 +163,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
self.mapView.scaleBar.hidden = NO;
+ self.mapView.showsUserHeadingIndicator = YES;
self.hudLabel.hidden = YES;
+ self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
if ([MGLAccountManager accessToken].length)
{
@@ -355,7 +357,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[settingsTitles addObjectsFromArray:@[
[NSString stringWithFormat:@"%@ Reuse Queue Stats", (_reuseQueueStatsEnabled ? @"Hide" :@"Show")],
@"Start World Tour",
- [NSString stringWithFormat:@"%@ Zoom Level", (_showZoomLevelEnabled ? @"Hide" :@"Show")],
+ [NSString stringWithFormat:@"%@ Zoom/Pitch/Direction Label", (_showZoomLevelEnabled ? @"Hide" :@"Show")],
@"Embedded Map View",
[NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")],
[NSString stringWithFormat:@"Show Labels in %@", (_usingLocaleBasedCountryLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@@ -550,6 +552,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.reuseQueueStatsEnabled = !self.reuseQueueStatsEnabled;
self.hudLabel.hidden = !self.reuseQueueStatsEnabled;
self.showZoomLevelEnabled = NO;
+ [self updateHUD];
break;
}
case MBXSettingsMiscellaneousShowZoomLevel:
@@ -557,6 +560,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.showZoomLevelEnabled = !self.showZoomLevelEnabled;
self.hudLabel.hidden = !self.showZoomLevelEnabled;
self.reuseQueueStatsEnabled = NO;
+ [self updateHUD];
break;
}
case MBXSettingsMiscellaneousScrollView:
@@ -1597,8 +1601,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[MGLStyle darkStyleURL],
[MGLStyle satelliteStyleURL],
[MGLStyle satelliteStreetsStyleURL],
- [MGLStyle trafficDayStyleURL],
- [MGLStyle trafficNightStyleURL],
+ [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-day-v2"],
+ [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-night-v2"],
+
];
NSAssert(styleNames.count == styleURLs.count, @"Style names and URLs don’t match.");
@@ -1873,22 +1878,33 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)mapViewRegionIsChanging:(MGLMapView *)mapView
{
+ [self updateHUD];
+}
+
+- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
+ [self updateHUD];
+}
+
+- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(MGLUserLocation *)userLocation {
+ [self updateHUD];
+}
+
+- (void)updateHUD {
+ if (!self.reuseQueueStatsEnabled && !self.showZoomLevelEnabled) return;
+
+ NSString *hudString;
+
if (self.reuseQueueStatsEnabled) {
NSUInteger queuedAnnotations = 0;
- for (NSArray *queue in self.mapView.annotationViewReuseQueueByIdentifier.allValues)
- {
+ for (NSArray *queue in self.mapView.annotationViewReuseQueueByIdentifier.allValues) {
queuedAnnotations += queue.count;
}
- self.hudLabel.text = [NSString stringWithFormat:@" Visible: %ld Queued: %ld", (unsigned long)mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations];
+ hudString = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (unsigned long)self.mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations];
} else if (self.showZoomLevelEnabled) {
- self.hudLabel.text = [NSString stringWithFormat:@" Zoom: %.2f", self.mapView.zoomLevel];
+ hudString = [NSString stringWithFormat:@"%.2f ∕ ↕\U0000FE0E%.f° ∕ %.f°", self.mapView.zoomLevel, self.mapView.camera.pitch, self.mapView.direction];
}
-}
-- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
- if (self.showZoomLevelEnabled) {
- self.hudLabel.text = [NSString stringWithFormat:@" Zoom: %.2f", self.mapView.zoomLevel];
- }
+ [self.hudLabel setTitle:hudString forState:UIControlStateNormal];
}
@end
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index c7bcd6e0f0..507582213f 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G8c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
@@ -33,17 +33,24 @@
<outletCollection property="gestureRecognizers" destination="lfd-mn-7en" appends="YES" id="0PH-gH-GRm"/>
</connections>
</view>
- <label opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
- <rect key="frame" x="179" y="626" width="180" height="21"/>
+ <button opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
+ <rect key="frame" x="319" y="606" width="40" height="21"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <accessibility key="accessibilityConfiguration">
+ <accessibilityTraits key="traits" button="YES" notEnabled="YES"/>
+ </accessibility>
<constraints>
- <constraint firstAttribute="width" constant="180" id="OL2-l5-I2f"/>
- <constraint firstAttribute="height" constant="21" id="xHg-ye-wzT"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="40" id="OL2-l5-I2f"/>
+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="xHg-ye-wzT"/>
</constraints>
- <fontDescription key="fontDescription" type="system" pointSize="8"/>
- <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
- <nil key="highlightedColor"/>
- </label>
+ <fontDescription key="fontDescription" type="system" pointSize="10"/>
+ <inset key="contentEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+ <integer key="value" value="2"/>
+ </userDefinedRuntimeAttribute>
+ </userDefinedRuntimeAttributes>
+ </button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@@ -51,7 +58,8 @@
<constraint firstItem="kNe-zV-9ha" firstAttribute="bottom" secondItem="m8o-i7-QIy" secondAttribute="top" id="Etp-BC-E1N"/>
<constraint firstAttribute="trailing" secondItem="kNe-zV-9ha" secondAttribute="trailing" id="MGr-8G-VEb"/>
<constraint firstItem="58y-pX-YyB" firstAttribute="trailing" secondItem="Z9X-fc-PUC" secondAttribute="trailingMargin" id="O3a-bR-boI"/>
- <constraint firstItem="m8o-i7-QIy" firstAttribute="top" secondItem="58y-pX-YyB" secondAttribute="bottom" constant="20" id="cjh-ZS-Mv4"/>
+ <constraint firstItem="58y-pX-YyB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Z9X-fc-PUC" secondAttribute="leadingMargin" id="ceH-yz-ewY"/>
+ <constraint firstItem="m8o-i7-QIy" firstAttribute="top" secondItem="58y-pX-YyB" secondAttribute="bottom" constant="40" id="cjh-ZS-Mv4"/>
<constraint firstItem="kNe-zV-9ha" firstAttribute="top" secondItem="Z9X-fc-PUC" secondAttribute="top" id="qMm-e9-jxH"/>
</constraints>
</view>
@@ -66,7 +74,7 @@
</connections>
</barButtonItem>
<button key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="KsN-ny-Hou">
- <rect key="frame" x="61" y="7" width="207" height="30"/>
+ <rect key="frame" x="65" y="5.5" width="203" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<state key="normal" title="Streets"/>
@@ -94,7 +102,7 @@
</rightBarButtonItems>
</navigationItem>
<connections>
- <outlet property="hudLabel" destination="58y-pX-YyB" id="MEh-ir-3IH"/>
+ <outlet property="hudLabel" destination="58y-pX-YyB" id="aGG-7a-bZR"/>
<outlet property="mapView" destination="kNe-zV-9ha" id="VNR-WO-1q4"/>
<segue destination="zvf-Qd-4Ru" kind="show" identifier="ShowSnapshots" id="hzX-Jp-UJq"/>
</connections>
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 060fb45d81..debbf1ccf3 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -229,8 +229,15 @@
9620BB391E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
9620BB3A1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
9620BB3B1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
+ 966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; };
+ 966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
+ 966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
+ 966FCF531F3C322400F2B6DE /* MGLUserLocationHeadingArrowLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF501F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.h */; };
+ 966FCF541F3C323300F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF511F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.m */; };
+ 966FCF551F3C323500F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF511F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.m */; };
968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
96E027231E57C76E004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027251E57C76E004B8E66 /* Localizable.strings */; };
+ 96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */; };
DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC8F1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC901D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */; };
@@ -707,6 +714,10 @@
9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
9660916E1E5BBFDC00A9A03B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
9660916F1E5BBFDE00A9A03B /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingBeamLayer.h; sourceTree = "<group>"; };
+ 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLUserLocationHeadingBeamLayer.m; sourceTree = "<group>"; };
+ 966FCF501F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingArrowLayer.h; sourceTree = "<group>"; };
+ 966FCF511F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLUserLocationHeadingArrowLayer.m; sourceTree = "<group>"; };
968F36B41E4D0FC6003A5522 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027241E57C76E004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027271E57C77A004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -717,6 +728,7 @@
96E0272C1E57C7E5004B8E66 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
96E0272D1E57C7E6004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
96E0272E1E57C7E7004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = "<group>"; };
DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
@@ -780,7 +792,7 @@
DA618B191E68883700CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ca; path = ca.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
DA618B1A1E68883900CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B1B1E68884E00CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
- DA618B1C1E6888EC00CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DA618B1C1E6888EC00CB7F44 /* ca */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Foundation.strings; sourceTree = "<group>"; };
DA618B1D1E6888F500CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ca; path = ca.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B1E1E688A3700CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Root.strings; sourceTree = "<group>"; };
DA618B251E68920500CB7F44 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Foundation.strings; sourceTree = "<group>"; };
@@ -789,6 +801,10 @@
DA618B2C1E68933600CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Root.strings; sourceTree = "<group>"; };
DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
+ DA704CBB1F637311004B3F28 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DA704CBC1F637405004B3F28 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DA704CBD1F63746E004B3F28 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
+ DA704CC71F6663A3004B3F28 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Foundation.strings; sourceTree = "<group>"; };
DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; };
DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; };
DA737ADA1E59139D00AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
@@ -904,7 +920,7 @@
DAA32CAC1E4C4971006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CB11E4C4C8A006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Root.strings; sourceTree = "<group>"; };
DAA32CB51E4C4CF4006F8D24 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Foundation.strings; sourceTree = "<group>"; };
- DAA32CB71E4C4ED8006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CB71E4C4ED8006F8D24 /* sv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CB81E4C4EE6006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Root.strings; sourceTree = "<group>"; };
DAA32CBC1E4C4F5D006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CBD1E4C4F62006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Foundation.strings; sourceTree = "<group>"; };
@@ -929,6 +945,7 @@
DABCABC01CB80717000A7C39 /* locations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locations.hpp; sourceTree = "<group>"; };
DAC49C621CD07D74009E1AA3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
DACCD9C81F1F473700BB09A1 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Root.strings; sourceTree = "<group>"; };
+ DACFE7981F66EA2100630DA8 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DAD165691CF41981001FF4B9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; };
DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; };
DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
@@ -944,8 +961,8 @@
DAF0D80F1DFE0EA000B28378 /* MGLRasterSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource_Private.h; sourceTree = "<group>"; };
DAF0D8121DFE0EC500B28378 /* MGLVectorSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorSource_Private.h; sourceTree = "<group>"; };
DAF0D8171DFE6B2800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
- DAFBD0D21E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Foundation.strings"; sourceTree = "<group>"; };
- DAFBD0D31E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ DAFBD0D21E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Foundation.strings"; sourceTree = "<group>"; };
+ DAFBD0D31E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
DAFBD0D41E3FA7A2000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Root.strings"; sourceTree = "<group>"; };
DD0902A21DB18DE700C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
@@ -1619,8 +1636,8 @@
DAD165841CF4D06B001FF4B9 /* Annotations */ = {
isa = PBXGroup;
children = (
- 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */,
404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */,
+ 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */,
40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */,
DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */,
DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */,
@@ -1639,6 +1656,11 @@
359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */,
354B83941D2E873E005D9406 /* MGLUserLocationAnnotationView.h */,
354B83951D2E873E005D9406 /* MGLUserLocationAnnotationView.m */,
+ 966FCF501F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.h */,
+ 966FCF511F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.m */,
+ 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */,
+ 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */,
+ 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */,
);
name = Annotations;
sourceTree = "<group>";
@@ -1695,6 +1717,7 @@
DA8847FB1CBAFA5100AB86E3 /* MGLShape.h in Headers */,
353933F51D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */,
DA88485A1CBAFB9800AB86E3 /* MGLUserLocation_Private.h in Headers */,
+ 966FCF531F3C322400F2B6DE /* MGLUserLocationHeadingArrowLayer.h in Headers */,
DA27C24F1CBB4C11000B0ECD /* MGLAccountManager_Private.h in Headers */,
DA8847FC1CBAFA5100AB86E3 /* MGLStyle.h in Headers */,
DD9BE4F71EB263C50079A3AF /* UIViewController+MGLAdditions.h in Headers */,
@@ -1726,9 +1749,11 @@
DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */,
DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */,
DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */,
+ 96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */,
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */,
DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */,
558DE7A01E5615E400C7916D /* MGLFoundation_Private.h in Headers */,
+ 966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */,
DA88483D1CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h in Headers */,
DA17BE301CC4BAC300402C41 /* MGLMapView_Private.h in Headers */,
DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */,
@@ -2265,6 +2290,7 @@
3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
DA00FC901D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */,
DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */,
+ 966FCF541F3C323300F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */,
DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */,
927FBD011F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */,
350098BD1D480108004B2AF0 /* MGLVectorSource.mm in Sources */,
@@ -2305,6 +2331,7 @@
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
7E016D861D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */,
DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */,
+ 966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
DA8848301CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m in Sources */,
353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
@@ -2349,6 +2376,7 @@
3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
DA00FC911D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */,
DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */,
+ 966FCF551F3C323500F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */,
DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */,
927FBD021F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */,
350098BE1D480108004B2AF0 /* MGLVectorSource.mm in Sources */,
@@ -2390,6 +2418,7 @@
35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
7E016D871D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */,
DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */,
+ 966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
DAA4E4231CBB730400178DFB /* MGLPolygon.mm in Sources */,
353AFA171D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
@@ -2538,6 +2567,8 @@
DA618B1C1E6888EC00CB7F44 /* ca */,
DA618B251E68920500CB7F44 /* lt */,
DAE9E0F11EB7BF1B001E8E8B /* es */,
+ DA704CBB1F637311004B3F28 /* ru */,
+ DA704CC71F6663A3004B3F28 /* uk */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -2556,6 +2587,7 @@
DA1AC0201E5B8917006DF1D6 /* uk */,
DA618B1D1E6888F500CB7F44 /* ca */,
DA618B261E68920D00CB7F44 /* lt */,
+ DACFE7981F66EA2100630DA8 /* vi */,
);
name = Foundation.stringsdict;
sourceTree = "<group>";
@@ -2581,6 +2613,8 @@
DA57D4AA1EBA8ED300793288 /* es */,
DA57D4AB1EBA909900793288 /* lt */,
DA57D4AC1EBA922A00793288 /* vi */,
+ DA704CBC1F637405004B3F28 /* uk */,
+ DA704CBD1F63746E004B3F28 /* zh-Hant */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
diff --git a/platform/ios/resources/es.lproj/Localizable.strings b/platform/ios/resources/es.lproj/Localizable.strings
index 6fbfb23dda..75f799fcd9 100644
--- a/platform/ios/resources/es.lproj/Localizable.strings
+++ b/platform/ios/resources/es.lproj/Localizable.strings
@@ -1,4 +1,4 @@
-/* Accessibility hint */
+/* Accessibility hint */
"ANNOTATION_A11Y_HINT" = "Muestra más información";
/* No comment provided by engineer. */
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Cancelar";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Regresa al mapa";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Gira el mapa para hacer frente al norte";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Acerca de este mapa";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "No se pudo cargar el mapa debido a un error desconocido.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "No se pudo cargar el mapa debido a un error de carga en el estilo.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -38,11 +47,20 @@
"MAP_A11Y_LABEL" = "Mapa";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "Zoom %1$dx\nAnotaciones visibles: %2$ld";
+"MAP_A11Y_VALUE" = "Zoom x%1$d\nAnotaciones visibles: %2$ld";
+
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "No se pudo cargar el mapa debido a que el estilo está dañado.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "La versión %@ de Mapbox iOS SDK está disponible:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "No se pudo cargar el mapa debido a que no se encuentra el estilo o está incompleto.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Ayudas a mejorar los mapas de OpenStreetMap y Mapbox al aportar datos de uso anónimos.";
diff --git a/platform/ios/resources/lt.lproj/Localizable.stringsdict b/platform/ios/resources/lt.lproj/Localizable.stringsdict
index 0200327f04..732a8d23ac 100644
--- a/platform/ios/resources/lt.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/lt.lproj/Localizable.stringsdict
@@ -14,11 +14,11 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
- <string>Priartinimas: %dx</string>
+ <string>Priartinimas %dx</string>
<key>few</key>
- <string>Priartinimas: %dx</string>
+ <string>Priartinimas %dx</string>
<key>other</key>
- <string>Priartinimas: %dx</string>
+ <string>Priartinimas %dx</string>
</dict>
<key>count</key>
<dict>
@@ -27,11 +27,11 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
- <string>Matomos anotacijos: %d anotacija</string>
+ <string>%d matoma anotacija</string>
<key>few</key>
- <string>Matomos anotacijos: %d anotacijos</string>
+ <string>%d matomos anotacijos</string>
<key>other</key>
- <string>Matomos anotacijos: %d anotacijų</string>
+ <string>%d matomų anotacijų</string>
</dict>
</dict>
</dict>
diff --git a/platform/ios/resources/ru.lproj/Localizable.strings b/platform/ios/resources/ru.lproj/Localizable.strings
index 1c3b46f057..40f59a3356 100644
--- a/platform/ios/resources/ru.lproj/Localizable.strings
+++ b/platform/ios/resources/ru.lproj/Localizable.strings
@@ -2,7 +2,7 @@
"ANNOTATION_A11Y_HINT" = "Показать больше информации";
/* No comment provided by engineer. */
-"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was:%@";
/* No comment provided by engineer. */
"API_CLIENT_400_REASON" = "The status code was %ld";
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Отмена";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Вернуться на карту";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Повернуть карту на север";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Об этой карте";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Не удалось загрузить карту из-за неизвестной ошибки.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Не удалось загрузить карту так как невозможно загрузить стиль.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -40,9 +49,18 @@
/* Map accessibility value */
"MAP_A11Y_VALUE" = "Масштаб %1$dx\n%2$ld аннотации(й) видны";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Не удалось загрузить карту из-за ошибки в стиле.";
+
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK версии %@теперь доступен.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Не удалось загрузить карту так как стиль не найден или несовместим.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Вы можете помочь сделать карты OpenStreetMap и Mapbox лучше путем предоставления анонимных данных об использовании.";
diff --git a/platform/ios/resources/sv.lproj/Localizable.strings b/platform/ios/resources/sv.lproj/Localizable.strings
index fb787b973a..b10b1b06ed 100644
--- a/platform/ios/resources/sv.lproj/Localizable.strings
+++ b/platform/ios/resources/sv.lproj/Localizable.strings
@@ -38,7 +38,7 @@
"LOAD_MAP_FAILED_DESC" = "Kartan kunde inte laddas på grund av att ett okänt fel inträffade.";
/* User-friendly error description */
-"LOAD_STYLE_FAILED_DESC" = "The map failed to load because the style can't be loaded.";
+"LOAD_STYLE_FAILED_DESC" = "Kartan kunde inte laddas på grund av att stilen är skadad.";
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -50,7 +50,7 @@
"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotering(ar) synliga";
/* User-friendly error description */
-"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
+"PARSE_STYLE_FAILED_DESC" = "Kartan kunde inte laddas på grund av att stilen är skadad.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
@@ -59,7 +59,7 @@
"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK version %@ är nu tillgängligt:";
/* User-friendly error description */
-"STYLE_NOT_FOUND_DESC" = "The map failed to load because the style can’t be found or is incompatible.";
+"STYLE_NOT_FOUND_DESC" = "Kartan kunde inte laddas på grund av ett okänt fel.";
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Du kan hjälpa till att göra OpenStreetMap och Mapbox karttjänster bättre genom att bidra med anonymiserad användningsdata.";
diff --git a/platform/ios/resources/uk.lproj/Localizable.strings b/platform/ios/resources/uk.lproj/Localizable.strings
index 86873c69c0..8392f945b8 100644
--- a/platform/ios/resources/uk.lproj/Localizable.strings
+++ b/platform/ios/resources/uk.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Скасувати";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Повернутись до мапи";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Обертає напрямок мапи на північ";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Про мапу";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Неможливо завантажити мапу через невідому помилку.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Неможливо завантажити мапу, бо неможливо завантажити стиль.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -38,13 +47,22 @@
"MAP_A11Y_LABEL" = "Мапа";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+"MAP_A11Y_VALUE" = "Масштаб %1$dx\n%2$ld підпис(ів) показано";
+
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Неможливо завантажити мапу, через помилки в стилі.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Доступна версія %@ Mapbox iOS SDK:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Неможливо завантажити мапу, бо неможливо знайти стиль або він несумісний.";
+
/* Telemetry prompt message */
-"TELEMETRY_DISABLED_MSG" = "Ви можете допомогти зробити мапи OpenStreetMap та Mapbox кращими надаючі анонімізовані дані про користування застосунком.";
+"TELEMETRY_DISABLED_MSG" = "Ви можете допомогти зробити мапи OpenStreetMap та Mapbox кращими надаючи анонімізовані дані про користування застосунком.";
/* Telemetry prompt button */
"TELEMETRY_DISABLED_OFF" = "Відмовитись";
@@ -53,7 +71,7 @@
"TELEMETRY_DISABLED_ON" = "Брати участь";
/* Telemetry prompt message */
-"TELEMETRY_ENABLED_MSG" = "Ви допомагаєте робити мапи OpenStreetMap та Mapbox кращими надаючі анонімізовані дані про користування застосунком.";
+"TELEMETRY_ENABLED_MSG" = "Ви допомагаєте робити мапи OpenStreetMap та Mapbox кращими надаючи анонімізовані дані про користування застосунком.";
/* Telemetry prompt button */
"TELEMETRY_ENABLED_OFF" = "Припинити участь";
@@ -68,7 +86,7 @@
"TELEMETRY_NAME" = "Телеметрія Mapbox";
/* Telemetry prompt title */
-"TELEMETRY_TITLE" = "Робить мапи Mapbox кращими";
+"TELEMETRY_TITLE" = "Робіть мапи Mapbox кращими";
/* Default user location annotation title */
"USER_DOT_TITLE" = "Ви тут";
diff --git a/platform/ios/resources/uk.lproj/Localizable.stringsdict b/platform/ios/resources/uk.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..a81b01477e
--- /dev/null
+++ b/platform/ios/resources/uk.lproj/Localizable.stringsdict
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Масштаб %dx</string>
+ <key>few</key>
+ <string>Масштаб %dx</string>
+ <key>other</key>
+ <string>Масштаб %dx</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>Показано %d підпис</string>
+ <key>few</key>
+ <string>Показано %d підписи</string>
+ <key>other</key>
+ <string>Показано %d підпис(ів)</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/zh-Hant.lproj/Localizable.strings b/platform/ios/resources/zh-Hant.lproj/Localizable.strings
index 1b4e7416d9..585ff3dd27 100644
--- a/platform/ios/resources/zh-Hant.lproj/Localizable.strings
+++ b/platform/ios/resources/zh-Hant.lproj/Localizable.strings
@@ -1,4 +1,4 @@
-/* Accessibility hint */
+/* Accessibility hint */
"ANNOTATION_A11Y_HINT" = "顯示信息";
/* No comment provided by engineer. */
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "取消";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "回到地圖";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "旋轉地圖使正北朝上";
@@ -19,24 +22,24 @@
/* Compass abbreviation for north */
"COMPASS_NORTH" = "北";
-/* Copyright notice in attribution sheet */
-"COPY_MAPBOX" = "© Mapbox";
-
-/* Copyright notice in attribution sheet */
-"COPY_OSM" = "© OpenStreetMap";
-
/* Instructions in Interface Builder designable; {key}, {plist file name} */
-"DESIGNABLE" = "在%2$@中將你的access token設爲%1$@可在這裏顯示Mapbox上的地圖\n\n更多說明請見";
+"DESIGNABLE" = "在%2$@中將你的access token設爲%1$@即可顯示Mapbox上的地圖\n\n更多說明請見";
/* Setup documentation URL display string; keep as short as possible */
"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
/* Accessibility hint */
-"INFO_A11Y_HINT" = "顯示致謝、用戶反饋及更多";
+"INFO_A11Y_HINT" = "顯示致謝、用戶意見表及更多";
/* Accessibility label */
"INFO_A11Y_LABEL" = "關於這個地圖";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "發生不知名的錯誤,無法載入地圖。";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "載入樣式表時發生錯誤,無法載入地圖。";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -44,14 +47,20 @@
"MAP_A11Y_LABEL" = "地圖";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "地圖縮放%1$d倍\n有%2$ld處標記可見";
+"MAP_A11Y_VALUE" = "縮放地圖%1$d倍\n可顯示%2$ld處標記";
-/* Action in attribution sheet */
-"MAP_FEEDBACK" = "改進地圖";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "樣式表有毀損,無法載入地圖。";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK %@版現已開放下載:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "找不到樣式表或樣式表不兼容,無法載入地圖。";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "你可以提供匿名數據來幫助OpenStreetMap和Mapbox的地圖變得更好。";
@@ -62,7 +71,7 @@
"TELEMETRY_DISABLED_ON" = "我要參與";
/* Telemetry prompt message */
-"TELEMETRY_ENABLED_MSG" = "你的匿名數據在幫助OpenStreetMap和Mapbox的地圖變得更好。";
+"TELEMETRY_ENABLED_MSG" = "你的匿名數據正在改善OpenStreetMap和Mapbox地圖。";
/* Telemetry prompt button */
"TELEMETRY_ENABLED_OFF" = "不再參與";
@@ -74,11 +83,11 @@
"TELEMETRY_MORE" = "詳細信息";
/* Action in attribution sheet */
-"TELEMETRY_NAME" = "Mapbox傳感數據";
+"TELEMETRY_NAME" = "Mapbox遙測";
/* Telemetry prompt title */
"TELEMETRY_TITLE" = "讓Mapbox地圖變得更好";
/* Default user location annotation title */
-"USER_DOT_TITLE" = "你在這裏";
+"USER_DOT_TITLE" = "你在這裡";
diff --git a/platform/ios/resources/zh-Hant.lproj/Localizable.stringsdict b/platform/ios/resources/zh-Hant.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..fc44e2e501
--- /dev/null
+++ b/platform/ios/resources/zh-Hant.lproj/Localizable.stringsdict
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>other</key>
+ <string>縮放層級%dx</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>other</key>
+ <string>可見%d處標示</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index a5e2f87e20..3a7342034a 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -31,7 +31,9 @@ function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
function finish { >&2 echo -en "\033[0m"; }
trap finish EXIT
-step "Configuring ${FORMAT:-dynamic and static} ${BUILDTYPE} framework for ${SDK}; symbols: ${SYMBOLS}"
+step "Configuring ${FORMAT:-dynamic and static} ${BUILDTYPE} framework for ${SDK} ${IOS_SDK_VERSION}; symbols: ${SYMBOLS}"
+
+xcodebuild -version
rm -rf ${OUTPUT}
if [[ ${BUILD_STATIC} == true ]]; then
diff --git a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
index c48dd6b27b..da5c7155a5 100644
--- a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
+++ b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
@@ -1,7 +1,15 @@
#import <UIKit/UIKit.h>
#import "MGLUserLocationAnnotationView.h"
+const CGFloat MGLUserLocationAnnotationDotSize = 22.0;
+const CGFloat MGLUserLocationAnnotationHaloSize = 115.0;
+
+const CGFloat MGLUserLocationAnnotationPuckSize = 45.0;
+const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6;
+
+// Threshold in radians between heading indicator rotation updates.
+const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
+
@interface MGLFaux3DUserLocationAnnotationView : MGLUserLocationAnnotationView
@end
-
diff --git a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
index 5f67f24f4e..7001569b30 100644
--- a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
+++ b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
@@ -2,14 +2,9 @@
#import "MGLMapView.h"
#import "MGLUserLocation.h"
-
-const CGFloat MGLUserLocationAnnotationDotSize = 22.0;
-const CGFloat MGLUserLocationAnnotationHaloSize = 115.0;
-
-const CGFloat MGLUserLocationAnnotationPuckSize = 45.0;
-const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6;
-
-#pragma mark -
+#import "MGLUserLocationHeadingIndicator.h"
+#import "MGLUserLocationHeadingArrowLayer.h"
+#import "MGLUserLocationHeadingBeamLayer.h"
@implementation MGLFaux3DUserLocationAnnotationView
{
@@ -18,14 +13,13 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
CALayer *_puckDot;
CAShapeLayer *_puckArrow;
- CALayer *_headingIndicatorLayer;
- CAShapeLayer *_headingIndicatorMaskLayer;
+ CALayer<MGLUserLocationHeadingIndicator> *_headingIndicatorLayer;
CALayer *_accuracyRingLayer;
CALayer *_dotBorderLayer;
CALayer *_dotLayer;
CALayer *_haloLayer;
- double _oldHeadingAccuracy;
+ CLLocationDirection _oldHeadingAccuracy;
CLLocationAccuracy _oldHorizontalAccuracy;
double _oldZoom;
double _oldPitch;
@@ -56,21 +50,18 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
- (void)setTintColor:(UIColor *)tintColor
{
+ CGColorRef newTintColor = [tintColor CGColor];
+
if (_puckModeActivated)
{
- _puckArrow.fillColor = [tintColor CGColor];
+ _puckArrow.fillColor = newTintColor;
}
else
{
- if (_accuracyRingLayer)
- {
- _accuracyRingLayer.backgroundColor = [tintColor CGColor];
- }
-
- _haloLayer.backgroundColor = [tintColor CGColor];
- _dotLayer.backgroundColor = [tintColor CGColor];
-
- _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage];
+ _accuracyRingLayer.backgroundColor = newTintColor;
+ _haloLayer.backgroundColor = newTintColor;
+ _dotLayer.backgroundColor = newTintColor;
+ [_headingIndicatorLayer updateTintColor:newTintColor];
}
}
@@ -80,7 +71,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
{
// disable implicit animation
[CATransaction begin];
- [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+ [CATransaction setDisableActions:YES];
CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(self.mapView.camera.pitch), 1.0, 0, 0);
self.layer.sublayerTransform = t;
@@ -138,7 +129,6 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
self.layer.sublayers = nil;
_headingIndicatorLayer = nil;
- _headingIndicatorMaskLayer = nil;
_accuracyRingLayer = nil;
_haloLayer = nil;
_dotBorderLayer = nil;
@@ -225,70 +215,67 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
[self updateFrameWithSize:MGLUserLocationAnnotationDotSize];
}
- BOOL showHeadingIndicator = self.mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading;
-
- // update heading indicator
+ // heading indicator (tinted, beam or arrow)
//
+ BOOL headingTrackingModeEnabled = self.mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading;
+ BOOL showHeadingIndicator = self.mapView.showsUserHeadingIndicator || headingTrackingModeEnabled;
+
if (showHeadingIndicator)
{
_headingIndicatorLayer.hidden = NO;
+ CLLocationDirection headingAccuracy = self.userLocation.heading.headingAccuracy;
- // heading indicator (tinted, semi-circle)
- //
- if ( ! _headingIndicatorLayer && self.userLocation.heading.headingAccuracy)
+ if (([_headingIndicatorLayer isMemberOfClass:[MGLUserLocationHeadingBeamLayer class]] && ! headingTrackingModeEnabled) ||
+ ([_headingIndicatorLayer isMemberOfClass:[MGLUserLocationHeadingArrowLayer class]] && headingTrackingModeEnabled))
{
- CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize;
-
- _headingIndicatorLayer = [CALayer layer];
- _headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize);
- _headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0);
- _headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage];
- _headingIndicatorLayer.contentsGravity = kCAGravityBottom;
- _headingIndicatorLayer.contentsScale = [UIScreen mainScreen].scale;
- _headingIndicatorLayer.opacity = 0.4;
- _headingIndicatorLayer.shouldRasterize = YES;
- _headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale;
- _headingIndicatorLayer.drawsAsynchronously = YES;
-
- [self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer];
+ [_headingIndicatorLayer removeFromSuperlayer];
+ _headingIndicatorLayer = nil;
+ _oldHeadingAccuracy = -1;
}
- // heading indicator accuracy mask (fan-shaped)
- //
- if ( ! _headingIndicatorMaskLayer && self.userLocation.heading.headingAccuracy)
+ if ( ! _headingIndicatorLayer && headingAccuracy)
{
- _headingIndicatorMaskLayer = [CAShapeLayer layer];
- _headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds;
- _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
-
- // apply the mask to the halo-radius-sized gradient layer
- _headingIndicatorLayer.mask = _headingIndicatorMaskLayer;
-
- _oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
-
+ if (headingTrackingModeEnabled)
+ {
+ _headingIndicatorLayer = [[MGLUserLocationHeadingBeamLayer alloc] initWithUserLocationAnnotationView:self];
+ [self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer];
+ }
+ else
+ {
+ _headingIndicatorLayer = [[MGLUserLocationHeadingArrowLayer alloc] initWithUserLocationAnnotationView:self];
+ [self.layer addSublayer:_headingIndicatorLayer];
+ _headingIndicatorLayer.zPosition = 1;
+ }
}
- else if (_oldHeadingAccuracy != self.userLocation.heading.headingAccuracy)
- {
- // recalculate the clipping mask based on updated accuracy
- _headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
- _oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
+ if (_oldHeadingAccuracy != headingAccuracy)
+ {
+ [_headingIndicatorLayer updateHeadingAccuracy:headingAccuracy];
+ _oldHeadingAccuracy = headingAccuracy;
}
if (self.userLocation.heading.trueHeading >= 0)
{
- _headingIndicatorLayer.affineTransform = CGAffineTransformRotate(CGAffineTransformIdentity, -MGLRadiansFromDegrees(self.mapView.direction - self.userLocation.heading.trueHeading));
+ CGFloat rotation = -MGLRadiansFromDegrees(self.mapView.direction - self.userLocation.heading.trueHeading);
+
+ // Don't rotate if the change is imperceptible.
+ if (fabs(rotation) > MGLUserLocationHeadingUpdateThreshold)
+ {
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+
+ _headingIndicatorLayer.affineTransform = CGAffineTransformRotate(CGAffineTransformIdentity, rotation);
+
+ [CATransaction commit];
+ }
}
}
else
{
[_headingIndicatorLayer removeFromSuperlayer];
- [_headingIndicatorMaskLayer removeFromSuperlayer];
_headingIndicatorLayer = nil;
- _headingIndicatorMaskLayer = nil;
}
-
// update accuracy ring (if zoom or horizontal accuracy have changed)
//
if (_accuracyRingLayer && (_oldZoom != self.mapView.zoomLevel || _oldHorizontalAccuracy != self.userLocation.location.horizontalAccuracy))
@@ -301,10 +288,10 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
_accuracyRingLayer.hidden = NO;
// disable implicit animation of the accuracy ring, unless triggered by a change in accuracy
- id shouldDisableActions = (_oldHorizontalAccuracy == self.userLocation.location.horizontalAccuracy) ? (id)kCFBooleanTrue : (id)kCFBooleanFalse;
+ BOOL shouldDisableActions = _oldHorizontalAccuracy == self.userLocation.location.horizontalAccuracy;
[CATransaction begin];
- [CATransaction setValue:shouldDisableActions forKey:kCATransactionDisableActions];
+ [CATransaction setDisableActions:shouldDisableActions];
_accuracyRingLayer.bounds = CGRectMake(0, 0, accuracyRingSize, accuracyRingSize);
_accuracyRingLayer.cornerRadius = accuracyRingSize / 2;
@@ -464,65 +451,4 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
return self.userLocation.location.horizontalAccuracy / [self.mapView metersPerPointAtLatitude:self.userLocation.coordinate.latitude] * 2.0;
}
-- (UIImage *)headingIndicatorTintedGradientImage
-{
- UIImage *image;
-
- CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0;
-
- UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0);
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- // gradient from the tint color to no-alpha tint color
- CGFloat gradientLocations[] = {0.0, 1.0};
- CGGradientRef gradient = CGGradientCreateWithColors(
- colorSpace,
- (__bridge CFArrayRef)@[
- (id)[self.mapView.tintColor CGColor],
- (id)[[self.mapView.tintColor colorWithAlphaComponent:0] CGColor]],
- gradientLocations);
-
- // draw the gradient from the center point to the edge (full halo radius)
- CGPoint centerPoint = CGPointMake(haloRadius, haloRadius);
- CGContextDrawRadialGradient(context, gradient,
- centerPoint, 0.0,
- centerPoint, haloRadius,
- kNilOptions);
-
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- CGGradientRelease(gradient);
- CGColorSpaceRelease(colorSpace);
-
- return image;
-}
-
-- (UIBezierPath *)headingIndicatorClippingMask
-{
- CGFloat accuracy = self.userLocation.heading.headingAccuracy;
-
- // size the mask using accuracy, but keep within a good display range
- CGFloat clippingDegrees = 90 - accuracy;
- clippingDegrees = fmin(clippingDegrees, 70); // most accurate
- clippingDegrees = fmax(clippingDegrees, 10); // least accurate
-
- CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize);
- UIBezierPath *ovalPath = UIBezierPath.bezierPath;
-
- // clip the oval to ± incoming accuracy degrees (converted to radians), from the top
- [ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))
- radius:CGRectGetWidth(ovalRect) / 2.0
- startAngle:MGLRadiansFromDegrees(-180 + clippingDegrees)
- endAngle:MGLRadiansFromDegrees(-clippingDegrees)
- clockwise:YES];
-
- [ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))];
- [ovalPath closePath];
-
- return ovalPath;
-}
-
@end
diff --git a/platform/ios/src/MGLMapView+IBAdditions.h b/platform/ios/src/MGLMapView+IBAdditions.h
index 3766d044d8..d02c938c57 100644
--- a/platform/ios/src/MGLMapView+IBAdditions.h
+++ b/platform/ios/src/MGLMapView+IBAdditions.h
@@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) IBInspectable BOOL allowsRotating;
@property (nonatomic) IBInspectable BOOL allowsTilting;
@property (nonatomic) IBInspectable BOOL showsUserLocation;
+@property (nonatomic) IBInspectable BOOL showsHeading;
@end
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index c3ffe1983e..528606fd4e 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -370,6 +370,23 @@ MGL_EXPORT IB_DESIGNABLE
- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment animated:(BOOL)animated;
/**
+ A Boolean value indicating whether the user location annotation may display a
+ permanent heading indicator.
+
+ Setting this property to `YES` causes the default user location annotation to
+ appear and always show an arrow-shaped heading indicator, if heading is
+ available. This property does not rotate the map; for that, see
+ `MGLUserTrackingModeFollowWithHeading`.
+
+ This property has no effect when `userTrackingMode` is
+ `MGLUserTrackingModeFollowWithHeading` or
+ `MGLUserTrackingModeFollowWithCourse`.
+
+ The default value of this property is `NO`.
+ */
+@property (nonatomic, assign) BOOL showsUserHeadingIndicator;
+
+/**
Whether the map view should display a heading calibration alert when necessary.
The default value is `YES`.
*/
@@ -589,7 +606,7 @@ MGL_EXPORT IB_DESIGNABLE
*
* The default minimumZoomLevel is 0.
*/
-@property (nonatomic) double minimumZoomLevel;
+@property (nonatomic) IBInspectable double minimumZoomLevel;
/**
* The maximum zoom level the map can be shown at.
@@ -600,7 +617,7 @@ MGL_EXPORT IB_DESIGNABLE
* The default maximumZoomLevel is 22. The upper bound for this property
* is 25.5.
*/
-@property (nonatomic) double maximumZoomLevel;
+@property (nonatomic) IBInspectable double maximumZoomLevel;
/**
The heading of the map, measured in degrees clockwise from true north.
@@ -1004,16 +1021,6 @@ MGL_EXPORT IB_DESIGNABLE
@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
/**
- The complete list of annotations associated with the receiver that are
- currently visible.
-
- The objects in this array must adopt the `MGLAnnotation` protocol. If no
- annotations are associated with the map view or if no annotations associated
- with the map view are currently visible, the value of this property is `nil`.
- */
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
-
-/**
Adds an annotation to the map view.
@note `MGLMultiPolyline`, `MGLMultiPolygon`, `MGLShapeCollection`, and
@@ -1108,6 +1115,16 @@ MGL_EXPORT IB_DESIGNABLE
- (nullable __kindof MGLAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
/**
+ The complete list of annotations associated with the receiver that are
+ currently visible.
+
+ The objects in this array must adopt the `MGLAnnotation` protocol. If no
+ annotations are associated with the map view or if no annotations associated
+ with the map view are currently visible, the value of this property is `nil`.
+ */
+@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
+
+/**
Returns the list of annotations associated with the receiver that intersect with
the given rectangle.
@@ -1276,6 +1293,11 @@ MGL_EXPORT IB_DESIGNABLE
`-[MGLVectorSource featuresInSourceLayersWithIdentifiers:predicate:]` and
`-[MGLShapeSource featuresMatchingPredicate:]` methods on the relevant sources.
+ The returned features may also include features corresponding to annotations.
+ These features are not object-equal to the `MGLAnnotation` objects that were
+ originally added to the map. To query the map for annotations, use
+ `visibleAnnotations` or `-[MGLMapView visibleAnnotationsInRect:]`.
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set
the style URL to an explicitly versioned style using a convenience method
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 49ef2bfb81..a03a5ad357 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -138,9 +138,6 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1;
const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10);
-// Context for KVO observing UILayoutGuides.
-static void * MGLLayoutGuidesUpdatedContext = &MGLLayoutGuidesUpdatedContext;
-
/// Unique identifier representing a single annotation in mbgl.
typedef uint32_t MGLAnnotationTag;
@@ -242,10 +239,14 @@ public:
@property (nonatomic) EAGLContext *context;
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
@property (nonatomic, readwrite) UIImageView *compassView;
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints;
@property (nonatomic, readwrite) UIImageView *logoView;
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints;
@property (nonatomic, readwrite) UIButton *attributionButton;
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
@property (nonatomic, readwrite) MGLStyle *style;
@property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer;
@property (nonatomic) UITapGestureRecognizer *doubleTap;
@@ -302,8 +303,6 @@ public:
NSDate *_userLocationAnimationCompletionDate;
/// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending.
BOOL _isChangingAnnotationLayers;
- BOOL _isObservingTopLayoutGuide;
- BOOL _isObservingBottomLayoutGuide;
BOOL _isWaitingForRedundantReachableNotification;
BOOL _isTargetingInterfaceBuilder;
@@ -483,21 +482,31 @@ public:
_selectedAnnotationTag = MGLAnnotationTagNotFound;
_annotationsNearbyLastTap = {};
- // setup logo bug
+ // setup logo
//
UIImage *logo = [MGLMapView resourceImageNamed:@"mapbox"];
_logoView = [[UIImageView alloc] initWithImage:logo];
_logoView.accessibilityTraits = UIAccessibilityTraitStaticText;
_logoView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"LOGO_A11Y_LABEL", nil, nil, @"Mapbox", @"Accessibility label");
+ _logoView.translatesAutoresizingMaskIntoConstraints = NO;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ if ([_logoView respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _logoView.accessibilityIgnoresInvertColors = YES; }
+#endif
[self addSubview:_logoView];
+ _logoViewConstraints = [NSMutableArray array];
// setup attribution
//
_attributionButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
_attributionButton.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_LABEL", nil, nil, @"About this map", @"Accessibility label");
_attributionButton.accessibilityHint = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_HINT", nil, nil, @"Shows credits, a feedback form, and more", @"Accessibility hint");
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ if ([_attributionButton respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _attributionButton.accessibilityIgnoresInvertColors = YES; }
+#endif
[_attributionButton addTarget:self action:@selector(showAttribution) forControlEvents:UIControlEventTouchUpInside];
+ _attributionButton.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_attributionButton];
+ _attributionButtonConstraints = [NSMutableArray array];
[_attributionButton addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:NULL];
// setup compass
@@ -509,12 +518,22 @@ public:
_compassView.accessibilityTraits = UIAccessibilityTraitButton;
_compassView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_LABEL", nil, nil, @"Compass", @"Accessibility label");
_compassView.accessibilityHint = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_HINT", nil, nil, @"Rotates the map to face due north", @"Accessibility hint");
+ _compassView.translatesAutoresizingMaskIntoConstraints = NO;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ if ([_compassView respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _compassView.accessibilityIgnoresInvertColors = YES; }
+#endif
[self addSubview:_compassView];
+ _compassViewConstraints = [NSMutableArray array];
// setup scale control
//
_scaleBar = [[MGLScaleBar alloc] init];
+ _scaleBar.translatesAutoresizingMaskIntoConstraints = NO;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ if ([_scaleBar respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _scaleBar.accessibilityIgnoresInvertColors = YES; }
+#endif
[self addSubview:_scaleBar];
+ _scaleBarConstraints = [NSMutableArray array];
// setup interaction
//
@@ -627,6 +646,9 @@ public:
_glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
_glView.layer.opaque = _opaque;
_glView.delegate = self;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ if ([_glView respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _glView.accessibilityIgnoresInvertColors = YES; }
+#endif
[_glView bindDrawable];
[self insertSubview:_glView atIndex:0];
_glView.contentMode = UIViewContentModeCenter;
@@ -674,48 +696,6 @@ public:
_isWaitingForRedundantReachableNotification = NO;
}
-- (void)willMoveToWindow:(UIWindow *)newWindow
-{
- [super willMoveToWindow:newWindow];
-
- if (newWindow) {
- [self addLayoutGuideObserversIfNeeded];
- } else {
- [self removeLayoutGuideObserversIfNeeded];
- }
-}
-
-- (void)addLayoutGuideObserversIfNeeded
-{
- UIViewController *viewController = self.viewControllerForLayoutGuides;
- BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets;
-
- if (useLayoutGuides && viewController.topLayoutGuide && !_isObservingTopLayoutGuide) {
- [(NSObject *)viewController.topLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
- _isObservingTopLayoutGuide = YES;
- }
-
- if (useLayoutGuides && viewController.bottomLayoutGuide && !_isObservingBottomLayoutGuide) {
- [(NSObject *)viewController.bottomLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
- _isObservingBottomLayoutGuide = YES;
- }
-}
-
-- (void)removeLayoutGuideObserversIfNeeded
-{
- UIViewController *viewController = self.viewControllerForLayoutGuides;
-
- if (_isObservingTopLayoutGuide) {
- [(NSObject *)viewController.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
- _isObservingTopLayoutGuide = NO;
- }
-
- if (_isObservingBottomLayoutGuide) {
- [(NSObject *)viewController.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
- _isObservingBottomLayoutGuide = NO;
- }
-}
-
- (void)dealloc
{
[_reachability stopNotifier];
@@ -724,8 +704,6 @@ public:
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_attributionButton removeObserver:self forKeyPath:@"hidden"];
- [self removeLayoutGuideObserversIfNeeded];
-
// Removing the annotations unregisters any outstanding KVO observers.
NSArray *annotations = self.annotations;
if (annotations)
@@ -751,6 +729,18 @@ public:
{
[EAGLContext setCurrentContext:nil];
}
+
+ [self.compassViewConstraints removeAllObjects];
+ self.compassViewConstraints = nil;
+
+ [self.scaleBarConstraints removeAllObjects];
+ self.scaleBarConstraints = nil;
+
+ [self.logoViewConstraints removeAllObjects];
+ self.logoViewConstraints = nil;
+
+ [self.attributionButtonConstraints removeAllObjects];
+ self.attributionButtonConstraints = nil;
}
- (void)setDelegate:(nullable id<MGLMapViewDelegate>)delegate
@@ -797,15 +787,207 @@ public:
return nil;
}
+- (void)updateConstraintsPreiOS11 {
+ // If we have a view controller reference and its automaticallyAdjustsScrollViewInsets
+ // is set to YES, use its view as the parent for constraints. -[MGLMapView adjustContentInset]
+ // already take top and bottom layout guides into account. If we don't have a reference, apply
+ // constraints against ourself to maintain placement of the subviews.
+ //
+ UIViewController *viewController = self.viewControllerForLayoutGuides;
+ BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets;
+ UIView *containerView = useLayoutGuides ? viewController.view : self;
+
+ // compass view
+ //
+ [containerView removeConstraints:self.compassViewConstraints];
+ [self.compassViewConstraints removeAllObjects];
+
+ if (useLayoutGuides) {
+ [self.compassViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.compassView
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:viewController.topLayoutGuide
+ attribute:NSLayoutAttributeBottom
+ multiplier:1.0
+ constant:5.0 + self.contentInset.top]];
+ }
+ [self.compassViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.compassView
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self
+ attribute:NSLayoutAttributeTop
+ multiplier:1.0
+ constant:5.0 + self.contentInset.top]];
+ [self.compassViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self
+ attribute:NSLayoutAttributeTrailing
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.compassView
+ attribute:NSLayoutAttributeTrailing
+ multiplier:1.0
+ constant:5.0 + self.contentInset.right]];
+
+ [containerView addConstraints:self.compassViewConstraints];
+
+ // scale bar view
+ //
+ [containerView removeConstraints:self.scaleBarConstraints];
+ [self.scaleBarConstraints removeAllObjects];
+
+ if (useLayoutGuides) {
+ [self.scaleBarConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.scaleBar
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:viewController.topLayoutGuide
+ attribute:NSLayoutAttributeBottom
+ multiplier:1.0
+ constant:5.0 + self.contentInset.top]];
+ }
+ [self.scaleBarConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.scaleBar
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self
+ attribute:NSLayoutAttributeTop
+ multiplier:1.0
+ constant:5.0 + self.contentInset.top]];
+ [self.scaleBarConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.scaleBar
+ attribute:NSLayoutAttributeLeft
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeLeft
+ multiplier:1.0
+ constant:8.0 + self.contentInset.left]];
+
+ [containerView addConstraints:self.scaleBarConstraints];
+
+ // logo view
+ //
+ [containerView removeConstraints:self.logoViewConstraints];
+ [self.logoViewConstraints removeAllObjects];
+
+ if (useLayoutGuides) {
+ [self.logoViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self.logoView
+ attribute:NSLayoutAttributeBaseline
+ multiplier:1.0
+ constant:8.0 + self.contentInset.bottom]];
+ }
+ [self.logoViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self.logoView
+ attribute:NSLayoutAttributeBaseline
+ multiplier:1
+ constant:8 + self.contentInset.bottom]];
+ [self.logoViewConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.logoView
+ attribute:NSLayoutAttributeLeading
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeLeading
+ multiplier:1.0
+ constant:8.0 + self.contentInset.left]];
+ [containerView addConstraints:self.logoViewConstraints];
+
+ // attribution button
+ //
+ [containerView removeConstraints:self.attributionButtonConstraints];
+ [self.attributionButtonConstraints removeAllObjects];
+
+ if (useLayoutGuides) {
+ [self.attributionButtonConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self.attributionButton
+ attribute:NSLayoutAttributeBaseline
+ multiplier:1
+ constant:8 + self.contentInset.bottom]];
+ }
+ [self.attributionButtonConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationGreaterThanOrEqual
+ toItem:self.attributionButton
+ attribute:NSLayoutAttributeBaseline
+ multiplier:1
+ constant:8 + self.contentInset.bottom]];
+
+ [self.attributionButtonConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self
+ attribute:NSLayoutAttributeTrailing
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.attributionButton
+ attribute:NSLayoutAttributeTrailing
+ multiplier:1
+ constant:8 + self.contentInset.right]];
+ [containerView addConstraints:self.attributionButtonConstraints];
+}
+
- (void)updateConstraints
{
- [super updateConstraints];
- // If we have a view controller reference and its automaticallyAdjustsScrollViewInsets
- // is set to YES, -[MGLMapView adjustContentInset] takes top and bottom layout
- // guides into account. To get notified about changes to the layout guides,
- // we need to observe their bounds and re-layout accordingly.
- [self addLayoutGuideObserversIfNeeded];
+// If compiling with the iOS 11+ SDK
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+ // If safeAreaLayoutGuide API exists
+ if ( [self respondsToSelector:@selector(safeAreaLayoutGuide)] ) {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpartial-availability"
+ UILayoutGuide *safeAreaLayoutGuide = self.safeAreaLayoutGuide;
+#pragma clang diagnostic pop
+ // compass view
+ [self removeConstraints:self.compassViewConstraints];
+ [self.compassViewConstraints removeAllObjects];
+ [self.compassViewConstraints addObject:[self.compassView.topAnchor constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor
+ constant:5.0 + self.contentInset.top]];
+ [self.compassViewConstraints addObject:[safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:self.compassView.rightAnchor
+ constant:8.0 + self.contentInset.right]];
+ [self addConstraints:self.compassViewConstraints];
+
+ // scale bar view
+ [self removeConstraints:self.scaleBarConstraints];
+ [self.scaleBarConstraints removeAllObjects];
+ [self.scaleBarConstraints addObject:[self.scaleBar.topAnchor constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor
+ constant:5.0 + self.contentInset.top]];
+ [self.scaleBarConstraints addObject:[self.scaleBar.leftAnchor constraintEqualToAnchor:safeAreaLayoutGuide.leftAnchor
+ constant:8.0 + self.contentInset.left]];
+ [self addConstraints:self.scaleBarConstraints];
+
+ // logo view
+ [self removeConstraints:self.logoViewConstraints];
+ [self.logoViewConstraints removeAllObjects];
+ [self.logoViewConstraints addObject:[safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:self.logoView.bottomAnchor
+ constant:8.0 + self.contentInset.bottom]];
+ [self.logoViewConstraints addObject:[self.logoView.leftAnchor constraintEqualToAnchor:safeAreaLayoutGuide.leftAnchor
+ constant:8.0 + self.contentInset.left]];
+ [self addConstraints:self.logoViewConstraints];
+
+ // attribution button
+ [self removeConstraints:self.attributionButtonConstraints];
+ [self.attributionButtonConstraints removeAllObjects];
+ [self.attributionButtonConstraints addObject:[safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:self.attributionButton.bottomAnchor
+ constant:8.0 + self.contentInset.bottom]];
+ [self.attributionButtonConstraints addObject:[safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:self.attributionButton.rightAnchor
+ constant:8.0 + self.contentInset.right]];
+ [self addConstraints:self.attributionButtonConstraints];
+ } else {
+ [self updateConstraintsPreiOS11];
+ }
+#else
+ [self updateConstraintsPreiOS11];
+#endif
+
+ [super updateConstraints];
}
- (BOOL)isOpaque
@@ -835,8 +1017,6 @@ public:
[super layoutSubviews];
[self adjustContentInset];
-
- [self layoutOrnaments];
if (!_isTargetingInterfaceBuilder) {
_mbglMap->setSize([self size]);
@@ -844,44 +1024,15 @@ public:
if (self.compassView.alpha)
{
- [self updateHeadingForDeviceOrientation];
[self updateCompass];
}
- [self updateUserLocationAnnotationView];
-}
+ if (self.compassView.alpha || self.showsUserHeadingIndicator)
+ {
+ [self updateHeadingForDeviceOrientation];
+ }
-- (void)layoutOrnaments
-{
- // scale bar
- self.scaleBar.frame = {
- self.contentInset.left+8,
- self.contentInset.top+5,
- CGRectGetWidth(self.scaleBar.frame),
- CGRectGetHeight(self.scaleBar.frame)
- };
-
- // compass
- self.compassView.center = {
- .x = CGRectGetWidth(self.bounds)-CGRectGetMidX(self.compassView.bounds)-self.contentInset.right-5,
- .y = CGRectGetMidY(self.compassView.bounds)+self.contentInset.top+5
- };
-
- // logo bug
- self.logoView.frame = {
- self.contentInset.left+8,
- CGRectGetHeight(self.bounds)-8-self.contentInset.bottom-CGRectGetHeight(self.logoView.bounds),
- CGRectGetWidth(self.logoView.bounds),
- CGRectGetHeight(self.logoView.bounds)
- };
-
- // attribution
- self.attributionButton.frame = {
- CGRectGetWidth(self.bounds)-CGRectGetWidth(self.attributionButton.bounds)-self.contentInset.right-8,
- CGRectGetHeight(self.bounds)-CGRectGetHeight(self.attributionButton.bounds)-self.contentInset.bottom-8,
- CGRectGetWidth(self.attributionButton.bounds),
- CGRectGetHeight(self.attributionButton.bounds)
- };
+ [self updateUserLocationAnnotationView];
}
/// Updates `contentInset` to reflect the current window geometry.
@@ -2043,10 +2194,6 @@ public:
[self updateCalloutView];
}
}
- else if (context == MGLLayoutGuidesUpdatedContext && [keyPath isEqualToString:@"bounds"])
- {
- [self setNeedsLayout];
- }
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
@@ -4146,33 +4293,41 @@ public:
{
self.locationManager = [[CLLocationManager alloc] init];
- if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
+ if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
- BOOL hasLocationDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
- if (!hasLocationDescription)
+ BOOL requiresWhenInUseUsageDescription = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11,0,0}];
+ BOOL hasWhenInUseUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
+ BOOL hasAlwaysUsageDescription;
+ if (requiresWhenInUseUsageDescription)
+ {
+ hasAlwaysUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"] && hasWhenInUseUsageDescription;
+ }
+ else
{
- [NSException raise:@"Missing Location Services usage description" format:
- @"This app must have a value for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in its Info.plist."];
+ hasAlwaysUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"];
}
- if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
+ if (hasAlwaysUsageDescription)
{
[self.locationManager requestAlwaysAuthorization];
}
- else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"])
+ else if (hasWhenInUseUsageDescription)
{
[self.locationManager requestWhenInUseAuthorization];
}
+ else
+ {
+ NSString *suggestedUsageKeys = requiresWhenInUseUsageDescription ?
+ @"NSLocationWhenInUseUsageDescription and (optionally) NSLocationAlwaysAndWhenInUseUsageDescription" :
+ @"NSLocationWhenInUseUsageDescription and/or NSLocationAlwaysUsageDescription";
+ [NSException raise:@"Missing Location Services usage description" format:@"This app must have a value for %@ in its Info.plist.", suggestedUsageKeys];
+ }
}
- self.locationManager.headingFilter = 5.0;
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
- if (self.userTrackingMode == MGLUserTrackingModeFollowWithHeading)
- {
- [self.locationManager startUpdatingHeading];
- }
+ [self validateUserHeadingUpdating];
}
else if ( ! shouldEnableLocationServices && self.locationManager)
{
@@ -4296,8 +4451,6 @@ public:
{
self.userTrackingState = MGLUserTrackingStatePossible;
- [self.locationManager stopUpdatingHeading];
-
// Immediately update the annotation view; other cases update inside
// the locationManager:didUpdateLocations: method.
[self updateUserLocationAnnotationView];
@@ -4310,14 +4463,6 @@ public:
self.userTrackingState = animated ? MGLUserTrackingStatePossible : MGLUserTrackingStateChanged;
self.showsUserLocation = YES;
- [self.locationManager stopUpdatingHeading];
-
- CLLocation *location = self.userLocation.location;
- if (location && self.userLocationAnnotationView)
- {
- [self locationManager:self.locationManager didUpdateLocations:@[location] animated:animated];
- }
-
break;
}
case MGLUserTrackingModeFollowWithHeading:
@@ -4334,19 +4479,21 @@ public:
[self setZoomLevel:self.currentMinimumZoom animated:YES];
}
- if (self.userLocationAnnotationView)
- {
- [self locationManager:self.locationManager didUpdateLocations:@[self.userLocation.location] animated:animated];
- }
-
- [self updateHeadingForDeviceOrientation];
-
- [self.locationManager startUpdatingHeading];
-
break;
}
}
+ if (_userTrackingMode != MGLUserTrackingModeNone)
+ {
+ CLLocation *location = self.userLocation.location;
+ if (location && self.userLocationAnnotationView)
+ {
+ [self locationManager:self.locationManager didUpdateLocations:@[location] animated:animated];
+ }
+ }
+
+ [self validateUserHeadingUpdating];
+
if ([self.delegate respondsToSelector:@selector(mapView:didChangeUserTrackingMode:animated:)])
{
[self.delegate mapView:self didChangeUserTrackingMode:_userTrackingMode animated:animated];
@@ -4385,14 +4532,43 @@ public:
if (self.userTrackingMode == MGLUserTrackingModeFollowWithCourse)
{
self.userTrackingState = MGLUserTrackingStatePossible;
- if (self.userLocation.location)
+
+ CLLocation *location = self.userLocation.location;
+ if (location)
{
- [self locationManager:self.locationManager didUpdateLocations:@[self.userLocation.location] animated:animated];
+ [self locationManager:self.locationManager didUpdateLocations:@[location] animated:animated];
}
}
}
}
+- (void)setShowsUserHeadingIndicator:(BOOL)showsUserHeadingIndicator
+{
+ _showsUserHeadingIndicator = showsUserHeadingIndicator;
+
+ if (_showsUserHeadingIndicator)
+ {
+ self.showsUserLocation = YES;
+
+ }
+ [self validateUserHeadingUpdating];
+}
+
+- (void)validateUserHeadingUpdating
+{
+ BOOL canShowPermanentHeadingIndicator = self.showsUserHeadingIndicator && self.userTrackingMode != MGLUserTrackingModeFollowWithCourse;
+
+ if (canShowPermanentHeadingIndicator || self.userTrackingMode == MGLUserTrackingModeFollowWithHeading)
+ {
+ [self updateHeadingForDeviceOrientation];
+ [self.locationManager startUpdatingHeading];
+ }
+ else
+ {
+ [self.locationManager stopUpdatingHeading];
+ }
+}
+
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[self locationManager:manager didUpdateLocations:locations animated:YES];
@@ -4640,6 +4816,11 @@ public:
self.userLocation.heading = newHeading;
+ if (self.showsUserHeadingIndicator || self.userTrackingMode == MGLUserTrackingModeFollowWithHeading)
+ {
+ [self updateUserLocationAnnotationView];
+ }
+
if ([self.delegate respondsToSelector:@selector(mapView:didUpdateUserLocation:)])
{
[self.delegate mapView:self didUpdateUserLocation:self.userLocation];
@@ -4676,30 +4857,39 @@ public:
{
// note that right/left device and interface orientations are opposites (see UIApplication.h)
//
+ CLDeviceOrientation orientation;
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case (UIInterfaceOrientationLandscapeLeft):
{
- self.locationManager.headingOrientation = CLDeviceOrientationLandscapeRight;
+ orientation = CLDeviceOrientationLandscapeRight;
break;
}
case (UIInterfaceOrientationLandscapeRight):
{
- self.locationManager.headingOrientation = CLDeviceOrientationLandscapeLeft;
+ orientation = CLDeviceOrientationLandscapeLeft;
break;
}
case (UIInterfaceOrientationPortraitUpsideDown):
{
- self.locationManager.headingOrientation = CLDeviceOrientationPortraitUpsideDown;
+ orientation = CLDeviceOrientationPortraitUpsideDown;
break;
}
case (UIInterfaceOrientationPortrait):
default:
{
- self.locationManager.headingOrientation = CLDeviceOrientationPortrait;
+ orientation = CLDeviceOrientationPortrait;
break;
}
}
+
+ // Setting the location manager's heading orientation causes it to send
+ // a heading event, which in turn makes us redraw, which kicks off a
+ // loop... so don't do that. rdar://34059173
+ if (self.locationManager.headingOrientation != orientation)
+ {
+ self.locationManager.headingOrientation = orientation;
+ }
}
}
@@ -5719,4 +5909,19 @@ private:
self.pitchEnabled = allowsTilting;
}
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingShowsHeading
+{
+ return [NSSet setWithObject:@"showsUserHeadingIndicator"];
+}
+
+- (BOOL)showsHeading
+{
+ return self.showsUserHeadingIndicator;
+}
+
+- (void)setShowsHeading:(BOOL)showsHeading
+{
+ self.showsUserHeadingIndicator = showsHeading;
+}
+
@end
diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h
index 8c6fe46136..91abadbcb7 100644
--- a/platform/ios/src/MGLUserLocation.h
+++ b/platform/ios/src/MGLUserLocation.h
@@ -20,8 +20,7 @@ MGL_EXPORT
/**
The current location of the device. (read-only)
- This property contains `nil` if the map view is not currently showing the user
- location or if the user’s location has not yet been determined.
+ This property returns `nil` if the user’s location has not yet been determined.
*/
@property (nonatomic, readonly, nullable) CLLocation *location;
diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m
index 1c9649c09e..074d138a72 100644
--- a/platform/ios/src/MGLUserLocation.m
+++ b/platform/ios/src/MGLUserLocation.m
@@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_END
{
if (self = [super init])
{
- _location = [[CLLocation alloc] initWithLatitude:MAXFLOAT longitude:MAXFLOAT];
_mapView = mapView;
}
@@ -102,7 +101,7 @@ NS_ASSUME_NONNULL_END
- (CLLocationCoordinate2D)coordinate
{
- return self.location.coordinate;
+ return _location ? _location.coordinate : kCLLocationCoordinate2DInvalid;
}
- (NSString *)title
diff --git a/platform/ios/src/MGLUserLocationHeadingArrowLayer.h b/platform/ios/src/MGLUserLocationHeadingArrowLayer.h
new file mode 100644
index 0000000000..6c01356944
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingArrowLayer.h
@@ -0,0 +1,11 @@
+#import <QuartzCore/QuartzCore.h>
+#import "MGLUserLocationAnnotationView.h"
+#import "MGLUserLocationHeadingIndicator.h"
+
+@interface MGLUserLocationHeadingArrowLayer : CAShapeLayer <MGLUserLocationHeadingIndicator>
+
+- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView;
+- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy;
+- (void)updateTintColor:(CGColorRef)color;
+
+@end
diff --git a/platform/ios/src/MGLUserLocationHeadingArrowLayer.m b/platform/ios/src/MGLUserLocationHeadingArrowLayer.m
new file mode 100644
index 0000000000..912ce30c35
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingArrowLayer.m
@@ -0,0 +1,59 @@
+#import "MGLUserLocationHeadingArrowLayer.h"
+
+#import "MGLFaux3DUserLocationAnnotationView.h"
+#import "MGLGeometry.h"
+
+const CGFloat MGLUserLocationHeadingArrowSize = 6;
+
+@implementation MGLUserLocationHeadingArrowLayer
+
+- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView
+{
+ CGFloat size = userLocationView.bounds.size.width + MGLUserLocationHeadingArrowSize;
+
+ self = [super init];
+ self.bounds = CGRectMake(0, 0, size, size);
+ self.position = CGPointMake(CGRectGetMidX(userLocationView.bounds), CGRectGetMidY(userLocationView.bounds));
+ self.path = [self arrowPath];
+ self.fillColor = userLocationView.tintColor.CGColor;
+ self.shouldRasterize = YES;
+ self.rasterizationScale = UIScreen.mainScreen.scale;
+ self.drawsAsynchronously = YES;
+
+ self.strokeColor = UIColor.whiteColor.CGColor;
+ self.lineWidth = 1.0;
+ self.lineJoin = kCALineJoinRound;
+
+ return self;
+}
+
+- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy
+{
+ // unimplemented
+}
+
+- (void)updateTintColor:(CGColorRef)color
+{
+ self.fillColor = color;
+}
+
+- (CGPathRef)arrowPath {
+ CGFloat center = roundf(CGRectGetMidX(self.bounds));
+ CGFloat size = MGLUserLocationHeadingArrowSize;
+
+ CGPoint top = CGPointMake(center, 0);
+ CGPoint left = CGPointMake(center - size, size);
+ CGPoint right = CGPointMake(center + size, size);
+ CGPoint middle = CGPointMake(center, size / M_PI);
+
+ UIBezierPath *bezierPath = [UIBezierPath bezierPath];
+ [bezierPath moveToPoint:top];
+ [bezierPath addLineToPoint:left];
+ [bezierPath addQuadCurveToPoint:right controlPoint:middle];
+ [bezierPath addLineToPoint:top];
+ [bezierPath closePath];
+
+ return bezierPath.CGPath;
+}
+
+@end
diff --git a/platform/ios/src/MGLUserLocationHeadingBeamLayer.h b/platform/ios/src/MGLUserLocationHeadingBeamLayer.h
new file mode 100644
index 0000000000..93f8ea17ab
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingBeamLayer.h
@@ -0,0 +1,11 @@
+#import <QuartzCore/QuartzCore.h>
+#import "MGLUserLocationAnnotationView.h"
+#import "MGLUserLocationHeadingIndicator.h"
+
+@interface MGLUserLocationHeadingBeamLayer : CALayer <MGLUserLocationHeadingIndicator>
+
+- (MGLUserLocationHeadingBeamLayer *)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView;
+- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy;
+- (void)updateTintColor:(CGColorRef)color;
+
+@end
diff --git a/platform/ios/src/MGLUserLocationHeadingBeamLayer.m b/platform/ios/src/MGLUserLocationHeadingBeamLayer.m
new file mode 100644
index 0000000000..efe7e4db93
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingBeamLayer.m
@@ -0,0 +1,104 @@
+#import "MGLUserLocationHeadingBeamLayer.h"
+
+#import "MGLFaux3DUserLocationAnnotationView.h"
+#import "MGLGeometry.h"
+
+@implementation MGLUserLocationHeadingBeamLayer
+{
+ CAShapeLayer *_maskLayer;
+}
+
+- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView
+{
+ CGFloat size = MGLUserLocationAnnotationHaloSize;
+
+ self = [super init];
+ self.bounds = CGRectMake(0, 0, size, size);
+ self.position = CGPointMake(CGRectGetMidX(userLocationView.bounds), CGRectGetMidY(userLocationView.bounds));
+ self.contents = (__bridge id)[self gradientImageWithTintColor:userLocationView.tintColor.CGColor];
+ self.contentsGravity = kCAGravityBottom;
+ self.contentsScale = UIScreen.mainScreen.scale;
+ self.opacity = 0.4;
+ self.shouldRasterize = YES;
+ self.rasterizationScale = UIScreen.mainScreen.scale;
+ self.drawsAsynchronously = YES;
+
+ _maskLayer = [CAShapeLayer layer];
+ _maskLayer.frame = self.bounds;
+ _maskLayer.path = [self clippingMaskForAccuracy:0];
+ self.mask = _maskLayer;
+
+ return self;
+}
+
+- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy
+{
+ // recalculate the clipping mask based on updated accuracy
+ _maskLayer.path = [self clippingMaskForAccuracy:accuracy];
+}
+
+- (void)updateTintColor:(CGColorRef)color
+{
+ // redraw the raw tinted gradient
+ self.contents = (__bridge id)[self gradientImageWithTintColor:color];
+}
+
+- (CGImageRef)gradientImageWithTintColor:(CGColorRef)tintColor
+{
+ UIImage *image;
+
+ CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0;
+
+ UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0);
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ // gradient from the tint color to no-alpha tint color
+ CGFloat gradientLocations[] = {0.0, 1.0};
+ CGGradientRef gradient = CGGradientCreateWithColors(
+ colorSpace,
+ (__bridge CFArrayRef)@[(__bridge id)tintColor,
+ (id)CFBridgingRelease(CGColorCreateCopyWithAlpha(tintColor, 0))],
+ gradientLocations);
+
+ // draw the gradient from the center point to the edge (full halo radius)
+ CGPoint centerPoint = CGPointMake(haloRadius, haloRadius);
+ CGContextDrawRadialGradient(context, gradient,
+ centerPoint, 0.0,
+ centerPoint, haloRadius,
+ kNilOptions);
+
+ image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ CGGradientRelease(gradient);
+ CGColorSpaceRelease(colorSpace);
+
+ return image.CGImage;
+}
+
+- (CGPathRef)clippingMaskForAccuracy:(CGFloat)accuracy
+{
+ // size the mask using accuracy, but keep within a good display range
+ CGFloat clippingDegrees = 90 - accuracy;
+ clippingDegrees = fmin(clippingDegrees, 70); // most accurate
+ clippingDegrees = fmax(clippingDegrees, 10); // least accurate
+
+ CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize);
+ UIBezierPath *ovalPath = UIBezierPath.bezierPath;
+
+ // clip the oval to ± incoming accuracy degrees (converted to radians), from the top
+ [ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))
+ radius:CGRectGetWidth(ovalRect) / 2.0
+ startAngle:MGLRadiansFromDegrees(-180 + clippingDegrees)
+ endAngle:MGLRadiansFromDegrees(-clippingDegrees)
+ clockwise:YES];
+
+ [ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))];
+ [ovalPath closePath];
+
+ return ovalPath.CGPath;
+}
+
+@end
diff --git a/platform/ios/src/MGLUserLocationHeadingIndicator.h b/platform/ios/src/MGLUserLocationHeadingIndicator.h
new file mode 100644
index 0000000000..61476b96a2
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingIndicator.h
@@ -0,0 +1,10 @@
+#import <QuartzCore/QuartzCore.h>
+#import "MGLUserLocationAnnotationView.h"
+
+@protocol MGLUserLocationHeadingIndicator <NSObject>
+
+- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView;
+- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy;
+- (void)updateTintColor:(CGColorRef)color;
+
+@end
diff --git a/platform/ios/uitest/KIF b/platform/ios/uitest/KIF
-Subproject 973a4cb653b54c3e8b2c0681f4097568ff0ac34
+Subproject c40b1048a6f35c6fd90376846a1a933844516b3
diff --git a/platform/ios/uitest/OHHTTPStubs b/platform/ios/uitest/OHHTTPStubs
-Subproject deed01a1592210a4c37f3f5c5f2b32fe0e41c60
+Subproject 4dc6f36375f78c0b3cfe58d90bb8a4e21df5196
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 2cd326ecd8..3ddffbb7fd 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -34,10 +34,14 @@
## 0.5.1
-This version of the Mapbox macOS SDK corresponds to version 3.6.2 of the Mapbox iOS SDK.
+This version of the Mapbox macOS SDK corresponds to version 3.6.4 of the Mapbox iOS SDK.
* Added an `MGLStyle.localizesLabels` property, off by default, that localizes any Mapbox Streets–sourced symbol layer into the user’s preferred language. ([#9582](https://github.com/mapbox/mapbox-gl-native/pull/9582))
* Fixed an issue that caused `-[MGLShapeSource featuresMatchingPredicate:]` and `-[MGLVectorSource featuresInSourceLayersWithIdentifiers:predicate:]` to always return an empty array. ([#9784](https://github.com/mapbox/mapbox-gl-native/pull/9784))
+* `MGLMapView`’s `minimumZoomLevel` and `maximumZoomLevel` properties are now available in Interface Builder’s Attributes inspector. ([#9729](https://github.com/mapbox/mapbox-gl-native/pull/9729))
+* Added a Hungarian localization. ([#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945))
+* Deprecated `+[MGLStyle trafficDayStyleURL]` and `+[MGLStyle trafficNightStyleURL]` with no replacement method. To use the Traffic Day and Traffic Night styles going forward, we recommend that you use the underlying URL. ([#9918](https://github.com/mapbox/mapbox-gl-native/pull/9918))
+* Fixed an issue where stale (but still valid) map data could be ignored in offline mode. ([#10012](https://github.com/mapbox/mapbox-gl-native/pull/10012))
## 0.5.0
diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
index 5b70c52681..dd60957bb5 100644
--- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec
+++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '0.5.0'
+ version = '0.5.1'
m.name = 'Mapbox-macOS-SDK-symbols'
m.version = "#{version}-symbols"
diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec
index 0b26b13beb..533d7499f5 100644
--- a/platform/macos/Mapbox-macOS-SDK.podspec
+++ b/platform/macos/Mapbox-macOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '0.5.0'
+ version = '0.5.1'
m.name = 'Mapbox-macOS-SDK'
m.version = version
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 406ff0ca9d..36ca4ad228 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -248,10 +248,10 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
styleURL = [MGLStyle satelliteStreetsStyleURL];
break;
case 7:
- styleURL = [MGLStyle trafficDayStyleURL];
+ styleURL = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-day-v2"];
break;
case 8:
- styleURL = [MGLStyle trafficNightStyleURL];
+ styleURL = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-night-v2"];
break;
default:
NSAssert(NO, @"Cannot set style from control with tag %li", (long)tag);
@@ -874,10 +874,10 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
state = [styleURL isEqual:[MGLStyle satelliteStreetsStyleURL]];
break;
case 7:
- state = [styleURL isEqual:[MGLStyle trafficDayStyleURL]];
+ state = [styleURL isEqual:[NSURL URLWithString:@"mapbox://styles/mapbox/traffic-day-v2"]];
break;
case 8:
- state = [styleURL isEqual:[MGLStyle trafficNightStyleURL]];
+ state = [styleURL isEqual:[NSURL URLWithString:@"mapbox://styles/mapbox/traffic-night-v2"]];
break;
default:
return NO;
diff --git a/platform/macos/app/hu.lproj/Localizable.strings b/platform/macos/app/hu.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/hu.lproj/Localizable.strings
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 40bbb07e8b..fcb0544479 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -402,21 +402,25 @@
DA6023EF1E4CE8E500DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
DA6023F01E4CE8FF00DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B131E68850300CB7F44 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
- DA618B141E68852C00CB7F44 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA618B141E68852C00CB7F44 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B151E6886DF00CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ca; path = ca.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B161E6886E000CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B171E68876C00CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Foundation.strings; sourceTree = "<group>"; };
- DA618B181E6887C600CB7F44 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA618B181E6887C600CB7F44 /* ca */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B231E6891ED00CB7F44 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Foundation.strings; sourceTree = "<group>"; };
DA618B241E6891F300CB7F44 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lt; path = lt.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B271E68926E00CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B2A1E6892B500CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
+ DA704CBA1F6372E8004B3F28 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DA704CBE1F637531004B3F28 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA704CBF1F637548004B3F28 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA704CC61F666385004B3F28 /* uk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Foundation.strings; sourceTree = "<group>"; };
DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; };
DA7262061DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; };
DA737ADE1E5914AD00AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
- DA737ADF1E5914D300AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737ADF1E5914D300AD2CDE /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
DA737AE31E5915A500AD2CDE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pl; path = pl.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA737AE41E5915B000AD2CDE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
DA737AEC1E59180E00AD2CDE /* uk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -476,7 +480,7 @@
DAA32CB31E4C4CC3006F8D24 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CBA1E4C4F10006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CC01E4C4F89006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Foundation.strings; sourceTree = "<group>"; };
- DAA32CC11E4C4F93006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CC11E4C4F93006F8D24 /* vi */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleLayerIconTransformer.h; sourceTree = "<group>"; };
DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleLayerIconTransformer.m; sourceTree = "<group>"; };
DAA998F91E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFillExtrusionStyleLayer.h; sourceTree = "<group>"; };
@@ -491,6 +495,7 @@
DACC22131CF3D3E200D220D9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; };
DACCD9C71F1F443B00BB09A1 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DACFE7971F66EA0C00630DA8 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; };
DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeCollection.mm; sourceTree = "<group>"; };
DAE6C2E11CC304F900DB3429 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
@@ -583,7 +588,7 @@
DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButtonTests.m; sourceTree = "<group>"; };
DAF0D80D1DFE0E5D00B28378 /* MGLPointCollection_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection_Private.h; sourceTree = "<group>"; };
DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
- DAFBD0D51E3FA969000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ DAFBD0D51E3FA969000CD6BF /* zh-Hant */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
DAFBD0D61E3FA983000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Foundation.strings"; sourceTree = "<group>"; };
DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
@@ -1333,6 +1338,7 @@
ca,
fi,
nl,
+ hu,
);
mainGroup = DA839E891CC2E3400062CAFB;
productRefGroup = DA839E931CC2E3400062CAFB /* Products */;
@@ -1560,6 +1566,7 @@
DA618B161E6886E000CB7F44 /* ca */,
DA618B271E68926E00CB7F44 /* fi */,
DAE8CCAB1E6E8B72009B5CB0 /* nl */,
+ DA704CBE1F637531004B3F28 /* hu */,
);
name = Localizable.strings;
sourceTree = "<group>";
@@ -1608,6 +1615,7 @@
DA618B181E6887C600CB7F44 /* ca */,
DA618B2A1E6892B500CB7F44 /* fi */,
DAE8CCAC1E6E8B8D009B5CB0 /* nl */,
+ DA704CBF1F637548004B3F28 /* hu */,
);
name = Localizable.strings;
sourceTree = "<group>";
@@ -1626,6 +1634,8 @@
DA618B231E6891ED00CB7F44 /* lt */,
DAE9E0F21EB7BF39001E8E8B /* es */,
DACCD9C71F1F443B00BB09A1 /* fr */,
+ DA704CBA1F6372E8004B3F28 /* ru */,
+ DA704CC61F666385004B3F28 /* uk */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -1644,6 +1654,7 @@
DAE8CCAA1E6E8605009B5CB0 /* ru */,
DA618B151E6886DF00CB7F44 /* ca */,
DA618B241E6891F300CB7F44 /* lt */,
+ DACFE7971F66EA0C00630DA8 /* vi */,
);
name = Foundation.stringsdict;
sourceTree = "<group>";
diff --git a/platform/macos/sdk/ca.lproj/Localizable.strings b/platform/macos/sdk/ca.lproj/Localizable.strings
index b679fa0459..cd3073a8cb 100644
--- a/platform/macos/sdk/ca.lproj/Localizable.strings
+++ b/platform/macos/sdk/ca.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "El mapa no s’ha carregat a causa d’un error desconegut.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "El mapa no s’ha carregat perquè l’estil no es pot carregar.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "El mapa no s’ha carregat perquè s’ha corromput l’estil.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "El mapa no s’ha carregat perquè no es troba l’estil o bé és incompatible.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/es.lproj/Localizable.strings b/platform/macos/sdk/es.lproj/Localizable.strings
index 4ebb97b440..8a9b51feb1 100644
--- a/platform/macos/sdk/es.lproj/Localizable.strings
+++ b/platform/macos/sdk/es.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "No se pudo cargar el mapa debido a un error desconocido.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "No se pudo cargar el mapa debido a un error de carga en el estilo.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "No se pudo cargar el mapa debido a que el estilo está dañado.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "No se pudo cargar el mapa debido a que no se encuentra el estilo o está incompleto.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/hu.lproj/Localizable.strings b/platform/macos/sdk/hu.lproj/Localizable.strings
new file mode 100644
index 0000000000..b3724190cb
--- /dev/null
+++ b/platform/macos/sdk/hu.lproj/Localizable.strings
@@ -0,0 +1,27 @@
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Egy ismeretlen hiba miatt nem sikerült betölteni a térképet.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Nem sikerült betölteni a térképet, mert a stílus nem tölthető be.";
+
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Nem sikerült betölteni a térképet, mert a stílus hibás.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Nem sikerült betölteni a térképet, mert a stílus nem található vagy inkompatibilis.";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Nagyítás";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Kicsinyítés";
+
diff --git a/platform/macos/sdk/ru.lproj/Localizable.strings b/platform/macos/sdk/ru.lproj/Localizable.strings
index 4fa1104cc7..067e05b14e 100644
--- a/platform/macos/sdk/ru.lproj/Localizable.strings
+++ b/platform/macos/sdk/ru.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Не удалось загрузит карту из-за неизвестной ошибки.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Не удалось загрузить карту так как невозможно загрузить стиль.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Не удалось загрузить карту из-за ошибки в стиле.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Не удалось загрузить карту так как стиль не найден или несовместим.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/uk.lproj/Localizable.strings b/platform/macos/sdk/uk.lproj/Localizable.strings
index 1be17a4d49..07782e81d5 100644
--- a/platform/macos/sdk/uk.lproj/Localizable.strings
+++ b/platform/macos/sdk/uk.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Неможливо завантажити мапу через невідому помилку.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Неможливо завантажити мапу, бо неможливо завантажити стиль.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Неможливо завантажити мапу, через помилки в стилі.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Неможливо завантажити мапу, бо неможливо знайти стиль або він несумісний.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/vi.lproj/Localizable.strings b/platform/macos/sdk/vi.lproj/Localizable.strings
index 086820b034..95e327d689 100644
--- a/platform/macos/sdk/vi.lproj/Localizable.strings
+++ b/platform/macos/sdk/vi.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì lỗi không rõ.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì không thể tải bảng kiểu.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì bảng kiểu bị hỏng.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Bản đồ bị thất bại khi tải vì không tìm thấy bảng kiểu hoặc bảng kiểu không tương thích.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/zh-Hant.lproj/Localizable.strings b/platform/macos/sdk/zh-Hant.lproj/Localizable.strings
index 4447371d71..e5cf4b7695 100644
--- a/platform/macos/sdk/zh-Hant.lproj/Localizable.strings
+++ b/platform/macos/sdk/zh-Hant.lproj/Localizable.strings
@@ -1,6 +1,18 @@
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "發生不知名錯誤,無法載入地圖。";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "載入樣式表時發生錯誤,無法載入地圖。";
+
/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "樣式表有毀損,無法載入地圖。";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "找不到樣式表或樣式表不兼容,無法載入地圖。";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index 2fa32ae1e4..04c2e77110 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -239,7 +239,7 @@ MGL_EXPORT IB_DESIGNABLE
The default value of this property is 0.
*/
-@property (nonatomic) double minimumZoomLevel;
+@property (nonatomic) IBInspectable double minimumZoomLevel;
/**
The maximum zoom level the map can be shown at.
@@ -250,7 +250,7 @@ MGL_EXPORT IB_DESIGNABLE
The default value of this property is 22. The upper bound for this property
is 25.5.
*/
-@property (nonatomic) double maximumZoomLevel;
+@property (nonatomic) IBInspectable double maximumZoomLevel;
/**
Changes the zoom level of the map and optionally animates the change.