From 582a0dd970d7a8f79cba37750ab71b28a4b93458 Mon Sep 17 00:00:00 2001 From: Aleksey Belouosv Date: Mon, 6 Aug 2018 18:13:26 +0300 Subject: [PATCH] [iOS] add booking hot offers to PP --- iphone/Maps/UI/PlacePage/MWMPlacePageData.h | 6 +- iphone/Maps/UI/PlacePage/MWMPlacePageData.mm | 107 ++++++++++-------- .../Preview/MWMPPPreviewLayoutHelper.mm | 31 ++--- .../PlacePageLayout/Preview/PPPReview.swift | 33 +++++- .../PlacePageLayout/Preview/PPPReview.xib | 76 +++++++++---- partners_api/booking_api.hpp | 8 +- 6 files changed, 168 insertions(+), 93 deletions(-) diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageData.h b/iphone/Maps/UI/PlacePage/MWMPlacePageData.h index 4c47b99de9..5596480704 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageData.h +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageData.h @@ -150,7 +150,10 @@ using NewSectionsAreReady = void (^)(NSRange const & range, MWMPlacePageData * d @property(copy, nonatomic) MWMVoidBlock refreshPreviewCallback; @property(copy, nonatomic) place_page::NewSectionsAreReady sectionsAreReadyCallback; @property(copy, nonatomic) MWMVoidBlock bannerIsReadyCallback; +@property(copy, nonatomic) MWMVoidBlock bookingDataUpdatedCallback; @property(nonatomic, readonly) MWMUGCViewModel * ugc; +@property(nonatomic, readonly) NSInteger bookingDiscount; +@property(nonatomic, readonly) BOOL isSmartDeal; // ready callback will be called from main queue. - (instancetype)initWithPlacePageInfo:(place_page::Info const &)info; @@ -174,13 +177,12 @@ using NewSectionsAreReady = void (^)(NSRange const & range, MWMPlacePageData * d // Booking - (void)fillOnlineBookingSections; - (MWMUGCRatingValueType *)bookingRating; -- (NSString *)bookingApproximatePricing; +- (NSString *)bookingPricing; - (NSURL *)sponsoredURL; - (NSURL *)deepLink; - (NSURL *)sponsoredDescriptionURL; - (NSURL *)bookingSearchURL; - (NSString *)sponsoredId; -- (void)assignOnlinePriceToLabel:(UILabel *)label; - (NSString *)hotelDescription; - (vector const &)facilities; - (vector const &)hotelReviews; diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm index 9beb505011..00e51c8b0e 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm @@ -38,6 +38,8 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; @property(copy, nonatomic) NSArray * viatorItems; @property(nonatomic) NSNumberFormatter * currencyFormatter; @property(nonatomic, readwrite) MWMUGCViewModel * ugc; +@property(nonatomic) NSInteger bookingDiscount; +@property(nonatomic) BOOL isSmartDeal; @end @@ -176,6 +178,51 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; }); } +- (void)requestBookingData +{ + network_policy::CallPartnersApi([self](auto const & canUseNetwork) { + auto const api = GetFramework().GetBookingApi(canUseNetwork); + if (!api) + return; + + std::string const currency = self.currencyFormatter.currencyCode.UTF8String; + + auto const func = [self, currency](std::string const & hotelId, + booking::Blocks const & blocks) { + if (currency != blocks.m_currency) + return; + + NSNumberFormatter * decimalFormatter = [[NSNumberFormatter alloc] init]; + decimalFormatter.numberStyle = NSNumberFormatterDecimalStyle; + + auto const price = blocks.m_totalMinPrice == booking::BlockInfo::kIncorrectPrice + ? "" + : std::to_string(blocks.m_totalMinPrice); + + NSNumber * currencyNumber = [decimalFormatter + numberFromString:[@(price.c_str()) + stringByReplacingOccurrencesOfString:@"." + withString:decimalFormatter + .decimalSeparator]]; + NSString * currencyString = [self.currencyFormatter stringFromNumber:currencyNumber]; + + dispatch_async(dispatch_get_main_queue(), ^{ + self.cachedMinPrice = [NSString stringWithCoreFormat:L(@"place_page_starting_from") + arguments:@[currencyString]]; + self.bookingDiscount = blocks.m_maxDiscount; + self.isSmartDeal = blocks.m_hasSmartDeal; + if (self.bookingDataUpdatedCallback) + self.bookingDataUpdatedCallback(); + }); + }; + + auto params = booking::BlockParams::MakeDefault(); + params.m_hotelId = self.sponsoredId.UTF8String; + params.m_currency = currency; + api->GetBlockAvailability(std::move(params), func); + }); +} + - (void)fillPreviewSection { if (self.title.length) m_previewRows.push_back(PreviewRows::Title); @@ -183,7 +230,10 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; if (self.subtitle.length || self.isMyPosition) m_previewRows.push_back(PreviewRows::Subtitle); if (self.schedule != OpeningHours::Unknown) m_previewRows.push_back(PreviewRows::Schedule); if (self.isBooking) + { m_previewRows.push_back(PreviewRows::Review); + [self requestBookingData]; + } if (self.address.length) m_previewRows.push_back(PreviewRows::Address); if (self.hotelType) @@ -522,7 +572,13 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; initWithValue:@(rating::GetRatingFormatted(ratingRaw).c_str()) type:[MWMPlacePageData ratingValueType:rating::GetImpress(ratingRaw)]]; } -- (NSString *)bookingApproximatePricing { return self.isBooking ? @(m_info.GetApproximatePricing().c_str()) : nil; } + +- (NSString *)bookingPricing +{ + ASSERT(self.isBooking, ("Only for booking.com hotels")); + return self.cachedMinPrice.length ? self.cachedMinPrice : @(m_info.GetApproximatePricing().c_str()); +} + - (NSURL *)sponsoredURL { // There are sponsors without URL. For such psrtners we do not show special button. @@ -566,55 +622,6 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; : nil; } -- (void)assignOnlinePriceToLabel:(UILabel *)label -{ - NSAssert(self.isBooking, @"Online price must be assigned to booking object!"); - if (self.cachedMinPrice.length) - { - label.text = self.cachedMinPrice; - return; - } - - network_policy::CallPartnersApi([self, label](auto const & canUseNetwork) { - auto const api = GetFramework().GetBookingApi(canUseNetwork); - if (!api) - return; - - std::string const currency = self.currencyFormatter.currencyCode.UTF8String; - - auto const func = [self, label, currency](std::string const & hotelId, - booking::Blocks const & blocks) { - if (currency != blocks.m_currency) - return; - - NSNumberFormatter * decimalFormatter = [[NSNumberFormatter alloc] init]; - decimalFormatter.numberStyle = NSNumberFormatterDecimalStyle; - - auto const price = blocks.m_totalMinPrice == booking::BlockInfo::kIncorrectPrice - ? "" - : std::to_string(blocks.m_totalMinPrice); - - NSNumber * currencyNumber = [decimalFormatter - numberFromString:[@(price.c_str()) - stringByReplacingOccurrencesOfString:@"." - withString:decimalFormatter - .decimalSeparator]]; - NSString * currencyString = [self.currencyFormatter stringFromNumber:currencyNumber]; - - self.cachedMinPrice = [NSString stringWithCoreFormat:L(@"place_page_starting_from") - arguments:@[currencyString]]; - dispatch_async(dispatch_get_main_queue(), ^{ - label.text = self.cachedMinPrice; - }); - }; - - auto params = booking::BlockParams::MakeDefault(); - params.m_hotelId = self.sponsoredId.UTF8String; - params.m_currency = currency; - api->GetBlockAvailability(std::move(params), func); - }); -} - - (NSNumberFormatter *)currencyFormatter { if (!_currencyFormatter) diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/MWMPPPreviewLayoutHelper.mm b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/MWMPPPreviewLayoutHelper.mm index cb62352316..f1aa8795fb 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/MWMPPPreviewLayoutHelper.mm +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/MWMPPPreviewLayoutHelper.mm @@ -227,26 +227,27 @@ std::array const kPreviewCells = {{[_MWMPPPTitle class], [reviewCell configWithRating:data.bookingRating canAddReview:NO reviewsCount:0 - priceSetter:^(UILabel * pricingLabel) { - pricingLabel.text = data.bookingApproximatePricing; - [data assignOnlinePriceToLabel:pricingLabel]; - } - onAddReview:^{ - }]; + price:data.bookingPricing + discount:data.bookingDiscount + smartDeal:data.isSmartDeal + onAddReview:nil]; + data.bookingDataUpdatedCallback = ^{ + [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; + }; } else { NSAssert(data.ugc, @""); [reviewCell configWithRating:data.ugc.summaryRating - canAddReview:data.ugc.isUGCUpdateEmpty - reviewsCount:data.ugc.totalReviewsCount - priceSetter:^(UILabel * _Nonnull pricingLabel) { - pricingLabel.text = @""; - } - onAddReview:^{ - [MWMPlacePageManagerHelper showUGCAddReview:MWMRatingSummaryViewValueTypeNoValue - fromPreview:YES]; - }]; + canAddReview:data.ugc.isUGCUpdateEmpty + reviewsCount:data.ugc.totalReviewsCount + price:@"" + discount:0 + smartDeal:NO + onAddReview:^{ + [MWMPlacePageManagerHelper showUGCAddReview:MWMRatingSummaryViewValueTypeNoValue + fromPreview:YES]; + }]; } return reviewCell; } diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.swift b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.swift index dacc8461ba..dfeddc6b80 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.swift +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.swift @@ -23,10 +23,35 @@ final class PPPReview: MWMTableViewCell { } } - private var onAddReview: (() -> Void)! + @IBOutlet private weak var discountView: UIView! + @IBOutlet private weak var discountLabel: UILabel! + @IBOutlet private weak var priceConstraint: NSLayoutConstraint! - @objc func config(rating: UGCRatingValueType, canAddReview: Bool, reviewsCount: UInt, priceSetter: (UILabel) -> Void, onAddReview: @escaping () -> Void) { + typealias OnAddReview = () -> () + private var onAddReview: OnAddReview? + + @objc func config(rating: UGCRatingValueType, + canAddReview: Bool, + reviewsCount: UInt, + price: String, + discount: Int, + smartDeal: Bool, + onAddReview: OnAddReview?) { self.onAddReview = onAddReview + pricingLabel.text = price + if discount > 0 { + priceConstraint.priority = .defaultLow + discountView.isHidden = false + discountLabel.text = "-\(discount)%" + } else if smartDeal { + priceConstraint.priority = .defaultLow + discountView.isHidden = false + discountLabel.text = "%" + } else { + priceConstraint.priority = .defaultHigh + discountView.isHidden = true + } + ratingSummaryView.textFont = UIFont.bold12() ratingSummaryView.value = rating.value ratingSummaryView.type = rating.type @@ -49,7 +74,6 @@ final class PPPReview: MWMTableViewCell { ratingSummaryView.noValueColor = UIColor.linkBlue() reviewsLabel.text = L("placepage_reviewed") pricingLabel.isHidden = false - priceSetter(pricingLabel) } } else { ratingSummaryView.defaultConfig() @@ -62,12 +86,11 @@ final class PPPReview: MWMTableViewCell { reviewsLabel.isHidden = true } pricingLabel.isHidden = false - priceSetter(pricingLabel) } } @IBAction private func addReview() { - onAddReview() + onAddReview?() } override func layoutSubviews() { diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.xib b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.xib index 4ee6b62f5f..82c92d69c8 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.xib +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/Preview/PPPReview.xib @@ -1,11 +1,11 @@ - + - + @@ -18,8 +18,8 @@ - - + + @@ -50,14 +50,22 @@ - - + + + - + - - + + + @@ -104,6 +137,9 @@ + + + diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp index 74182e2fd7..ca23e3a658 100644 --- a/partners_api/booking_api.hpp +++ b/partners_api/booking_api.hpp @@ -51,7 +51,7 @@ struct HotelInfo struct Deals { - enum Type + enum class Type { /// Good price. Smart, @@ -88,6 +88,11 @@ struct Blocks m_totalMinPrice = block.m_minPrice; m_currency = block.m_currency; } + if (!m_hasSmartDeal) + { + auto const & types = block.m_deals.m_types; + m_hasSmartDeal = std::find(types.cbegin(), types.cend(), Deals::Type::Smart) != types.cend(); + } if (block.m_deals.m_discount > m_maxDiscount) m_maxDiscount = block.m_deals.m_discount; @@ -98,6 +103,7 @@ struct Blocks std::string m_currency; uint8_t m_maxDiscount = 0; + bool m_hasSmartDeal = false; std::vector m_blocks; };