forked from organicmaps/organicmaps
[core] Booking extended info
This commit is contained in:
parent
cc8deb008f
commit
ac35fbaf10
17 changed files with 540 additions and 507 deletions
|
@ -12,7 +12,7 @@ void FromJSON(json_t * root, string & result)
|
|||
void FromJSONObject(json_t * root, string const & field, string & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
|
||||
|
@ -31,7 +31,7 @@ void FromJSONObject(json_t * root, string const & field, strings::UniString & re
|
|||
void FromJSONObject(json_t * root, string const & field, double & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
|
||||
|
@ -43,7 +43,7 @@ void FromJSONObject(json_t * root, string const & field, double & result)
|
|||
void FromJSONObject(json_t * root, string const & field, json_int_t & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
|
||||
|
@ -55,7 +55,7 @@ void FromJSONObject(json_t * root, string const & field, json_int_t & result)
|
|||
void FromJSONObjectOptionalField(json_t * root, string const & field, string & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ void FromJSONObjectOptionalField(json_t * root, string const & field, string & r
|
|||
void FromJSONObjectOptionalField(json_t * root, string const & field, json_int_t & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
{
|
||||
|
@ -82,10 +82,25 @@ void FromJSONObjectOptionalField(json_t * root, string const & field, json_int_t
|
|||
result = json_integer_value(val);
|
||||
}
|
||||
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, double & result)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
{
|
||||
result = 0.0;
|
||||
return;
|
||||
}
|
||||
if (!json_is_number(val))
|
||||
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json number."));
|
||||
result = json_number_value(val);
|
||||
}
|
||||
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, bool & result, bool def)
|
||||
{
|
||||
if (!json_is_object(root))
|
||||
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
|
||||
MYTHROW(my::Json::Exception, ("Bad json object while parsing", field));
|
||||
json_t * val = json_object_get(root, field.c_str());
|
||||
if (!val)
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ void FromJSONObject(json_t * root, string const & field, vector<T> & result)
|
|||
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, string & result);
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, json_int_t & result);
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, double & result);
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, bool & result, bool def = false);
|
||||
void FromJSONObjectOptionalField(json_t * root, string const & field, json_t *& result);
|
||||
|
||||
|
|
|
@ -487,18 +487,18 @@ place_page::Info & Framework::GetPlacePageInfo()
|
|||
{
|
||||
return m_info;
|
||||
}
|
||||
void Framework::RequestBookingMinPrice(
|
||||
JNIEnv * env, jobject policy, string const & hotelId, string const & currencyCode,
|
||||
function<void(string const &, string const &)> const & callback)
|
||||
void Framework::RequestBookingMinPrice(JNIEnv * env, jobject policy,
|
||||
string const & hotelId, string const & currencyCode,
|
||||
booking::GetMinPriceCallback const & callback)
|
||||
{
|
||||
auto const bookingApi = m_work.GetBookingApi(ToNativeNetworkPolicy(env, policy));
|
||||
if (bookingApi)
|
||||
bookingApi->GetMinPrice(hotelId, currencyCode, callback);
|
||||
}
|
||||
|
||||
void Framework::RequestBookingInfo(JNIEnv * env, jobject policy, string const & hotelId,
|
||||
string const & lang,
|
||||
function<void(BookingApi::HotelInfo const &)> const & callback)
|
||||
void Framework::RequestBookingInfo(JNIEnv * env, jobject policy,
|
||||
string const & hotelId, string const & lang,
|
||||
booking::GetHotelInfoCallback const & callback)
|
||||
{
|
||||
auto const bookingApi = m_work.GetBookingApi(ToNativeNetworkPolicy(env, policy));
|
||||
if (bookingApi)
|
||||
|
|
|
@ -161,12 +161,12 @@ namespace android
|
|||
|
||||
void SetPlacePageInfo(place_page::Info const & info);
|
||||
place_page::Info & GetPlacePageInfo();
|
||||
void RequestBookingMinPrice(JNIEnv * env, jobject policy, string const & hotelId,
|
||||
string const & currency,
|
||||
function<void(string const &, string const &)> const & callback);
|
||||
void RequestBookingInfo(JNIEnv * env, jobject policy, string const & hotelId,
|
||||
string const & lang,
|
||||
function<void(BookingApi::HotelInfo const &)> const & callback);
|
||||
void RequestBookingMinPrice(JNIEnv * env, jobject policy,
|
||||
string const & hotelId, string const & currency,
|
||||
booking::GetMinPriceCallback const & callback);
|
||||
void RequestBookingInfo(JNIEnv * env, jobject policy,
|
||||
string const & hotelId, string const & lang,
|
||||
booking::GetHotelInfoCallback const & callback);
|
||||
|
||||
bool HasSpaceForMigration();
|
||||
storage::TCountryId PreMigrate(ms::LatLon const & position, storage::Storage::TChangeCountryFunction const & statusChangeListener,
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
using namespace booking;
|
||||
|
||||
jclass g_sponsoredClass;
|
||||
jclass g_facilityTypeClass;
|
||||
jclass g_nearbyObjectClass;
|
||||
|
@ -24,6 +26,7 @@ jmethodID g_hotelInfoConstructor;
|
|||
jmethodID g_sponsoredClassConstructor;
|
||||
jmethodID g_priceCallback;
|
||||
jmethodID g_infoCallback;
|
||||
string g_lastRequestedHotelId;
|
||||
|
||||
void PrepareClassRefs(JNIEnv * env, jclass sponsoredClass)
|
||||
{
|
||||
|
@ -47,8 +50,8 @@ void PrepareClassRefs(JNIEnv * env, jclass sponsoredClass)
|
|||
g_imageConstructor =
|
||||
jni::GetConstructorID(env, g_imageClass, "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
g_reviewConstructor = jni::GetConstructorID(env, g_reviewClass,
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||
"String;Ljava/lang/String;Ljava/lang/String;FJ)V");
|
||||
"(JFLjava/lang/String;Ljava/lang/"
|
||||
"String;Ljava/lang/String;)V");
|
||||
g_hotelInfoConstructor = jni::GetConstructorID(
|
||||
env, g_hotelInfoClass,
|
||||
"(Ljava/lang/String;[Lcom/mapswithme/maps/gallery/Image;[Lcom/mapswithme/maps/widget/"
|
||||
|
@ -69,10 +72,41 @@ void PrepareClassRefs(JNIEnv * env, jclass sponsoredClass)
|
|||
"(Ljava/lang/String;Lcom/mapswithme/maps/widget/placepage/Sponsored$HotelInfo;)V");
|
||||
}
|
||||
|
||||
jobjectArray ToPhotosArray(JNIEnv * env, vector<HotelPhotoUrls> const & photos)
|
||||
{
|
||||
return jni::ToJavaArray(env, g_imageClass, photos,
|
||||
[](JNIEnv * env, HotelPhotoUrls const & item) {
|
||||
return env->NewObject(g_imageClass, g_imageConstructor,
|
||||
jni::ToJavaString(env, item.m_original),
|
||||
jni::ToJavaString(env, item.m_small));
|
||||
});
|
||||
}
|
||||
|
||||
jobjectArray ToFacilitiesArray(JNIEnv * env, vector<HotelFacility> const & facilities)
|
||||
{
|
||||
return jni::ToJavaArray(env, g_facilityTypeClass, facilities,
|
||||
[](JNIEnv * env, HotelFacility const & item) {
|
||||
return env->NewObject(g_facilityTypeClass, g_facilityConstructor,
|
||||
jni::ToJavaString(env, item.m_facilityType),
|
||||
jni::ToJavaString(env, item.m_name));
|
||||
});
|
||||
}
|
||||
|
||||
jobjectArray ToReviewsArray(JNIEnv * env, vector<HotelReview> const & reviews)
|
||||
{
|
||||
return jni::ToJavaArray(env, g_reviewClass, reviews,
|
||||
[](JNIEnv * env, HotelReview const & item) {
|
||||
return env->NewObject(
|
||||
g_reviewClass, g_reviewConstructor,
|
||||
time_point_cast<milliseconds>(item.m_date).time_since_epoch().count(),
|
||||
item.m_score, jni::ToJavaString(env, item.m_author),
|
||||
jni::ToJavaString(env, item.m_pros), jni::ToJavaString(env, item.m_cons));
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// static Sponsored nativeGetCurrent();
|
||||
JNIEXPORT jobject JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativeGetCurrent(
|
||||
JNIEnv * env, jclass clazz)
|
||||
|
@ -98,17 +132,21 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ
|
|||
PrepareClassRefs(env, clazz);
|
||||
|
||||
string const hotelId = jni::ToNativeString(env, id);
|
||||
g_lastRequestedHotelId = hotelId;
|
||||
|
||||
string const code = jni::ToNativeString(env, currencyCode);
|
||||
|
||||
g_framework->RequestBookingMinPrice(
|
||||
env, policy, hotelId, code, [hotelId](string const & price, string const & currency) {
|
||||
GetPlatform().RunOnGuiThread([=]() {
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
env->CallStaticVoidMethod(g_sponsoredClass, g_priceCallback,
|
||||
jni::ToJavaString(env, hotelId), jni::ToJavaString(env, price),
|
||||
jni::ToJavaString(env, currency));
|
||||
});
|
||||
g_framework->RequestBookingMinPrice(env, policy, hotelId, code,
|
||||
[](string const & hotelId, string const & price, string const & currency) {
|
||||
GetPlatform().RunOnGuiThread([hotelId, price, currency]() {
|
||||
if (g_lastRequestedHotelId != hotelId)
|
||||
return;
|
||||
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
env->CallStaticVoidMethod(g_sponsoredClass, g_priceCallback, jni::ToJavaString(env, hotelId),
|
||||
jni::ToJavaString(env, price), jni::ToJavaString(env, currency));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// static void nativeRequestInfo(String id, String locale);
|
||||
|
@ -118,48 +156,26 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ
|
|||
PrepareClassRefs(env, clazz);
|
||||
|
||||
string const hotelId = jni::ToNativeString(env, id);
|
||||
g_lastRequestedHotelId = hotelId;
|
||||
|
||||
string const code = jni::ToNativeString(env, locale);
|
||||
|
||||
g_framework->RequestBookingInfo(
|
||||
env, policy, hotelId, code, [hotelId](BookingApi::HotelInfo const & hotelInfo) {
|
||||
GetPlatform().RunOnGuiThread([=]() {
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
g_framework->RequestBookingInfo(env, policy, hotelId, code, [hotelId](HotelInfo const & hotelInfo) {
|
||||
GetPlatform().RunOnGuiThread([hotelId, hotelInfo]() {
|
||||
if (g_lastRequestedHotelId != hotelId)
|
||||
return;
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
|
||||
auto description = jni::ToJavaString(env, hotelInfo.m_description);
|
||||
auto photos =
|
||||
jni::ToJavaArray(env, g_imageClass, hotelInfo.m_photos,
|
||||
[](JNIEnv * env, BookingApi::HotelPhotoUrls const & item) {
|
||||
return env->NewObject(g_imageClass, g_imageConstructor,
|
||||
jni::ToJavaString(env, item.m_original),
|
||||
jni::ToJavaString(env, item.m_small));
|
||||
});
|
||||
auto facilities = jni::ToJavaArray(env, g_facilityTypeClass, hotelInfo.m_facilities,
|
||||
[](JNIEnv * env, BookingApi::Facility const & item) {
|
||||
return env->NewObject(
|
||||
g_facilityTypeClass, g_facilityConstructor,
|
||||
jni::ToJavaString(env, item.m_id),
|
||||
jni::ToJavaString(env, item.m_localizedName));
|
||||
});
|
||||
auto reviews = jni::ToJavaArray(
|
||||
env, g_reviewClass, hotelInfo.m_reviews,
|
||||
[](JNIEnv * env, BookingApi::HotelReview const & item) {
|
||||
return env->NewObject(
|
||||
g_reviewClass, g_reviewConstructor,
|
||||
jni::ToJavaString(env, item.m_reviewNeutral),
|
||||
jni::ToJavaString(env, item.m_reviewPositive),
|
||||
jni::ToJavaString(env, item.m_reviewNegative),
|
||||
jni::ToJavaString(env, item.m_author),
|
||||
jni::ToJavaString(env, item.m_authorPictUrl), item.m_rating,
|
||||
time_point_cast<milliseconds>(item.m_date).time_since_epoch().count());
|
||||
});
|
||||
auto nearby = env->NewObjectArray(0, g_nearbyObjectClass, 0);
|
||||
auto description = jni::ToJavaString(env, hotelInfo.m_description);
|
||||
auto photos = ToPhotosArray(env, hotelInfo.m_photos);
|
||||
auto facilities = ToFacilitiesArray(env, hotelInfo.m_facilities);
|
||||
auto reviews = ToReviewsArray(env, hotelInfo.m_reviews);
|
||||
auto nearby = env->NewObjectArray(0, g_nearbyObjectClass, 0);
|
||||
|
||||
env->CallStaticVoidMethod(
|
||||
g_sponsoredClass, g_infoCallback, jni::ToJavaString(env, hotelId),
|
||||
env->NewObject(g_hotelInfoClass, g_hotelInfoConstructor, description, photos,
|
||||
facilities, reviews, nearby));
|
||||
});
|
||||
});
|
||||
env->CallStaticVoidMethod(g_sponsoredClass, g_infoCallback, jni::ToJavaString(env, hotelId),
|
||||
env->NewObject(g_hotelInfoClass, g_hotelInfoConstructor, description,
|
||||
photos, facilities, reviews, nearby));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
@ -7,54 +7,42 @@ import android.support.annotation.Nullable;
|
|||
|
||||
public class Review implements Parcelable
|
||||
{
|
||||
@Nullable
|
||||
private final String mReview;
|
||||
@Nullable
|
||||
private final String mReviewPositive;
|
||||
@Nullable
|
||||
private final String mReviewNegative;
|
||||
private final long mDate;
|
||||
private final float mRating;
|
||||
@NonNull
|
||||
private final String mAuthor;
|
||||
@NonNull
|
||||
private final String mAuthorAvatar;
|
||||
private final float mRating;
|
||||
private final long mDate;
|
||||
@Nullable
|
||||
private final String mPros;
|
||||
@Nullable
|
||||
private final String mCons;
|
||||
|
||||
public Review(@Nullable String review, @Nullable String reviewPositive,
|
||||
@Nullable String reviewNegative, @NonNull String author,
|
||||
@NonNull String authorAvatar,
|
||||
float rating, long date)
|
||||
public Review(long date, float rating, @NonNull String author, @Nullable String pros,
|
||||
@Nullable String cons)
|
||||
{
|
||||
mReview = review;
|
||||
mReviewPositive = reviewPositive;
|
||||
mReviewNegative = reviewNegative;
|
||||
mAuthor = author;
|
||||
mAuthorAvatar = authorAvatar;
|
||||
mRating = rating;
|
||||
mDate = date;
|
||||
mRating = rating;
|
||||
mAuthor = author;
|
||||
mPros = pros;
|
||||
mCons = cons;
|
||||
}
|
||||
|
||||
protected Review(Parcel in)
|
||||
{
|
||||
mReview = in.readString();
|
||||
mReviewPositive = in.readString();
|
||||
mReviewNegative = in.readString();
|
||||
mAuthor = in.readString();
|
||||
mAuthorAvatar = in.readString();
|
||||
mRating = in.readFloat();
|
||||
mDate = in.readLong();
|
||||
mRating = in.readFloat();
|
||||
mAuthor = in.readString();
|
||||
mPros = in.readString();
|
||||
mCons = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags)
|
||||
{
|
||||
dest.writeString(mReview);
|
||||
dest.writeString(mReviewPositive);
|
||||
dest.writeString(mReviewNegative);
|
||||
dest.writeString(mAuthor);
|
||||
dest.writeString(mAuthorAvatar);
|
||||
dest.writeFloat(mRating);
|
||||
dest.writeLong(mDate);
|
||||
dest.writeFloat(mRating);
|
||||
dest.writeString(mAuthor);
|
||||
dest.writeString(mPros);
|
||||
dest.writeString(mCons);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,21 +67,15 @@ public class Review implements Parcelable
|
|||
};
|
||||
|
||||
@Nullable
|
||||
public String getReview()
|
||||
public String getPros()
|
||||
{
|
||||
return mReview;
|
||||
return mPros;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getReviewPositive()
|
||||
public String getCons()
|
||||
{
|
||||
return mReviewPositive;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getReviewNegative()
|
||||
{
|
||||
return mReviewNegative;
|
||||
return mCons;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -102,13 +84,6 @@ public class Review implements Parcelable
|
|||
return mAuthor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@NonNull
|
||||
public String getAuthorAvatar()
|
||||
{
|
||||
return mAuthorAvatar;
|
||||
}
|
||||
|
||||
public float getRating()
|
||||
{
|
||||
return mRating;
|
||||
|
|
|
@ -127,7 +127,6 @@ class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.BaseViewHolder>
|
|||
final TextView mUserName;
|
||||
final TextView mCommentDate;
|
||||
final TextView mRating;
|
||||
final TextView mReview;
|
||||
final View mPositiveReview;
|
||||
final TextView mTvPositiveReview;
|
||||
final View mNegativeReview;
|
||||
|
@ -140,7 +139,6 @@ class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.BaseViewHolder>
|
|||
mUserName = (TextView) itemView.findViewById(R.id.tv__user_name);
|
||||
mCommentDate = (TextView) itemView.findViewById(R.id.tv__comment_date);
|
||||
mRating = (TextView) itemView.findViewById(R.id.tv__user_rating);
|
||||
mReview = (TextView) itemView.findViewById(R.id.tv__review);
|
||||
mPositiveReview = itemView.findViewById(R.id.ll__positive_review);
|
||||
mTvPositiveReview = (TextView) itemView.findViewById(R.id.tv__positive_review);
|
||||
mNegativeReview = itemView.findViewById(R.id.ll__negative_review);
|
||||
|
@ -156,31 +154,23 @@ class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.BaseViewHolder>
|
|||
Date date = new Date(item.getDate());
|
||||
mCommentDate.setText(DateFormat.getMediumDateFormat(mCommentDate.getContext()).format(date));
|
||||
mRating.setText(String.format(Locale.getDefault(), "%.1f", item.getRating()));
|
||||
if (TextUtils.isEmpty(item.getReviewPositive()))
|
||||
if (TextUtils.isEmpty(item.getPros()))
|
||||
{
|
||||
UiUtils.hide(mPositiveReview);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.show(mPositiveReview);
|
||||
mTvPositiveReview.setText(item.getReviewPositive());
|
||||
mTvPositiveReview.setText(item.getPros());
|
||||
}
|
||||
if (TextUtils.isEmpty(item.getReviewNegative()))
|
||||
if (TextUtils.isEmpty(item.getCons()))
|
||||
{
|
||||
UiUtils.hide(mNegativeReview);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.show(mNegativeReview);
|
||||
mTvNegativeReview.setText(item.getReviewNegative());
|
||||
}
|
||||
if (UiUtils.isHidden(mNegativeReview) && UiUtils.isHidden(mPositiveReview))
|
||||
{
|
||||
UiUtils.showIf(!TextUtils.isEmpty(item.getReview()), mReview);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.hide(mReview);
|
||||
mTvNegativeReview.setText(item.getCons());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,23 +113,23 @@ class ReviewAdapter extends BaseAdapter
|
|||
Date date = new Date(item.getDate());
|
||||
mCommentDate.setText(DateFormat.getMediumDateFormat(mCommentDate.getContext()).format(date));
|
||||
mRating.setText(String.format(Locale.getDefault(), "%.1f", item.getRating()));
|
||||
if (TextUtils.isEmpty(item.getReviewPositive()))
|
||||
if (TextUtils.isEmpty(item.getPros()))
|
||||
{
|
||||
UiUtils.hide(mPositiveReview);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.show(mPositiveReview);
|
||||
mTvPositiveReview.setText(item.getReviewPositive());
|
||||
mTvPositiveReview.setText(item.getPros());
|
||||
}
|
||||
if (TextUtils.isEmpty(item.getReviewNegative()))
|
||||
if (TextUtils.isEmpty(item.getCons()))
|
||||
{
|
||||
UiUtils.hide(mNegativeReview);
|
||||
}
|
||||
else
|
||||
{
|
||||
UiUtils.show(mNegativeReview);
|
||||
mTvNegativeReview.setText(item.getReviewNegative());
|
||||
mTvNegativeReview.setText(item.getCons());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ void initFieldsMap()
|
|||
return;
|
||||
}
|
||||
auto success = [self, completion, failure, currency, currencyFormatter](
|
||||
string const & minPrice, string const & priceCurrency) {
|
||||
string const & hotelId, string const & minPrice, string const & priceCurrency) {
|
||||
if (currency != priceCurrency)
|
||||
{
|
||||
failure();
|
||||
|
|
|
@ -248,7 +248,8 @@ using namespace place_page;
|
|||
|
||||
string const currency = currencyFormatter.currencyCode.UTF8String;
|
||||
|
||||
auto const func = [self, label, currency, currencyFormatter](string const & minPrice,
|
||||
auto const func = [self, label, currency, currencyFormatter](string const & hotelId,
|
||||
string const & minPrice,
|
||||
string const & priceCurrency) {
|
||||
if (currency != priceCurrency)
|
||||
return;
|
||||
|
|
|
@ -471,7 +471,7 @@ Framework::~Framework()
|
|||
m_model.SetOnMapDeregisteredCallback(nullptr);
|
||||
}
|
||||
|
||||
BookingApi * Framework::GetBookingApi(platform::NetworkPolicy const & policy)
|
||||
booking::Api * Framework::GetBookingApi(platform::NetworkPolicy const & policy)
|
||||
{
|
||||
if (policy.CanUse())
|
||||
return m_bookingApi.get();
|
||||
|
@ -479,7 +479,7 @@ BookingApi * Framework::GetBookingApi(platform::NetworkPolicy const & policy)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
BookingApi const * Framework::GetBookingApi(platform::NetworkPolicy const & policy) const
|
||||
booking::Api const * Framework::GetBookingApi(platform::NetworkPolicy const & policy) const
|
||||
{
|
||||
if (policy.CanUse())
|
||||
return m_bookingApi.get();
|
||||
|
|
|
@ -165,7 +165,7 @@ protected:
|
|||
|
||||
BookmarkManager m_bmManager;
|
||||
|
||||
unique_ptr<BookingApi> m_bookingApi = make_unique<BookingApi>();
|
||||
unique_ptr<booking::Api> m_bookingApi = make_unique<booking::Api>();
|
||||
unique_ptr<uber::Api> m_uberApi = make_unique<uber::Api>();
|
||||
|
||||
df::DrapeApi m_drapeApi;
|
||||
|
@ -199,8 +199,8 @@ public:
|
|||
virtual ~Framework();
|
||||
|
||||
/// Get access to booking api helpers
|
||||
BookingApi * GetBookingApi(platform::NetworkPolicy const & policy);
|
||||
BookingApi const * GetBookingApi(platform::NetworkPolicy const & policy) const;
|
||||
booking::Api * GetBookingApi(platform::NetworkPolicy const & policy);
|
||||
booking::Api const * GetBookingApi(platform::NetworkPolicy const & policy) const;
|
||||
uber::Api * GetUberApi(platform::NetworkPolicy const & policy);
|
||||
|
||||
df::DrapeApi & GetDrapeApi() { return m_drapeApi; }
|
||||
|
|
|
@ -1,37 +1,240 @@
|
|||
#include "partners_api/booking_api.hpp"
|
||||
|
||||
#include "platform/http_client.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/gmtime.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/thread.hpp"
|
||||
|
||||
#include "std/chrono.hpp"
|
||||
#include "std/initializer_list.hpp"
|
||||
#include "std/iomanip.hpp"
|
||||
#include "std/iostream.hpp"
|
||||
#include "std/sstream.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
||||
#include "3party/jansson/myjansson.hpp"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
char constexpr BookingApi::kDefaultCurrency[1];
|
||||
|
||||
BookingApi::BookingApi() : m_affiliateId(BOOKING_AFFILIATE_ID), m_testingMode(false)
|
||||
namespace
|
||||
{
|
||||
stringstream ss;
|
||||
ss << BOOKING_KEY << ":" << BOOKING_SECRET;
|
||||
m_apiUrl = "https://" + ss.str() + "@distribution-xml.booking.com/json/bookings.";
|
||||
using namespace platform;
|
||||
using namespace booking;
|
||||
|
||||
string const kBookingApiBaseUrl = "https://distribution-xml.booking.com/json/bookings";
|
||||
string const kExtendedHotelInfoBaseUrl = "";
|
||||
string const kPhotoOriginalUrl = "http://aff.bstatic.com/images/hotel/max500/";
|
||||
string const kPhotoSmallUrl = "http://aff.bstatic.com/images/hotel/square60/";
|
||||
|
||||
bool RunSimpleHttpRequest(string const & url, string & result)
|
||||
{
|
||||
HttpClient request(url);
|
||||
request.SetUserAndPassword(BOOKING_KEY, BOOKING_SECRET);
|
||||
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
|
||||
{
|
||||
result = request.ServerResponse();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string BookingApi::GetBookHotelUrl(string const & baseUrl, string const & /* lang */) const
|
||||
string MakeApiUrl(string const & func, initializer_list<pair<string, string>> const & params,
|
||||
bool testing)
|
||||
{
|
||||
return GetDescriptionUrl(baseUrl) + "#availability";
|
||||
ostringstream os;
|
||||
os << kBookingApiBaseUrl << "." << func << "?";
|
||||
|
||||
bool firstRun = true;
|
||||
for (auto const & param : params)
|
||||
{
|
||||
if (firstRun)
|
||||
{
|
||||
firstRun = false;
|
||||
os << "";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "&";
|
||||
}
|
||||
os << param.first << "=" << param.second;
|
||||
}
|
||||
|
||||
if (testing)
|
||||
os << "&show_test=1";
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
string BookingApi::GetDescriptionUrl(string const & baseUrl, string const & /* lang */) const
|
||||
void ClearHotelInfo(HotelInfo & info)
|
||||
{
|
||||
return baseUrl + "?aid=" + m_affiliateId;
|
||||
info.m_hotelId.clear();
|
||||
info.m_description.clear();
|
||||
info.m_photos.clear();
|
||||
info.m_facilities.clear();
|
||||
info.m_reviews.clear();
|
||||
info.m_score = 0.0;
|
||||
info.m_scoreCount = 0;
|
||||
}
|
||||
|
||||
void BookingApi::GetMinPrice(string const & hotelId, string const & currency,
|
||||
function<void(string const &, string const &)> const & fn)
|
||||
vector<HotelFacility> ParseFacilities(json_t const * facilitiesArray)
|
||||
{
|
||||
vector<HotelFacility> facilities;
|
||||
|
||||
if (facilitiesArray == nullptr || !json_is_array(facilitiesArray))
|
||||
return facilities;
|
||||
|
||||
size_t sz = json_array_size(facilitiesArray);
|
||||
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
auto item = json_array_get(facilitiesArray, i);
|
||||
|
||||
HotelFacility facility;
|
||||
my::FromJSONObject(item, "facility_type", facility.m_facilityType);
|
||||
my::FromJSONObject(item, "name", facility.m_name);
|
||||
|
||||
facilities.push_back(move(facility));
|
||||
}
|
||||
|
||||
return facilities;
|
||||
}
|
||||
|
||||
vector<HotelPhotoUrls> ParsePhotos(json_t const * photosArray)
|
||||
{
|
||||
if (photosArray == nullptr || !json_is_array(photosArray))
|
||||
return {};
|
||||
|
||||
vector<HotelPhotoUrls> photos;
|
||||
size_t sz = json_array_size(photosArray);
|
||||
string photoId;
|
||||
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
auto item = json_array_get(photosArray, i);
|
||||
my::FromJSON(item, photoId);
|
||||
|
||||
// First three digits of id are used as part of path to photo on the server.
|
||||
if (photoId.size() < 3)
|
||||
{
|
||||
LOG(LWARNING, ("Incorrect photo id =", photoId));
|
||||
continue;
|
||||
}
|
||||
|
||||
string url(photoId.substr(0, 3) + "/" + photoId + ".jpg");
|
||||
photos.push_back({kPhotoSmallUrl + url, kPhotoOriginalUrl + url});
|
||||
}
|
||||
|
||||
return photos;
|
||||
}
|
||||
|
||||
vector<HotelReview> ParseReviews(json_t const * reviewsArray)
|
||||
{
|
||||
if (reviewsArray == nullptr || !json_is_array(reviewsArray))
|
||||
return {};
|
||||
|
||||
vector<HotelReview> reviews;
|
||||
size_t sz = json_array_size(reviewsArray);
|
||||
string date;
|
||||
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
auto item = json_array_get(reviewsArray, i);
|
||||
HotelReview review;
|
||||
|
||||
my::FromJSONObject(item, "date", date);
|
||||
istringstream ss(date);
|
||||
tm t = {};
|
||||
ss >> get_time(&t, "%Y-%m-%d %H:%M:%S");
|
||||
if (ss.fail())
|
||||
{
|
||||
LOG(LWARNING, ("Incorrect review date =", date));
|
||||
continue;
|
||||
}
|
||||
review.m_date = system_clock::from_time_t(mktime(&t));
|
||||
|
||||
double score;
|
||||
my::FromJSONObject(item, "average_score", score);
|
||||
review.m_score = static_cast<float>(score);
|
||||
|
||||
my::FromJSONObject(item, "author", review.m_author);
|
||||
my::FromJSONObject(item, "pros", review.m_pros);
|
||||
my::FromJSONObject(item, "cons", review.m_cons);
|
||||
|
||||
reviews.push_back(move(review));
|
||||
}
|
||||
|
||||
return reviews;
|
||||
}
|
||||
|
||||
void FillHotelInfo(string const & src, HotelInfo & info)
|
||||
{
|
||||
my::Json root(src.c_str());
|
||||
|
||||
my::FromJSONObjectOptionalField(root.get(), "description", info.m_description);
|
||||
double score;
|
||||
my::FromJSONObjectOptionalField(root.get(), "average_score", score);
|
||||
info.m_score = static_cast<float>(score);
|
||||
|
||||
json_int_t scoreCount = 0;
|
||||
my::FromJSONObjectOptionalField(root.get(), "score_count", scoreCount);
|
||||
info.m_scoreCount = scoreCount;
|
||||
|
||||
auto const facilitiesArray = json_object_get(root.get(), "facilities");
|
||||
info.m_facilities = ParseFacilities(facilitiesArray);
|
||||
|
||||
auto const photosArray = json_object_get(root.get(), "photos");
|
||||
info.m_photos = ParsePhotos(photosArray);
|
||||
|
||||
auto const reviewsArray = json_object_get(root.get(), "reviews");
|
||||
info.m_reviews = ParseReviews(reviewsArray);
|
||||
}
|
||||
|
||||
void FillPriceAndCurrency(string const & src, string const & currency, string & minPrice,
|
||||
string & priceCurrency)
|
||||
{
|
||||
my::Json root(src.c_str());
|
||||
if (!json_is_array(root.get()))
|
||||
MYTHROW(my::Json::Exception, ("The answer must contain a json array."));
|
||||
size_t const rootSize = json_array_size(root.get());
|
||||
|
||||
if (rootSize == 0)
|
||||
return;
|
||||
|
||||
// Read default hotel price and currency.
|
||||
auto obj = json_array_get(root.get(), 0);
|
||||
my::FromJSONObject(obj, "min_price", minPrice);
|
||||
my::FromJSONObject(obj, "currency_code", priceCurrency);
|
||||
|
||||
if (currency.empty() || priceCurrency == currency)
|
||||
return;
|
||||
|
||||
// Try to get price in requested currency.
|
||||
json_t * arr = json_object_get(obj, "other_currency");
|
||||
if (arr == nullptr || !json_is_array(arr))
|
||||
return;
|
||||
|
||||
size_t sz = json_array_size(arr);
|
||||
string code;
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
auto el = json_array_get(arr, i);
|
||||
my::FromJSONObject(el, "currency_code", code);
|
||||
if (code == currency)
|
||||
{
|
||||
priceCurrency = code;
|
||||
my::FromJSONObject(el, "min_price", minPrice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace booking
|
||||
{
|
||||
// static
|
||||
bool RawApi::GetHotelAvailability(string const & hotelId, string const & currency, string & result,
|
||||
bool testing /* = false */)
|
||||
{
|
||||
char dateArrival[12]{};
|
||||
char dateDeparture[12]{};
|
||||
|
@ -45,48 +248,69 @@ void BookingApi::GetMinPrice(string const & hotelId, string const & currency,
|
|||
string url = MakeApiUrl("getHotelAvailability", {{"hotel_ids", hotelId},
|
||||
{"currency_code", currency},
|
||||
{"arrival_date", dateArrival},
|
||||
{"departure_date", dateDeparture}});
|
||||
auto const callback = [this, fn, currency](downloader::HttpRequest & answer)
|
||||
{
|
||||
{"departure_date", dateDeparture}},
|
||||
testing);
|
||||
return RunSimpleHttpRequest(url, result);
|
||||
}
|
||||
|
||||
// static
|
||||
bool RawApi::GetExtendedInfo(string const & hotelId, string const & lang, string & result)
|
||||
{
|
||||
ostringstream os;
|
||||
os << kExtendedHotelInfoBaseUrl;
|
||||
// Last three digits of id are used as part of path to hotel extended info on the server.
|
||||
if (hotelId.size() > 3)
|
||||
os << hotelId.substr(hotelId.size() - 3);
|
||||
else
|
||||
os << "000";
|
||||
string langCode;
|
||||
if (lang.empty())
|
||||
{
|
||||
langCode = "en";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const pos = lang.find('_');
|
||||
if (pos != string::npos)
|
||||
langCode = lang.substr(0, pos);
|
||||
else
|
||||
langCode = lang;
|
||||
}
|
||||
|
||||
os << "/" << hotelId << "/" << langCode << ".json";
|
||||
|
||||
return RunSimpleHttpRequest(os.str(), result);
|
||||
}
|
||||
|
||||
string Api::GetBookHotelUrl(string const & baseUrl) const
|
||||
{
|
||||
return GetDescriptionUrl(baseUrl) + "#availability";
|
||||
}
|
||||
|
||||
string Api::GetDescriptionUrl(string const & baseUrl) const
|
||||
{
|
||||
return baseUrl + string("?aid=") + BOOKING_AFFILIATE_ID;
|
||||
}
|
||||
|
||||
void Api::GetMinPrice(string const & hotelId, string const & currency,
|
||||
GetMinPriceCallback const & fn)
|
||||
{
|
||||
auto const testingMode = m_testingMode;
|
||||
|
||||
threads::SimpleThread([hotelId, currency, fn, testingMode]()
|
||||
{
|
||||
string minPrice;
|
||||
string priceCurrency;
|
||||
string httpResult;
|
||||
if (!RawApi::GetHotelAvailability(hotelId, currency, httpResult, testingMode))
|
||||
{
|
||||
fn(hotelId, minPrice, priceCurrency);
|
||||
return;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if (sz > 0)
|
||||
{
|
||||
// Read default hotel price and currency.
|
||||
auto obj = json_array_get(root.get(), 0);
|
||||
my::FromJSONObject(obj, "min_price", minPrice);
|
||||
my::FromJSONObject(obj, "currency_code", priceCurrency);
|
||||
|
||||
// Try to get price in requested currency.
|
||||
if (!currency.empty() && priceCurrency != currency)
|
||||
{
|
||||
json_t * arr = json_object_get(obj, "other_currency");
|
||||
if (arr && json_is_array(arr))
|
||||
{
|
||||
size_t sz = json_array_size(arr);
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
auto el = json_array_get(arr, i);
|
||||
string code;
|
||||
my::FromJSONObject(el, "currency_code", code);
|
||||
if (code == currency)
|
||||
{
|
||||
priceCurrency = code;
|
||||
my::FromJSONObject(el, "min_price", minPrice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FillPriceAndCurrency(httpResult, currency, minPrice, priceCurrency);
|
||||
}
|
||||
catch (my::Json::Exception const & e)
|
||||
{
|
||||
|
@ -94,180 +318,35 @@ void BookingApi::GetMinPrice(string const & hotelId, string const & currency,
|
|||
minPrice.clear();
|
||||
priceCurrency.clear();
|
||||
}
|
||||
fn(minPrice, priceCurrency);
|
||||
m_request.reset();
|
||||
};
|
||||
|
||||
m_request.reset(downloader::HttpRequest::Get(url, callback));
|
||||
fn(hotelId, minPrice, priceCurrency);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
// TODO(mgsergio): This is just a mockup, make it a real function.
|
||||
void BookingApi::GetHotelInfo(string const & hotelId, string const & /* lang */,
|
||||
function<void(HotelInfo const & hotelInfo)> const & fn)
|
||||
void Api::GetHotelInfo(string const & hotelId, string const & lang, GetHotelInfoCallback const & fn)
|
||||
{
|
||||
HotelInfo info;
|
||||
threads::SimpleThread([hotelId, lang, fn]()
|
||||
{
|
||||
HotelInfo info;
|
||||
info.m_hotelId = hotelId;
|
||||
|
||||
info.m_hotelId = "000";
|
||||
info.m_description = "Interesting place among SoHo, Little "
|
||||
"Italy and China town. Modern design. "
|
||||
"Great view from roof. Near subway. "
|
||||
"Free refreshment every afternoon. "
|
||||
"The staff was very friendly.";
|
||||
string result;
|
||||
if (!RawApi::GetExtendedInfo(hotelId, lang, result))
|
||||
{
|
||||
fn(info);
|
||||
return;
|
||||
}
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage9.static.itmages.ru/i/16/0915/h_1473944906_4427771_63a7c2282b.jpg",
|
||||
"http://storage7.static.itmages.ru/i/16/0915/h_1473945189_5545647_db54564f06.jpg"});
|
||||
try
|
||||
{
|
||||
FillHotelInfo(result, info);
|
||||
}
|
||||
catch (my::Json::Exception const & e)
|
||||
{
|
||||
LOG(LERROR, (e.Msg()));
|
||||
ClearHotelInfo(info);
|
||||
}
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage9.static.itmages.ru/i/16/0915/h_1473944906_1573275_450fcd78b0.jpg",
|
||||
"http://storage8.static.itmages.ru/i/16/0915/h_1473945194_6402871_b68c63c705.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473944906_6998375_f1ba6024a5.jpg",
|
||||
"http://storage7.static.itmages.ru/i/16/0915/h_1473945188_9401486_7185c713bc.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage7.static.itmages.ru/i/16/0915/h_1473944904_8294064_035b4328ee.jpg",
|
||||
"http://storage9.static.itmages.ru/i/16/0915/h_1473945189_8999398_d9bfe0d56d.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage6.static.itmages.ru/i/16/0915/h_1473944904_2231876_680171f67f.jpg",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945190_2042562_c6cfcccd18.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage7.static.itmages.ru/i/16/0915/h_1473944904_2871576_660e0aad58.jpg",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945190_9605355_94164142b7.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage8.static.itmages.ru/i/16/0915/h_1473944905_3578559_d4e95070e9.jpg",
|
||||
"http://storage3.static.itmages.ru/i/16/0915/h_1473945190_3367031_145793d530.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage8.static.itmages.ru/i/16/0915/h_1473944905_5596402_9bdce96ace.jpg",
|
||||
"http://storage4.static.itmages.ru/i/16/0915/h_1473945191_2783367_2440027ece.jpg"});
|
||||
|
||||
info.m_photos.push_back({
|
||||
"http://storage8.static.itmages.ru/i/16/0915/h_1473944905_4312757_433c687f4d.jpg",
|
||||
"http://storage6.static.itmages.ru/i/16/0915/h_1473945191_1817571_b945aa1f3e.jpg"});
|
||||
|
||||
info.m_facilities = {
|
||||
{"non_smoking_rooms", "Non smoking rooms"},
|
||||
{"gym", "Training gym"},
|
||||
{"pets_are_allowed", "Pets are allowed"}
|
||||
};
|
||||
|
||||
info.m_reviews = {
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous1",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_5332083_b44af613bd.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_7504873_be0fe246e3.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945374_9397526_996bbca0d7.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous1",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_5332083_b44af613bd.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_7504873_be0fe246e3.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945374_9397526_996bbca0d7.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous1",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_5332083_b44af613bd.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_7504873_be0fe246e3.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945374_9397526_996bbca0d7.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous1",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_5332083_b44af613bd.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage2.static.itmages.ru/i/16/0915/h_1473945375_7504873_be0fe246e3.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
),
|
||||
HotelReview::CriticReview(
|
||||
"Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly.",
|
||||
"Little bit noise from outside",
|
||||
"Anonymous2",
|
||||
"http://storage1.static.itmages.ru/i/16/0915/h_1473945374_9397526_996bbca0d7.jpg",
|
||||
9.2,
|
||||
system_clock::now()
|
||||
)
|
||||
};
|
||||
|
||||
fn(info);
|
||||
}
|
||||
|
||||
string BookingApi::MakeApiUrl(string const & func,
|
||||
initializer_list<pair<string, string>> const & params)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << m_apiUrl << func << "?";
|
||||
bool firstRun = true;
|
||||
for (auto const & param : params)
|
||||
ss << (firstRun ? firstRun = false, "" : "&") << param.first << "=" << param.second;
|
||||
if (m_testingMode)
|
||||
ss << "&show_test=1";
|
||||
|
||||
return ss.str();
|
||||
fn(info);
|
||||
}).detach();
|
||||
}
|
||||
} // namespace booking
|
||||
|
|
|
@ -1,138 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/http_request.hpp"
|
||||
|
||||
#include "std/chrono.hpp"
|
||||
#include "std/function.hpp"
|
||||
#include "std/initializer_list.hpp"
|
||||
#include "std/limits.hpp"
|
||||
#include "std/shared_ptr.hpp"
|
||||
#include "std/string.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
#include "std/utility.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
class BookingApi
|
||||
namespace booking
|
||||
{
|
||||
string m_affiliateId;
|
||||
string m_apiUrl;
|
||||
bool m_testingMode;
|
||||
struct HotelPhotoUrls
|
||||
{
|
||||
string m_small;
|
||||
string m_original;
|
||||
};
|
||||
|
||||
struct HotelReview
|
||||
{
|
||||
/// An issue date.
|
||||
time_point<system_clock> m_date;
|
||||
/// Author's hotel evaluation.
|
||||
float m_score = 0.0;
|
||||
/// Review author name.
|
||||
string m_author;
|
||||
/// Review text. There can be either one or both positive/negative review.
|
||||
string m_pros;
|
||||
string m_cons;
|
||||
};
|
||||
|
||||
struct HotelFacility
|
||||
{
|
||||
string m_facilityType;
|
||||
string m_name;
|
||||
};
|
||||
|
||||
struct HotelInfo
|
||||
{
|
||||
string m_hotelId;
|
||||
|
||||
string m_description;
|
||||
vector<HotelPhotoUrls> m_photos;
|
||||
vector<HotelFacility> m_facilities;
|
||||
vector<HotelReview> m_reviews;
|
||||
float m_score = 0.0;
|
||||
uint32_t m_scoreCount = 0;
|
||||
};
|
||||
|
||||
class RawApi
|
||||
{
|
||||
public:
|
||||
struct HotelPhotoUrls
|
||||
{
|
||||
string m_small;
|
||||
string m_original;
|
||||
};
|
||||
static bool GetHotelAvailability(string const & hotelId, string const & currency, string & result,
|
||||
bool testing = false);
|
||||
static bool GetExtendedInfo(string const & hotelId, string const & lang, string & result);
|
||||
};
|
||||
|
||||
struct HotelReview
|
||||
{
|
||||
HotelReview() = default;
|
||||
// C++11 doesn't allow aggragate initialization for structs with default member initializer.
|
||||
// But C++14 does.
|
||||
HotelReview(string const & reviewPositive,
|
||||
string const & reviewNegative,
|
||||
string const & reviewNeutral,
|
||||
string const & author,
|
||||
string const & authorPictUrl,
|
||||
float const rating,
|
||||
time_point<system_clock> const date)
|
||||
: m_reviewPositive(reviewPositive)
|
||||
, m_reviewNegative(reviewNegative)
|
||||
, m_reviewNeutral(reviewNeutral)
|
||||
, m_author(author)
|
||||
, m_authorPictUrl(authorPictUrl)
|
||||
, m_rating(rating)
|
||||
, m_date(date)
|
||||
{
|
||||
}
|
||||
using GetMinPriceCallback = function<void(string const & hotelId, string const & price, string const & currency)>;
|
||||
using GetHotelInfoCallback = function<void(HotelInfo const & hotelInfo)>;
|
||||
|
||||
class Api
|
||||
{
|
||||
public:
|
||||
void SetTestingMode(bool testing) { m_testingMode = testing; }
|
||||
|
||||
static HotelReview CriticReview(string const & reviewPositive,
|
||||
string const & reviewNegative,
|
||||
string const & author,
|
||||
string const & authorPictUrl,
|
||||
float const rating,
|
||||
time_point<system_clock> const date)
|
||||
{
|
||||
return {
|
||||
reviewPositive,
|
||||
reviewNegative,
|
||||
"",
|
||||
author,
|
||||
authorPictUrl,
|
||||
rating,
|
||||
date
|
||||
};
|
||||
}
|
||||
|
||||
static HotelReview NeutralReview(string const & reviewNeutral,
|
||||
string const & author,
|
||||
string const & authorPictUrl,
|
||||
float const rating,
|
||||
time_point<system_clock> const date)
|
||||
{
|
||||
return {
|
||||
"",
|
||||
"",
|
||||
reviewNeutral,
|
||||
author,
|
||||
authorPictUrl,
|
||||
rating,
|
||||
date
|
||||
};
|
||||
}
|
||||
|
||||
static auto constexpr kInvalidRating = numeric_limits<float>::max();
|
||||
|
||||
/// Review text. There can be either one or both positive/negative review or
|
||||
/// a neutral one.
|
||||
string m_reviewPositive;
|
||||
string m_reviewNegative;
|
||||
string m_reviewNeutral;
|
||||
/// Review author name.
|
||||
string m_author;
|
||||
/// Url to a author's picture.
|
||||
string m_authorPictUrl;
|
||||
/// Author's hotel evaluation.
|
||||
float m_rating = kInvalidRating;
|
||||
/// An issue date.
|
||||
time_point<system_clock> m_date;
|
||||
};
|
||||
|
||||
struct Facility
|
||||
{
|
||||
string m_id;
|
||||
string m_localizedName;
|
||||
};
|
||||
|
||||
struct HotelInfo
|
||||
{
|
||||
string m_hotelId;
|
||||
|
||||
string m_description;
|
||||
vector<HotelPhotoUrls> m_photos;
|
||||
vector<Facility> m_facilities;
|
||||
vector<HotelReview> m_reviews;
|
||||
};
|
||||
|
||||
static constexpr const char kDefaultCurrency[1] = {0};
|
||||
|
||||
BookingApi();
|
||||
string GetBookHotelUrl(string const & baseUrl, string const & lang = string()) const;
|
||||
string GetDescriptionUrl(string const & baseUrl, string const & lang = string()) const;
|
||||
inline void SetTestingMode(bool testing) { m_testingMode = testing; }
|
||||
|
||||
string GetBookHotelUrl(string const & baseUrl) const;
|
||||
string GetDescriptionUrl(string const & baseUrl) const;
|
||||
// Real-time information methods (used for retriving rapidly changing information).
|
||||
// These methods send requests directly to Booking.
|
||||
void GetMinPrice(string const & hotelId, string const & currency,
|
||||
function<void(string const &, string const &)> const & fn);
|
||||
|
||||
void GetMinPrice(string const & hotelId, string const & currency, GetMinPriceCallback const & fn);
|
||||
|
||||
// Static information methods (use for information that can be cached).
|
||||
// These methods use caching server to prevent Booking from being ddossed.
|
||||
void GetHotelInfo(string const & hotelId, string const & lang,
|
||||
function<void(HotelInfo const & hotelInfo)> const & fn);
|
||||
void GetHotelInfo(string const & hotelId, string const & lang, GetHotelInfoCallback const & fn);
|
||||
|
||||
protected:
|
||||
unique_ptr<downloader::HttpRequest> m_request;
|
||||
string MakeApiUrl(string const & func, initializer_list<pair<string, string>> const & params);
|
||||
private:
|
||||
bool m_testingMode = false;
|
||||
};
|
||||
} // namespace booking
|
||||
|
|
|
@ -2,32 +2,43 @@
|
|||
|
||||
#include "partners_api/booking_api.hpp"
|
||||
|
||||
UNIT_TEST(Booking_SmokeTest)
|
||||
namespace
|
||||
{
|
||||
BookingApi api;
|
||||
string const kHotelId = "98251"; // Special hotel id for testing.
|
||||
|
||||
string url = api.GetBookHotelUrl("http://someurl.com");
|
||||
TEST(!url.empty(), ());
|
||||
UNIT_TEST(Booking_GetHotelAvailability)
|
||||
{
|
||||
string result;
|
||||
TEST(booking::RawApi::GetHotelAvailability(kHotelId, "", result, true), ());
|
||||
TEST(!result.empty(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Booking_GetExtendedInfo)
|
||||
{
|
||||
string result;
|
||||
TEST(booking::RawApi::GetExtendedInfo(kHotelId, "", result), ());
|
||||
TEST(!result.empty(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Booking_GetMinPrice)
|
||||
{
|
||||
BookingApi api;
|
||||
booking::Api api;
|
||||
api.SetTestingMode(true);
|
||||
string const kHotelId = "98251"; // Special hotel id for testing.
|
||||
|
||||
{
|
||||
string price;
|
||||
string currency;
|
||||
api.GetMinPrice(kHotelId, BookingApi::kDefaultCurrency,
|
||||
[&price, ¤cy](string const & val, string const & curr)
|
||||
{
|
||||
string hotelId;
|
||||
api.GetMinPrice(kHotelId, "" /* default currency */,
|
||||
[&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr) {
|
||||
hotelId = id;
|
||||
price = val;
|
||||
currency = curr;
|
||||
testing::StopEventLoop();
|
||||
});
|
||||
testing::RunEventLoop();
|
||||
|
||||
TEST_EQUAL(hotelId, kHotelId, ());
|
||||
TEST(!price.empty(), ());
|
||||
TEST(!currency.empty(), ());
|
||||
TEST_EQUAL(currency, "USD", ());
|
||||
|
@ -36,14 +47,17 @@ UNIT_TEST(Booking_GetMinPrice)
|
|||
{
|
||||
string price;
|
||||
string currency;
|
||||
api.GetMinPrice(kHotelId, "RUB", [&price, ¤cy](string const & val, string const & curr)
|
||||
string hotelId;
|
||||
api.GetMinPrice(kHotelId, "RUB", [&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr)
|
||||
{
|
||||
hotelId = id;
|
||||
price = val;
|
||||
currency = curr;
|
||||
testing::StopEventLoop();
|
||||
});
|
||||
testing::RunEventLoop();
|
||||
|
||||
TEST_EQUAL(hotelId, kHotelId, ());
|
||||
TEST(!price.empty(), ());
|
||||
TEST(!currency.empty(), ());
|
||||
TEST_EQUAL(currency, "RUB", ());
|
||||
|
@ -52,32 +66,37 @@ UNIT_TEST(Booking_GetMinPrice)
|
|||
{
|
||||
string price;
|
||||
string currency;
|
||||
api.GetMinPrice(kHotelId, "ISK", [&price, ¤cy](string const & val, string const & curr)
|
||||
string hotelId;
|
||||
api.GetMinPrice(kHotelId, "ISK", [&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr)
|
||||
{
|
||||
hotelId = id;
|
||||
price = val;
|
||||
currency = curr;
|
||||
testing::StopEventLoop();
|
||||
});
|
||||
testing::RunEventLoop();
|
||||
|
||||
TEST_EQUAL(hotelId, kHotelId, ());
|
||||
TEST(!price.empty(), ());
|
||||
TEST(!currency.empty(), ());
|
||||
TEST_EQUAL(currency, "ISK", ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(GetHotelInfo) // GetHotelInfo is a mockup now.
|
||||
UNIT_TEST(GetHotelInfo)
|
||||
{
|
||||
BookingApi api;
|
||||
BookingApi::HotelInfo info;
|
||||
booking::Api api;
|
||||
booking::HotelInfo info;
|
||||
|
||||
api.GetHotelInfo("000", "en", [&info](BookingApi::HotelInfo const & i)
|
||||
api.GetHotelInfo(kHotelId, "en", [&info](booking::HotelInfo const & i)
|
||||
{
|
||||
info = i;
|
||||
});
|
||||
|
||||
TEST_EQUAL(info.m_hotelId, kHotelId, ());
|
||||
TEST(!info.m_description.empty(), ());
|
||||
TEST_EQUAL(info.m_photos.size(), 9, ());
|
||||
TEST_EQUAL(info.m_photos.size(), 5, ());
|
||||
TEST_EQUAL(info.m_facilities.size(), 3, ());
|
||||
TEST_EQUAL(info.m_reviews.size(), 12, ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ HttpClient & HttpClient::SetReceivedFile(string const & received_file)
|
|||
|
||||
HttpClient & HttpClient::SetUserAndPassword(string const & user, string const & password)
|
||||
{
|
||||
m_headers.emplace("Authorization", "Basic" + base64::Encode(user + ":" + password));
|
||||
m_headers.emplace("Authorization", "Basic " + base64::Encode(user + ":" + password));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,6 @@
|
|||
347F33301C4540A8009758CC /* suggest.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 347F33151C4540A8009758CC /* suggest.hpp */; };
|
||||
349B65891D4F21E5001798E2 /* lazy_centers_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 349B65871D4F21E5001798E2 /* lazy_centers_table.cpp */; };
|
||||
349B658A1D4F21E5001798E2 /* lazy_centers_table.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 349B65881D4F21E5001798E2 /* lazy_centers_table.hpp */; };
|
||||
34EEAD701E55AE4300E95575 /* token_range.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34EEAD6F1E55AE4300E95575 /* token_range.hpp */; };
|
||||
34EEAD721E55AE5C00E95575 /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34EEAD711E55AE5C00E95575 /* utils.cpp */; };
|
||||
34F5583B1DBF2E0E00A4FC11 /* libalohalitics.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F5583A1DBF2E0E00A4FC11 /* libalohalitics.a */; };
|
||||
34F5583D1DBF2E2700A4FC11 /* libeditor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F5583C1DBF2E2700A4FC11 /* libeditor.a */; };
|
||||
34F5583F1DBF2E3400A4FC11 /* libpugixml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F5583E1DBF2E3400A4FC11 /* libpugixml.a */; };
|
||||
|
@ -73,6 +71,8 @@
|
|||
34F558491DBF2EC700A4FC11 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F558481DBF2EC700A4FC11 /* libz.tbd */; };
|
||||
397AFE061D6C9AC700F583E7 /* downloader_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 397AFE041D6C9AC700F583E7 /* downloader_search_callback.cpp */; };
|
||||
397AFE071D6C9AC700F583E7 /* downloader_search_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 397AFE051D6C9AC700F583E7 /* downloader_search_callback.hpp */; };
|
||||
3DBC1C581E55B22F0016897F /* token_range.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DBC1C561E55B22F0016897F /* token_range.hpp */; };
|
||||
3DBC1C591E55B22F0016897F /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC1C571E55B22F0016897F /* utils.cpp */; };
|
||||
56D5456E1C74A48C00E3719C /* mode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56D5456C1C74A48C00E3719C /* mode.cpp */; };
|
||||
56D5456F1C74A48C00E3719C /* mode.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56D5456D1C74A48C00E3719C /* mode.hpp */; };
|
||||
670F88741CE4C032003F68BA /* types_skipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670F88721CE4C032003F68BA /* types_skipper.cpp */; };
|
||||
|
@ -240,8 +240,6 @@
|
|||
347F33151C4540A8009758CC /* suggest.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = suggest.hpp; sourceTree = "<group>"; };
|
||||
349B65871D4F21E5001798E2 /* lazy_centers_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lazy_centers_table.cpp; sourceTree = "<group>"; };
|
||||
349B65881D4F21E5001798E2 /* lazy_centers_table.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lazy_centers_table.hpp; sourceTree = "<group>"; };
|
||||
34EEAD6F1E55AE4300E95575 /* token_range.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = token_range.hpp; sourceTree = "<group>"; };
|
||||
34EEAD711E55AE5C00E95575 /* utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cpp; sourceTree = "<group>"; };
|
||||
34F558371DBF2C8B00A4FC11 /* common-debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-debug.xcconfig"; path = "../common-debug.xcconfig"; sourceTree = "<group>"; };
|
||||
34F558381DBF2C8B00A4FC11 /* common-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-release.xcconfig"; path = "../common-release.xcconfig"; sourceTree = "<group>"; };
|
||||
34F5583A1DBF2E0E00A4FC11 /* libalohalitics.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libalohalitics.a; path = "../../../omim-xcode-build/Debug/libalohalitics.a"; sourceTree = "<group>"; };
|
||||
|
@ -254,6 +252,8 @@
|
|||
34F558481DBF2EC700A4FC11 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
397AFE041D6C9AC700F583E7 /* downloader_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = downloader_search_callback.cpp; sourceTree = "<group>"; };
|
||||
397AFE051D6C9AC700F583E7 /* downloader_search_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = downloader_search_callback.hpp; sourceTree = "<group>"; };
|
||||
3DBC1C561E55B22F0016897F /* token_range.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = token_range.hpp; sourceTree = "<group>"; };
|
||||
3DBC1C571E55B22F0016897F /* utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cpp; sourceTree = "<group>"; };
|
||||
56D5456C1C74A48C00E3719C /* mode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mode.cpp; sourceTree = "<group>"; };
|
||||
56D5456D1C74A48C00E3719C /* mode.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mode.hpp; sourceTree = "<group>"; };
|
||||
670F88721CE4C032003F68BA /* types_skipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types_skipper.cpp; sourceTree = "<group>"; };
|
||||
|
@ -484,6 +484,8 @@
|
|||
675346B21A4055CF00A0A8C3 /* search */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3DBC1C561E55B22F0016897F /* token_range.hpp */,
|
||||
3DBC1C571E55B22F0016897F /* utils.cpp */,
|
||||
675346BE1A40560D00A0A8C3 /* algos.hpp */,
|
||||
675346BF1A40560D00A0A8C3 /* approximate_string_match.cpp */,
|
||||
675346C01A40560D00A0A8C3 /* approximate_string_match.hpp */,
|
||||
|
@ -600,12 +602,10 @@
|
|||
345C8DAE1D2D15A50037E3A6 /* streets_matcher.hpp */,
|
||||
F652D8E61CFDE21900FC29A0 /* string_intersection.hpp */,
|
||||
347F33151C4540A8009758CC /* suggest.hpp */,
|
||||
34EEAD6F1E55AE4300E95575 /* token_range.hpp */,
|
||||
F652D8E71CFDE21900FC29A0 /* token_slice.cpp */,
|
||||
F652D8E81CFDE21900FC29A0 /* token_slice.hpp */,
|
||||
670F88721CE4C032003F68BA /* types_skipper.cpp */,
|
||||
670F88731CE4C032003F68BA /* types_skipper.hpp */,
|
||||
34EEAD711E55AE5C00E95575 /* utils.cpp */,
|
||||
3461C9A11D79949600E6E6F5 /* utils.hpp */,
|
||||
3465B27F1D5DE71A0021E14D /* viewport_search_callback.cpp */,
|
||||
3465B2801D5DE71A0021E14D /* viewport_search_callback.hpp */,
|
||||
|
@ -636,7 +636,6 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
34EEAD701E55AE4300E95575 /* token_range.hpp in Headers */,
|
||||
3461C9A51D79949600E6E6F5 /* utils.hpp in Headers */,
|
||||
345C8DB01D2D15A50037E3A6 /* cbv.hpp in Headers */,
|
||||
F652D90C1CFDE21900FC29A0 /* street_vicinity_loader.hpp in Headers */,
|
||||
|
@ -840,7 +839,6 @@
|
|||
F652D8F01CFDE21900FC29A0 /* geocoder.cpp in Sources */,
|
||||
F652D8F21CFDE21900FC29A0 /* geometry_cache.cpp in Sources */,
|
||||
34586B8C1DCB1E8300CF7FC9 /* locality_scorer_test.cpp in Sources */,
|
||||
34EEAD721E55AE5C00E95575 /* utils.cpp in Sources */,
|
||||
34586B8E1DCB1E8300CF7FC9 /* nearby_points_sweeper_test.cpp in Sources */,
|
||||
345C8DB11D2D15A50037E3A6 /* geocoder_context.cpp in Sources */,
|
||||
3461C9A31D79949600E6E6F5 /* editor_delegate.cpp in Sources */,
|
||||
|
|
Loading…
Add table
Reference in a new issue