diff --git a/CMakeLists.txt b/CMakeLists.txt index e12de134fbc..63fbb6b2ec1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,9 @@ endif() set(OMIM_ROOT ${CMAKE_SOURCE_DIR}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OMIM_ROOT}/cmake") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + include(OmimPlatform) include(OmimOptions) include(OmimConfig) diff --git a/android/app/src/main/cpp/app/organicmaps/Framework.cpp b/android/app/src/main/cpp/app/organicmaps/Framework.cpp index 4c42f3569e1..01f16ffd3cf 100644 --- a/android/app/src/main/cpp/app/organicmaps/Framework.cpp +++ b/android/app/src/main/cpp/app/organicmaps/Framework.cpp @@ -1458,7 +1458,8 @@ Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring jstring subtitle, jobject markType, jint intermediateIndex, jboolean isMyPosition, - jdouble lat, jdouble lon) + jdouble lat, jdouble lon, + jboolean reorderIntermediatePoints) { RouteMarkData data; data.m_title = jni::ToNativeString(env, title); @@ -1468,7 +1469,7 @@ Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring data.m_isMyPosition = static_cast(isMyPosition); data.m_position = m2::PointD(mercator::FromLatLon(lat, lon)); - frm()->GetRoutingManager().AddRoutePoint(std::move(data)); + frm()->GetRoutingManager().AddRoutePoint(std::move(data), reorderIntermediatePoints); } JNIEXPORT void JNICALL diff --git a/android/app/src/main/java/app/organicmaps/Framework.java b/android/app/src/main/java/app/organicmaps/Framework.java index 6cb44a302d6..9d98ab61190 100644 --- a/android/app/src/main/java/app/organicmaps/Framework.java +++ b/android/app/src/main/java/app/organicmaps/Framework.java @@ -230,15 +230,21 @@ public static Date getDataVersion() public static native void nativeShowCountry(String countryId, boolean zoomToDownloadButton); public static void addRoutePoint(RouteMarkData point) + { + addRoutePoint(point, true); + } + + public static void addRoutePoint(RouteMarkData point, boolean reorderIntermediatePoints) { Framework.nativeAddRoutePoint(point.mTitle, point.mSubtitle, point.mPointType, point.mIntermediateIndex, point.mIsMyPosition, - point.mLat, point.mLon); + point.mLat, point.mLon, reorderIntermediatePoints); } public static native void nativeAddRoutePoint(String title, String subtitle, @NonNull RouteMarkType markType, int intermediateIndex, boolean isMyPosition, - double lat, double lon); + double lat, double lon, + boolean reorderIntermediatePoints); public static native void nativeRemoveRoutePoints(); diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/data/Metadata.java b/android/app/src/main/java/app/organicmaps/bookmarks/data/Metadata.java index 2dcd71bb048..5efbc8a3837 100644 --- a/android/app/src/main/java/app/organicmaps/bookmarks/data/Metadata.java +++ b/android/app/src/main/java/app/organicmaps/bookmarks/data/Metadata.java @@ -67,7 +67,8 @@ public enum MetadataType FMD_WEBSITE_MENU(46), FMD_SELF_SERVICE(47), FMD_OUTDOOR_SEATING(48), - FMD_NETWORK(49); + FMD_NETWORK(49), + FMD_MAX_POWER(50); private final int mMetaType; MetadataType(int metadataType) @@ -76,7 +77,7 @@ public enum MetadataType } @NonNull - public static MetadataType fromInt(@IntRange(from = 1, to = 49) int metaType) + public static MetadataType fromInt(@IntRange(from = 1, to = 50) int metaType) { for (MetadataType type : values()) if (type.mMetaType == metaType) diff --git a/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java b/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java index 2929e9f3cce..9456259bf62 100644 --- a/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java +++ b/android/app/src/main/java/app/organicmaps/routing/ManageRouteBottomSheet.java @@ -141,42 +141,9 @@ else if (buttonId == R.id.btn__plan) // Secondly, add the starting point. Framework.addRoutePoint(newRoutePoints.get(0)); - // And then, add all intermediate points. + // And then, add all intermediate points (with no reordering). for (int pos = 1; pos < newRoutePoints.size() - 1; pos++) - Framework.addRoutePoint(newRoutePoints.get(pos)); - - // Intermediate route points are added sorted by distance. - // We have to make sure that they follow the requested order. - RouteMarkData[] finalRoutePoints = Framework.nativeGetRoutePoints(); - - for (int first = 1; first < newRoutePoints.size() - 1; first++) - { - int secondIndex = -1; - - for (int second = first; second < newRoutePoints.size() - 1; second++) - { - if (finalRoutePoints[first].equals(newRoutePoints.get(second))) - { - secondIndex = second; - break; - } - } - - if (secondIndex < 0) - { - // Something went bad. Intermediate point not found in the route points. - break; - } - - if (first != secondIndex) - { - // Intermediate point needs to be moved. - Framework.nativeMoveRoutePoint(secondIndex, first); - - // Refresh final route points. - finalRoutePoints = Framework.nativeGetRoutePoints(); - } - } + Framework.addRoutePoint(newRoutePoints.get(pos), false); // Launch route planning. RoutingController.get().launchPlanning(); diff --git a/android/app/src/main/java/app/organicmaps/routing/RoutingController.java b/android/app/src/main/java/app/organicmaps/routing/RoutingController.java index 79d937aded7..04ee5ca1580 100644 --- a/android/app/src/main/java/app/organicmaps/routing/RoutingController.java +++ b/android/app/src/main/java/app/organicmaps/routing/RoutingController.java @@ -778,7 +778,8 @@ private static void addRoutePoint(@NonNull RouteMarkType type, @NonNull MapObjec Framework.nativeAddRoutePoint(description.first /* title */, description.second /* subtitle */, type, 0 /* intermediateIndex */, point.isMyPosition(), - point.getLat(), point.getLon()); + point.getLat(), point.getLon(), + true /* reorderIntermediatePoints */); } @NonNull diff --git a/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java b/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java index f9694bbbec2..109f18c1061 100644 --- a/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java +++ b/android/app/src/main/java/app/organicmaps/settings/SettingsPrefsFragment.java @@ -319,7 +319,7 @@ private void init3dModePrefsCallbacks() pref.setOnPreferenceChangeListener((preference, newValue) -> { Framework.Params3dMode current = new Framework.Params3dMode(); Framework.nativeGet3dMode(current); - Framework.nativeSet3dMode(current.enabled, (Boolean)newValue); + Framework.nativeSet3dMode(current.enabled, (Boolean) newValue); return true; }); } diff --git a/android/app/src/main/java/app/organicmaps/util/ThemeSwitcher.java b/android/app/src/main/java/app/organicmaps/util/ThemeSwitcher.java index 3a2f1553485..d3528af80e0 100644 --- a/android/app/src/main/java/app/organicmaps/util/ThemeSwitcher.java +++ b/android/app/src/main/java/app/organicmaps/util/ThemeSwitcher.java @@ -37,11 +37,19 @@ public void run() // Cancel old checker UiThread.cancelDelayedTasks(mAutoThemeChecker); + String theme; if (navAuto || ThemeUtils.isAutoTheme(mContext)) { UiThread.runLater(mAutoThemeChecker, CHECK_INTERVAL_MS); - setThemeAndMapStyle(calcAutoTheme()); + theme = calcAutoTheme(); } + else + { + // Happens when exiting the Navigation mode. Should restore the light. + theme = mContext.getResources().getString(R.string.theme_default); + } + + setThemeAndMapStyle(theme); } }; diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java index 78c99f0c41d..bfea2acedfa 100644 --- a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java @@ -120,6 +120,8 @@ public class PlacePageView extends Fragment implements View.OnClickListener, private TextView mTvOutdoorSeating; private View mEntrance; private TextView mTvEntrance; + private View mMaxPower; + private TextView mTvMaxPower; private View mEditPlace; private View mAddOrganisation; private View mAddPlace; @@ -276,6 +278,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat mTvCuisine = mFrame.findViewById(R.id.tv__place_cuisine); mEntrance = mFrame.findViewById(R.id.ll__place_entrance); mTvEntrance = mEntrance.findViewById(R.id.tv__place_entrance); + mMaxPower = mFrame.findViewById(R.id.ll__place_max_power); + mTvMaxPower = mFrame.findViewById(R.id.tv__place_max_power); mEditPlace = mFrame.findViewById(R.id.ll__place_editor); mEditPlace.setOnClickListener(this); mAddOrganisation = mFrame.findViewById(R.id.ll__add_organisation); @@ -294,6 +298,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat mDriveThrough.setOnLongClickListener(this); mSelfService.setOnLongClickListener(this); mOutdoorSeating.setOnLongClickListener(this); + mMaxPower.setOnLongClickListener(this); mDownloaderIcon = new DownloaderStatusIcon(mPreview.findViewById(R.id.downloader_status_frame)); @@ -469,6 +474,9 @@ private void refreshDetails() final String outdoorSeating = mMapObject.getMetadata(Metadata.MetadataType.FMD_OUTDOOR_SEATING); refreshMetadataOrHide(outdoorSeating.equals("yes") ? getString(R.string.outdoor_seating) : "", mOutdoorSeating, mTvOutdoorSeating); + final String maxPower = mMapObject.getMetadata(Metadata.MetadataType.FMD_MAX_POWER); + refreshMetadataOrHide(!TextUtils.isEmpty(maxPower) ? getString(R.string.maximum_value, maxPower) : "", mMaxPower, mTvMaxPower); + // showTaxiOffer(mapObject); if (RoutingController.get().isNavigating() || RoutingController.get().isPlanning()) @@ -668,6 +676,8 @@ else if (id == R.id.ll__place_drive_through) items.add(mTvDriveThrough.getText().toString()); else if (id == R.id.ll__place_outdoor_seating) items.add(mTvOutdoorSeating.getText().toString()); + else if (id == R.id.ll__place_max_power) + items.add(mTvMaxPower.getText().toString()); final Context context = requireContext(); if (items.size() == 1) diff --git a/android/app/src/main/res/drawable/ic_max_power_white.xml b/android/app/src/main/res/drawable/ic_max_power_white.xml new file mode 100644 index 00000000000..771ef6cead5 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_max_power_white.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/layout/place_page_details.xml b/android/app/src/main/res/layout/place_page_details.xml index b554c603dd7..1821c21c9ef 100644 --- a/android/app/src/main/res/layout/place_page_details.xml +++ b/android/app/src/main/res/layout/place_page_details.xml @@ -66,6 +66,8 @@ + + diff --git a/android/app/src/main/res/layout/place_page_max_power.xml b/android/app/src/main/res/layout/place_page_max_power.xml new file mode 100644 index 00000000000..a903d2f3604 --- /dev/null +++ b/android/app/src/main/res/layout/place_page_max_power.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index fcec4b6e954..94f9f879069 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -901,6 +901,8 @@ Select option Outdoor seating + + Maximum: %s For the most accurate navigation, we recommend disabling power saving mode in phone\'s battery settings. diff --git a/cmake/OmimConfig.cmake b/cmake/OmimConfig.cmake index 0bcef5f0efb..a24d126e5cf 100644 --- a/cmake/OmimConfig.cmake +++ b/cmake/OmimConfig.cmake @@ -7,8 +7,6 @@ set(3PARTY_INCLUDE_DIRS "${OMIM_ROOT}/3party/boost") set(OMIM_DATA_DIR "${OMIM_ROOT}/data") set(OMIM_USER_RESOURCES_DIR "${OMIM_ROOT}/data") -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - # GCC 10.0 is required to support header inclusion in base/string_utils.hpp if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0) message(FATAL_ERROR "Minimum supported g++ version is 10.0, yours is ${CMAKE_CXX_COMPILER_VERSION}") diff --git a/data/categories.txt b/data/categories.txt index b5439c37a8a..6668b15b005 100644 --- a/data/categories.txt +++ b/data/categories.txt @@ -93,7 +93,7 @@ hu:Hol lehet enni valamit|Élelmiszer id:Tempat makan|Makanan it:Dove mangiare|Cibo ja:食事場所|飲食|飲食店 -ko:어디서먹을까|음식 +ko:어디서 먹을까|음식 lv:Kur paēst|Ēst|Ēdiens mr:जेवायचे ठिकाण|जेवण|अन्न|भोजन nb:Spisesteder|Mat @@ -105,15 +105,15 @@ es:Dónde comer|Comer|Comida et:Kus süüa|Toit eu:Non jan|Jaten sr:Где јести|Јело|Храна|Gde jesti|Jelo|Hrana -sv:Var att äta|Mat +sv:Matmöjligheter|Mat th:กินร้านไหนดี|อาหาร tr:Nerede yenir|Yemek uk:Де поїсти|Їжа vi:Ăn ở đâu|ẩm thực zh-Hans:在哪儿吃|食物 -zh-Hant:在哪兒吃|飲食 -el:Πού να φάμε|Φαγητό -he:אוכל +zh-Hant:在哪裡吃|飲食 +el:Μέρη για φαγητό|Φαγητό +he:איפה לאכול|אוכל sk:Kde sa najesť|Jedlo sw:Sehemu ya kula fa:غذا|کجا غذا بخوریم @@ -136,7 +136,7 @@ eu:Produktuak|Jan fa:غذا|فروشگاه|عطاری fi:Elintarvikkeet|Ruoka fr:4Epiceries|5Nourriture|5Alimentation -he:חניה +he:מצרכים hi:3किराने का सामान hu:Élelmiszer|Ennivaló|Üzlet id:Toserba|Makanan|Toko @@ -153,7 +153,7 @@ pt-BR:Mercados|Alimentação ro:4Alimentare|Produse|Alimentație|Mâncare sk:Potraviny|Jedlo sr:Намирнице|Храна|Namirnice|Hrana -sv:Produkter|Mat +sv:Matvaror|Produkter|Mat sw:Migahawani th:ซื้อของกินของใช้|อาหาร tr:3Market|Bakkal|Yiyecek @@ -177,7 +177,7 @@ fi:Liikenne fr:5Transport de:Verkehr hi:4सार्वजनिक परिवहन -hu:Közlekedés +hu:Közlekedés|Tömegközlekedés id:5Transportasi it:5Trasporto ja:交通機関 @@ -203,13 +203,13 @@ zh-Hant:交通 el:Συγκοινωνία he:תחבורה sk:Doprava -fa:حمل و مواصلات +fa:حمل و نقل # First keyword should match [category_fuel] definition in strings.txt! @category_fuel en:2Gas|Gasoline|3Petrol|4Diesel|3Fuel -ru:3бензин|3дизель|4топливо|газ -be:3бензін|3дызель|4паліва|газ +ru:3бензин|3дизель|4топливо|газ|АЗС +be:3бензін|3дызель|4паліва|газ|АЗС bg:Гориво|Бензиностанция ar:1وقود|بنزين|سولار|ديزل|وقود الحافلات ca:Benzinera @@ -239,12 +239,12 @@ sr:5Гориво|4Бензин|3Дизел|Гас|Бензинска стани sv:3Bensin th:ก๊าซ tr:3Benzinlik|3Yakıt|3Akaryakıt|2Dizel|2Gaz -uk:3бензин|3дызель|4паліва|газ +uk:3бензин|3дызель|4паліва|газ|АЗС vi:Khí đốt zh-Hans:加油站 zh-Hant:加油站 -el:Υγρά Καύσιμα -he:גז +el:Βενζινάδικο|Υγρά Καύσιμα +he:דלק sk:3Čerpacia stanica sw:Sheli fa:سوخت|بنزین|دیزل|گازوئیل @@ -312,14 +312,14 @@ eu:4Erosketak fa:فروشگاه|خرید کردن fi:Ostokset fr:4Shopping -he:חנות +he:קניות hi:4खरीदारी hu:Bevásárlás id:Berbelanja -it:4Shopping +it:4Shopping|Negozi ja:ショッピング ko:쇼핑 -lv:4iepirkšanās +lv:4Iepirkšanās mr:खरेदी|शॉपिंग nb:4Shopping nl:Winkelen @@ -330,7 +330,7 @@ ro:4Shopping|Cumpărături sk:Nakupovanie sr:Шопинг|Куповина|Šoping|Kupovina sw:Manunuzi -sv:4Shopping +sv:4Shopping|Handel th:ช็อปปิง tr:4Alışveriş uk:3Шопінг @@ -357,7 +357,7 @@ hi:4होटल hu:Szálloda|Szállodák|Hotel|Hotelek id:Hotel|Hotel it:Hôtel|Alberghi -ja:ホテル +ja:ホテル|宿|宿泊|旅館 ko:호텔 lv:Viesnīca|Hotelis mr:मुक्कामगृह|लॉज|निवासगृह|हॉटेल @@ -376,7 +376,7 @@ tr:Otel|Oteller uk:4Готель|готелі vi:Khách sạn zh-Hans:酒店|旅店|賓館 -zh-Hant:旅馆|飯店|酒店|宾馆 +zh-Hant:旅館|旅馆|飯店|酒店|宾馆 el:4Ξενοδοχείο|Διαμονή|Ξενοδοχεία he:מלון|בתי sk:Hotel|Hotely @@ -391,14 +391,14 @@ be:4Славутасці|4турызм bg:5Забележителности|4Туризъм ar:سياحة ca:Turisme -cs:Pamětihodnost +cs:Pamětihodnost|Památky da:5Seværdigheder|4Turisme|3sightseeing nl:5Bezienswaardigheden|4Toerisme fi:4Nähtävyydet fr:5Sites touristiques|4Tourisme|4Attraction de:4Sehenswürdigkeit|4Attraktion|4Tourismus|Touristenattraktion|Sehenswürdigkeiten hi:जगहें -hu:4Látnivaló|4Túrizmus +hu:4Látnivalók|4Túrizmus id:Pemandangan it:5Luoghi turistici|4Turistico ja:観光 @@ -437,14 +437,14 @@ ar:ترفيه وتسلية|تسلية ca:Entreteniment cs:Zábava da:Underholdning -nl:Uitgaan +nl:Amusement|Uitgaan fi:Viihde fr:Divertissement de:Unterhaltung hi:मनोरंजन hu:Szórakozás id:Hiburan -it:Divertimento +it:Intrattenimento|Divertimento ja:エンターテイメント ko:엔터테인먼트 lv:3Izklaide|Atpūta @@ -485,6 +485,7 @@ nl:Nachtleven fi:Yöelämä fr:Vie nocturne de:Nachtleben +he:חיי לילה hi:रात्रि जीवन hu:Éjjeli élet id:Kehidupan Malam @@ -492,7 +493,7 @@ it:Vita notturna ja:ナイトライフ ko:유흥|나이트 라이프|밤의 생활 lv:Naktsdzīve -mr:नाईटलाईफ +mr:नाईटलाईफ|रात्रीजीवन nb:Nattliv pl:Życie nocne pt:Vida noturna @@ -502,7 +503,7 @@ es:Vida nocturna|noche et:Ööelu eu:Gaueko bizitza sr:Ноћни живот|Noćni život -sv:Nattliv +sv:Nattliv|Nöjesliv th:ไนท์ไลฟ์ tr:Gece hayatı uk:Нічне життя @@ -529,8 +530,9 @@ nl:Gezinsvakantie fi:Vapaa-aikaa lasten kanssa fr:Vacances en famille de:Freizeit mit Kindern +he:שעשועים hi:पारिवारिक अवकाश -hu:Pihenés a gyerekekkel +hu:Családi kiruccanás id:Liburan keluarga it:Divertimento in famiglia|Vacanze bambini ja:家族の休日 @@ -539,14 +541,14 @@ lv:Atpūta ģimenei|Ģimene mr:कौटुंबिक सुट्टी nb:Familieferie pl:Wypoczynek z dziećmi -pt:Atividades com crianças +pt:Passeios com crianças pt-BR:Feriados em família ro:Divertisment cu copiii|Divertisment cu familia|Vacanță cu copiii es:Ocio en familia|Diversión en familia et:Perepuhkus eu:Umeekin atseden hartu sr:Све за децу|Sve za decu -sv:Semester med barn +sv:Familjesemester th:วันหยุดสำหรับครอบครัว tr:Aile tatili uk:Відпочинок з дітьми @@ -573,7 +575,7 @@ nl:3Geldautomaat fi:Pankkiautomaatti fr:DAB|GAB|argent|Distributeur de billets de:3Geldautomat|4Bankautomat|7Bargeldautomat -hi:3एटीएम|3स्वचालित गणक मशीन (एटीएम) +hi:3एटीएम|3स्वचालित गणक मशीन hu:4Pénzautomata id:2ATM it:3Bancomat @@ -601,7 +603,7 @@ el:ATM he:כספומט sk:3Bankomat sw:Benki|fedha -fa:خود پرداز +fa:خود‌پرداز # First keyword should match [category_rv] definition in strings.txt! @@ -618,15 +620,17 @@ el:Για RV es:5Caravanas|5Autocaravanas|5Motorhome|camper et:Haagiselamud eu:Karabanak -fa:RV ﯼﺍﺮﺑ +fa:امکانات ماشین کاروان fi:Karavaanaritilat fr:Aménagements pour camping-car|4caravane|mobile home -he:םינאוורק רובע -hu:RV számára +he:עבור קרוואנים +hi:आरवी सुविधाएं +hu:Lakókocsis létesítmények id:Untuk RV ja:RV用 ko:RV용 lv:4Treileru laukumi|4Treileri|5Karavāna +mr:कँपिंग वाहन सोयी it:Per camper nb:Bobilanlegg nl:Caravan faciliteiten|4Caravans|5Campers @@ -640,7 +644,7 @@ sr:За кампер возила|Za kamper vozila sv:För husbil sw:Kwa RV th:สำหรับ RV -tr:4Karavan Tesisleri +tr:4Karavan tesisleri uk:Для автобудинків|5Автодім|5Автобудинок|5Трейлер|5Караван|Будинок на колесах vi:Đối với RV zh-Hans:房车设施 @@ -700,6 +704,7 @@ nl:3Bank fi:3Pankki fr:3Banque de:3Bank +hi:3बैंक hu:3Bank id:3Bank it:3Banca @@ -738,7 +743,7 @@ be:4Сэканд-хэнд bg:Втора употреба ca:Segona mà cs:Second-hand -da:Brugt +da:Brugt|Genbrugsbutikker de:Second-hand el:Μεταχειρισμένα es:Segunda mano @@ -748,7 +753,8 @@ fa:دست دوم fi:Käytetyt tavarat fr:D'occasion he:יד שניה -hu:Second-hand +hi:सेकंड हैंड +hu:Second-hand|Használt cikk id:Tangan kedua it:Di seconda mano ja:中古品 @@ -764,14 +770,14 @@ ro:La mâna a doua ru:4Секонд-хенд sk:Second-hand sr:6Секонд-хенд|6Sekond-hend -sv:Begagnad +sv:Begagnad|Begagnat sw:Mtumba th:มือสอง tr:İkinci el uk:Секонд-хенд vi:Đồ cũ zh-Hans:二手货 -zh-Hant:二手貨 +zh-Hant:二手商店 amenity-bank|@category_bank en:money|U+1F3E6|U+1F4B0|U+1F4B2|U+1F4B3|U+1F4B4|U+1F4B5|U+1F4B6|U+1F4B7 @@ -784,7 +790,6 @@ da:3penge nl:geld fr:argent de:3Bankfiliale|Geld -hi:3बैंक hu:pénz id:uang it:soldi @@ -821,11 +826,13 @@ bg:Рециклиране|Преизползване|Разделно събир ar:إعادة تدوير|استغلال المخلفات|المواد القابلة لإعادة التدوير|جمع القمامة بشكل منفصل|فرز النفايات|إعادة الاستخدام ca:Reciclatge|Reciclatge de residus|Eliminació de residus|Materials reciclables|Recollida selectiva d’escombraries|Classificació de residus|Reutilització cs:Recyklace|Využití odpadu|Recyklovatelné|Oddělený sběr odpadků|Třídění odpadu|Opětovné použití -da:Genbrug|Affaldsudnyttelse|Genanvendelig|Separate dagrenovationer|Affaldssortering +da:Recirkulering|Genbrug|Affaldsudnyttelse|Genanvendelig|Separate dagrenovationer|Affaldssortering nl:Recycling|Afvalgebruik|Recyclebaar materiaal|Gescheiden afvalinzameling|Afval sorteren|Hergebruik fi:Jätteiden kierrätys|Jätteiden hyötykäyttö|Kierrätyskelpoinen jäte|Jätelajittelu|Jätteiden lajittelu|Hyötykäyttö fr:4Recyclage|Traitement des déchets|Dépôt de matières recyclables|Tri de déchets|Tri des déchets|Réutilisation de:Recycling|Abfallverwertung|Recyclebares Material|Getrennte Müllsammlung|Müllsortierung|Wiederverwendung +he:מיחזור +hi:पुनर्चक्रण hu:Újrahasznosítás|Hulladékhasznosítás|Újrahasznosítható|Elkülönített hulladékgyűjtés|Hulladék válogatás|Újrafelhasználás id:Mendaur ulang|Pemanfaatan limbah|Dapat didaur ulang|Pemisahan pengumpulan sampah|Pemilahan limbah|Penggunaan kembali it:Riciclo|Utilizzazione dei rifiuti|Ritiro dei materiali riciclabili|Separazione dei rifiuti|Raccolta differenziata|Riutilizzo @@ -837,13 +844,13 @@ nb:Resirkulering|Avfallsutnytting|Gjenvinningsstasjon|Kildesortering|Gjenbruk pl:Recykling|Recyrkulacja|Utylizacja odpadów|Do recyklingu|Segregacja śmieci|Sortowanie śmieci|Odzysk pt:Reciclagem|Ecoponto|Recicláveis|Separação de lixo|Reutilização pt-BR:Reciclagem|Utilização de resíduos|Recicláveis|Coleta de seletiva|Separação de lixo|Reuso -ro:Reciclarea deșeurilor|Reciclare|Recepționarea reciclării|Colectarea separată a gunoiului|Sortarea gunoiului|Reutilizare +ro:Reciclarea deșeurilor|4Reciclare|Recepționarea reciclării|Colectarea separată a gunoiului|Sortarea gunoiului|Reutilizare es:Reciclaje|Reciclaje de residuos|Eliminación de residuos|Materiales reciclables|Recogida selectiva de basura|Clasificación de residuos|Reutilización eu:Hondakinen birziklapena|Hondakinak ezabatzea|Material birziklagarriak|Zabor bilketa selektiboa|Hondakinak sailkatzea|Berrerabilpena et:Taaskasutus|Jäätmete kasutamine|Jäätmete äraandmine|Taaskasutatavad|Prügi eraldi korjamine|Prügi sorteerimne|Taaskasutus es-MX:Reciclaje|Reciclaje de desechos|Eliminación de desechos|Materiales reciclables|Recogida separada de basura|Clasificación de desechos|Reutilización sr:6Рециклажа|6Reciklaža -sv:Återvinning av avfall|Avfallsbehandling|Återvinningsbart avfall|Separat sopinsamling|Sopsortering|Återanvändning +sv:Återvinning|Avfallsbehandling|Återvinningsbart avfall|Separat sopinsamling|Sopsortering|Återanvändning th:การรีไซเคิล|การใช้ประโยชน์จากขยะ|รีไซเคิลได้|ที่รวบรวมขยะแยกประเภท|การแยกขยะ|รียูส tr:4Geri dönüşüm|4Atık kullanımı|4Geri dönüştürülebilir nesneler|4Ayrı çöp toplama|4Atık ayırma|5Yeniden kullanım uk:5Переробка відходів|Утилізація відходів|5Прийом вторсировини|5Здати вторсировину|5Роздільний збір сміття|Сортування сміття|Повторне використання @@ -5731,6 +5738,7 @@ nl:4Ziekenhuis|4hospitaal fi:5Sairaala fr:4Hôpital de:4Krankenhaus +hi:3चिकित्सालय hu:4Kórház id:5Rumahsakit|Rumah sakit it:4Ospedale @@ -5771,7 +5779,6 @@ nl:kliniek|hospitaal|3dokter|3eerste hulp fr:clinique|3médecin|3docteur de:4Spital|Klinik|3Arzt|Doktor|Medizinische Einrichtung|Medizinisches Zentrum|Gesundheitswesen|3Ambulanz|Gesundheitsdienstleistungen|Erste Hilfe et:Haigla|kliinik|3arst|meditsiinikeskus|terviseteenused|esmaabi -hi:3चिकित्सालय hu:rendelőintézet|3orvos ja:クリニック|医師|医者|ドクター|救急|診療 lv:Slimnīca|klīnika|poliklīnika|ārsts|dakteris|medicīnas centrs|medicīniskie pakalpojumi|ambulance @@ -5804,11 +5811,10 @@ nl:4Kliniek|ziekenhuis|hospitaal fi:4Klinikka|sairaala fr:4Clinique|hôpital de:4Klinik|Krankenhaus|Ambulanz|Arzt|Diagnostik|Gesundheitsdienstleistungen|4Doktor -hi:3चिकित्सालय hu:Rendelőintézet|kórház|szanatórium id:4Klinik|rumah sakit it:4Clinica|ospedale -ja:クリニック|病院、診療所|病院 +ja:クリニック|病院、診療所 lv:Klīnika|slimnīca|poliklīnika|U+1F3E5|U+1F489 mr:चिकित्सालय|क्लिनिक|दवाखाना nb:4Klinikk|sykehus @@ -5846,7 +5852,7 @@ hi:3चिकित्सक hu:Rendelő|Klinika|orvosi rendelő|kórház id:Praktik dokter|Klinik|rumah sakit it:Studio medico|Clinica|ambulatorio|ospedale -ja:医者のオフィス|クリニック|病院 +ja:医者のオフィス|クリニック lv:Ārsts|dakteris|klīnika|poliklīnika|U+1F489|U+1F3E5|U+1F691 mr:वैद्य|डॉक्टर|चिकित्सक nb:Legekontor|Klinikk|legesenter|sykehus @@ -7475,6 +7481,7 @@ sk:Záchody sw:Choo fa:دستشویی|توالت mr:शौचालय +hi:3शौचालय amenity-toilets|toilets-yes|@category_toilet en:wc|5restroom|4bathroom|loo|lavatory|U+1F6BD|U+1F6BE|U+1F4A9|U+1F6BB|U+1F6B9|U+1F6BA @@ -7485,7 +7492,6 @@ cs:wc|toalety nl:WC|toilet fr:wc de:WC -hi:3शौचालय hu:WC it:WC ja:お手洗い|便所|厠 @@ -7502,7 +7508,6 @@ tr:WC|tuvalet|umumi tuvalet zh-Hant:2洗手間|wc el:μπάνιο|χώρος ανάγκης|αποχωρητήριο|wc sk:3Toalety|wc -mr:शौचालय amenity-university en:4University|U+1F393|Uni @@ -8517,7 +8522,7 @@ tr:3Pansiyon|motel uk:3Хостел|отель|мотель|вітальниця vi:Nhà trọ zh-Hans:2旅馆|旅店 -zh-Hant:1旅舍|旅館|青年旅舍|青年旅館|住宿|飯店|3汽車旅館|3motel +zh-Hant:1旅舍|青年旅舍|青年旅館|住宿|飯店|3汽車旅館|3motel el:Πανδοχείο|ξενοδοχείο|μοτέλ sk:3Hostel|ubytovňa|motel sw:Bweni @@ -8537,7 +8542,7 @@ de:Gasthaus hi:3होटल hu:Szálloda|hotel|motel|szállás it:albergo -ja:宿|宿泊|旅館 +ja:ホテル lv:motelis|U+1F3E8|U+1F62A|U+1F634| pl:Hotel pt:motel @@ -8551,7 +8556,7 @@ th:โมเทล tr:motel uk:мотель zh-Hans:2宾馆|汽车旅馆|旅店 -zh-Hant:1飯店|1汽車旅館|旅館|住宿|賓館|招待所 +zh-Hant:1飯店|1汽車旅館|住宿|賓館|招待所 el:μοτέλ sk:ubytovňa|motel sw:Hoteli @@ -8589,7 +8594,7 @@ tr:Misafir evi|pansiyon|misafirhane uk:5Гостинний дім|хостел|постояльний двір vi:Nhà khách zh-Hans:1招待所์|์旅馆์|์旅社|旅店 -zh-Hant:1賓館|旅館|飯店|旅舍|住宿|招待所 +zh-Hant:1賓館|飯店|旅舍|住宿|招待所 el:Ξενώνας|ξενοδοχείο|ξενώνας sk:Penzión|hostel|ubytovňa sw:Gesti @@ -8629,7 +8634,7 @@ tr:3Motel|pansiyon uk:3Мотель|хостел vi:Nhà nghỉ zh-Hans:1汽车旅馆|旅店 -zh-Hant:1汽車旅館|3motel|旅館|飯店|住宿| +zh-Hant:1汽車旅館|3motel|飯店|住宿| el:Μοτέλ|ξενοδοχείο|ξενώνας sk:3Motel|penzión|hostel|ubytovňa fa:مُتل @@ -8666,7 +8671,7 @@ tr:3Dağda konaklama|otel uk:4Гірський притулок|4будиночок|3хибара|турпритулок|4притулок|гірський готель|гірська хатинка vi:Nhà ở trên núi|khách sạn zh-Hans:山上住宿|旅馆|旅店 -zh-Hant:1山上住宿|飯店|旅館|住宿|旅舍|2高山住宿 +zh-Hant:1山上住宿|飯店|住宿|旅舍|2高山住宿 el:Ορεινό καταφύγιο|ξενοδοχείο|ξενώνας|αλπική καλύβα sk:4Horská chata|horský hotel|hotel @@ -10131,7 +10136,7 @@ mr:इमारत|बिल्डिंग|वाडा @category_police en:4Police ru:4Полиция|милиция -be:4Паліцыя +be:4Паліцыя|міліція bg:4Полиция ca:Policia ar:شرطة @@ -10141,17 +10146,18 @@ nl:4Politie fi:4Poliisi fr:4Police|4gendarmerie de:Polizeistation|4Polizei +hi:3थाना hu:4Rendőrség id:4Polisi it:4Polizia ja:警察 -ko:경찰 +ko:치안대 lv:4Policija nb:4Politi pl:4Policja pt:4Polícia pt-BR:4Polícia -ro:4Poliție +ro:4Poliție|Poliția es:4Policía et:4Politsei eu:4Poliziak @@ -10178,7 +10184,6 @@ ca:Policia cs:4bezpečnost de:Polizeiwache|Polizei fr:Poste de police|Commissariat -hi:3थाना it:6Commissariato|5Questura|4Caserma|4Guardia|5Carabinieri ja:1屯所|ポリス|交番|お巡りさん|おまわりさん|通報 ko:보안대 @@ -10305,6 +10310,7 @@ fa:اب fi:3Vesi fr:3Eau|L'eau he:מים +hi:जल hu:3Víz id:3Air it:3Acqua @@ -10322,7 +10328,7 @@ sr:Вода|Voda sv:3Vatten sw:4Maji th:น้ำ -tr:Su Kaynağı +tr:Su Kaynağı|Su uk:3Вода|джерело води vi:Nước zh-Hans:水 @@ -12086,14 +12092,14 @@ pl:Krawiec pt-BR:Alfaiate|costureiro|conserto de roupas pt:Alfaiate ro:Croitor -ru:4Ателье|портной|4ремонт одежды|швейная мастерская|5пошив одежды +ru:4Ателье|Портной|4Ремонт одежды|4Швейная мастерская|5Пошив одежды|Кройка|Шитьё sk:Krajčírstvo sr:Кројач|Krojač sv:Skräddare sw:Mshonaji nguo th:ช่างตัดเสื้อ tr:Terzi -uk:4Ательє|4Ремонт одягу|швейна майстерня +uk:4Ательє|4Ремонт одягу|4Швейна майстерня vi:Thợ may zh-Hans:裁缝 zh-Hant:裁縫師 @@ -16962,6 +16968,7 @@ lv:Auduma veikals|tekstilu veikals nl:Stoffenwinkel pt:Loja de tecidos pt-BR:Loja de aviamentos +ru:Текстиль|Ткани sr:Текстил|Метража|Tekstil|Metraža tr:Kumaş mağazası|Tekstil mağazası es:Mercería @@ -17624,7 +17631,7 @@ zh-Hant:香水 shop-sewing|@shop en:3Sewing Supplies|4Haberdashery ar:معدات الخياطة -be:Швейныя прыналежнасці +be:4Швейныя прыналежнасці bg:Шивашки консумативи ca:Material de costura|Mercería cs:Šicí potřeby @@ -17651,14 +17658,14 @@ pl:Przybory do szycia pt:Materiais de costura pt-BR:Materiais de costura ro:Rechizite de cusut -ru:Швейные принадлежности +ru:4Швейные принадлежности|Кройка|Шитьё sk:Šijacie potreby sr:Пазамантерија|Pozamanterija sv:Sytillbehör sw:Vifaa vya kushona th:อุปกรณ์เย็บผ้า tr:Dikiş malzemeleri -uk:Швейні приладдя +uk:4Швейні приладдя vi:Nguồn cung cấp may zh-Hans:缝纫用品 zh-Hant:縫紉用品 diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 216b379c709..007efc944a4 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -472,6 +472,200 @@ std::string MetadataTagProcessorImpl::ValidateAndFormat_duration(std::string con return format(hours); } +std::string MetadataTagProcessorImpl::MaxChargingPower(std::string_view const & previousMetadata, std::string const & k, std::string v) +{ + std::string_view constexpr kMaxPowerDC{" kW DC"}; + std::string_view constexpr kMaxPowerAC{" kW AC"}; + std::string_view constexpr kMaxPowerDelim{", "}; + char constexpr kMaxPowerPoint='.'; + size_t pos = 0; + std::string dc, ac, prev = static_cast(previousMetadata); + + if (prev.size() > 1) { + if ((pos = prev.find(kMaxPowerDelim)) != std::string::npos) { + dc = prev.substr(0, pos - kMaxPowerDC.size()); + ac = prev.substr(pos + kMaxPowerDelim.size(), prev.size() - (pos + kMaxPowerDelim.size() + kMaxPowerAC.size())); + + if (kMaxPowerPoint != '.') { + std::replace(dc.begin(), dc.end(), kMaxPowerPoint, '.'); + std::replace(ac.begin(), ac.end(), kMaxPowerPoint, '.'); + } + } else if ((pos = prev.find(kMaxPowerDC)) != std::string::npos) { + dc = prev.substr(0, pos); + if (kMaxPowerPoint != '.') + std::replace(dc.begin(), dc.end(), kMaxPowerPoint, '.'); + } else if ((pos = prev.find(kMaxPowerAC)) != std::string::npos) { + ac = prev.substr(0, pos); + if (kMaxPowerPoint != '.') + std::replace(ac.begin(), ac.end(), kMaxPowerPoint, '.'); + } + } + + while ((pos = v.find("к")) != std::string::npos) { + v[pos] = 'k'; + v[pos + 1] = ' '; + } + + while ((pos = v.find("К")) != std::string::npos) { + v[pos] = 'k'; + v[pos + 1] = ' '; + } + + while ((pos = v.find("в")) != std::string::npos) { + v[pos] = 'w'; + v[pos + 1] = ' '; + } + + while ((pos = v.find("В")) != std::string::npos) { + v[pos] = 'w'; + v[pos + 1] = ' '; + } + + std::transform(v.begin(), v.end(), v.begin(), ::tolower); + if (v.find("http") != std::string::npos) + return prev; + v.erase(std::remove_if(v.begin(), v.end(), ::isspace), v.end()); + + char split = ' '; + size_t mult = 0; + + if ((pos = v.find(';')) != std::string::npos) + split = ';'; + else if ((pos = v.find('+')) != std::string::npos) + split = '+'; + else if ((pos = v.find('=')) != std::string::npos) + split = '='; + else if ((pos = v.find('-')) != std::string::npos) + split = '-'; + else if ((pos = v.find(':')) != std::string::npos) + split = ':'; + else if ((pos = v.find('/')) != std::string::npos) + split = '/'; + else if ((pos = v.find('\\')) != std::string::npos) + split = '\\'; + else if ((pos = v.find(',')) != std::string::npos) { + if (((mult = v.find("kw")) != std::string::npos) && (v.find("kw", mult + 1) != std::string::npos)) { + split = ','; + } else { + split = ' '; + pos = v.size(); + } + } else + pos = v.size(); + + bool typedc = false; + + if ((k.find("combo") != std::string::npos) || (k.find("chademo") != std::string::npos) || + (k.find("super") != std::string::npos) || (k.find("bosch") != std::string::npos) || + (k.find("gb_dc") != std::string::npos) || (k.find("3105") != std::string::npos) || + (k.find("roadster") != std::string::npos)) + typedc = true; + + size_t last = 0, watts = 0; + float numeric = 0.0, maximum = 0.0; + std::string part, result; + + do { + part = v.substr(last, pos - last); + std::replace(part.begin(), part.end(), ',', '.'); + if (((mult = part.find('(')) != std::string::npos) && ((watts = part.find(')', mult + 1)) != std::string::npos)) + part.erase(mult, mult - watts); + + if ((mult = part.find('x')) != std::string::npos) { + if (mult < ((part.size() + 1) >> 1)) { + part = part.substr(mult + 1, part.size() - (mult + 1)); + } else { + part = part.substr(0, mult); + } + } else if ((mult = part.find('*')) != std::string::npos) { + if (mult < ((part.size() + 1) >> 1)) { + part = part.substr(mult + 1, part.size() - (mult + 1)); + } else { + part = part.substr(0, mult); + } + } else if ((mult = part.find("×")) != std::string::npos) { + if (mult < (part.size() >> 1)) { + part = part.substr(mult + 2, part.size() - (mult + 2)); + } else { + part = part.substr(0, mult); + } + } + + if ((watts = part.find('w')) != std::string::npos) + watts = ((part.find('k') == std::string::npos) ? 0 : std::string::npos); + if ((mult = part.find("kva")) != std::string::npos) + part = part.substr(0, mult); + if ((mult = part.find('w')) != std::string::npos) + part = part.substr(0, mult); + mult = part.size(); + part.erase(std::remove_if(part.begin(), part.end(), [](unsigned char c) { return ((!std::isdigit(c)) && (c != '.')); }), part.end()); + if (part.size() < (mult >> 1)) + part = ""; + + try { + numeric = std::stof(part); + } catch (const std::invalid_argument& e) { + numeric = 0.0; + } catch (const std::out_of_range& e) { + numeric = 0.0; + } + + if ((watts != std::string::npos) || (numeric > 2000.0)) { + numeric /= 1000.0; + std::stringstream stream; + stream << std::fixed << std::setprecision(numeric < 100.0 ? 1 : 0) << numeric; + part = stream.str(); + } + + if (numeric > maximum) { + if (((mult = part.find('.')) != std::string::npos) && (mult < (part.size() - 2))) { + std::stringstream stream; + stream << std::fixed << std::setprecision(numeric < 100.0 ? 1 : 0) << numeric; + part = stream.str(); + } + + maximum = numeric; + + if ((part.find('.') != std::string::npos) && (part[part.size() - 1] == '0')) + result = part.substr(0, part.size() - 2); + else + result = part; + } + + last = pos; + pos = v.find(split, last + 1); + } while ((last++) < (v.size() - 1)); + + if (maximum == 0.0) + return prev; + + if (((k.find("nacs") != std::string::npos) || (k == "charging_station:output")) && (maximum >= 50.0)) + typedc = true; + if ((typedc) && (((dc.empty()) || (maximum > std::stof(dc))))) + dc = result; + if ((!typedc) && (((ac.empty()) || (maximum > std::stof(ac))))) + ac = result; + + if (!dc.empty()) { + if (!ac.empty()) { + if (kMaxPowerPoint != '.') + std::replace(dc.begin(), dc.end(), '.', kMaxPowerPoint); + if (kMaxPowerPoint != '.') + std::replace(ac.begin(), ac.end(), '.', kMaxPowerPoint); + prev = dc + static_cast(kMaxPowerDC) + static_cast(kMaxPowerDelim) + ac + static_cast(kMaxPowerAC); + } else { + if (kMaxPowerPoint != '.') + std::replace(dc.begin(), dc.end(), '.', kMaxPowerPoint); + prev = dc + static_cast(kMaxPowerDC); + } + } else if (!ac.empty()) { + if (kMaxPowerPoint != '.') + std::replace(ac.begin(), ac.end(), '.', kMaxPowerPoint); + prev = ac + static_cast(kMaxPowerAC); + } + + return prev; +} MetadataTagProcessor::~MetadataTagProcessor() { @@ -566,6 +760,7 @@ void MetadataTagProcessor::operator()(std::string const & k, std::string const & case Metadata::FMD_SELF_SERVICE: valid = ValidateAndFormat_self_service(v); break; case Metadata::FMD_OUTDOOR_SEATING: valid = ValidateAndFormat_outdoor_seating(v); break; case Metadata::FMD_NETWORK: valid = ValidateAndFormat_operator(v); break; + case Metadata::FMD_MAX_POWER: valid = MaxChargingPower(md.Get(Metadata::FMD_MAX_POWER), k, v); break; // Metadata types we do not get from OSM. case Metadata::FMD_CUISINE: case Metadata::FMD_DESCRIPTION: // processed separately diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp index 3a6e43eb16b..bd24c632a58 100644 --- a/generator/osm2meta.hpp +++ b/generator/osm2meta.hpp @@ -40,6 +40,7 @@ struct MetadataTagProcessorImpl static std::string ValidateAndFormat_drive_through(std::string v); static std::string ValidateAndFormat_self_service(std::string v); static std::string ValidateAndFormat_outdoor_seating(std::string v); + std::string MaxChargingPower(std::string_view const & previousMetadata, std::string const & k, std::string v); protected: FeatureBuilderParams & m_params; diff --git a/indexer/feature_meta.cpp b/indexer/feature_meta.cpp index 983492cffe1..fa7db4eabc4 100644 --- a/indexer/feature_meta.cpp +++ b/indexer/feature_meta.cpp @@ -154,6 +154,8 @@ bool Metadata::TypeFromString(string_view k, Metadata::EType & outType) outType = Metadata::FMD_OUTDOOR_SEATING; else if (k == "network") outType = Metadata::FMD_NETWORK; + else if (k == "charging_station:output" || (k.starts_with("socket:") && k.ends_with(":output"))) + outType = Metadata::FMD_MAX_POWER; else return false; @@ -277,6 +279,7 @@ string ToString(Metadata::EType type) case Metadata::FMD_SELF_SERVICE: return "self_service"; case Metadata::FMD_OUTDOOR_SEATING: return "outdoor_seating"; case Metadata::FMD_NETWORK: return "network"; + case Metadata::FMD_MAX_POWER: return "max_power"; case Metadata::FMD_COUNT: CHECK(false, ("FMD_COUNT can not be used as a type.")); }; diff --git a/indexer/feature_meta.hpp b/indexer/feature_meta.hpp index 17312b69a26..32447733feb 100644 --- a/indexer/feature_meta.hpp +++ b/indexer/feature_meta.hpp @@ -155,6 +155,7 @@ class Metadata : public MetadataBase FMD_SELF_SERVICE = 47, FMD_OUTDOOR_SEATING = 48, FMD_NETWORK = 49, + FMD_MAX_POWER = 50, FMD_COUNT }; diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index cd0705a9689..25f149b2960 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -466,7 +466,6 @@ TwoLevelPOIChecker::TwoLevelPOIChecker() : ftypes::BaseChecker(2 /* level */) {"highway", "rest_area"}, {"highway", "services"}, {"highway", "speed_camera"}, - {"man_made", "communications_tower"}, {"man_made", "cross"}, {"man_made", "lighthouse"}, {"man_made", "water_tap"}, diff --git a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h index e2d5439de9c..a4e69d08884 100644 --- a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h +++ b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, readonly, nullable) NSString *selfService; @property(nonatomic, readonly, nullable) NSString *outdoorSeating; @property(nonatomic, readonly, nullable) NSString *network; +@property(nonatomic, readonly, nullable) NSString *maxPower; @end diff --git a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm index 8fb9fee4fc5..eb10a458aba 100644 --- a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm +++ b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm @@ -92,6 +92,7 @@ - (instancetype)initWithRawData:(Info const &)rawData ohLocalization:(id(iPhone: @autoclosure () -> T, iPad: @autoclosure () -> T) -> T { - if traitCollection.verticalSizeClass == .regular && traitCollection.horizontalSizeClass == .regular { - return iPad() - } - return iPhone() + isiPad ? iPad() : iPhone() } func alternativeSizeClass(iPhone: () -> Void, iPad: () -> Void) { - if traitCollection.verticalSizeClass == .regular && traitCollection.horizontalSizeClass == .regular { - iPad() - } else { - iPhone() - } + isiPad ? iPad() : iPhone() } } diff --git a/iphone/Maps/Common/Common.swift b/iphone/Maps/Common/Common.swift index 757d309d3bc..79f85d43f41 100644 --- a/iphone/Maps/Common/Common.swift +++ b/iphone/Maps/Common/Common.swift @@ -1,19 +1,24 @@ import Foundation -var isIPad: Bool { return UI_USER_INTERFACE_IDIOM() == .pad } +var isiPad: Bool { + if #available(iOS 14.0, *), ProcessInfo.processInfo.isiOSAppOnMac { + return true + } + return UIDevice.current.userInterfaceIdiom == .pad +} func L(_ key: String) -> String { return NSLocalizedString(key, comment: "") } -func alternative(iPhone: T, iPad: T) -> T { return isIPad ? iPad : iPhone } +func alternative(iPhone: T, iPad: T) -> T { isiPad ? iPad : iPhone } func iPadSpecific(_ f: () -> Void) { - if isIPad { + if isiPad { f() } } func iPhoneSpecific(_ f: () -> Void) { - if !isIPad { + if !isiPad { f() } } diff --git a/iphone/Maps/Core/Theme/GlobalStyleSheet.swift b/iphone/Maps/Core/Theme/GlobalStyleSheet.swift index bed3b22e57e..3afe39ae749 100644 --- a/iphone/Maps/Core/Theme/GlobalStyleSheet.swift +++ b/iphone/Maps/Core/Theme/GlobalStyleSheet.swift @@ -452,7 +452,7 @@ extension GlobalStyleSheet: IStyleSheet { s.shadowRadius = 6 s.cornerRadius = .modalSheet s.clip = false - s.maskedCorners = isIPad ? [] : [.layerMinXMinYCorner, .layerMaxXMinYCorner] + s.maskedCorners = isiPad ? [] : [.layerMinXMinYCorner, .layerMaxXMinYCorner] } case .modalSheetContent: return .addFrom(Self.modalSheetBackground) { s in diff --git a/iphone/Maps/Core/Theme/PlacePageStyleSheet.swift b/iphone/Maps/Core/Theme/PlacePageStyleSheet.swift index dbece4923e2..13667c4a04c 100644 --- a/iphone/Maps/Core/Theme/PlacePageStyleSheet.swift +++ b/iphone/Maps/Core/Theme/PlacePageStyleSheet.swift @@ -125,7 +125,7 @@ extension PlacePageStyleSheet: IStyleSheet { case .ppBackgroundView: return .addFrom(GlobalStyleSheet.modalSheetBackground) { s in s.backgroundColor = colors.pressBackground - s.maskedCorners = isIPad ? CACornerMask.all : [.layerMinXMinYCorner, .layerMaxXMinYCorner] + s.maskedCorners = isiPad ? CACornerMask.all : [.layerMinXMinYCorner, .layerMaxXMinYCorner] s.clip = false } case .ppView: diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/Contents.json b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/Contents.json new file mode 100644 index 00000000000..a48ec0fe904 --- /dev/null +++ b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "ic_placepage_max_power.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/ic_placepage_max_power.svg b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/ic_placepage_max_power.svg new file mode 100644 index 00000000000..c78278bdae5 --- /dev/null +++ b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_max_power.imageset/ic_placepage_max_power.svg @@ -0,0 +1,4 @@ + + + + diff --git a/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings b/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings index e270db143d9..175a23820bf 100644 --- a/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings +++ b/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings @@ -1005,7 +1005,6 @@ /* Main screen title "Map" displayed in the navigation back button's menu. */ "map" = "Map"; -"drive_through" = "Drive-through"; /* Restaurant or other food place's menu URL field in the Editor */ "website_menu" = "Menu Link"; @@ -1046,12 +1045,18 @@ /* Title for the "Open in Another App" button on the PlacePage. */ "open_in_app" = "Open in Another App"; -/* To indicate if the place proposed self service... */ +/* To indicate if the place has self-service. */ "self_service" = "Self-service"; -/* To indicate if restaurant or other place has outdoor seating */ +/* To indicate if the place has a drive-through. */ +"drive_through" = "Drive-through"; + +/* To indicate if restaurant or other place has outdoor seating. */ "outdoor_seating" = "Outdoor seating"; +/* To indicate a maximum value. */ +"maximum_value" = "Maximum: %@"; + /* Title for the "Recently Deleted Lists" button on the Bookmarks and Lists screen. */ "bookmarks_recently_deleted" = "Recently Deleted Lists"; diff --git a/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift b/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift index 86140be75d8..33c96f3b6bb 100644 --- a/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift +++ b/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift @@ -130,7 +130,7 @@ final class SearchOnMapTests: XCTestCase { searchManager.results = results interactor.handle(.didSelectResult(results[0], withQuery: query)) - if isIPad { + if isiPad { XCTAssertEqual(currentState, .searching) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) } else { @@ -145,7 +145,7 @@ final class SearchOnMapTests: XCTestCase { interactor.handle(.didSelectPlaceOnMap) - if isIPad { + if isiPad { XCTAssertNotEqual(view.viewModel.presentationStep, .hidden) } else { XCTAssertEqual(view.viewModel.presentationStep, .hidden) @@ -163,7 +163,7 @@ final class SearchOnMapTests: XCTestCase { searchManager.results = results interactor.handle(.didSelectResult(results[0], withQuery: query)) - if isIPad { + if isiPad { XCTAssertEqual(currentState, .searching) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) } else { diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift b/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift index 1b84292a23a..474dbb01b84 100644 --- a/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift @@ -128,6 +128,7 @@ class PlacePageInfoViewController: UIViewController { private var outdoorSeatingView: InfoItemViewController? private var driveThroughView: InfoItemViewController? private var networkView: InfoItemViewController? + private var maxPowerView: InfoItemViewController? weak var placePageInfoData: PlacePageInfoData! weak var delegate: PlacePageInfoViewControllerDelegate? @@ -262,6 +263,10 @@ class PlacePageInfoViewController: UIViewController { driveThroughView = createInfoItem(driveThrough, icon: UIImage(named: "ic_placepage_drive_through")) } + if let maxPower = placePageInfoData.maxPower { + maxPowerView = createInfoItem(maxPower, icon: UIImage(named: "ic_placepage_max_power")) + } + if let email = placePageInfoData.email { emailView = createInfoItem(email, icon: UIImage(named: "ic_placepage_email"), diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift index f84ad6231b0..198f5d5dd2c 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift @@ -48,7 +48,7 @@ final class SearchOnMapInteractor: NSObject { case .didSelectResult(let result, let query): return processSelectedResult(result, query: query) case .didSelectPlaceOnMap: - return isIPad ? .none : .setSearchScreenHidden(true) + return isiPad ? .none : .setSearchScreenHidden(true) case .didDeselectPlaceOnMap: return deselectPlaceOnMap() case .didStartDraggingMap: @@ -113,7 +113,7 @@ final class SearchOnMapInteractor: NSObject { @unknown default: fatalError("Unsupported routingTooltipSearch") } - return isIPad ? .none : .setSearchScreenHidden(true) + return isiPad ? .none : .setSearchScreenHidden(true) case .suggestion: let suggestionQuery = SearchQuery(result.suggestion, locale: query.locale, diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 7f105b50226..5bd704ad1f2 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -841,7 +841,7 @@ bool RoutingManager::CouldAddIntermediatePoint() const < RoutePointsLayout::kMaxIntermediatePointsCount + 2; } -void RoutingManager::AddRoutePoint(RouteMarkData && markData) +void RoutingManager::AddRoutePoint(RouteMarkData && markData, bool reorderIntermediatePoints) { ASSERT(m_bmManager != nullptr, ()); RoutePointsLayout routePoints(*m_bmManager); @@ -859,7 +859,9 @@ void RoutingManager::AddRoutePoint(RouteMarkData && markData) markData.m_isVisible = !markData.m_isMyPosition; routePoints.AddRoutePoint(std::move(markData)); - ReorderIntermediatePoints(); + + if (reorderIntermediatePoints) + ReorderIntermediatePoints(); } void RoutingManager::ContinueRouteToPoint(RouteMarkData && markData) diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 278cc18bbbe..b38ef542bce 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -227,7 +227,7 @@ class RoutingManager final /// will not return previous data, only newer. void GenerateNotifications(std::vector & notifications, bool announceStreets); - void AddRoutePoint(RouteMarkData && markData); + void AddRoutePoint(RouteMarkData && markData, bool reorderIntermediatePoints = true); void ContinueRouteToPoint(RouteMarkData && markData); std::vector GetRoutePoints() const; size_t GetRoutePointsCount() const; diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index d2d75a671d6..95a3390b335 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -126,6 +126,8 @@ copy_resources( countries.txt drules_proto_default_light.bin drules_proto_default_dark.bin + drules_proto_outdoors_light.bin + drules_proto_outdoors_dark.bin drules_proto_vehicle_light.bin drules_proto_vehicle_dark.bin editor.config diff --git a/search/processor.cpp b/search/processor.cpp index 7b2a0ac8aaf..d634766da49 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -226,7 +226,7 @@ void Processor::SetInputLocale(string const & locale) return; int8_t const code = StringUtf8Multilang::GetLangIndex(languages::Normalize(locale)); - LOG(LDEBUG, ("New input locale:", locale, "locale code:", code)); + LOG(LDEBUG, ("New input locale:", locale, "; locale code:", int(code))); m_keywordsScorer.SetLanguages(LanguageTier::LANGUAGE_TIER_INPUT, feature::GetSimilar(code)); m_inputLocaleCode = CategoriesHolder::MapLocaleToInteger(locale); } diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index 0b4175cc2f6..e1653a94038 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -237,9 +237,9 @@ UNIT_CLASS_TEST(MwmTestsFixture, NY_Subway) auto const & results = request->Results(); TEST_GREATER(results.size(), kTopResults, ()); - /// @todo Equal food and metro results, so test 2 food on top. + /// @todo Equal food and metro results, so test 1 food on top. Range const top10(results, 0, kTopResults); - TEST_EQUAL(CountClassifType(top10, cl.GetTypeByPath({"amenity", "fast_food"})), 2, ()); + TEST_GREATER(CountClassifType(top10, cl.GetTypeByPath({"amenity", "fast_food"})), 0, ()); TEST_GREATER(CountClassifType(top10, cl.GetTypeByPath({"railway", "station", "subway"})), 6, ()); } { @@ -587,7 +587,7 @@ UNIT_CLASS_TEST(MwmTestsFixture, Generic_Buildings_Rank) // results[0] is a named POI ~9km (https://www.openstreetmap.org/node/9730886727) Range const range(results, 1, kResultsCount); - EqualClassifType(range, GetClassifTypes({{"man_made", "tower", "communication"}})); + EqualClassifType(range, GetClassifTypes({{"man_made", "tower", "communication"}, {"man_made", "communications_tower"}})); TEST_LESS(SortedByDistance(range, center).first, 3000.0, ()); }