diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/app/organicmaps/Framework.cpp index 34c64a2835..ac5ad0a6af 100644 --- a/android/jni/app/organicmaps/Framework.cpp +++ b/android/jni/app/organicmaps/Framework.cpp @@ -1106,14 +1106,8 @@ Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) { - static std::array const kBookmarkExtensions = { - std::string{kKmzExtension}, - std::string{kKmlExtension}, - std::string{kKmbExtension}, - std::string{kGpxExtension} - }; - - return jni::ToJavaStringArray(env, kBookmarkExtensions); + const vector exts = { kKmzExtension, kKmlExtension, kKmbExtension, kGpxExtension }; + return jni::ToJavaStringArray(env, exts); } JNIEXPORT void JNICALL diff --git a/data/gpx_test_data/color.gpx b/data/gpx_test_data/color.gpx index 56a81bef96..0de2801302 100644 --- a/data/gpx_test_data/color.gpx +++ b/data/gpx_test_data/color.gpx @@ -77,4 +77,35 @@ + + + black + + + Black + + + + + 75.59999 + + + + + + + reset to red + + + UnussportedGarminColor + + + + + 75.59999 + + + + + \ No newline at end of file diff --git a/docs/DEBUG_COMMANDS.md b/docs/DEBUG_COMMANDS.md index ae8d261505..d37d4ee060 100644 --- a/docs/DEBUG_COMMANDS.md +++ b/docs/DEBUG_COMMANDS.md @@ -27,13 +27,6 @@ For more information, please see the source code at [`Framework::ParseSearchQuer - `?isolines`: Enable the isolines layer. - `?no-isolines`: Disable the isolines layer. -### 3D mode (for the Qt desktop app only) -- `?3d`: Enable 3D (perspective) mode. -- `?b3d`: Enable 3D buildings. -- `?2d`: Disable 3D mode and buildings. - -The source code is at [`SearchPanel::Try3dModeCmd`](../qt/search_panel.cpp). - ### Information - `?debug-info`: Show renderer version, zoom scale and FPS counter in the top left corner of the map. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ff8b4f3e53..6f99e547ee 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -130,7 +130,7 @@ sudo dnf install -y \ freetype-devel \ libicu-devel \ libstdc++-devel \ - mesa-libGL-devel \ + libgl1-mesa-devel \ libglvnd-devel \ qt6-qtbase-devel \ qt6-qtsvg-devel \ @@ -268,7 +268,7 @@ To switch themes you can enter this commands: - `?vlight` - Day theme for vehicle navigation - `?vdark` - Night theme for vehicle navigation -There are also other commands for turning on/off isolines, antialiasing, etc. Check [DEBUG_COMMANDS.md](DEBUG_COMMANDS.md) to learn about them. +There are also other commands for turning on/off isolines, antialiasing, etc. Check [the code](https://github.com/organicmaps/organicmaps/blob/6ae19b40c2b7a515338eb128547df05da13bdb78/map/framework.cpp#L2570-L2671) to learn about them. ### More options diff --git a/drape_frontend/area_shape.cpp b/drape_frontend/area_shape.cpp index ff702c0a72..46c94e5cc1 100644 --- a/drape_frontend/area_shape.cpp +++ b/drape_frontend/area_shape.cpp @@ -41,10 +41,7 @@ void AreaShape::Draw(ref_ptr context, ref_ptr } if (m_params.m_is3D) - { - if (m_vertexes.size() < 10000) - DrawArea3D(context, batcher, colorUv, outlineUv, region.GetTexture()); - } + DrawArea3D(context, batcher, colorUv, outlineUv, region.GetTexture()); else if (m_params.m_hatching) DrawHatchingArea(context, batcher, colorUv, region.GetTexture(), textures->GetHatchingTexture()); else diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 6f127ce92b..43216af1a9 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -695,9 +695,7 @@ void BackendRenderer::RenderFrame() void BackendRenderer::InitContextDependentResources() { - // Increase this value for big features. uint32_t constexpr kBatchSize = 5000; - m_batchersPool = make_unique_dp>(kReadingThreadsCount, std::bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3), kBatchSize, kBatchSize); diff --git a/indexer/caching_rank_table_loader.cpp b/indexer/caching_rank_table_loader.cpp index e540c7a797..dbaa3627ba 100644 --- a/indexer/caching_rank_table_loader.cpp +++ b/indexer/caching_rank_table_loader.cpp @@ -3,7 +3,14 @@ #include "search/dummy_rank_table.hpp" #include "indexer/data_source.hpp" +#include "indexer/feature.hpp" +#include "defines.hpp" + +namespace +{ +uint8_t const kNoRank = 0; +} // namespace CachingRankTableLoader::CachingRankTableLoader(DataSource const & dataSource, std::string const & sectionName) @@ -16,7 +23,7 @@ uint8_t CachingRankTableLoader::Get(FeatureID const & featureId) const auto const handle = m_dataSource.GetMwmHandleById(featureId.m_mwmId); if (!handle.IsAlive()) - return search::RankTable::kNoRank; + return kNoRank; auto it = m_deserializers.find(featureId.m_mwmId); diff --git a/indexer/caching_rank_table_loader.hpp b/indexer/caching_rank_table_loader.hpp index c8dc5d5b40..2e80429ae7 100644 --- a/indexer/caching_rank_table_loader.hpp +++ b/indexer/caching_rank_table_loader.hpp @@ -6,6 +6,7 @@ #include "base/macros.hpp" +#include #include #include #include @@ -19,14 +20,13 @@ class CachingRankTableLoader public: CachingRankTableLoader(DataSource const & dataSource, std::string const & sectionName); - /// @return 0 if there is no rank for feature. uint8_t Get(FeatureID const & featureId) const; void OnMwmDeregistered(platform::LocalCountryFile const & localFile); private: DataSource const & m_dataSource; std::string const m_sectionName; - mutable std::map> m_deserializers; + mutable std::map const> m_deserializers; DISALLOW_COPY(CachingRankTableLoader); }; diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index ecf1926bb2..8c065b6990 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -346,16 +346,16 @@ IsWayChecker::IsWayChecker() {"primary", Regular}, {"primary_link", Regular}, {"residential", Residential}, - {"road", Minors}, + {"road", Outdoor}, {"secondary", Regular}, {"secondary_link",Regular}, - {"service", Minors}, + {"service", Residential}, {"tertiary", Regular}, {"tertiary_link", Regular}, {"track", Outdoor}, {"trunk", Motorway}, {"trunk_link", Motorway}, - {"unclassified", Minors}, + {"unclassified", Outdoor}, }; m_ranks.Reserve(std::size(types)); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index c4611a541b..65eb507c9f 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -222,7 +222,6 @@ public: Pedestrian, Cycleway, Outdoor, - Minors, Residential, Regular, Motorway, diff --git a/indexer/indexer_tests/rank_table_test.cpp b/indexer/indexer_tests/rank_table_test.cpp index 07a4287011..879c33dc86 100644 --- a/indexer/indexer_tests/rank_table_test.cpp +++ b/indexer/indexer_tests/rank_table_test.cpp @@ -85,7 +85,8 @@ UNIT_TEST(RankTableBuilder_EndToEnd) base::CopyFileX(originalMapPath, mapPath); SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, mapPath)); - auto const localFile = platform::LocalCountryFile::MakeForTesting("minsk-pass-copy"); + platform::LocalCountryFile localFile = + platform::LocalCountryFile::MakeForTesting("minsk-pass-copy"); TEST(localFile.OnDisk(MapFileType::Map), ()); vector ranks; @@ -105,3 +106,57 @@ UNIT_TEST(RankTableBuilder_EndToEnd) TestTable(ranks, mapPath); } + +UNIT_TEST(RankTableBuilder_WrongEndianness) +{ + char const kTestFile[] = "test.mwm"; + SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, kTestFile)); + + vector ranks = {0, 1, 2, 3, 4}; + { + FilesContainerW wcont(kTestFile); + search::RankTableBuilder::Create(ranks, wcont, SEARCH_RANKS_FILE_TAG); + } + + // Load rank table in host endianness. + unique_ptr table; + { + FilesContainerR rcont(kTestFile); + table = search::RankTable::Load(rcont, SEARCH_RANKS_FILE_TAG); + TEST(table.get(), ()); + TestTable(ranks, *table); + } + + // Serialize rank table in opposite endianness. + { + vector data; + { + MemWriter writer(data); + table->Serialize(writer, false /* preserveHostEndianness */); + } + + FilesContainerW wcont(kTestFile); + wcont.Write(data, SEARCH_RANKS_FILE_TAG); + } + + // Try to load rank table from opposite endianness. + { + FilesContainerR rcont(kTestFile); + auto table = search::RankTable::Load(rcont, SEARCH_RANKS_FILE_TAG); + TEST(table.get(), ()); + TestTable(ranks, *table); + } + + // It's impossible to map rank table from opposite endianness. + { + FilesMappingContainer mcont(kTestFile); + auto table = search::RankTable::Load(mcont, SEARCH_RANKS_FILE_TAG); + TEST(!table.get(), ()); + } + + // Try to re-create rank table in test file. + TEST(search::SearchRankTableBuilder::CreateIfNotExists(kTestFile), ()); + + // Try to load and map rank table - both methods should work now. + TestTable(ranks, kTestFile); +} diff --git a/indexer/rank_table.cpp b/indexer/rank_table.cpp index 348e05d00a..d7511fbf6e 100644 --- a/indexer/rank_table.cpp +++ b/indexer/rank_table.cpp @@ -1,10 +1,17 @@ #include "indexer/rank_table.hpp" +#include "indexer/classificator.hpp" #include "indexer/data_header.hpp" +#include "indexer/feature_algo.hpp" #include "indexer/feature_impl.hpp" +#include "indexer/feature_utils.hpp" #include "indexer/features_vector.hpp" #include "indexer/ftypes_matcher.hpp" +#include "platform/local_country_file.hpp" +#include "platform/local_country_file_utils.hpp" + +#include "coding/endianness.hpp" #include "coding/files_container.hpp" #include "coding/file_writer.hpp" #include "coding/memory_region.hpp" @@ -13,30 +20,54 @@ #include "coding/succinct_mapper.hpp" #include "coding/writer.hpp" -#include "base/exception.hpp" +#include "base/assert.hpp" #include "base/logging.hpp" +#include "base/macros.hpp" +#include "base/math.hpp" #include +#include #include +#include #include "defines.hpp" +using namespace std; namespace search { -using namespace std; - namespace { -size_t constexpr kVersionOffset = 0; -size_t constexpr kHeaderSize = 8; +uint64_t const kVersionOffset = 0; +uint64_t const kFlagsOffset = 1; +uint64_t const kHeaderSize = 8; + +enum class CheckResult +{ + CorruptedHeader, + EndiannessMismatch, + EndiannessMatch +}; + +template +CheckResult CheckEndianness(TReader && reader) +{ + if (reader.Size() < kHeaderSize) + return CheckResult::CorruptedHeader; + uint8_t flags; + reader.Read(kFlagsOffset, &flags, sizeof(flags)); + bool const isHostBigEndian = IsBigEndianMacroBased(); + bool const isDataBigEndian = flags & 1; + if (isHostBigEndian != isDataBigEndian) + return CheckResult::EndiannessMismatch; + return CheckResult::EndiannessMatch; +} unique_ptr GetMemoryRegionForTag(FilesContainerR const & rcont, FilesContainerBase::Tag const & tag) { if (!rcont.IsExist(tag)) - return {}; - + return unique_ptr(); FilesContainerR::TReader reader = rcont.GetReader(tag); vector buffer(static_cast(reader.Size())); reader.Read(0, buffer.data(), buffer.size()); @@ -47,13 +78,13 @@ unique_ptr GetMemoryRegionForTag(FilesMappingContainer const FilesContainerBase::Tag const & tag) { if (!mcont.IsExist(tag)) - return {}; - + return unique_ptr(); FilesMappingContainer::Handle handle = mcont.Map(tag); return make_unique(std::move(handle)); } -// RankTable version 0, uses simple dense coding to store and access array of ranks. +// RankTable version 1, uses simple dense coding to store and access +// array of ranks. class RankTableV0 : public RankTable { public: @@ -68,7 +99,7 @@ public: // May be there is a better way to inject this code. Without this check search engine crashes here. //ASSERT_LESS(i, Size(), ()); if (i >= Size()) - return kNoRank; + return 0; return m_coding.Get(i); } @@ -76,23 +107,60 @@ public: RankTable::Version GetVersion() const override { return V0; } void Serialize(Writer & writer, bool preserveHostEndianness) override { + static uint64_t const padding = 0; + uint8_t const version = GetVersion(); - size_t constexpr kVersionSize = sizeof(version); - writer.Write(&version, kVersionSize); - - uint64_t const padding = 0; - static_assert(kHeaderSize % 8 == 0); // next succinct vector should be aligned - writer.Write(&padding, kHeaderSize - kVersionSize); - - Freeze(m_coding, writer, "SimpleDenseCoding"); + uint8_t const flags = preserveHostEndianness ? IsBigEndianMacroBased() : !IsBigEndianMacroBased(); + writer.Write(&version, sizeof(version)); + writer.Write(&flags, sizeof(flags)); + writer.Write(&padding, 6); + if (preserveHostEndianness) + Freeze(m_coding, writer, "SimpleDenseCoding"); + else + ReverseFreeze(m_coding, writer, "SimpleDenseCoding"); } // Loads RankTableV0 from a raw memory region. - template static unique_ptr Load(unique_ptr && region) + static unique_ptr Load(unique_ptr && region) { + if (!region.get()) + return unique_ptr(); + + auto const result = + CheckEndianness(MemReader(region->ImmutableData(), static_cast(region->Size()))); + if (result != CheckResult::EndiannessMatch) + return unique_ptr(); + auto table = make_unique(); + coding::Map(table->m_coding, region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); table->m_region = std::move(region); - coding::Map(table->m_coding, table->m_region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); + return table; + } + + // Loads RankTableV0 from a raw memory region. Modifies region in + // the case of endianness mismatch. + static unique_ptr Load(unique_ptr && region) + { + if (!region.get()) + return unique_ptr(); + + unique_ptr table; + switch ( + CheckEndianness(MemReader(region->ImmutableData(), static_cast(region->Size())))) + { + case CheckResult::CorruptedHeader: + break; + case CheckResult::EndiannessMismatch: + table.reset(new RankTableV0()); + coding::ReverseMap(table->m_coding, region->MutableData() + kHeaderSize, "SimpleDenseCoding"); + table->m_region = std::move(region); + break; + case CheckResult::EndiannessMatch: + table.reset(new RankTableV0()); + coding::Map(table->m_coding, region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); + table->m_region = std::move(region); + break; + } return table; } @@ -108,6 +176,7 @@ void SerializeRankTable(RankTable & table, FilesContainerW & wcont, string const { if (wcont.IsExist(sectionName)) wcont.DeleteSection(sectionName); + ASSERT(!wcont.IsExist(sectionName), ()); vector buffer; { @@ -148,22 +217,77 @@ unique_ptr LoadRankTable(unique_ptr && region) return {}; } +uint8_t CalcEventRank(FeatureType & /*ft*/) +{ + //TODO: add custom event processing, i.e. fc2018. + return 0; +} + +uint8_t CalcTransportRank(FeatureType & ft) +{ + uint8_t const kTransportRank = 2; + if (ftypes::IsRailwayStationChecker::Instance()(ft) || + ftypes::IsSubwayStationChecker::Instance()(ft) || ftypes::IsAirportChecker::Instance()(ft)) + { + return kTransportRank; + } + + return 0; +} + // Calculates search rank for a feature. uint8_t CalcSearchRank(FeatureType & ft) { - return feature::PopulationToRank(ftypes::GetPopulation(ft)); + auto const eventRank = CalcEventRank(ft); + auto const transportRank = CalcTransportRank(ft); + auto const populationRank = feature::PopulationToRank(ftypes::GetPopulation(ft)); + + return base::Clamp(eventRank + transportRank + populationRank, 0, + static_cast(numeric_limits::max())); } // Creates rank table if it does not exists in |rcont| or has wrong -// endianness. Otherwise (table exists and has correct format) returns null. +// endianness. Otherwise (table exists and has correct format) returns +// null. unique_ptr CreateSearchRankTableIfNotExists(FilesContainerR & rcont) { - if (rcont.IsExist(SEARCH_RANKS_FILE_TAG)) - return {}; + unique_ptr table; - vector ranks; - SearchRankTableBuilder::CalcSearchRanks(rcont, ranks); - return make_unique(ranks); + if (rcont.IsExist(SEARCH_RANKS_FILE_TAG)) + { + switch (CheckEndianness(rcont.GetReader(SEARCH_RANKS_FILE_TAG))) + { + case CheckResult::CorruptedHeader: + { + // Worst case - we need to create rank table from scratch. + break; + } + case CheckResult::EndiannessMismatch: + { + // Try to copy whole serialized data and instantiate table via + // reverse mapping. + auto region = GetMemoryRegionForTag(rcont, SEARCH_RANKS_FILE_TAG); + table = LoadRankTable(std::move(region)); + break; + } + case CheckResult::EndiannessMatch: + { + // Table exists and has proper format. Nothing to do here. + return unique_ptr(); + } + } + } + + // Table doesn't exist or has wrong format. It's better to create it + // from scratch. + if (!table) + { + vector ranks; + SearchRankTableBuilder::CalcSearchRanks(rcont, ranks); + table = make_unique(ranks); + } + + return table; } } // namespace @@ -189,6 +313,37 @@ void SearchRankTableBuilder::CalcSearchRanks(FilesContainerR & rcont, vector table; + { + ModelReaderPtr reader = platform::GetCountryReader(localFile, MapFileType::Map); + if (!reader.GetPtr()) + return false; + + mapPath = reader.GetName(); + + FilesContainerR rcont(reader); + table = CreateSearchRankTableIfNotExists(rcont); + } + + if (table) + SerializeRankTable(*table, mapPath, SEARCH_RANKS_FILE_TAG); + + return true; + } + catch (exception & e) + { + LOG(LWARNING, ("Can' create rank table for:", localFile, ":", e.what())); + return false; + } +} + // static bool SearchRankTableBuilder::CreateIfNotExists(string const & mapPath) noexcept { @@ -205,7 +360,7 @@ bool SearchRankTableBuilder::CreateIfNotExists(string const & mapPath) noexcept return true; } - catch (RootException const & e) + catch (exception & e) { LOG(LWARNING, ("Can' create rank table for:", mapPath, ":", e.what())); return false; diff --git a/indexer/rank_table.hpp b/indexer/rank_table.hpp index 7a26a2fa86..6f2a19886c 100644 --- a/indexer/rank_table.hpp +++ b/indexer/rank_table.hpp @@ -48,8 +48,7 @@ public: virtual ~RankTable() = default; - static uint8_t constexpr kNoRank = 0; - /// @return rank of the i-th feature, or kNoRank if there is no rank. + // Returns rank of the i-th feature. virtual uint8_t Get(uint64_t i) const = 0; // Returns total number of ranks (or features, as there is a 1-1 correspondence). @@ -113,6 +112,7 @@ public: // // Return true if rank table was successfully generated and written // or already exists and has correct format. + static bool CreateIfNotExists(platform::LocalCountryFile const & localFile) noexcept; static bool CreateIfNotExists(std::string const & mapPath) noexcept; }; } // namespace search diff --git a/indexer/search_string_utils.cpp b/indexer/search_string_utils.cpp index 6f32e2a950..7ded9149e9 100644 --- a/indexer/search_string_utils.cpp +++ b/indexer/search_string_utils.cpp @@ -30,9 +30,6 @@ std::vector const kAllowedMisprints = { MakeUniString("ао"), MakeUniString("еиэ"), MakeUniString("шщ"), - // Spanish - MakeUniString("jh"), // "Jose" <-> "Hose" - MakeUniString("fh"), // "Hernández" <-> "Fernández" }; std::pair const kPreprocessReplacements[] = { diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h index 6e5d34c8d8..f867bc2b41 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h @@ -28,7 +28,6 @@ NS_SWIFT_NAME(BookmarkGroup) @property(nonatomic, readonly, getter=isVisible) BOOL visible; @property(nonatomic, readonly, getter=isEmpty) BOOL empty; @property(nonatomic, readonly) BOOL hasDescription; -@property(nonatomic, readonly) BOOL isHtmlDescription; @property(nonatomic, readonly) MWMBookmarkGroupAccessStatus accessStatus; @property(nonatomic, readonly) NSArray *bookmarks; @property(nonatomic, readonly) NSArray *tracks; diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m index 7cfd57950b..3c991fa6a7 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m @@ -84,8 +84,4 @@ return [self.manager getCategoryGroupType:self.categoryId]; } -- (BOOL)isHtmlDescription { - return [self.manager isHtmlDescription:self.categoryId]; -} - @end diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h index 5898dc6d39..5afef3cc85 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h @@ -47,7 +47,6 @@ NS_SWIFT_NAME(BookmarksManager) - (MWMBookmarkGroupType)getCategoryGroupType:(MWMMarkGroupID)groupId; - (nullable NSURL *)getCategoryImageUrl:(MWMMarkGroupID)groupId; - (BOOL)hasExtraInfo:(MWMMarkGroupID)groupId; -- (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId; - (MWMMarkGroupID)createCategoryWithName:(NSString *)name; - (void)setCategory:(MWMMarkGroupID)groupId name:(NSString *)name; diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm index e10dd71c17..f784405dc8 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm @@ -287,11 +287,6 @@ static BookmarkManager::SortingType convertSortingTypeToCore(MWMBookmarksSorting return !data.m_description.empty() || !data.m_annotation.empty(); } -- (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId { - auto const description = GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_description); - return strings::IsHTML(description); -} - - (MWMMarkGroupID)createCategoryWithName:(NSString *)name { auto groupId = self.bm.CreateBookmarkCategory(name.UTF8String); diff --git a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift index 762d8fc636..75771818db 100644 --- a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift +++ b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift @@ -4,7 +4,7 @@ protocol BookmarksListInfoViewControllerDelegate: AnyObject { } final class BookmarksListInfoViewController: UIViewController { - var info: IBookmarksListInfoViewModel? { + var info: IBookmakrsListInfoViewModel? { didSet { guard isViewLoaded, let info = info else { return } updateInfo(info) @@ -26,23 +26,17 @@ final class BookmarksListInfoViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + descriptionButton.setTitle(L("placepage_place_description").uppercased(), for: .normal) separatorsConstraints.forEach { $0.constant = 1 / UIScreen.main.scale } - descriptionButton.titleLabel?.numberOfLines = 2 guard let info = info else { return } updateInfo(info) } - private func updateInfo(_ info: IBookmarksListInfoViewModel) { + private func updateInfo(_ info: IBookmakrsListInfoViewModel) { titleLabel.text = info.title descriptionButton.isHidden = !info.hasDescription - if info.hasDescription { - let description = info.isHtmlDescription - ? BookmarksListInfoViewController.getPlainText(info.description) - : info.description - descriptionButton.setTitle(description, for: .normal) - } - + titleImageView.isHidden = true if let imageUrl = info.imageUrl { titleImageView.wi_setImage(with: imageUrl, transitionDuration: 0) { [weak self] (image, error) in @@ -52,9 +46,4 @@ final class BookmarksListInfoViewController: UIViewController { } } } - - private static func getPlainText(_ htmlText: String) -> String? { - let formattedText = NSAttributedString.string(withHtml: htmlText, defaultAttributes: [:]) - return formattedText?.string - } } diff --git a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib index aa13283583..f79f370e30 100644 --- a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib +++ b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib @@ -60,7 +60,7 @@ -