Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorr.kuznetsov <r.kuznetsov@corp.mail.ru>2016-07-05 18:10:18 +0300
committerr.kuznetsov <r.kuznetsov@corp.mail.ru>2016-08-23 14:59:15 +0300
commitfafbc2469db5a3c5e4e00dd0c3d2d349d43f3074 (patch)
treeaf5f1740135a75c28f06deae40d8876c7216db64
parent135a12cd030a8bf0c62caaae621bc625a8ff1be1 (diff)
Added bookmark generation for bookingsbooking-selection
-rw-r--r--android/jni/com/mapswithme/maps/Framework.cpp6
-rw-r--r--android/src/com/mapswithme/maps/Framework.java2
-rw-r--r--android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java2
-rw-r--r--base/string_utils.cpp7
-rw-r--r--base/string_utils.hpp13
-rw-r--r--iphone/Maps/Classes/MWMPlacePageViewManager.mm2
-rw-r--r--map/booking_api.cpp128
-rw-r--r--map/booking_api.hpp39
-rw-r--r--map/booking_collector.cpp106
-rw-r--r--map/booking_collector.hpp29
-rw-r--r--map/framework.cpp121
-rw-r--r--map/framework.hpp14
-rw-r--r--map/map.pro2
-rw-r--r--xcode/map/map.xcodeproj/project.pbxproj8
14 files changed, 457 insertions, 22 deletions
diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp
index cf12d836f9..4dd4c86157 100644
--- a/android/jni/com/mapswithme/maps/Framework.cpp
+++ b/android/jni/com/mapswithme/maps/Framework.cpp
@@ -1103,4 +1103,10 @@ Java_com_mapswithme_maps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv
return jni::ToJavaString(env, g_framework->GetPlacePageInfo().FormatCuisines());
}
+JNIEXPORT void JNICALL
+Java_com_mapswithme_maps_Framework_nativeTryToBookHotel(JNIEnv * env, jclass, jstring jHotelId)
+{
+ frm()->GetBookingCollector().TryToBookHotel(jni::ToNativeString(env, jHotelId));
+}
+
} // extern "C"
diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java
index 35eb79b54c..db12e4db94 100644
--- a/android/src/com/mapswithme/maps/Framework.java
+++ b/android/src/com/mapswithme/maps/Framework.java
@@ -223,4 +223,6 @@ public class Framework
public static native boolean nativeIsInChoosePositionMode();
public static native boolean nativeIsDownloadedMapAtScreenCenter();
public static native String nativeGetActiveObjectFormattedCuisine();
+
+ public static native void nativeTryToBookHotel(String hotelId);
}
diff --git a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java
index 0e94928639..14ce7d97b9 100644
--- a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java
+++ b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java
@@ -450,6 +450,8 @@ public class PlacePageView extends RelativeLayout
final Location location = LocationHelper.INSTANCE.getLastKnownLocation();
Statistics.INSTANCE.trackEvent(event, location, params);
+ Framework.nativeTryToBookHotel(info.getId());
+
try
{
followUrl(book ? info.urlBook : info.urlDescription);
diff --git a/base/string_utils.cpp b/base/string_utils.cpp
index 6d017e2405..804b2e14ee 100644
--- a/base/string_utils.cpp
+++ b/base/string_utils.cpp
@@ -344,4 +344,11 @@ void ParseCSVRow(string const & s, char const delimiter, vector<string> & target
target.clear();
}
+system_clock::time_point ToTimePoint(string const & str, string const & format)
+{
+ tm outTm = {};
+ strptime(str.c_str(), format.c_str(), &outTm);
+ return system_clock::from_time_t(mktime(&outTm));
+}
+
} // namespace strings
diff --git a/base/string_utils.hpp b/base/string_utils.hpp
index 179a5d560b..461c992b84 100644
--- a/base/string_utils.hpp
+++ b/base/string_utils.hpp
@@ -1,10 +1,12 @@
#pragma once
#include "base/buffer_vector.hpp"
+#include "base/gmtime.hpp"
#include "base/stl_add.hpp"
#include "std/algorithm.hpp"
#include "std/cstdint.hpp"
+#include "std/chrono.hpp"
#include "std/iterator.hpp"
#include "std/limits.hpp"
#include "std/regex.hpp"
@@ -518,4 +520,15 @@ size_t EditDistance(TIter const & b1, TIter const & e1, TIter const & b2, TIter
}
return prev[m];
}
+
+template<size_t BufferSize>
+string FromTimePoint(system_clock::time_point const & timePoint, string const & format)
+{
+ char buffer[BufferSize]{};
+ tm t = my::GmTime(system_clock::to_time_t(timePoint));
+ strftime(buffer, sizeof(buffer), format.c_str(), &t);
+ return buffer;
+}
+
+system_clock::time_point ToTimePoint(string const & str, string const & format);
} // namespace strings
diff --git a/iphone/Maps/Classes/MWMPlacePageViewManager.mm b/iphone/Maps/Classes/MWMPlacePageViewManager.mm
index 288f410ca8..9e2712002c 100644
--- a/iphone/Maps/Classes/MWMPlacePageViewManager.mm
+++ b/iphone/Maps/Classes/MWMPlacePageViewManager.mm
@@ -226,6 +226,8 @@ extern NSString * const kBookmarksChangedNotification;
withParameters:stat
atLocation:[MWMLocationManager lastLocation]];
+ GetFramework().GetBookingCollector().TryToBookHotel(string(en.hotelId.UTF8String));
+
UIViewController * vc = static_cast<UIViewController *>([MapViewController controller]);
NSURL * url = isDescription ? self.entity.bookingDescriptionUrl : self.entity.bookingUrl;
NSAssert(url, @"Booking url can't be nil!");
diff --git a/map/booking_api.cpp b/map/booking_api.cpp
index d852fc860c..ef0476cd2f 100644
--- a/map/booking_api.cpp
+++ b/map/booking_api.cpp
@@ -1,9 +1,10 @@
#include "map/booking_api.hpp"
-#include "base/gmtime.hpp"
+#include "geometry/mercator.hpp"
+
#include "base/logging.hpp"
+#include "base/string_utils.hpp"
-#include "std/chrono.hpp"
#include "std/iostream.hpp"
#include "std/sstream.hpp"
@@ -13,6 +14,12 @@
char const BookingApi::kDefaultCurrency[1];
+string const kRequestTimestampFormat = "%Y-%m-%d+%H:%M:%S";
+string const kResponseTimestampFormat = "%Y-%m-%d %H:%M:%S";
+string const kResponseDateFormat = "%Y-%m-%d";
+
+string const kServerUrl = "http://tile.osmz.ru/bt/";
+
BookingApi::BookingApi() : m_affiliateId(BOOKING_AFFILIATE_ID)
{
stringstream ss;
@@ -32,22 +39,19 @@ string BookingApi::GetDescriptionUrl(string const & baseUrl, string const & /* l
void BookingApi::GetMinPrice(string const & hotelId, string const & currency,
function<void(string const &, string const &)> const & fn)
{
- char dateArrival[12]{};
- char dateDeparture[12]{};
-
system_clock::time_point p = system_clock::from_time_t(time(nullptr));
- tm arrival = my::GmTime(system_clock::to_time_t(p));
- tm departure = my::GmTime(system_clock::to_time_t(p + hours(24)));
- strftime(dateArrival, sizeof(dateArrival), "%Y-%m-%d", &arrival);
- strftime(dateDeparture, sizeof(dateDeparture), "%Y-%m-%d", &departure);
-
- string url = MakeApiUrl("getHotelAvailability", {{"hotel_ids", hotelId},
- {"currency_code", currency},
- {"arrival_date", dateArrival},
- {"departure_date", dateDeparture}});
+
+ int constexpr kBufferSize = 12;
+ string const kFormat = "%Y-%m-%d";
+ string const dateArrival = strings::FromTimePoint<kBufferSize>(p, kFormat);
+ string const dateDeparture = strings::FromTimePoint<kBufferSize>(p + hours(24), kFormat);
+
+ string url = MakeApiUrl(m_apiUrl, "getHotelAvailability", {{"hotel_ids", hotelId},
+ {"currency_code", currency},
+ {"arrival_date", dateArrival},
+ {"departure_date", dateDeparture}});
auto const callback = [this, fn, currency](downloader::HttpRequest & answer)
{
-
string minPrice;
string priceCurrency;
try
@@ -94,20 +98,104 @@ void BookingApi::GetMinPrice(string const & hotelId, string const & currency,
priceCurrency.clear();
}
fn(minPrice, priceCurrency);
- m_request.reset();
+ m_minPriceRequest.reset();
+ };
+
+ m_minPriceRequest.reset(downloader::HttpRequest::Get(url, callback));
+}
+
+void BookingApi::GetBookingDetails(system_clock::time_point const & timestampBegin,
+ system_clock::time_point const & timestampEnd,
+ vector<string> const & hotelIds,
+ function<void(vector<Details> const & details, bool success)> const & fn)
+{
+ if (fn == nullptr)
+ return;
+
+ if (hotelIds.empty())
+ {
+ fn({}, false /* success */);
+ return;
+ }
+
+ int constexpr kBufferSize = 32;
+ string const dateBegin = strings::FromTimePoint<kBufferSize>(timestampBegin, kRequestTimestampFormat);
+ string const dateEnd = strings::FromTimePoint<kBufferSize>(timestampEnd, kRequestTimestampFormat);
+ string const hotelIdsStr = strings::JoinStrings(hotelIds, ",");
+ string url = MakeApiUrl(kServerUrl, "q", {{"after", dateBegin},
+ {"before", dateEnd},
+ {"hotel_ids", hotelIdsStr}});
+ auto const callback = [this, fn](downloader::HttpRequest & answer)
+ {
+ vector<Details> details;
+ bool success = true;
+ try
+ {
+ my::Json root(answer.Data().c_str());
+ if (!json_is_array(root.get()))
+ MYTHROW(my::Json::Exception, ("The answer must contain a json array."));
+ size_t const sz = json_array_size(root.get());
+ json_int_t intVal;
+ string strVal;
+ double lat, lon;
+ details.reserve(sz);
+ for (size_t i = 0; i < sz; i++)
+ {
+ Details bookingDetails;
+ auto obj = json_array_get(root.get(), i);
+
+ my::FromJSONObject(obj, "hotel_id", intVal);
+ bookingDetails.m_hotelId = strings::to_string(intVal);
+
+ my::FromJSONObjectOptionalField(obj, "booking_id", intVal);
+ if (intVal != 0)
+ bookingDetails.m_bookingId = strings::to_string(intVal);
+
+ my::FromJSONObjectOptionalField(obj, "arrival_date", strVal);
+ if (!strVal.empty())
+ {
+ bookingDetails.m_arrivalDate = strings::ToTimePoint(strVal, kResponseDateFormat);
+ bookingDetails.hasArrivalDate = true;
+ }
+
+ my::FromJSONObjectOptionalField(obj, "departure_date", strVal);
+ if (!strVal.empty())
+ {
+ bookingDetails.m_departureDate = strings::ToTimePoint(strVal, kResponseDateFormat);
+ bookingDetails.hasDepartureDate = true;
+ }
+
+ my::FromJSONObject(obj, "booking_datetime", strVal);
+ bookingDetails.m_bookingTimestamp = strings::ToTimePoint(strVal, kResponseTimestampFormat);
+
+ my::FromJSONObject(obj, "lat", lat);
+ my::FromJSONObject(obj, "lon", lon);
+ bookingDetails.m_point = MercatorBounds::FromLatLon(lat, lon);
+
+ details.push_back(move(bookingDetails));
+ }
+ }
+ catch (my::Json::Exception const & e)
+ {
+ LOG(LWARNING, (e.Msg()));
+ success = false;
+ }
+
+ fn(details, success);
+ m_bookingDetailsRequest.reset();
};
- m_request.reset(downloader::HttpRequest::Get(url, callback));
+ m_bookingDetailsRequest.reset(downloader::HttpRequest::Get(url, callback));
}
-string BookingApi::MakeApiUrl(string const & func,
+string BookingApi::MakeApiUrl(string const & url, string const & func,
initializer_list<pair<string, string>> const & params)
{
stringstream ss;
- ss << m_apiUrl << func << "?";
+ ss << url << func << "?";
bool firstRun = true;
for (auto const & param : params)
ss << (firstRun ? firstRun = false, "" : "&") << param.first << "=" << param.second;
return ss.str();
-} \ No newline at end of file
+}
diff --git a/map/booking_api.hpp b/map/booking_api.hpp
index 76fef16c7c..3ecd6058a1 100644
--- a/map/booking_api.hpp
+++ b/map/booking_api.hpp
@@ -1,7 +1,10 @@
#pragma once
+#include "geometry/point2d.hpp"
+
#include "platform/http_request.hpp"
+#include "std/chrono.hpp"
#include "std/function.hpp"
#include "std/initializer_list.hpp"
#include "std/string.hpp"
@@ -16,13 +19,45 @@ class BookingApi
public:
static constexpr const char kDefaultCurrency[1] = {0};
+ struct Details
+ {
+ string m_bookingId;
+ string m_hotelId;
+ m2::PointD m_point;
+ system_clock::time_point m_arrivalDate;
+ system_clock::time_point m_departureDate;
+ system_clock::time_point m_bookingTimestamp;
+ bool hasArrivalDate = false;
+ bool hasDepartureDate = false;
+
+ Details() = default;
+ Details(string const & bookingId, string const & hotelId, m2::PointD const & point,
+ system_clock::time_point const & arrivalDate,
+ system_clock::time_point const & departureDate,
+ system_clock::time_point const & bookingTimestamp)
+ : m_bookingId(bookingId)
+ , m_hotelId(hotelId)
+ , m_point(point)
+ , m_arrivalDate(arrivalDate)
+ , m_departureDate(departureDate)
+ , m_bookingTimestamp(bookingTimestamp)
+ {}
+ };
+
BookingApi();
string GetBookingUrl(string const & baseUrl, string const & lang = string()) const;
string GetDescriptionUrl(string const & baseUrl, string const & lang = string()) const;
void GetMinPrice(string const & hotelId, string const & currency,
function<void(string const &, string const &)> const & fn);
+ void GetBookingDetails(system_clock::time_point const & timestampBegin,
+ system_clock::time_point const & timestampEnd,
+ vector<string> const & hotelIds,
+ function<void(vector<Details> const & details, bool success)> const & fn);
protected:
- unique_ptr<downloader::HttpRequest> m_request;
- string MakeApiUrl(string const & func, initializer_list<pair<string, string>> const & params);
+ unique_ptr<downloader::HttpRequest> m_minPriceRequest;
+ unique_ptr<downloader::HttpRequest> m_bookingDetailsRequest;
+
+ static string MakeApiUrl(string const & url, string const & func,
+ initializer_list<pair<string, string>> const & params);
};
diff --git a/map/booking_collector.cpp b/map/booking_collector.cpp
new file mode 100644
index 0000000000..856820f32f
--- /dev/null
+++ b/map/booking_collector.cpp
@@ -0,0 +1,106 @@
+#include "map/booking_collector.hpp"
+
+#include "platform/settings.hpp"
+
+#include "base/gmtime.hpp"
+#include "base/stl_helpers.hpp"
+#include "base/string_utils.hpp"
+
+#include "std/algorithm.hpp"
+#include "std/sstream.hpp"
+
+namespace
+{
+string const kTimestampFormat = "%Y-%m-%d %H:%M:%S";
+
+string SerializeTimestamp(system_clock::time_point const & timestamp)
+{
+ int constexpr kBufferSize = 32;
+ return strings::FromTimePoint<kBufferSize>(timestamp, kTimestampFormat);
+}
+
+system_clock::time_point DeserializeTimestamp(string const & str)
+{
+ return strings::ToTimePoint(str, kTimestampFormat);
+}
+
+string SerializeHotels(vector<string> const & hotels)
+{
+ return strings::JoinStrings(hotels, ",");
+}
+
+vector<string> DeserializeHotels(string const & str)
+{
+ vector<string> result;
+ strings::Tokenize(str, ",", [&result](string const & token)
+ {
+ result.push_back(token);
+ });
+ return result;
+}
+} // namespace
+
+void BookingCollector::Serialize()
+{
+ settings::Set("BookingTimestampBegin", SerializeTimestamp(m_data.m_timestampBegin));
+ settings::Set("BookingTimestampEnd", SerializeTimestamp(m_data.m_timestampEnd));
+ settings::Set("BookingHotels", SerializeHotels(m_data.m_hotelIds));
+}
+
+void BookingCollector::Deserialize()
+{
+ string outVal;
+ if (settings::Get("BookingTimestampBegin", outVal))
+ m_data.m_timestampBegin = DeserializeTimestamp(outVal);
+
+ if (settings::Get("BookingTimestampEnd", outVal))
+ m_data.m_timestampEnd = DeserializeTimestamp(outVal);
+
+ if (settings::Get("BookingHotels", outVal))
+ m_data.m_hotelIds = DeserializeHotels(outVal);
+}
+
+void BookingCollector::TryToBookHotel(string const & hotelId)
+{
+ if (m_data.m_hotelIds.empty())
+ {
+ m_data.m_timestampBegin = system_clock::from_time_t(time(nullptr));
+ m_data.m_timestampEnd = m_data.m_timestampBegin + minutes(30);
+ }
+ else
+ {
+ system_clock::time_point t = system_clock::from_time_t(time(nullptr));
+ if (t > m_data.m_timestampEnd)
+ m_data.m_timestampEnd = t + minutes(30);
+ }
+
+ if (find(m_data.m_hotelIds.begin(), m_data.m_hotelIds.end(), hotelId) == m_data.m_hotelIds.end())
+ m_data.m_hotelIds.push_back(hotelId);
+}
+
+void BookingCollector::RestoreData(Data const & data)
+{
+ if (m_data.m_hotelIds.empty())
+ {
+ m_data.m_timestampBegin = data.m_timestampBegin;
+ m_data.m_timestampEnd = data.m_timestampEnd;
+ m_data.m_hotelIds = data.m_hotelIds;
+ }
+ else
+ {
+ m_data.m_timestampBegin = min(m_data.m_timestampBegin, data.m_timestampBegin);
+ m_data.m_timestampEnd = max(m_data.m_timestampEnd, data.m_timestampEnd);
+
+ // Paste hotels and remove duplicates.
+ auto & v = m_data.m_hotelIds;
+ v.insert(v.end(), data.m_hotelIds.begin(), data.m_hotelIds.end());
+ my::SortUnique(v);
+ }
+}
+
+BookingCollector::Data BookingCollector::CollectData()
+{
+ BookingCollector::Data data;
+ swap(m_data, data);
+ return data;
+}
diff --git a/map/booking_collector.hpp b/map/booking_collector.hpp
new file mode 100644
index 0000000000..e1dc9a2773
--- /dev/null
+++ b/map/booking_collector.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "std/chrono.hpp"
+#include "std/string.hpp"
+#include "std/vector.hpp"
+
+class BookingCollector
+{
+public:
+ struct Data
+ {
+ system_clock::time_point m_timestampBegin;
+ system_clock::time_point m_timestampEnd;
+ vector<string> m_hotelIds;
+ };
+
+ BookingCollector() = default;
+
+ void Serialize();
+ void Deserialize();
+
+ void TryToBookHotel(string const & hotelId);
+
+ Data CollectData();
+ void RestoreData(Data const & data);
+
+private:
+ Data m_data;
+};
diff --git a/map/framework.cpp b/map/framework.cpp
index aa9732b0ff..1a0343dbff 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -69,6 +69,7 @@
#include "geometry/rect2d.hpp"
#include "geometry/triangle2d.hpp"
+#include "base/gmtime.hpp"
#include "base/logging.hpp"
#include "base/math.hpp"
#include "base/scope_guard.hpp"
@@ -346,6 +347,9 @@ Framework::Framework()
m_stringsBundle.SetDefaultString("routing_failed_route_not_found", "There is no route found between the selected origin and destination.Please select a different start or end point.");
m_stringsBundle.SetDefaultString("routing_failed_internal_error", "Internal error occurred. Please try to delete and download the map again. If problem persist please contact us at support@maps.me.");
+ m_stringsBundle.SetDefaultString("booking_category", "Booked hotels");
+ //m_stringsBundle.SetDefaultString("booking_desc", "Arrival: %s\nDeparture: %s");
+
m_model.InitClassificator();
m_model.SetOnMapDeregisteredCallback(bind(&Framework::OnMapDeregistered, this, _1));
LOG(LDEBUG, ("Classificator initialized"));
@@ -821,6 +825,118 @@ void Framework::ClearBookmarks()
m_bmManager.ClearItems();
}
+void Framework::UpdateBookings()
+{
+ BookingCollector::Data data = m_bookingCollector.CollectData();
+ if (data.m_hotelIds.empty())
+ return;
+
+ m_bookingApi.GetBookingDetails(data.m_timestampBegin, data.m_timestampEnd, data.m_hotelIds,
+ [this, data](vector<BookingApi::Details> const & details, bool success)
+ {
+ UpdateBookingsOnUiThread(details, data, success);
+ });
+}
+
+void Framework::UpdateBookingsOnUiThread(vector<BookingApi::Details> const & details,
+ BookingCollector::Data const & data, bool success)
+{
+ GetPlatform().RunOnGuiThread([this, details, data, success]()
+ {
+ if (success)
+ UpdateBookingBookmarks(details);
+ else
+ m_bookingCollector.RestoreData(data);
+ });
+}
+
+void Framework::UpdateBookingBookmarks(vector<BookingApi::Details> const & details)
+{
+ if (details.empty())
+ return;
+
+ // Find or create category.
+ string categoryName = m_stringsBundle.GetString("booking_category");
+ int categoryIndex = -1;
+ ASSERT_LESS_OR_EQUAL(GetBmCategoriesCount(), numeric_limits<int>::max(), ());
+ for (size_t i = 0; i < GetBmCategoriesCount(); ++i)
+ {
+ if (GetBmCategory(i)->GetName() == categoryName)
+ {
+ categoryIndex = static_cast<int>(i);
+ break;
+ }
+ }
+ if (categoryIndex == -1)
+ categoryIndex = AddCategory(categoryName);
+
+ // Find new bookings.
+ vector<BookingApi::Details> newBookings;
+ newBookings.reserve(details.size());
+ {
+ BookmarkCategory * cat = GetBmCategory(categoryIndex);
+ BookmarkCategory::Guard guard(*cat);
+ double const kEps = 1e-5;
+ for (BookingApi::Details const & bookingDetails : details)
+ {
+ bool isNewBooking = true;
+ for (size_t i = 0; i < guard.m_controller.GetUserMarkCount(); ++i)
+ {
+ UserMark const * bookmark = guard.m_controller.GetUserMark(i);
+ if (bookmark->GetPivot().EqualDxDy(bookingDetails.m_point, kEps))
+ {
+ isNewBooking = false;
+ break;
+ }
+ }
+ if (isNewBooking)
+ newBookings.push_back(bookingDetails);
+ }
+ }
+
+ // Create bookmarks.
+ for (BookingApi::Details const & bookingDetails : newBookings)
+ {
+ // TODO: Now we do not show additional information, because we aren't able to
+ // determine user's booking precisely.
+ string desc;
+ //int constexpr kDateBufferSize = 12;
+ //string const kFormat = "%Y-%m-%d";
+ //string const dateArrival = strings::FromTimePoint<kDateBufferSize>(bookingDetails.m_arrivalDate, kFormat);
+ //string const dateDeparture = strings::FromTimePoint<kDateBufferSize>(bookingDetails.m_departureDate, kFormat);
+
+ //int constexpr kBufferSize = 1024;
+ //char buffer[kBufferSize];
+ //snprintf(buffer, kBufferSize, m_stringsBundle.GetString("booking_desc").c_str(),
+ // dateArrival.c_str(), dateDeparture.c_str());
+ //desc = buffer;
+
+ string bookmarkTitle = GetBookingBookmarkTitle(bookingDetails.m_point);
+ if (bookmarkTitle.empty())
+ continue;
+ string const kBookmarkType = "placemark-hotel";
+ BookmarkData bm(bookmarkTitle, kBookmarkType, desc);
+ AddBookmark(categoryIndex, bookingDetails.m_point, bm);
+ }
+}
+
+string Framework::GetBookingBookmarkTitle(m2::PointD const & pt)
+{
+ string result;
+ constexpr int kScale = scales::GetUpperScale();
+ constexpr double kSelectRectWidthInMeters = 1.0;
+ m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(pt, kSelectRectWidthInMeters);
+ int8_t langCode = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm());
+ if (langCode == StringUtf8Multilang::kUnsupportedLanguageCode)
+ langCode = StringUtf8Multilang::kDefaultCode;
+ m_model.ForEachFeature(rect, [&](FeatureType & ft)
+ {
+ if (result.empty() && ftypes::IsBookingChecker::Instance()(ft))
+ ft.GetName(langCode, result);
+ }, kScale);
+ return result;
+}
+
namespace
{
@@ -1247,6 +1363,8 @@ void Framework::EnterBackground()
SaveViewport();
+ m_bookingCollector.Serialize();
+
ms::LatLon const ll = MercatorBounds::ToLatLon(GetViewportCenter());
alohalytics::Stats::Instance().LogEvent("Framework::EnterBackground", {{"zoom", strings::to_string(GetDrawScale())},
{"foregroundSeconds", strings::to_string(
@@ -1262,6 +1380,9 @@ void Framework::EnterBackground()
void Framework::EnterForeground()
{
+ m_bookingCollector.Deserialize();
+ UpdateBookings();
+
m_startForegroundTime = my::Timer::LocalTime();
double const time = m_startForegroundTime - m_startBackgroundTime;
CallDrapeFunction(bind(&df::DrapeEngine::SetTimeInBackground, _1, time));
diff --git a/map/framework.hpp b/map/framework.hpp
index ff78f9b079..739119a3ed 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -2,6 +2,7 @@
#include "map/api_mark_point.hpp"
#include "map/booking_api.hpp"
+#include "map/booking_collector.hpp"
#include "map/bookmark.hpp"
#include "map/bookmark_manager.hpp"
#include "map/displacement_mode_manager.hpp"
@@ -148,6 +149,7 @@ protected:
BookmarkManager m_bmManager;
BookingApi m_bookingApi;
+ BookingCollector m_bookingCollector;
bool m_isRenderingEnabled;
@@ -178,6 +180,9 @@ public:
BookingApi & GetBookingApi() { return m_bookingApi; }
BookingApi const & GetBookingApi() const { return m_bookingApi; }
+ BookingCollector & GetBookingCollector() { return m_bookingCollector; }
+ BookingCollector const & GetBookingCollector() const { return m_bookingCollector; }
+
/// Migrate to new version of very different data.
bool IsEnoughSpaceForMigrate() const;
storage::TCountryId PreMigrate(ms::LatLon const & position, storage::Storage::TChangeCountryFunction const & change,
@@ -276,6 +281,9 @@ public:
BookmarkAndCategory FindBookmark(UserMark const * mark) const;
BookmarkManager & GetBookmarkManager() { return m_bmManager; }
+ /// Create/update bookmarks for booked hotels.
+ void UpdateBookings();
+
m2::PointD GetSearchMarkSize(SearchMarkType searchMarkType);
protected:
@@ -304,6 +312,12 @@ private:
df::SelectionShape::ESelectedObject selectionType,
place_page::Info const & info);
void InvalidateUserMarks();
+
+ void UpdateBookingsOnUiThread(vector<BookingApi::Details> const & details,
+ BookingCollector::Data const & data, bool success);
+ void UpdateBookingBookmarks(vector<BookingApi::Details> const & details);
+ string GetBookingBookmarkTitle(m2::PointD const & pt);
+
public:
void DeactivateMapSelection(bool notifyUI);
/// Used to "refresh" UI in some cases (e.g. feature editing).
diff --git a/map/map.pro b/map/map.pro
index 582f3744d1..feb578c589 100644
--- a/map/map.pro
+++ b/map/map.pro
@@ -13,6 +13,7 @@ include($$ROOT_DIR/common.pri)
HEADERS += \
api_mark_point.hpp \
booking_api.hpp \
+ booking_collector.hpp \
bookmark.hpp \
bookmark_manager.hpp \
displacement_mode_manager.hpp \
@@ -36,6 +37,7 @@ SOURCES += \
address_finder.cpp \
api_mark_point.cpp \
booking_api.cpp \
+ booking_collector.cpp \
bookmark.cpp \
bookmark_manager.cpp \
displacement_mode_manager.cpp \
diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj
index 94ecc3ac72..e27c845fb7 100644
--- a/xcode/map/map.xcodeproj/project.pbxproj
+++ b/xcode/map/map.xcodeproj/project.pbxproj
@@ -13,6 +13,8 @@
34583BD01C88556800F94664 /* place_page_info.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34583BCE1C88556800F94664 /* place_page_info.hpp */; };
34921F661BFA0A6900737D6E /* api_mark_point.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34921F611BFA0A6900737D6E /* api_mark_point.hpp */; };
45201E931CE4AC90008A4842 /* api_mark_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45201E921CE4AC90008A4842 /* api_mark_point.cpp */; };
+ 45D2C84E1D33A623001E9B73 /* booking_collector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45D2C84C1D33A623001E9B73 /* booking_collector.cpp */; };
+ 45D2C84F1D33A623001E9B73 /* booking_collector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 45D2C84D1D33A623001E9B73 /* booking_collector.hpp */; };
670E39401C46C5C700E9C0A6 /* gps_tracker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670E393E1C46C5C700E9C0A6 /* gps_tracker.cpp */; };
670E39411C46C5C700E9C0A6 /* gps_tracker.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 670E393F1C46C5C700E9C0A6 /* gps_tracker.hpp */; };
674A29F01B26FD6F001A525C /* testingmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 674A29EE1B26FD5F001A525C /* testingmain.cpp */; };
@@ -129,6 +131,8 @@
34583BCE1C88556800F94664 /* place_page_info.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = place_page_info.hpp; sourceTree = "<group>"; };
34921F611BFA0A6900737D6E /* api_mark_point.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = api_mark_point.hpp; sourceTree = "<group>"; };
45201E921CE4AC90008A4842 /* api_mark_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = api_mark_point.cpp; sourceTree = "<group>"; };
+ 45D2C84C1D33A623001E9B73 /* booking_collector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = booking_collector.cpp; sourceTree = "<group>"; };
+ 45D2C84D1D33A623001E9B73 /* booking_collector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = booking_collector.hpp; sourceTree = "<group>"; };
670D05A41B0DF4250013A7AC /* defaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = defaults.xcconfig; path = ../defaults.xcconfig; sourceTree = "<group>"; };
670E393E1C46C5C700E9C0A6 /* gps_tracker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_tracker.cpp; sourceTree = "<group>"; };
670E393F1C46C5C700E9C0A6 /* gps_tracker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gps_tracker.hpp; sourceTree = "<group>"; };
@@ -429,6 +433,8 @@
674A2A371B2715FB001A525C /* osm_opening_hours.hpp */,
6788507C1D059068004201E1 /* booking_api.cpp */,
6788507D1D059068004201E1 /* booking_api.hpp */,
+ 45D2C84C1D33A623001E9B73 /* booking_collector.cpp */,
+ 45D2C84D1D33A623001E9B73 /* booking_collector.hpp */,
);
name = map;
path = ../../map;
@@ -455,6 +461,7 @@
675346491A4054E800A0A8C3 /* bookmark_manager.hpp in Headers */,
F6B2830A1C1B03320081957A /* gps_track.hpp in Headers */,
675346631A4054E800A0A8C3 /* feature_vec_model.hpp in Headers */,
+ 45D2C84F1D33A623001E9B73 /* booking_collector.hpp in Headers */,
6753469C1A4054E800A0A8C3 /* track.hpp in Headers */,
675346651A4054E800A0A8C3 /* framework.hpp in Headers */,
674A2A381B2715FB001A525C /* osm_opening_hours.hpp in Headers */,
@@ -571,6 +578,7 @@
F6B283031C1B03320081957A /* gps_track_collection.cpp in Sources */,
6753469B1A4054E800A0A8C3 /* track.cpp in Sources */,
675346621A4054E800A0A8C3 /* feature_vec_model.cpp in Sources */,
+ 45D2C84E1D33A623001E9B73 /* booking_collector.cpp in Sources */,
6753469D1A4054E800A0A8C3 /* user_mark_container.cpp in Sources */,
674C38621BFF3095000D603B /* user_mark.cpp in Sources */,
675346641A4054E800A0A8C3 /* framework.cpp in Sources */,