[iOS] [refactoring] place page UI

This commit is contained in:
Aleksey Belouosv 2019-12-04 03:37:52 +03:00 committed by Alexander Boriskov
parent c46c2e25f7
commit b763eb5126
45 changed files with 5329 additions and 314 deletions

View file

@ -760,8 +760,7 @@ using namespace std;
#pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(location::GpsInfo const &)info {
CLLocation *location = [[CLLocation alloc] initWithLatitude:info.m_latitude longitude:info.m_longitude];
- (void)onLocationUpdate:(CLLocation *)location {
[self.tableView.visibleCells enumerateObjectsUsingBlock:^(UITableViewCell *cell, NSUInteger idx, BOOL *stop) {
auto const indexPath = [self.tableView indexPathForCell:cell];
auto const &section = [self currentSections][indexPath.section];

View file

@ -98,7 +98,7 @@ final class EditOnWebViewController: MWMViewController {
private func presentSharingOptions() {
guard let url = MWMBookmarksManager.shared().webEditorUrl(forCategoryId: category.categoryId,
language: AppInfo.shared()?.twoLetterLanguageId ?? "en") else {
language: AppInfo.shared().twoLetterLanguageId ) else {
assert(false, "Unexpected empty url for category \(category.title)")
return
}

View file

@ -4,7 +4,7 @@ final class TagsDataSource: NSObject {
private var maxTagsNumber: Int = 0
func loadTags(onComplete: @escaping (Bool) -> Void) {
MWMBookmarksManager.shared().loadTags(withLanguage: AppInfo.shared()?.twoLetterLanguageId) { tags, maxTagsNumber in
MWMBookmarksManager.shared().loadTags(withLanguage: AppInfo.shared().twoLetterLanguageId) { tags, maxTagsNumber in
if let tags = tags {
self.tagGroups = tags
self.maxTagsNumber = maxTagsNumber

View file

@ -26,6 +26,7 @@
#import "FacebookNativeAdAdapter.h"
#import "CoreNotificationWrapper.h"
#import "MapViewController.h"
#import "MWMActionBarButton.h"
#import "MWMActivityViewController.h"
#import "MWMAlertViewController.h"
#import "MWMAvailableAreaAffectDirection.h"

View file

@ -10,7 +10,7 @@
self.tintColor = [UIColor colorWithName:colorName];
}
- (void) setBorderColorName:(NSString*) colorName {
- (void)setBorderColorName:(NSString *)colorName {
self.layer.borderColor = [UIColor colorWithName:colorName].CGColor;
}

View file

@ -1,6 +1,6 @@
import UIKit
@IBDesignable final class RatingSummaryView: UIView {
final class RatingSummaryView: UIView {
@IBInspectable var value: String = RatingSummaryViewSettings.Default.value {
didSet {
guard oldValue != value else { return }

View file

@ -25,5 +25,5 @@
#pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo { [self close:self.rightButtonAction]; }
- (void)onLocationUpdate:(CLLocation *)location { [self close:self.rightButtonAction]; }
@end

View file

@ -10,6 +10,7 @@
#import "MapViewController.h"
#import "SwiftBridge.h"
#import "UIImageView+Coloring.h"
#import "location_util.h"
#include "geometry/angles.hpp"
@ -339,20 +340,21 @@ BOOL defaultOrientation(CGSize const & size)
#pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo
- (void)onLocationUpdate:(CLLocation *)location
{
BOOL const hasLocation = ([MWMLocationManager lastLocation] != nil);
if (self.hasLocation != hasLocation)
[self updateToastView];
}
- (void)onHeadingUpdate:(location::CompassInfo const &)info
- (void)onHeadingUpdate:(CLHeading *)heading
{
auto transform = CATransform3DIdentity;
auto lastLocation = [MWMLocationManager lastLocation];
if (lastLocation && self.state == MWMNavigationInfoViewStateNavigation &&
[MWMRouter type] == MWMRouterTypePedestrian)
{
auto const info = location_util::compassInfoFromHeading(heading);
auto const angle = ang::AngleTo(lastLocation.mercator,
self.navigationInfo.pedestrianDirectionPosition.mercator);
transform = CATransform3DMakeRotation(M_PI_2 - angle - info.m_bearing, 0, 0, 1);

View file

@ -21,6 +21,7 @@
#include <CoreApi/Framework.h>
#import <CoreApi/MWMFrameworkHelper.h>
#import <CoreApi/PlacePageData.h>
#include "drape_frontend/user_event_stream.hpp"
@ -98,6 +99,7 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
@property(nonatomic) BOOL needDeferFocusNotification;
@property(nonatomic) BOOL deferredFocusValue;
@property(nonatomic) PlacePageViewController *placePageVC;
@end
@ -108,7 +110,15 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
#pragma mark - Map Navigation
- (void)dismissPlacePage { [self.controlsManager dismissPlacePage]; }
- (void)dismissPlacePage {
[self.placePageVC.view removeFromSuperview];
[self.placePageVC willMoveToParentViewController:nil];
[self.placePageVC removeFromParentViewController];
self.placePageVC = nil;
// [self dismissViewControllerAnimated:YES completion:nil];
// [self.controlsManager dismissPlacePage];
}
- (void)onMapObjectDeselected:(bool)switchFullScreenMode
{
[self dismissPlacePage];
@ -127,12 +137,26 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
}
- (void)onMapObjectSelected {
self.controlsManager.hidden = NO;
[self.controlsManager showPlacePage];
[self dismissPlacePage];
self.placePageVC = (PlacePageViewController *)[[UIStoryboard instance:MWMStoryboardPlacePage] instantiateInitialViewController];
self.placePageVC.placePageData = [[PlacePageData alloc] init];
[self addChildViewController:self.placePageVC];
[self.view addSubview:self.placePageVC.view];
self.placePageVC.view.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.placePageVC.view.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.placePageVC.view.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
[self.placePageVC.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[self.placePageVC.view.rightAnchor constraintEqualToAnchor:self.view.rightAnchor]
]];
[self.placePageVC didMoveToParentViewController:self];
// [self presentViewController:placePageVC animated:YES completion:nil];
// self.controlsManager.hidden = NO;
// [self.controlsManager showPlacePage];
}
- (void)onMapObjectUpdated {
[self.controlsManager updatePlacePage];
// [self.controlsManager updatePlacePage];
}
- (void)checkMaskedPointer:(UITouch *)touch withEvent:(df::TouchEvent &)e

View file

@ -238,7 +238,7 @@
#pragma mark - MWMLocationObserver implementation
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo {
- (void)onLocationUpdate:(CLLocation *)location {
NSMutableArray<NSString *> * turnNotifications = [NSMutableArray array];
std::vector<std::string> notifications;
self.rm.GenerateNotifications(notifications);

View file

@ -1,6 +1,5 @@
#import "MWMMyPositionMode.h"
@protocol MWMLocationObserver;
#import "MWMLocationObserver.h"
@interface MWMLocationManager : NSObject
@ -8,8 +7,8 @@
+ (void)stop;
+ (BOOL)isStarted;
+ (void)addObserver:(id<MWMLocationObserver>)observer;
+ (void)removeObserver:(id<MWMLocationObserver>)observer;
+ (void)addObserver:(id<MWMLocationObserver>)observer NS_SWIFT_NAME(add(observer:));
+ (void)removeObserver:(id<MWMLocationObserver>)observer NS_SWIFT_NAME(remove(observer:));
+ (void)setMyPositionMode:(MWMMyPositionMode)mode;

View file

@ -5,6 +5,7 @@
#import "MWMRouter.h"
#import "MapsAppDelegate.h"
#import "SwiftBridge.h"
#import "location_util.h"
#include <CoreApi/Framework.h>
@ -15,42 +16,6 @@ namespace
using Observer = id<MWMLocationObserver>;
using Observers = NSHashTable<Observer>;
location::GpsInfo gpsInfoFromLocation(CLLocation * l, location::TLocationSource source)
{
location::GpsInfo info;
info.m_source = source;
info.m_latitude = l.coordinate.latitude;
info.m_longitude = l.coordinate.longitude;
info.m_timestamp = l.timestamp.timeIntervalSince1970;
if (l.horizontalAccuracy >= 0.0)
info.m_horizontalAccuracy = l.horizontalAccuracy;
if (l.verticalAccuracy >= 0.0)
{
info.m_verticalAccuracy = l.verticalAccuracy;
info.m_altitude = l.altitude;
}
if (l.course >= 0.0)
info.m_bearing = l.course;
if (l.speed >= 0.0)
info.m_speedMpS = l.speed;
return info;
}
location::CompassInfo compassInfoFromHeading(CLHeading * h)
{
location::CompassInfo info;
if (h.trueHeading >= 0.0)
info.m_bearing = base::DegToRad(h.trueHeading);
else if (h.headingAccuracy >= 0.0)
info.m_bearing = base::DegToRad(h.magneticHeading);
return info;
}
typedef NS_OPTIONS(NSUInteger, MWMLocationFrameworkUpdate) {
MWMLocationFrameworkUpdateNone = 0,
MWMLocationFrameworkUpdateLocation = 1 << 0,
@ -160,7 +125,7 @@ void setShowLocationAlert(BOOL needShow) {
@property(nonatomic) GeoMode geoMode;
@property(nonatomic) CLHeading * lastHeadingInfo;
@property(nonatomic) CLLocation * lastLocationInfo;
@property(nonatomic) location::TLocationError lastLocationStatus;
@property(nonatomic) MWMLocationStatus lastLocationStatus;
@property(nonatomic) MWMLocationPredictor * predictor;
@property(nonatomic) Observers * observers;
@property(nonatomic) MWMLocationFrameworkUpdate frameworkUpdateMode;
@ -252,7 +217,7 @@ void setShowLocationAlert(BOOL needShow) {
MWMLocationManager * manager = [self manager];
if (!manager.started || !manager.lastLocationInfo ||
manager.lastLocationInfo.horizontalAccuracy < 0 ||
manager.lastLocationStatus != location::TLocationError::ENoError)
manager.lastLocationStatus != MWMLocationStatusNoError)
return nil;
return manager.lastLocationInfo;
}
@ -260,8 +225,8 @@ void setShowLocationAlert(BOOL needShow) {
+ (BOOL)isLocationProhibited
{
auto const status = [self manager].lastLocationStatus;
return status == location::TLocationError::EDenied ||
status == location::TLocationError::EGPSIsOff;
return status == MWMLocationStatusDenied ||
status == MWMLocationStatusGPSIsOff;
}
+ (CLHeading *)lastHeading
@ -274,10 +239,10 @@ void setShowLocationAlert(BOOL needShow) {
#pragma mark - Observer notifications
- (void)processLocationStatus:(location::TLocationError)locationError
- (void)processLocationStatus:(MWMLocationStatus)locationError
{
self.lastLocationStatus = locationError;
if (self.lastLocationStatus != location::TLocationError::ENoError)
if (self.lastLocationStatus != MWMLocationStatusNoError)
self.frameworkUpdateMode |= MWMLocationFrameworkUpdateStatus;
for (Observer observer in self.observers)
{
@ -290,17 +255,17 @@ void setShowLocationAlert(BOOL needShow) {
{
self.lastHeadingInfo = headingInfo;
self.frameworkUpdateMode |= MWMLocationFrameworkUpdateHeading;
location::CompassInfo const compassInfo = compassInfoFromHeading(headingInfo);
// location::CompassInfo const compassInfo = compassInfoFromHeading(headingInfo);
for (Observer observer in self.observers)
{
if ([observer respondsToSelector:@selector(onHeadingUpdate:)])
[observer onHeadingUpdate:compassInfo];
[observer onHeadingUpdate:headingInfo];
}
}
- (void)processLocationUpdate:(CLLocation *)locationInfo
{
if (!locationInfo || self.lastLocationStatus != location::TLocationError::ENoError)
if (!locationInfo || self.lastLocationStatus != MWMLocationStatusNoError)
return;
[self onLocationUpdate:locationInfo source:self.locationSource];
if (![self.lastLocationInfo isEqual:locationInfo])
@ -309,7 +274,7 @@ void setShowLocationAlert(BOOL needShow) {
- (void)onLocationUpdate:(CLLocation *)locationInfo source:(location::TLocationSource)source
{
location::GpsInfo const gpsInfo = gpsInfoFromLocation(locationInfo, source);
location::GpsInfo const gpsInfo = location_util::gpsInfoFromLocation(locationInfo, source);
GpsTracker::Instance().OnLocationUpdated(gpsInfo);
self.lastLocationInfo = locationInfo;
@ -318,23 +283,23 @@ void setShowLocationAlert(BOOL needShow) {
for (Observer observer in self.observers)
{
if ([observer respondsToSelector:@selector(onLocationUpdate:)])
[observer onLocationUpdate:gpsInfo];
[observer onLocationUpdate:locationInfo];
}
}
#pragma mark - Location Status
- (void)setLastLocationStatus:(location::TLocationError)lastLocationStatus
- (void)setLastLocationStatus:(MWMLocationStatus)lastLocationStatus
{
_lastLocationStatus = lastLocationStatus;
switch (lastLocationStatus)
{
case location::ENoError: break;
case location::ENotSupported:
case MWMLocationStatusNoError: break;
case MWMLocationStatusNotSupported:
[[MWMAlertViewController activeAlertController] presentLocationServiceNotSupportedAlert];
break;
case location::EDenied:
case location::EGPSIsOff:
case MWMLocationStatusDenied:
case MWMLocationStatusGPSIsOff:
if (needShowLocationAlert()) {
[[MWMAlertViewController activeAlertController] presentLocationAlertWithCancelBlock:^{
setShowLocationAlert(NO);
@ -465,15 +430,15 @@ void setShowLocationAlert(BOOL needShow) {
if (location.horizontalAccuracy < 0.)
return;
self.lastLocationStatus = location::TLocationError::ENoError;
self.lastLocationStatus = MWMLocationStatusNoError;
self.locationSource = location::EAppleNative;
[self processLocationUpdate:location];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if (self.lastLocationStatus == location::TLocationError::ENoError && error.code == kCLErrorDenied)
[self processLocationStatus:location::EDenied];
if (self.lastLocationStatus == MWMLocationStatusNoError && error.code == kCLErrorDenied)
[self processLocationStatus:MWMLocationStatusDenied];
}
#pragma mark - Start / Stop
@ -528,12 +493,12 @@ void setShowLocationAlert(BOOL needShow) {
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusNotDetermined: doStart(); return YES;
case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied: [self processLocationStatus:location::EDenied]; break;
case kCLAuthorizationStatusDenied: [self processLocationStatus:MWMLocationStatusDenied]; break;
}
}
else
{
[self processLocationStatus:location::EGPSIsOff];
[self processLocationStatus:MWMLocationStatusGPSIsOff];
}
return NO;
}
@ -561,13 +526,13 @@ void setShowLocationAlert(BOOL needShow) {
if (self.frameworkUpdateMode & MWMLocationFrameworkUpdateLocation)
{
location::GpsInfo const gpsInfo =
gpsInfoFromLocation(self.lastLocationInfo, self.locationSource);
location_util::gpsInfoFromLocation(self.lastLocationInfo, self.locationSource);
f.OnLocationUpdate(gpsInfo);
}
if (self.frameworkUpdateMode & MWMLocationFrameworkUpdateHeading)
f.OnCompassUpdate(compassInfoFromHeading(self.lastHeadingInfo));
f.OnCompassUpdate(location_util::compassInfoFromHeading(self.lastHeadingInfo));
if (self.frameworkUpdateMode & MWMLocationFrameworkUpdateStatus)
f.OnLocationError(self.lastLocationStatus);
f.OnLocationError((location::TLocationError)self.lastLocationStatus);
self.frameworkUpdateMode = MWMLocationFrameworkUpdateNone;
}
else

View file

@ -1,10 +1,21 @@
#include "platform/location.hpp"
//#include "platform/location.hpp"
typedef NS_ENUM(NSInteger, MWMLocationStatus) {
MWMLocationStatusNoError,
MWMLocationStatusNotSupported,
MWMLocationStatusDenied,
MWMLocationStatusGPSIsOff
};
NS_ASSUME_NONNULL_BEGIN
@protocol MWMLocationObserver<NSObject>
@optional
- (void)onHeadingUpdate:(location::CompassInfo const &)compassinfo;
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo;
- (void)onLocationError:(location::TLocationError)locationError;
- (void)onHeadingUpdate:(CLHeading *)heading;
- (void)onLocationUpdate:(CLLocation *)location;
- (void)onLocationError:(MWMLocationStatus)locationError;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,41 @@
#pragma once
namespace location_util {
static location::GpsInfo gpsInfoFromLocation(CLLocation * l, location::TLocationSource source)
{
location::GpsInfo info;
info.m_source = source;
info.m_latitude = l.coordinate.latitude;
info.m_longitude = l.coordinate.longitude;
info.m_timestamp = l.timestamp.timeIntervalSince1970;
if (l.horizontalAccuracy >= 0.0)
info.m_horizontalAccuracy = l.horizontalAccuracy;
if (l.verticalAccuracy >= 0.0)
{
info.m_verticalAccuracy = l.verticalAccuracy;
info.m_altitude = l.altitude;
}
if (l.course >= 0.0)
info.m_bearing = l.course;
if (l.speed >= 0.0)
info.m_speedMpS = l.speed;
return info;
}
static location::CompassInfo compassInfoFromHeading(CLHeading * h)
{
location::CompassInfo info;
if (h.trueHeading >= 0.0)
info.m_bearing = base::DegToRad(h.trueHeading);
else if (h.headingAccuracy >= 0.0)
info.m_bearing = base::DegToRad(h.magneticHeading);
return info;
}
} // namespace location_util

View file

@ -612,7 +612,7 @@ void logPointEvent(MWMRoutePoint * point, NSString * eventType)
#pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(location::GpsInfo const &)info
- (void)onLocationUpdate:(CLLocation *)location
{
if (![MWMRouter isRoutingActive])
return;

View file

@ -344,10 +344,13 @@
45FFD65D1E965EBE00DB854E /* liblocal_ads.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 45FFD65C1E965EBE00DB854E /* liblocal_ads.a */; };
4707E4B12372FE860017DF6E /* PlacePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707E4AF2372FE860017DF6E /* PlacePageViewController.swift */; };
4707E4B42372FF480017DF6E /* PlacePage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707E4B32372FF480017DF6E /* PlacePage.storyboard */; };
4707E4B62375B2900017DF6E /* PlacePageInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707E4B52375B2900017DF6E /* PlacePageInfoViewController.swift */; };
4707E4B62375B2900017DF6E /* PlacePagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707E4B52375B2900017DF6E /* PlacePagePreviewViewController.swift */; };
470A89FD21342A9D00D72FBF /* TutorialBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470A89FC21342A9D00D72FBF /* TutorialBlurView.swift */; };
470A89FF2134517600D72FBF /* BookmarksTutorialBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = 470A89FE2134517600D72FBF /* BookmarksTutorialBlur.xib */; };
470A8A012136097000D72FBF /* SubwayTutorialBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = 470A8A002136073000D72FBF /* SubwayTutorialBlur.xib */; };
470F0B7A23882955006AEC94 /* PlacePageReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470F0B7923882955006AEC94 /* PlacePageReviewViewController.swift */; };
470F0B7D238842EA006AEC94 /* ExpandableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470F0B7C238842EA006AEC94 /* ExpandableLabel.swift */; };
470F0B7F2388431E006AEC94 /* StarRatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470F0B7E2388431E006AEC94 /* StarRatingView.swift */; };
470F5A5B2181DE7500754295 /* PaidRouteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470F5A592181DE7400754295 /* PaidRouteViewController.swift */; };
470F5A5C2181DE7500754295 /* PaidRouteViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 470F5A5A2181DE7400754295 /* PaidRouteViewController.xib */; };
470F5A7D2189BB2F00754295 /* PaidRoutePurchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470F5A7C2189BB2F00754295 /* PaidRoutePurchase.swift */; };
@ -364,6 +367,12 @@
471C448C2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471C448A2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift */; };
471C448D2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 471C448B2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib */; };
4726254921C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4726254821C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift */; };
472848F72383F8F700176158 /* WikiDescriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472848F62383F8F600176158 /* WikiDescriptionViewController.swift */; };
472848F92384CEC900176158 /* TaxiViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472848F82384CEC900176158 /* TaxiViewController.swift */; };
472848FB238573EE00176158 /* RatingSummaryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472848FA238573EE00176158 /* RatingSummaryViewController.swift */; };
472848FD2386A17500176158 /* AddReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472848FC2386A17300176158 /* AddReviewViewController.swift */; };
472848FF2386BE6E00176158 /* PlacePageReviewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472848FE2386BE6E00176158 /* PlacePageReviewsViewController.swift */; };
472849012388098300176158 /* MyReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472849002388098300176158 /* MyReviewViewController.swift */; };
47289E5A2212DFFF002ABFC0 /* EditOnWebAlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47289E582212DFFF002ABFC0 /* EditOnWebAlertViewController.swift */; };
47289E5B2212DFFF002ABFC0 /* EditOnWebAlertViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47289E592212DFFF002ABFC0 /* EditOnWebAlertViewController.xib */; };
4728F69322CF89A400E00028 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4728F69222CF89A400E00028 /* GradientView.swift */; };
@ -378,6 +387,10 @@
474AC76C2139E4F2002F9BF9 /* RemoveAdsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */; };
474AC76D2139E4F2002F9BF9 /* RemoveAdsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */; };
474C9F5A213FF75800369009 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474C9F59213FF75800369009 /* StoreKit.framework */; };
475EFDBB238FDDB200A24B4C /* CatalogSingleItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EFDBA238FDDB200A24B4C /* CatalogSingleItemViewController.swift */; };
475EFDBD239002D700A24B4C /* CatalogGalleryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EFDBC239002D700A24B4C /* CatalogGalleryViewController.swift */; };
475EFDBF239031CD00A24B4C /* PlacePageBookmarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EFDBE239031CD00A24B4C /* PlacePageBookmarkViewController.swift */; };
475EFDC123907DAA00A24B4C /* OpeningHoursViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EFDC023907DAA00A24B4C /* OpeningHoursViewController.swift */; };
4767CD9F20AAD48A00BD8166 /* Checkmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CD9E20AAD48A00BD8166 /* Checkmark.swift */; };
4767CDA420AAF66B00BD8166 /* NSAttributedString+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CDA320AAF66B00BD8166 /* NSAttributedString+HTML.swift */; };
4767CDA620AB1F6200BD8166 /* LeftAlignedIconButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CDA520AB1F6200BD8166 /* LeftAlignedIconButton.swift */; };
@ -392,12 +405,17 @@
4788738F20EE30B300F6826B /* LayersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4788738D20EE30B300F6826B /* LayersViewController.swift */; };
4788739020EE30B300F6826B /* LayersViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4788738E20EE30B300F6826B /* LayersViewController.xib */; };
4788739220EE326500F6826B /* VerticallyAlignedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4788739120EE326400F6826B /* VerticallyAlignedButton.swift */; };
479388F92395A4D3006ECACC /* ActionBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479388F82395A4D3006ECACC /* ActionBarViewController.swift */; };
479D305722C627CB00D18278 /* MWMMegafonBannerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 479D305522C627CB00D18278 /* MWMMegafonBannerViewController.xib */; };
479D305B22C62F4000D18278 /* MWMBookmarksBannerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 479D305922C62F4000D18278 /* MWMBookmarksBannerViewController.xib */; };
479D306122C6634900D18278 /* MWMMegafonBannerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 479D305F22C6634900D18278 /* MWMMegafonBannerViewController.m */; };
479D306522C664CE00D18278 /* MWMDownloadBannerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 479D306422C664CE00D18278 /* MWMDownloadBannerViewController.m */; };
479D306822C66C8F00D18278 /* MWMBookmarksBannerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 479D306722C66C8F00D18278 /* MWMBookmarksBannerViewController.m */; };
479EE94A2292FB03009DEBA6 /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479EE9492292FB03009DEBA6 /* ActivityIndicator.swift */; };
47A0416D238DBB6200D84E95 /* HotelPhotosViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A0416C238DBB6200D84E95 /* HotelPhotosViewController.swift */; };
47A0416F238DD0FD00D84E95 /* HotelDescriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A0416E238DD0FD00D84E95 /* HotelDescriptionViewController.swift */; };
47A04171238DE8AE00D84E95 /* HotelFacilitiesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A04170238DE8AE00D84E95 /* HotelFacilitiesViewController.swift */; };
47A04173238E989200D84E95 /* HotelReviewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A04172238E989200D84E95 /* HotelReviewsViewController.swift */; };
47A65CAD2350044800DCD85F /* CoreApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47A65CAC2350044800DCD85F /* CoreApi.framework */; };
47A6F3C4235F47B90053FBA4 /* BookmarksSubscriptionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47A6F3C1235F47B90053FBA4 /* BookmarksSubscriptionViewController.xib */; };
47A6F3C5235F47B90053FBA4 /* BookmarksSubscriptionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A6F3C2235F47B90053FBA4 /* BookmarksSubscriptionButton.swift */; };
@ -439,12 +457,14 @@
47E6CB0B2178BA3600EA102B /* SearchBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47E6CB092178BA3600EA102B /* SearchBannerCell.swift */; };
47E6CB0C2178BA3600EA102B /* SearchBannerCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47E6CB0A2178BA3600EA102B /* SearchBannerCell.xib */; };
47E8163323B17734008FD836 /* MWMStorage+UI.m in Sources */ = {isa = PBXBuildFile; fileRef = 47E8163223B17734008FD836 /* MWMStorage+UI.m */; };
47E98C102382C80600C800E0 /* PlacePageInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47E98C0F2382C80600C800E0 /* PlacePageInfoViewController.swift */; };
47EF05B321504D8F00EAC269 /* RemoveAdsPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EF05B221504D8F00EAC269 /* RemoveAdsPresentationController.swift */; };
47F4F21323A6EC420022FD56 /* DownloadMapsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */; };
47F4F21523A6F06F0022FD56 /* AvailableMapsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */; };
47F67D1521CAB21B0069754E /* MWMImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 47F67D1421CAB21B0069754E /* MWMImageCoder.m */; };
47F6E51221F61908004580CA /* CoreNotificationWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47F6E51121F61908004580CA /* CoreNotificationWrapper.mm */; };
47F6E51721FB3C51004580CA /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F6E51621FB3C51004580CA /* Notifications.swift */; };
47F701F6238C8A8300D18E95 /* PlacePageButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F701F5238C8A8300D18E95 /* PlacePageButtonsViewController.swift */; };
47F86CFF20C936FC00FEE291 /* TabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F86CFE20C936FC00FEE291 /* TabView.swift */; };
47F86D0120C93D8D00FEE291 /* TabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F86D0020C93D8D00FEE291 /* TabViewController.swift */; };
47FA14D1230D52FC003DA979 /* PhoneNumberAuthorizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FA14D0230D52FC003DA979 /* PhoneNumberAuthorizationViewController.swift */; };
@ -768,7 +788,7 @@
F6E2FE461E097BA00083EBEC /* MWMDirectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC961E097B9F0083EBEC /* MWMDirectionView.xib */; };
F6E2FE491E097BA00083EBEC /* MWMPlacePageData.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC981E097B9F0083EBEC /* MWMPlacePageData.mm */; };
F6E2FE4C1E097BA00083EBEC /* MWMPlacePageManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC9A1E097B9F0083EBEC /* MWMPlacePageManager.mm */; };
F6E2FE4F1E097BA00083EBEC /* MWMActionBarButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.mm */; };
F6E2FE4F1E097BA00083EBEC /* MWMActionBarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.m */; };
F6E2FE521E097BA00083EBEC /* MWMActionBarButton.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FCA01E097B9F0083EBEC /* MWMActionBarButton.xib */; };
F6E2FE551E097BA00083EBEC /* MWMPlacePageActionBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCA21E097B9F0083EBEC /* MWMPlacePageActionBar.mm */; };
F6E2FE581E097BA00083EBEC /* MWMPlacePageActionBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FCA31E097B9F0083EBEC /* MWMPlacePageActionBar.xib */; };
@ -1422,10 +1442,13 @@
46F8A2EB10EB63040045521A /* MapViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MapViewController.h; sourceTree = "<group>"; };
4707E4AF2372FE860017DF6E /* PlacePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageViewController.swift; sourceTree = "<group>"; };
4707E4B32372FF480017DF6E /* PlacePage.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PlacePage.storyboard; sourceTree = "<group>"; };
4707E4B52375B2900017DF6E /* PlacePageInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageInfoViewController.swift; sourceTree = "<group>"; };
4707E4B52375B2900017DF6E /* PlacePagePreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePagePreviewViewController.swift; sourceTree = "<group>"; };
470A89FC21342A9D00D72FBF /* TutorialBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialBlurView.swift; sourceTree = "<group>"; };
470A89FE2134517600D72FBF /* BookmarksTutorialBlur.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BookmarksTutorialBlur.xib; sourceTree = "<group>"; };
470A8A002136073000D72FBF /* SubwayTutorialBlur.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SubwayTutorialBlur.xib; sourceTree = "<group>"; };
470F0B7923882955006AEC94 /* PlacePageReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageReviewViewController.swift; sourceTree = "<group>"; };
470F0B7C238842EA006AEC94 /* ExpandableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableLabel.swift; sourceTree = "<group>"; };
470F0B7E2388431E006AEC94 /* StarRatingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarRatingView.swift; sourceTree = "<group>"; };
470F5A592181DE7400754295 /* PaidRouteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaidRouteViewController.swift; sourceTree = "<group>"; };
470F5A5A2181DE7400754295 /* PaidRouteViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PaidRouteViewController.xib; sourceTree = "<group>"; };
470F5A7C2189BB2F00754295 /* PaidRoutePurchase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaidRoutePurchase.swift; sourceTree = "<group>"; };
@ -1443,6 +1466,12 @@
471C448A2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionGoToCatalogViewController.swift; sourceTree = "<group>"; };
471C448B2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SubscriptionGoToCatalogViewController.xib; sourceTree = "<group>"; };
4726254821C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageDescriptionViewController.swift; sourceTree = "<group>"; };
472848F62383F8F600176158 /* WikiDescriptionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WikiDescriptionViewController.swift; sourceTree = "<group>"; };
472848F82384CEC900176158 /* TaxiViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaxiViewController.swift; sourceTree = "<group>"; };
472848FA238573EE00176158 /* RatingSummaryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingSummaryViewController.swift; sourceTree = "<group>"; };
472848FC2386A17300176158 /* AddReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReviewViewController.swift; sourceTree = "<group>"; };
472848FE2386BE6E00176158 /* PlacePageReviewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageReviewsViewController.swift; sourceTree = "<group>"; };
472849002388098300176158 /* MyReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyReviewViewController.swift; sourceTree = "<group>"; };
47289E582212DFFF002ABFC0 /* EditOnWebAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditOnWebAlertViewController.swift; sourceTree = "<group>"; };
47289E592212DFFF002ABFC0 /* EditOnWebAlertViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EditOnWebAlertViewController.xib; sourceTree = "<group>"; };
4728F69222CF89A400E00028 /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = CustomViews/GradientView.swift; sourceTree = "<group>"; };
@ -1463,6 +1492,10 @@
474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsViewController.swift; sourceTree = "<group>"; };
474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RemoveAdsViewController.xib; sourceTree = "<group>"; };
474C9F59213FF75800369009 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
475EFDBA238FDDB200A24B4C /* CatalogSingleItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSingleItemViewController.swift; sourceTree = "<group>"; };
475EFDBC239002D700A24B4C /* CatalogGalleryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogGalleryViewController.swift; sourceTree = "<group>"; };
475EFDBE239031CD00A24B4C /* PlacePageBookmarkViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageBookmarkViewController.swift; sourceTree = "<group>"; };
475EFDC023907DAA00A24B4C /* OpeningHoursViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpeningHoursViewController.swift; sourceTree = "<group>"; };
4767CD9E20AAD48A00BD8166 /* Checkmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkmark.swift; sourceTree = "<group>"; };
4767CDA320AAF66B00BD8166 /* NSAttributedString+HTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+HTML.swift"; sourceTree = "<group>"; };
4767CDA520AB1F6200BD8166 /* LeftAlignedIconButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftAlignedIconButton.swift; sourceTree = "<group>"; };
@ -1479,6 +1512,7 @@
4788738D20EE30B300F6826B /* LayersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayersViewController.swift; sourceTree = "<group>"; };
4788738E20EE30B300F6826B /* LayersViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LayersViewController.xib; sourceTree = "<group>"; };
4788739120EE326400F6826B /* VerticallyAlignedButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticallyAlignedButton.swift; sourceTree = "<group>"; };
479388F82395A4D3006ECACC /* ActionBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionBarViewController.swift; sourceTree = "<group>"; };
4797A4DB226F4B2900D3A984 /* DeepLinkHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkHandler.swift; sourceTree = "<group>"; };
479D305522C627CB00D18278 /* MWMMegafonBannerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MWMMegafonBannerViewController.xib; sourceTree = "<group>"; };
479D305922C62F4000D18278 /* MWMBookmarksBannerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MWMBookmarksBannerViewController.xib; sourceTree = "<group>"; };
@ -1489,6 +1523,10 @@
479D306622C66C8F00D18278 /* MWMBookmarksBannerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMBookmarksBannerViewController.h; sourceTree = "<group>"; };
479D306722C66C8F00D18278 /* MWMBookmarksBannerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMBookmarksBannerViewController.m; sourceTree = "<group>"; };
479EE9492292FB03009DEBA6 /* ActivityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ActivityIndicator.swift; path = CustomViews/ActivityIndicator.swift; sourceTree = "<group>"; };
47A0416C238DBB6200D84E95 /* HotelPhotosViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotelPhotosViewController.swift; sourceTree = "<group>"; };
47A0416E238DD0FD00D84E95 /* HotelDescriptionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotelDescriptionViewController.swift; sourceTree = "<group>"; };
47A04170238DE8AE00D84E95 /* HotelFacilitiesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotelFacilitiesViewController.swift; sourceTree = "<group>"; };
47A04172238E989200D84E95 /* HotelReviewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotelReviewsViewController.swift; sourceTree = "<group>"; };
47A65CAC2350044800DCD85F /* CoreApi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreApi.framework; sourceTree = BUILT_PRODUCTS_DIR; };
47A6F3C1235F47B90053FBA4 /* BookmarksSubscriptionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BookmarksSubscriptionViewController.xib; sourceTree = "<group>"; };
47A6F3C2235F47B90053FBA4 /* BookmarksSubscriptionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksSubscriptionButton.swift; sourceTree = "<group>"; };
@ -1539,6 +1577,7 @@
47E6CB0A2178BA3600EA102B /* SearchBannerCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchBannerCell.xib; sourceTree = "<group>"; };
47E8163123B17734008FD836 /* MWMStorage+UI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMStorage+UI.h"; sourceTree = "<group>"; };
47E8163223B17734008FD836 /* MWMStorage+UI.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MWMStorage+UI.m"; sourceTree = "<group>"; };
47E98C0F2382C80600C800E0 /* PlacePageInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageInfoViewController.swift; sourceTree = "<group>"; };
47EF05B221504D8F00EAC269 /* RemoveAdsPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsPresentationController.swift; sourceTree = "<group>"; };
47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadMapsViewController.swift; sourceTree = "<group>"; };
47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableMapsDataSource.swift; sourceTree = "<group>"; };
@ -1550,6 +1589,8 @@
47F6E51121F61908004580CA /* CoreNotificationWrapper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreNotificationWrapper.mm; sourceTree = "<group>"; };
47F6E51321F61974004580CA /* CoreNotificationWrapper+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CoreNotificationWrapper+Core.h"; sourceTree = "<group>"; };
47F6E51621FB3C51004580CA /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
47F701EC238C2F8400D18E95 /* location_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = location_util.h; sourceTree = "<group>"; };
47F701F5238C8A8300D18E95 /* PlacePageButtonsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageButtonsViewController.swift; sourceTree = "<group>"; };
47F86CFE20C936FC00FEE291 /* TabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabView.swift; sourceTree = "<group>"; };
47F86D0020C93D8D00FEE291 /* TabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabViewController.swift; sourceTree = "<group>"; };
47FA14D0230D52FC003DA979 /* PhoneNumberAuthorizationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberAuthorizationViewController.swift; sourceTree = "<group>"; };
@ -1983,7 +2024,7 @@
F6E2FC9A1E097B9F0083EBEC /* MWMPlacePageManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPlacePageManager.mm; sourceTree = "<group>"; };
F6E2FC9B1E097B9F0083EBEC /* MWMPlacePageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMPlacePageProtocol.h; sourceTree = "<group>"; };
F6E2FC9E1E097B9F0083EBEC /* MWMActionBarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMActionBarButton.h; sourceTree = "<group>"; };
F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMActionBarButton.mm; sourceTree = "<group>"; };
F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMActionBarButton.m; sourceTree = "<group>"; };
F6E2FCA01E097B9F0083EBEC /* MWMActionBarButton.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMActionBarButton.xib; sourceTree = "<group>"; };
F6E2FCA11E097B9F0083EBEC /* MWMPlacePageActionBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMPlacePageActionBar.h; sourceTree = "<group>"; };
F6E2FCA21E097B9F0083EBEC /* MWMPlacePageActionBar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMPlacePageActionBar.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@ -2543,6 +2584,7 @@
3404752E1E081A4600C92850 /* MWMLocationPredictor.h */,
3404752F1E081A4600C92850 /* MWMLocationPredictor.mm */,
3486B5031E27948F0069C126 /* MWMMyPositionMode.h */,
47F701EC238C2F8400D18E95 /* location_util.h */,
);
path = Location;
sourceTree = "<group>";
@ -3437,6 +3479,15 @@
path = Promo;
sourceTree = "<group>";
};
470F0B7B238842AD006AEC94 /* Views */ = {
isa = PBXGroup;
children = (
470F0B7C238842EA006AEC94 /* ExpandableLabel.swift */,
470F0B7E2388431E006AEC94 /* StarRatingView.swift */,
);
path = Views;
sourceTree = "<group>";
};
470F5A7B2189BA7200754295 /* InappPurchase */ = {
isa = PBXGroup;
children = (
@ -4421,7 +4472,26 @@
4726254821C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift */,
4707E4AF2372FE860017DF6E /* PlacePageViewController.swift */,
4707E4B32372FF480017DF6E /* PlacePage.storyboard */,
4707E4B52375B2900017DF6E /* PlacePageInfoViewController.swift */,
4707E4B52375B2900017DF6E /* PlacePagePreviewViewController.swift */,
47E98C0F2382C80600C800E0 /* PlacePageInfoViewController.swift */,
472848F62383F8F600176158 /* WikiDescriptionViewController.swift */,
472848F82384CEC900176158 /* TaxiViewController.swift */,
472848FA238573EE00176158 /* RatingSummaryViewController.swift */,
472848FC2386A17300176158 /* AddReviewViewController.swift */,
472848FE2386BE6E00176158 /* PlacePageReviewsViewController.swift */,
472849002388098300176158 /* MyReviewViewController.swift */,
470F0B7923882955006AEC94 /* PlacePageReviewViewController.swift */,
47F701F5238C8A8300D18E95 /* PlacePageButtonsViewController.swift */,
47A0416C238DBB6200D84E95 /* HotelPhotosViewController.swift */,
47A0416E238DD0FD00D84E95 /* HotelDescriptionViewController.swift */,
47A04170238DE8AE00D84E95 /* HotelFacilitiesViewController.swift */,
47A04172238E989200D84E95 /* HotelReviewsViewController.swift */,
475EFDBA238FDDB200A24B4C /* CatalogSingleItemViewController.swift */,
475EFDBC239002D700A24B4C /* CatalogGalleryViewController.swift */,
475EFDBE239031CD00A24B4C /* PlacePageBookmarkViewController.swift */,
479388F82395A4D3006ECACC /* ActionBarViewController.swift */,
470F0B7B238842AD006AEC94 /* Views */,
475EFDC023907DAA00A24B4C /* OpeningHoursViewController.swift */,
);
path = PlacePage;
sourceTree = "<group>";
@ -4460,7 +4530,7 @@
isa = PBXGroup;
children = (
F6E2FC9E1E097B9F0083EBEC /* MWMActionBarButton.h */,
F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.mm */,
F6E2FC9F1E097B9F0083EBEC /* MWMActionBarButton.m */,
F6E2FCA01E097B9F0083EBEC /* MWMActionBarButton.xib */,
F6E2FCA11E097B9F0083EBEC /* MWMPlacePageActionBar.h */,
F6E2FCA21E097B9F0083EBEC /* MWMPlacePageActionBar.mm */,
@ -5303,6 +5373,7 @@
34AB66651FC5AA330078E451 /* TransportTransitTrain.swift in Sources */,
343064411E9FDC7300DC7665 /* SearchIndex.swift in Sources */,
F6664BFA1E6459CB00E703C2 /* PPFacilityCell.swift in Sources */,
475EFDBD239002D700A24B4C /* CatalogGalleryViewController.swift in Sources */,
CDCA273F2238087700167D87 /* MWMCarPlaySearchService.mm in Sources */,
348B926D1FF3B5E100379009 /* UIView+Animation.swift in Sources */,
F6E2FDE91E097BA00083EBEC /* MWMObjectsCategorySelectorController.mm in Sources */,
@ -5325,6 +5396,7 @@
F6E2FDF81E097BA00083EBEC /* MWMOpeningHoursAllDayTableViewCell.mm in Sources */,
472E3F4C2147D5700020E412 /* Subscription.swift in Sources */,
340B33C61F3AEFDB00A8C1B4 /* MWMRouter+RouteManager.mm in Sources */,
472848FF2386BE6E00176158 /* PlacePageReviewsViewController.swift in Sources */,
F6E2FE191E097BA00083EBEC /* MWMOpeningHoursTimeSpanTableViewCell.mm in Sources */,
F6E407D01FC45EF5001F7821 /* MWMDiscoveryController.mm in Sources */,
F6E2FDEC1E097BA00083EBEC /* MWMOpeningHoursAddClosedTableViewCell.mm in Sources */,
@ -5332,6 +5404,7 @@
F6E2FE101E097BA00083EBEC /* MWMOpeningHoursTableViewCell.mm in Sources */,
47C8789D22DF662700A772DA /* SubscriptionExpiredViewController.swift in Sources */,
6741A9B01BF340DE002C974C /* MapsAppDelegate.mm in Sources */,
472848FD2386A17500176158 /* AddReviewViewController.swift in Sources */,
4719A645219CBD65009F9AA7 /* IPendingTransactionsHandler.swift in Sources */,
34F742321E0834F400AC1FD6 /* UIViewController+Navigation.m in Sources */,
340475811E081B3300C92850 /* iosOGLContextFactory.mm in Sources */,
@ -5363,6 +5436,7 @@
3404163C1E7BDFE000E2B6D6 /* PhotosViewController.swift in Sources */,
47E8163323B17734008FD836 /* MWMStorage+UI.m in Sources */,
34AB66471FC5AA330078E451 /* RouteManagerTableView.swift in Sources */,
47E98C102382C80600C800E0 /* PlacePageInfoViewController.swift in Sources */,
47DF72B922520CE20004AB10 /* MWMRoutingOptions.mm in Sources */,
F6E2FE611E097BA00083EBEC /* MWMBookmarkCell.mm in Sources */,
99B6A74E2362F5CD002C94CB /* PromoCoordinator.swift in Sources */,
@ -5376,6 +5450,7 @@
99CB34BF2369EAAC001D28AD /* TermsOfUseViewController.swift in Sources */,
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */,
3404F48B202894EA0090E401 /* BMCViewController.swift in Sources */,
472848FB238573EE00176158 /* RatingSummaryViewController.swift in Sources */,
349D1ABC1E2D05EF004A2006 /* SearchBar.swift in Sources */,
993F5511237C622700545511 /* DeepLinkCatalogueStrategy.swift in Sources */,
34E50DF81F6FCC96008EED49 /* UGCReviewCell.swift in Sources */,
@ -5412,6 +5487,7 @@
34845DAF1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift in Sources */,
CD6E8677226774C700D1EDF7 /* CPConstants.swift in Sources */,
F6791B141C43DF0B007A8A6E /* MWMStartButton.m in Sources */,
47A04171238DE8AE00D84E95 /* HotelFacilitiesViewController.swift in Sources */,
479D306522C664CE00D18278 /* MWMDownloadBannerViewController.m in Sources */,
F6E2FEDF1E097BA00083EBEC /* MWMSearchManager+Layout.m in Sources */,
F64D9CA01C899C350063FA30 /* MWMEditorViralAlert.mm in Sources */,
@ -5420,6 +5496,7 @@
6741A9CF1BF340DE002C974C /* MWMLocationAlert.m in Sources */,
474AC76C2139E4F2002F9BF9 /* RemoveAdsViewController.swift in Sources */,
34ABA62D1C2D57D500FE1BEC /* MWMInputPasswordValidator.m in Sources */,
475EFDBB238FDDB200A24B4C /* CatalogSingleItemViewController.swift in Sources */,
BBED27022292F6C000788143 /* BookmarksSection.mm in Sources */,
F6E2FDA11E097BA00083EBEC /* MWMEditorAdditionalNamesTableViewController.mm in Sources */,
999D3A67237BFA4600C5F7A8 /* SubscriptionViewBuilder.swift in Sources */,
@ -5431,6 +5508,7 @@
34ABA6171C2D185C00FE1BEC /* MWMAuthorizationOSMLoginViewController.mm in Sources */,
991CE2DD2373145C009EB02A /* PromoAfterBookingCampaign.swift in Sources */,
995739042355CAA30019AEE7 /* PageIndicator.swift in Sources */,
470F0B7D238842EA006AEC94 /* ExpandableLabel.swift in Sources */,
B33D21AF20DAF9F000BAD749 /* Toast.swift in Sources */,
33B19C67218B481700B323A7 /* TagCollectionViewCell.swift in Sources */,
6741A9D41BF340DE002C974C /* MWMAlertViewController.mm in Sources */,
@ -5459,6 +5537,7 @@
349D1ACF1E2E325B004A2006 /* MWMBottomMenuCollectionViewCell.m in Sources */,
F6E2FF451E097BA00083EBEC /* SettingsTableViewLinkCell.swift in Sources */,
34C9BD0A1C6DBCDA000DC38D /* MWMNavigationController.m in Sources */,
472848F72383F8F700176158 /* WikiDescriptionViewController.swift in Sources */,
CDB92CF822A5350500EC757C /* MWMDiscoveryHotelViewModel.m in Sources */,
F6550C1F1FD81B3800352D88 /* RatingSummaryView+DefaultConfig.swift in Sources */,
991CE2C02371D349009EB02A /* PromoCampaign.swift in Sources */,
@ -5475,7 +5554,7 @@
F6E2FD8C1E097BA00083EBEC /* MWMNoMapsView.m in Sources */,
34D3B0361E389D05004100F9 /* MWMEditorSelectTableViewCell.m in Sources */,
F6E2FD711E097BA00083EBEC /* MWMMapDownloaderTableViewCell.m in Sources */,
F6E2FE4F1E097BA00083EBEC /* MWMActionBarButton.mm in Sources */,
F6E2FE4F1E097BA00083EBEC /* MWMActionBarButton.m in Sources */,
47F86CFF20C936FC00FEE291 /* TabView.swift in Sources */,
34AB66741FC5AA330078E451 /* BaseRoutePreviewStatus.swift in Sources */,
340475531E081A4600C92850 /* MWMCustomFacebookEvents.mm in Sources */,
@ -5495,11 +5574,15 @@
1DFA2F6A20D3B57400FB2C66 /* UIColor+PartnerColor.m in Sources */,
347BFA901F27909200E5531F /* MenuArea.swift in Sources */,
343E75981E5B1EE20041226A /* MWMCollectionViewController.m in Sources */,
47F701F6238C8A8300D18E95 /* PlacePageButtonsViewController.swift in Sources */,
B3E3B50220D485FA00DA8C13 /* DownloadedBookmarksDataSource.swift in Sources */,
477D7AC7218F1515007EE2CB /* IPaidRoutePurchase.swift in Sources */,
34E776141F14B17F003040B3 /* AvailableArea.swift in Sources */,
475EFDC123907DAA00A24B4C /* OpeningHoursViewController.swift in Sources */,
47A0416D238DBB6200D84E95 /* HotelPhotosViewController.swift in Sources */,
34AB66081FC5AA320078E451 /* MWMNavigationDashboardManager.mm in Sources */,
F6664C131E645A4100E703C2 /* MWMPPReviewCell.mm in Sources */,
47A0416F238DD0FD00D84E95 /* HotelDescriptionViewController.swift in Sources */,
991CE2BF2371D349009EB02A /* PromoCampaignManager.swift in Sources */,
F6E2FE431E097BA00083EBEC /* MWMDirectionView.mm in Sources */,
470F5A5B2181DE7500754295 /* PaidRouteViewController.swift in Sources */,
@ -5608,6 +5691,7 @@
993F550C237C622700545511 /* DeepLinkSubscriptionStrategy.swift in Sources */,
F6E2FD6B1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m in Sources */,
CDCA27842245090900167D87 /* ListenerContainer.swift in Sources */,
475EFDBF239031CD00A24B4C /* PlacePageBookmarkViewController.swift in Sources */,
47E3C7252111E41B008B3B27 /* DimmedModalPresentationController.swift in Sources */,
99CB34CD236B054B001D28AD /* DeepLinkInfoRouter.swift in Sources */,
99CB34B72369E188001D28AD /* WelcomeRouter.swift in Sources */,
@ -5619,6 +5703,7 @@
34FE5A6F1F18F30F00BCA729 /* TrafficButtonArea.swift in Sources */,
F6E2FF691E097BA00083EBEC /* MWMUnitsController.mm in Sources */,
6741AA031BF340DE002C974C /* MWMActivityViewController.mm in Sources */,
472849012388098300176158 /* MyReviewViewController.swift in Sources */,
F6E2FE9D1E097BA00083EBEC /* MWMiPhonePlacePageLayoutImpl.mm in Sources */,
CDCA27382237F1BD00167D87 /* BookmarkInfo.swift in Sources */,
993F5509237C622700545511 /* DeepLinkHandlerStrategy.swift in Sources */,
@ -5655,11 +5740,13 @@
6741AA0B1BF340DE002C974C /* MWMMapViewControlsManager.mm in Sources */,
F6E2FED91E097BA00083EBEC /* MWMSearchContentView.m in Sources */,
F6BD1D211CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */,
472848F92384CEC900176158 /* TaxiViewController.swift in Sources */,
34AB66321FC5AA330078E451 /* RouteManagerHeaderView.swift in Sources */,
347040301EA6470700038379 /* BorderedButton.swift in Sources */,
34F1ADD31F6BC09E001CE79D /* PPPReview.swift in Sources */,
F6E2FF4B1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */,
F6E2FE791E097BA00083EBEC /* MWMOpeningHoursLayoutHelper.mm in Sources */,
47A04173238E989200D84E95 /* HotelReviewsViewController.swift in Sources */,
472E3F4A2146C4CD0020E412 /* MWMPurchaseManager.mm in Sources */,
34ABA6211C2D517500FE1BEC /* MWMInputValidator.m in Sources */,
47C7F97521930F5300C2760C /* IInAppBilling.swift in Sources */,
@ -5679,7 +5766,7 @@
34AB66621FC5AA330078E451 /* TransportTransitSeparator.swift in Sources */,
CDCA2743223F8D1E00167D87 /* ListItemInfo.swift in Sources */,
B32FE74020D2844600EF7446 /* DownloadedBookmarksViewController.swift in Sources */,
4707E4B62375B2900017DF6E /* PlacePageInfoViewController.swift in Sources */,
4707E4B62375B2900017DF6E /* PlacePagePreviewViewController.swift in Sources */,
340416541E7C09C200E2B6D6 /* PhotoScalingView.swift in Sources */,
4767CDA820AB401000BD8166 /* LinkTextView.swift in Sources */,
47289E5A2212DFFF002ABFC0 /* EditOnWebAlertViewController.swift in Sources */,
@ -5696,6 +5783,7 @@
344BEAF61F66BDC30045DC45 /* RatingSummaryViewSettings.swift in Sources */,
F6E2FD921E097BA00083EBEC /* MWMBookmarkColorViewController.mm in Sources */,
CD96C71C22A8113100DB7CFE /* MWMDiscoveryControllerViewModel.mm in Sources */,
470F0B7F2388431E006AEC94 /* StarRatingView.swift in Sources */,
F63AF5061EA6162400A1DB98 /* FilterTypeCell.swift in Sources */,
347752881F725002000D46A3 /* UGCAddReviewRatingCell.swift in Sources */,
47E3C7332111F4D8008B3B27 /* CoverVerticalDismissalAnimator.swift in Sources */,
@ -5785,6 +5873,7 @@
47B06E0021BAAC270094CCAD /* GeoZoneTracker.swift in Sources */,
3404F4952028A1B80090E401 /* BMCPermissionsCell.swift in Sources */,
340416441E7BED3900E2B6D6 /* PhotosTransitionAnimator.swift in Sources */,
479388F92395A4D3006ECACC /* ActionBarViewController.swift in Sources */,
34AB66261FC5AA330078E451 /* RouteManagerDimView.swift in Sources */,
993F5514237C622700545511 /* DeepLinkStrategyFactory.swift in Sources */,
6741AA291BF340DE002C974C /* ColorPickerView.mm in Sources */,
@ -5817,6 +5906,7 @@
F5BD29FF26AD58255766C51A /* DiscoverySpinnerCell.swift in Sources */,
47E3C72B2111E62A008B3B27 /* FadeOutAnimatedTransitioning.swift in Sources */,
F5BD255A0838E70EC012748E /* DiscoverySearchCell.swift in Sources */,
470F0B7A23882955006AEC94 /* PlacePageReviewViewController.swift in Sources */,
47C7F9732191E15A00C2760C /* InAppBilling.swift in Sources */,
F5BD2CA4DBEFACBC48195F39 /* DiscoveryCollectionHolderCell.swift in Sources */,
);

View file

@ -0,0 +1,98 @@
class ActionBarViewController: UIViewController {
@IBOutlet var stackView: UIStackView!
var placePageData: PlacePageData!
var isRoutePlanning = false
var canAddStop = false
private var visibleButtons: [ActionBarButtonType] = []
private var additionalButtons: [ActionBarButtonType] = []
override func viewDidLoad() {
super.viewDidLoad()
configButton1()
configButton2()
configButton3()
configButton4()
for buttonType in visibleButtons {
var selected = false
var disabled = false
if buttonType == .bookmark {
if let bookmarkData = placePageData.bookmarkData {
selected = true
disabled = bookmarkData.isEditable
}
}
guard let button = ActionBarButton(delegate: self,
buttonType: buttonType,
partnerIndex: -1,
isSelected: selected,
isDisabled: disabled) else { continue }
stackView.addArrangedSubview(button)
}
}
private func configButton1() {
var buttons: [ActionBarButtonType] = []
if isRoutePlanning {
buttons.append(.routeFrom)
}
if placePageData.previewData.isBookingPlace {
buttons.append(.booking)
}
if placePageData.sponsoredType == .partner {
buttons.append(.partner)
}
if placePageData.bookingSearchUrl != nil {
buttons.append(.bookingSearch)
}
if placePageData.infoData.phone != nil, AppInfo.shared().canMakeCalls {
buttons.append(.call)
}
if !isRoutePlanning {
buttons.append(.routeFrom)
}
assert(buttons.count > 0)
visibleButtons.append(buttons[0])
if buttons.count > 1 {
additionalButtons.append(contentsOf: buttons.suffix(from: 1))
}
}
private func configButton2() {
var buttons: [ActionBarButtonType] = []
if canAddStop {
buttons.append(.routeAddStop)
}
buttons.append(.bookmark)
assert(buttons.count > 0)
visibleButtons.append(buttons[0])
if buttons.count > 1 {
additionalButtons.append(contentsOf: buttons.suffix(from: 1))
}
}
private func configButton3() {
visibleButtons.append(.routeTo)
}
private func configButton4() {
if additionalButtons.isEmpty {
visibleButtons.append(.share)
} else {
additionalButtons.append(.share)
visibleButtons.append(.more)
}
}
}
extension ActionBarViewController: ActionBarButtonDelegate {
func tapOnButton(with type: ActionBarButtonType) {
}
}

View file

@ -0,0 +1,34 @@
protocol AddReviewViewControllerDelegate: AnyObject {
func didRate(_ rating: UgcSummaryRatingType)
}
class AddReviewViewController: UIViewController {
@IBOutlet var horribleButton: UIButton!
@IBOutlet var badButton: UIButton!
@IBOutlet var normalButton: UIButton!
@IBOutlet var goodButton: UIButton!
@IBOutlet var excellentButton: UIButton!
weak var delegate: AddReviewViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func onRate(_ sender: UIButton) {
switch sender {
case horribleButton:
delegate?.didRate(.horrible)
case badButton:
delegate?.didRate(.bad)
case normalButton:
delegate?.didRate(.normal)
case goodButton:
delegate?.didRate(.good)
case excellentButton:
delegate?.didRate(.excellent)
default:
fatalError()
}
}
}

View file

@ -0,0 +1,102 @@
class CatalogPromoItemCell: UICollectionViewCell {
@IBOutlet var itemImageView: UIImageView!
@IBOutlet var titleLabel: UILabel!
@IBOutlet var subtitleLabel: UILabel!
@IBOutlet var proLabel: UILabel!
@IBOutlet var proContainerView: UIView!
typealias OnDetails = () -> Void
private var onDetails: OnDetails?
override func prepareForReuse() {
super.prepareForReuse()
itemImageView.image = UIImage(named: "img_guide_placeholder")
titleLabel.text = ""
subtitleLabel.text = ""
proLabel.text = ""
proContainerView.isHidden = true
onDetails = nil
}
func config(promoItem: CatalogPromoItem, onDetails: @escaping OnDetails) {
setImage(promoItem.imageUrl)
titleLabel.text = promoItem.guideName
subtitleLabel.text = promoItem.guideAuthor
self.onDetails = onDetails
guard !promoItem.categoryLabel.isEmpty else {
proContainerView.isHidden = true
return
}
proLabel.text = promoItem.categoryLabel
if promoItem.hexColor.count == 6 {
proContainerView.backgroundColor = UIColor(fromHexString: promoItem.hexColor)
} else {
proContainerView.backgroundColor = UIColor.ratingRed()
}
proContainerView.isHidden = false
}
@IBAction func onDetails(_ sender: UIButton) {
onDetails?()
}
private func setImage(_ imageUrl: String?) {
guard let imageUrl = imageUrl else { return }
if let url = URL(string: imageUrl) {
itemImageView.image = UIImage(named: "img_guide_placeholder")
itemImageView.wi_setImage(with: url, transitionDuration: kDefaultAnimationDuration)
} else {
itemImageView.image = UIImage(named: "img_guide_placeholder")
}
}
}
protocol CatalogGalleryViewControllerDelegate: AnyObject {
func promoGalleryDidSelectItemAtIndex(_ index: Int)
func promoGalleryDidPressMore()
}
class CatalogGalleryViewController: UIViewController {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var collectionView: UICollectionView!
var promoData: CatalogPromoData? {
didSet {
guard let promoData = promoData else { return }
collectionView?.reloadData()
titleLabel.text = String(coreFormat: L("pp_discovery_place_related_tag_header"),
arguments: [promoData.tagsString])
}
}
weak var delegate: CatalogGalleryViewControllerDelegate?
}
extension CatalogGalleryViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let promoData = promoData else { return 0 }
return promoData.promoItems.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item < promoData!.promoItems.count {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DiscoveryGuideCell", for: indexPath) as! CatalogPromoItemCell
cell.config(promoItem: promoData!.promoItems[indexPath.item]) { [weak self] in
self?.delegate?.promoGalleryDidSelectItemAtIndex(indexPath.item)
}
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MoreCell", for: indexPath)
return cell
}
}
}
extension CatalogGalleryViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == promoData!.promoItems.count {
delegate?.promoGalleryDidPressMore()
} else {
delegate?.promoGalleryDidSelectItemAtIndex(indexPath.item)
}
}
}

View file

@ -0,0 +1,46 @@
protocol CatalogSingleItemViewControllerDelegate: AnyObject {
func catalogPromoItemDidPressView()
func catalogPromoItemDidPressMore()
}
class CatalogSingleItemViewController: UIViewController {
@IBOutlet var placeTitleLabel: UILabel!
@IBOutlet var placeDescriptionLabel: UILabel!
@IBOutlet var guideNameLabel: UILabel!
@IBOutlet var guideAuthorLabel: UILabel!
@IBOutlet var placeImageView: UIImageView!
@IBOutlet var headerLabel: UILabel!
var promoItem: CatalogPromoItem? {
didSet {
updateViews()
}
}
weak var delegate: CatalogSingleItemViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
headerLabel.text = L("pp_discovery_place_related_header").uppercased()
updateViews()
}
private func updateViews() {
guard let promoItem = promoItem else { return }
placeTitleLabel.text = promoItem.placeTitle
placeDescriptionLabel.text = promoItem.placeDescription
guideNameLabel.text = promoItem.guideName
guideAuthorLabel.text = promoItem.guideAuthor
guard let url = URL(string: promoItem.imageUrl) else {
return
}
placeImageView.wi_setImage(with: url)
}
@IBAction func onMore(_ sender: UIButton) {
delegate?.catalogPromoItemDidPressMore()
}
@IBAction func onView(_ sender: UIButton) {
delegate?.catalogPromoItemDidPressView()
}
}

View file

@ -0,0 +1,31 @@
protocol HotelDescriptionViewControllerDelegate: AnyObject {
func hotelDescriptionDidPressMore()
}
class HotelDescriptionViewController: UIViewController {
@IBOutlet var descriptionExpandableLabel: ExpandableLabel!
@IBOutlet var moreButton: UIButton!
var hotelDescription: String? {
didSet {
descriptionExpandableLabel.textLabel.text = hotelDescription
}
}
weak var delegate: HotelDescriptionViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
descriptionExpandableLabel.textLabel.numberOfLines = 3
descriptionExpandableLabel.textLabel.text = hotelDescription
descriptionExpandableLabel.textLabel.font = UIFont.regular16()
descriptionExpandableLabel.textLabel.textColor = UIColor.blackPrimaryText()
descriptionExpandableLabel.expandButton.setTitleColor(UIColor.linkBlue(), for: .normal)
descriptionExpandableLabel.expandButton.titleLabel?.font = UIFont.regular16()
descriptionExpandableLabel.expandButton.setTitle(L("booking_show_more"), for: .normal)
}
@IBAction func onMoreButton(_ sender: UIButton) {
delegate?.hotelDescriptionDidPressMore()
}
}

View file

@ -0,0 +1,64 @@
class HotelFacilityViewController: UIViewController {
@IBOutlet var facilityLabel: UILabel!
var facility: String!
override func viewDidLoad() {
super.viewDidLoad()
facilityLabel.text = facility
}
}
protocol HotelFacilitiesViewControllerDelegate: AnyObject {
func facilitiesDidPressMore()
}
class HotelFacilitiesViewController: UIViewController {
@IBOutlet var stackView: UIStackView!
var facilities: [HotelFacility]? {
didSet {
updateFacilities()
}
}
weak var delegate: HotelFacilitiesViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
updateFacilities()
}
private func updateFacilities() {
guard let facilities = facilities else { return }
let count = min(facilities.count, 3)
for i in 0..<count {
addFacility(facilities[i].name)
}
if facilities.count > count {
addMoreButton()
}
}
@objc func onMoreButton(_ sender: UIButton) {
delegate?.facilitiesDidPressMore()
}
private func addFacility(_ facility: String) {
let vc = storyboard!.instantiateViewController(ofType: HotelFacilityViewController.self)
vc.facility = facility
addChild(vc)
stackView.addArrangedSubview(vc.view)
vc.didMove(toParent: self)
}
private func addMoreButton() {
let button = UIButton()
button.setTitle(L("booking_show_more"), for: .normal)
button.titleLabel?.font = UIFont.regular16()
button.setTitleColor(UIColor.linkBlue(), for: .normal)
button.heightAnchor.constraint(equalToConstant: 44).isActive = true
stackView.addArrangedSubview(button)
button.addTarget(self, action: #selector(onMoreButton(_:)), for: .touchUpInside)
}
}

View file

@ -0,0 +1,50 @@
class PhotoCell: UICollectionViewCell {
@IBOutlet var imageView: UIImageView!
@IBOutlet var dimView: UIView!
func config(_ imageUrlString: String, dimmed: Bool = false) {
guard let imageUrl = URL(string: imageUrlString) else { return }
imageView.wi_setImage(with: imageUrl)
dimView.isHidden = !dimmed
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.wi_cancelImageRequest()
}
}
protocol HotelPhotosViewControllerDelegate: AnyObject {
func didSelectItemAt(_ index: Int)
}
class HotelPhotosViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView!
var photos: [HotelPhotoUrl]? {
didSet {
collectionView?.reloadData()
}
}
weak var delegate: HotelPhotosViewControllerDelegate?
}
extension HotelPhotosViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
min(photos?.count ?? 0, 5)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let photoCell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
if let photoItem = photos?[indexPath.item] {
photoCell.config(photoItem.thumbnail)
}
return photoCell
}
}
extension HotelPhotosViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.didSelectItemAt(indexPath.item)
}
}

View file

@ -0,0 +1,101 @@
class HotelReviewViewController: UIViewController {
@IBOutlet var authorLabel: UILabel!
@IBOutlet var dateLabel: UILabel!
@IBOutlet var ratingLabel: UILabel!
@IBOutlet var positiveView: UIView!
@IBOutlet var positiveLabel: UILabel!
@IBOutlet var negativeView: UIView!
@IBOutlet var negativeLabel: UILabel!
var review: HotelReview!
override func viewDidLoad() {
super.viewDidLoad()
authorLabel.text = review.author
ratingLabel.text = NSNumber(value: review.score).stringValue
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
dateLabel.text = formatter.string(from: review.date)
if let positiveReview = review.pros {
positiveLabel.text = positiveReview
positiveView.isHidden = false
}
if let negativeReview = review.cons {
negativeLabel.text = negativeReview
negativeView.isHidden = false
}
}
}
protocol HotelReviewsViewControllerDelegate: AnyObject {
func hotelReviewsDidPressMore()
}
class HotelReviewsViewController: UIViewController {
@IBOutlet var stackView: UIStackView!
@IBOutlet var totalRatingLabel: UILabel!
@IBOutlet var reviewsCountLabel: UILabel!
var totalScore: Float = 0 {
didSet {
totalRatingLabel?.text = NSNumber(value: totalScore).stringValue
}
}
var reviewCount: UInt = 0 {
didSet {
reviewsCountLabel?.text = String(format:L("placepage_summary_rating_description"), reviewCount)
}
}
var reviews: [HotelReview]? {
didSet {
updateReviews()
}
}
weak var delegate: HotelReviewsViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
totalRatingLabel.text = NSNumber(value: totalScore).stringValue
reviewsCountLabel.text = String(format:L("placepage_summary_rating_description"), reviewCount)
updateReviews()
}
private func updateReviews() {
guard let reviews = reviews else { return }
let count = min(reviews.count, 3)
for i in 0..<count {
addReview(reviews[i])
}
if reviewCount > count {
addMoreButton()
}
}
@objc func onMoreButton(_ sender: UIButton) {
delegate?.hotelReviewsDidPressMore()
}
private func addReview(_ review: HotelReview) {
let vc = storyboard!.instantiateViewController(ofType: HotelReviewViewController.self)
vc.review = review
addChild(vc)
stackView.addArrangedSubview(vc.view)
vc.didMove(toParent: self)
}
private func addMoreButton() {
let button = UIButton()
button.setTitle(L("reviews_on_bookingcom"), for: .normal)
button.titleLabel?.font = UIFont.regular16()
button.setTitleColor(UIColor.linkBlue(), for: .normal)
button.heightAnchor.constraint(equalToConstant: 44).isActive = true
stackView.addArrangedSubview(button)
button.addTarget(self, action: #selector(onMoreButton(_:)), for: .touchUpInside)
}
}

View file

@ -12,6 +12,7 @@
#import "MWMStorage+UI.h"
#import "SwiftBridge.h"
#import "MWMMapViewControlsManager+AddPlace.h"
#import "location_util.h"
#import <CoreApi/CoreApi.h>
@ -298,7 +299,7 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
#pragma mark - MWMLocationObserver
- (void)onHeadingUpdate:(location::CompassInfo const &)info
- (void)onHeadingUpdate:(CLHeading *)heading
{
auto lastLocation = [MWMLocationManager lastLocation];
auto data = self.data;
@ -310,6 +311,7 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
if (base::AlmostEqualAbs(locationMercator, dataMercator, 1e-10))
return;
auto const info = location_util::compassInfoFromHeading(heading);
auto const angle = ang::AngleTo(locationMercator, dataMercator) + info.m_bearing;
[self.layout rotateDirectionArrowToAngle:angle];
}
@ -321,7 +323,7 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
[self.layout setSpeedAndAltitude:location_helpers::formattedSpeedAndAltitude(MWMLocationManager.lastLocation)];
}
- (void)onLocationUpdate:(location::GpsInfo const &)locationInfo
- (void)onLocationUpdate:(CLLocation *)location
{
[self setupSpeedAndDistance];
}

View file

@ -0,0 +1,48 @@
class MyReviewViewController: UIViewController {
@IBOutlet var dateLabel: UILabel!
@IBOutlet var expandableLabel: ExpandableLabel! {
didSet {
expandableLabel.textLabel.font = UIFont.regular14()
expandableLabel.textLabel.textColor = UIColor.blackPrimaryText()
expandableLabel.expandButton.setTitleColor(UIColor.linkBlue(), for: .normal)
expandableLabel.expandButton.titleLabel?.font = UIFont.regular14()
expandableLabel.expandButton.setTitle(L("placepage_more_button"), for: .normal)
}
}
@IBOutlet var ratingViews: [UIView]!
@IBOutlet var ratingLabels: [UILabel]!
@IBOutlet var starViews: [StarRatingView]! {
didSet {
starViews.forEach {
$0.activeColor = UIColor.ratingYellow()
$0.inactiveColor = UIColor.blackDividers()
}
}
}
var myReview: UgcMyReview!
lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
return formatter
} ()
override func viewDidLoad() {
super.viewDidLoad()
dateLabel.text = dateFormatter.string(from: myReview.date)
expandableLabel.textLabel.text = myReview.text
for i in 0..<3 {
if myReview.starRatings.count > i {
let starRating = myReview.starRatings[i]
ratingLabels[i].text = L(starRating.title)
starViews[i].rating = Int(round(starRating.value))
} else {
ratingViews[i].isHidden = true
}
}
}
}

View file

@ -0,0 +1,30 @@
//
// OpeningHoursViewController.swift
// MAPS.ME
//
// Created by aleksey.belousov on 29/11/2019.
// Copyright © 2019 MapsWithMe. All rights reserved.
//
import UIKit
class OpeningHoursViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,87 @@
protocol PlacePageBookmarkViewControllerDelegate: AnyObject {
func bookmarkDidPressEdit()
}
class PlacePageBookmarkViewController: UIViewController {
@IBOutlet var stackView: UIStackView!
@IBOutlet var spinner: UIImageView!
@IBOutlet var editButton: UIButton!
@IBOutlet var expandableLabel: ExpandableLabel! {
didSet {
expandableLabel.textLabel.font = UIFont.regular14()
expandableLabel.textLabel.textColor = UIColor.blackPrimaryText()
expandableLabel.textLabel.numberOfLines = 5
expandableLabel.expandButton.setTitleColor(UIColor.linkBlue(), for: .normal)
expandableLabel.expandButton.titleLabel?.font = UIFont.regular14()
expandableLabel.expandButton.setTitle(L("placepage_more_button"), for: .normal)
}
}
var bookmarkData: PlacePageBookmarkData? {
didSet {
updateViews()
}
}
weak var delegate: PlacePageBookmarkViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
updateViews()
}
func updateViews() {
guard let bookmarkData = bookmarkData else { return }
editButton.isEnabled = bookmarkData.isEditable
if let description = bookmarkData.bookmarkDescription {
if bookmarkData.isHtmlDescription {
setHtmlDescription(description)
} else {
expandableLabel.textLabel.text = description
}
}
}
private func setHtmlDescription(_ htmlDescription: String) {
DispatchQueue.global().async {
let font = UIFont.regular14()
let color = UIColor.blackPrimaryText()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 4
let attributedString: NSAttributedString
if let str = NSMutableAttributedString(htmlString: htmlDescription, baseFont: font, paragraphStyle: paragraphStyle) {
str.addAttribute(NSAttributedString.Key.foregroundColor,
value: color,
range: NSRange(location: 0, length: str.length))
attributedString = str;
} else {
attributedString = NSAttributedString(string: htmlDescription,
attributes: [NSAttributedString.Key.font : font,
NSAttributedString.Key.foregroundColor: color,
NSAttributedString.Key.paragraphStyle: paragraphStyle])
}
DispatchQueue.main.async {
self.expandableLabel.textLabel.attributedText = attributedString
}
}
}
private func startSpinner() {
editButton.isHidden = true
let postfix = UIColor.isNightMode() ? "dark" : "light"
spinner.image = UIImage(named: "Spinner_" + postfix)
spinner.isHidden = false
spinner.startRotation()
}
private func stopSpinner() {
editButton.isHidden = false
spinner.isHidden = true
spinner.stopRotation()
}
@IBAction func onEdit(_ sender: UIButton) {
delegate?.bookmarkDidPressEdit()
}
}

View file

@ -0,0 +1,43 @@
protocol PlacePageButtonsViewControllerDelegate: AnyObject {
func didPressHotels()
func didPressAddPlace()
func didPressEditPlace()
func didPressAddBusiness()
}
class PlacePageButtonsViewController: UIViewController {
@IBOutlet var bookingButton: UIButton!
@IBOutlet var addPlaceButton: UIButton!
@IBOutlet var editPlaceButton: UIButton!
@IBOutlet var addBusinessButton: UIButton!
var buttonsData: PlacePageButtonsData!
weak var delegate: PlacePageButtonsViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
bookingButton.isHidden = !buttonsData.showHotelDescription
addPlaceButton.isHidden = !buttonsData.showAddPlace
editPlaceButton.isHidden = !buttonsData.showEditPlace
addBusinessButton.isHidden = !buttonsData.showAddBusiness
// Do any additional setup after loading the view.
}
@IBAction func onBooking(_ sender: UIButton) {
delegate?.didPressHotels()
}
@IBAction func onAddPlace(_ sender: UIButton) {
delegate?.didPressAddPlace()
}
@IBAction func onEditPlace(_ sender: UIButton) {
delegate?.didPressEditPlace()
}
@IBAction func onAddBusiness(_ sender: UIButton) {
delegate?.didPressAddBusiness()
}
}

View file

@ -1,30 +1,174 @@
//
// PlacePageInfoViewController.swift
// MAPS.ME
//
// Created by aleksey.belousov on 08/11/2019.
// Copyright © 2019 MapsWithMe. All rights reserved.
//
class InfoItemViewController: UIViewController {
enum Style {
case regular
case link
}
import UIKit
typealias TapHandler = () -> Void
@IBOutlet var imageView: UIImageView!
@IBOutlet var infoLabel: UILabel!
@IBOutlet var accessoryImage: UIImageView!
@IBOutlet var separatorView: UIView!
@IBOutlet var tapGestureRecognizer: UITapGestureRecognizer!
var tapHandler: TapHandler?
var style: Style = .regular {
didSet {
switch style {
case .regular:
imageView?.mwm_coloring = .black
infoLabel?.textColor = UIColor.blackPrimaryText()
case .link:
imageView?.mwm_coloring = .blue
infoLabel?.textColor = UIColor.linkBlue()
}
}
}
@IBAction func onTap(_ sender: UITapGestureRecognizer) {
tapHandler?()
}
override func viewDidLoad() {
super.viewDidLoad()
if style == .link {
imageView.mwm_coloring = .blue
infoLabel.textColor = UIColor.linkBlue()
}
}
}
protocol PlacePageInfoViewControllerDelegate: AnyObject {
func didPressCall()
func didPressWebsite()
func didPressEmail()
func didPressLocalAd()
}
class PlacePageInfoViewController: UIViewController {
private typealias TapHandler = InfoItemViewController.TapHandler
private typealias Style = InfoItemViewController.Style
override func viewDidLoad() {
super.viewDidLoad()
@IBOutlet var stackView: UIStackView!
// Do any additional setup after loading the view.
private var openingHoursView: InfoItemViewController?
private var phoneView: InfoItemViewController?
private var websiteView: InfoItemViewController?
private var emailView: InfoItemViewController?
private var cuisineView: InfoItemViewController?
private var operatorView: InfoItemViewController?
private var wifiView: InfoItemViewController?
private var addressView: InfoItemViewController?
private var coordinatesView: InfoItemViewController?
private var localAdsButton: UIButton?
var placePageInfoData: PlacePageInfoData!
weak var delegate: PlacePageInfoViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
if let openingHoursString = placePageInfoData.openingHoursString {
openingHoursView = createInfoItem(openingHoursString, icon: UIImage(named: "ic_placepage_open_hours")) {
}
openingHoursView?.accessoryImage.image = UIImage(named: "ic_arrow_gray_down")
openingHoursView?.accessoryImage.isHidden = false
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if let phone = placePageInfoData.phone {
var cellStyle: Style = .regular
if let phoneUrl = placePageInfoData.phoneUrl, UIApplication.shared.canOpenURL(phoneUrl) {
cellStyle = .link
}
phoneView = createInfoItem(phone, icon: UIImage(named: "ic_placepage_phone_number"), style: cellStyle) { [weak self] in
self?.delegate?.didPressCall()
}
}
*/
if let website = placePageInfoData.website {
websiteView = createInfoItem(website, icon: UIImage(named: "ic_placepage_website"), style: .link) { [weak self] in
self?.delegate?.didPressWebsite()
}
}
if let email = placePageInfoData.email {
emailView = createInfoItem(email, icon: UIImage(named: "ic_placepage_email"), style: .link) { [weak self] in
self?.delegate?.didPressEmail()
}
}
if let cuisine = placePageInfoData.cuisine {
cuisineView = createInfoItem(cuisine, icon: UIImage(named: "ic_placepage_cuisine"))
}
if let ppOperator = placePageInfoData.ppOperator {
operatorView = createInfoItem(ppOperator, icon: UIImage(named: "ic_placepage_operator"))
}
if placePageInfoData.wifiAvailable {
wifiView = createInfoItem(L("WiFi_available"), icon: UIImage(named: "ic_placepage_wifi"))
}
if let address = placePageInfoData.address {
addressView = createInfoItem(address, icon: UIImage(named: "ic_placepage_adress"))
}
if let coordinates = placePageInfoData.formattedCoordinates {
coordinatesView = createInfoItem(coordinates, icon: UIImage(named: "ic_placepage_coordinate")) {
}
coordinatesView?.accessoryImage.image = UIImage(named: "ic_placepage_change")
coordinatesView?.accessoryImage.isHidden = false
}
switch placePageInfoData.localAdsStatus {
case .candidate:
localAdsButton = createLocalAdsButton(L("create_campaign_button"))
case .customer:
localAdsButton = createLocalAdsButton(L("view_campaign_button"))
case .notAvailable, .hidden:
coordinatesView?.separatorView.isHidden = true
@unknown default:
fatalError()
}
}
// MARK: private
@objc private func onLocalAdsButton(_ sender: UIButton) {
delegate?.didPressLocalAd()
}
private func createLocalAdsButton(_ title: String) -> UIButton {
let button = UIButton()
button.setTitle(title, for: .normal)
button.titleLabel?.font = UIFont.regular17()
button.setTitleColor(UIColor.linkBlue(), for: .normal)
button.heightAnchor.constraint(equalToConstant: 44).isActive = true
stackView.addArrangedSubview(button)
button.addTarget(self, action: #selector(onLocalAdsButton(_:)), for: .touchUpInside)
return button
}
private func createInfoItem(_ info: String,
icon: UIImage?,
style: Style = .regular,
tapHandler: TapHandler? = nil) -> InfoItemViewController {
let vc = storyboard!.instantiateViewController(ofType: InfoItemViewController.self)
addToStack(vc)
vc.imageView.image = icon
vc.infoLabel.text = info
vc.style = style
vc.tapHandler = tapHandler
return vc;
}
private func addToStack(_ viewController: UIViewController) {
addChild(viewController)
stackView.addArrangedSubview(viewController.view)
viewController.didMove(toParent: self)
}
}

View file

@ -1,43 +1,50 @@
enum class EButton // Required button's order
{
Booking,
BookingSearch,
Bookmark,
Call,
Download,
More,
Opentable,
Partner,
RouteAddStop,
RouteFrom,
RouteRemoveStop,
RouteTo,
Share,
AvoidToll,
AvoidDirty,
AvoidFerry
};
typedef NS_ENUM(NSInteger, MWMActionBarButtonType) {
MWMActionBarButtonTypeBooking,
MWMActionBarButtonTypeBookingSearch,
MWMActionBarButtonTypeBookmark,
MWMActionBarButtonTypeCall,
MWMActionBarButtonTypeDownload,
MWMActionBarButtonTypeMore,
MWMActionBarButtonTypeOpentable,
MWMActionBarButtonTypePartner,
MWMActionBarButtonTypeRouteAddStop,
MWMActionBarButtonTypeRouteFrom,
MWMActionBarButtonTypeRouteRemoveStop,
MWMActionBarButtonTypeRouteTo,
MWMActionBarButtonTypeShare,
MWMActionBarButtonTypeAvoidToll,
MWMActionBarButtonTypeAvoidDirty,
MWMActionBarButtonTypeAvoidFerry
} NS_SWIFT_NAME(ActionBarButtonType);
NSString * titleForButton(EButton type, int partnerIndex, BOOL isSelected);
#ifdef __cplusplus
extern "C" {
#endif
NSString * titleForButton(MWMActionBarButtonType type, int partnerIndex, BOOL isSelected);
#ifdef __cplusplus
}
#endif
@class MWMActionBarButton;
@class MWMCircularProgress;
NS_SWIFT_NAME(ActionBarButtonDelegate)
@protocol MWMActionBarButtonDelegate <NSObject>
- (void)tapOnButtonWithType:(EButton)type;
- (void)tapOnButtonWithType:(MWMActionBarButtonType)type;
@end
NS_SWIFT_NAME(ActionBarButton)
@interface MWMActionBarButton : UIView
+ (MWMActionBarButton *)buttonWithDelegate:(id<MWMActionBarButtonDelegate>)delegate
buttonType:(EButton)type
buttonType:(MWMActionBarButtonType)type
partnerIndex:(int)partnerIndex
isSelected:(BOOL)isSelected
isDisabled:(BOOL)isDisabled;
- (EButton)type;
- (MWMActionBarButtonType)type;
- (MWMCircularProgress *)mapDownloadProgress;
- (int)partnerIndex;

View file

@ -1,6 +1,6 @@
#import "MWMActionBarButton.h"
#import "MWMButton.h"
#import "MWMCircularProgress.h"
#import "MWMCircularProgress+Swift.h"
NSString * titleForPartner(int partnerIndex)
{
@ -10,26 +10,26 @@ NSString * titleForPartner(int partnerIndex)
return localizedStr;
}
NSString * titleForButton(EButton type, int partnerIndex, BOOL isSelected)
NSString * titleForButton(MWMActionBarButtonType type, int partnerIndex, BOOL isSelected)
{
switch (type)
{
case EButton::Download: return L(@"download");
case EButton::Booking:
case EButton::Opentable: return L(@"book_button");
case EButton::BookingSearch: return L(@"booking_search");
case EButton::Call: return L(@"placepage_call_button");
case EButton::Bookmark: return L(isSelected ? @"delete" : @"save");
case EButton::RouteFrom: return L(@"p2p_from_here");
case EButton::RouteTo: return L(@"p2p_to_here");
case EButton::Share: return L(@"share");
case EButton::More: return L(@"placepage_more_button");
case EButton::RouteAddStop: return L(@"placepage_add_stop");
case EButton::RouteRemoveStop: return L(@"placepage_remove_stop");
case EButton::AvoidToll: return L(@"avoid_toll_roads_placepage");
case EButton::AvoidDirty: return L(@"avoid_unpaved_roads_placepage");
case EButton::AvoidFerry: return L(@"avoid_ferry_crossing_placepage");
case EButton::Partner: return titleForPartner(partnerIndex);
case MWMActionBarButtonTypeDownload: return L(@"download");
case MWMActionBarButtonTypeBooking:
case MWMActionBarButtonTypeOpentable: return L(@"book_button");
case MWMActionBarButtonTypeBookingSearch: return L(@"booking_search");
case MWMActionBarButtonTypeCall: return L(@"placepage_call_button");
case MWMActionBarButtonTypeBookmark: return L(isSelected ? @"delete" : @"save");
case MWMActionBarButtonTypeRouteFrom: return L(@"p2p_from_here");
case MWMActionBarButtonTypeRouteTo: return L(@"p2p_to_here");
case MWMActionBarButtonTypeShare: return L(@"share");
case MWMActionBarButtonTypeMore: return L(@"placepage_more_button");
case MWMActionBarButtonTypeRouteAddStop: return L(@"placepage_add_stop");
case MWMActionBarButtonTypeRouteRemoveStop: return L(@"placepage_remove_stop");
case MWMActionBarButtonTypeAvoidToll: return L(@"avoid_toll_roads_placepage");
case MWMActionBarButtonTypeAvoidDirty: return L(@"avoid_unpaved_roads_placepage");
case MWMActionBarButtonTypeAvoidFerry: return L(@"avoid_ferry_crossing_placepage");
case MWMActionBarButtonTypePartner: return titleForPartner(partnerIndex);
}
}
@ -63,7 +63,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
@interface MWMActionBarButton () <MWMCircularProgressProtocol>
@property(nonatomic) EButton type;
@property(nonatomic) MWMActionBarButtonType type;
@property(nonatomic) MWMCircularProgress * mapDownloadProgress;
@property(nonatomic) int partnerIndex;
@property(weak, nonatomic) IBOutlet MWMButton * button;
@ -81,7 +81,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
self.extraBackground.hidden = YES;
switch (self.type)
{
case EButton::Download:
case MWMActionBarButtonTypeDownload:
{
if (self.mapDownloadProgress)
return;
@ -96,7 +96,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
[self.mapDownloadProgress setColoring:MWMButtonColoringBlue forStates:affectedStates];
break;
}
case EButton::Booking:
case MWMActionBarButtonTypeBooking:
[self.button setImage:[UIImage imageNamed:@"ic_booking_logo"] forState:UIControlStateNormal];
self.label.textColor = UIColor.whiteColor;
self.backgroundColor = [UIColor bookingBackground];
@ -106,7 +106,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
self.extraBackground.hidden = NO;
}
break;
case EButton::BookingSearch:
case MWMActionBarButtonTypeBookingSearch:
[self.button setImage:[UIImage imageNamed:@"ic_booking_search"]
forState:UIControlStateNormal];
self.label.textColor = UIColor.whiteColor;
@ -117,7 +117,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
self.extraBackground.hidden = NO;
}
break;
case EButton::Opentable:
case MWMActionBarButtonTypeOpentable:
[self.button setImage:[UIImage imageNamed:@"ic_opentable"] forState:UIControlStateNormal];
self.label.textColor = UIColor.whiteColor;
self.backgroundColor = [UIColor opentableBackground];
@ -127,46 +127,46 @@ UIColor * backgroundColorForPartner(int partnerIndex)
self.extraBackground.hidden = NO;
}
break;
case EButton::Call:
case MWMActionBarButtonTypeCall:
[self.button setImage:[UIImage imageNamed:@"ic_placepage_phone_number"]
forState:UIControlStateNormal];
break;
case EButton::Bookmark: [self setupBookmarkButton:isSelected]; break;
case EButton::RouteFrom:
case MWMActionBarButtonTypeBookmark: [self setupBookmarkButton:isSelected]; break;
case MWMActionBarButtonTypeRouteFrom:
[self.button setImage:[UIImage imageNamed:@"ic_route_from"] forState:UIControlStateNormal];
break;
case EButton::RouteTo:
case MWMActionBarButtonTypeRouteTo:
[self.button setImage:[UIImage imageNamed:@"ic_route_to"] forState:UIControlStateNormal];
break;
case EButton::Share:
case MWMActionBarButtonTypeShare:
[self.button setImage:[UIImage imageNamed:@"ic_menu_share"] forState:UIControlStateNormal];
break;
case EButton::More:
case MWMActionBarButtonTypeMore:
[self.button setImage:[UIImage imageNamed:@"ic_placepage_more"]
forState:UIControlStateNormal];
break;
case EButton::RouteAddStop:
case MWMActionBarButtonTypeRouteAddStop:
[self.button setImage:[UIImage imageNamed:@"ic_add_route_point"]
forState:UIControlStateNormal];
break;
case EButton::RouteRemoveStop:
case MWMActionBarButtonTypeRouteRemoveStop:
[self.button setImage:[UIImage imageNamed:@"ic_remove_route_point"]
forState:UIControlStateNormal];
break;
case EButton::Partner:
case MWMActionBarButtonTypePartner:
[self.button setImage:imageForPartner(self.partnerIndex) forState:UIControlStateNormal];
self.label.textColor = textColorForPartner(self.partnerIndex);
self.backgroundColor = backgroundColorForPartner(self.partnerIndex);
break;
case EButton::AvoidToll:
case MWMActionBarButtonTypeAvoidToll:
[self.button setImage:[UIImage imageNamed:@"ic_avoid_tolls"]
forState:UIControlStateNormal];
break;
case EButton::AvoidDirty:
case MWMActionBarButtonTypeAvoidDirty:
[self.button setImage:[UIImage imageNamed:@"ic_avoid_dirty"]
forState:UIControlStateNormal];
break;
case EButton::AvoidFerry:
case MWMActionBarButtonTypeAvoidFerry:
[self.button setImage:[UIImage imageNamed:@"ic_avoid_ferry"]
forState:UIControlStateNormal];
break;
@ -175,7 +175,7 @@ UIColor * backgroundColorForPartner(int partnerIndex)
}
+ (MWMActionBarButton *)buttonWithDelegate:(id<MWMActionBarButtonDelegate>)delegate
buttonType:(EButton)type
buttonType:(MWMActionBarButtonType)type
partnerIndex:(int)partnerIndex
isSelected:(BOOL)isSelected
isDisabled:(BOOL)isDisabled
@ -191,12 +191,12 @@ UIColor * backgroundColorForPartner(int partnerIndex)
- (void)progressButtonPressed:(MWMCircularProgress *)progress
{
[self.delegate tapOnButtonWithType:EButton::Download];
[self.delegate tapOnButtonWithType:MWMActionBarButtonTypeDownload];
}
- (IBAction)tap
{
if (self.type == EButton::Bookmark)
if (self.type == MWMActionBarButtonTypeBookmark)
[self setBookmarkSelected:!self.button.isSelected];
[self.delegate tapOnButtonWithType:self.type];

View file

@ -10,8 +10,8 @@
@interface MWMPlacePageActionBar ()<MWMActionBarButtonDelegate>
{
std::vector<EButton> m_visibleButtons;
std::vector<EButton> m_additionalButtons;
std::vector<MWMActionBarButtonType> m_visibleButtons;
std::vector<MWMActionBarButtonType> m_additionalButtons;
}
@property(nonatomic) NSLayoutConstraint * visibleConstraint;
@ -49,39 +49,39 @@
- (void)setFirstButton:(MWMPlacePageData *)data
{
std::vector<EButton> buttons;
std::vector<MWMActionBarButtonType> buttons;
if (self.isAreaNotDownloaded)
{
buttons.push_back(EButton::Download);
buttons.push_back(MWMActionBarButtonTypeDownload);
}
else
{
BOOL const isRoutePlanning =
[MWMNavigationDashboardManager manager].state != MWMNavigationDashboardStateHidden;
if (isRoutePlanning)
buttons.push_back(EButton::RouteFrom);
buttons.push_back(MWMActionBarButtonTypeRouteFrom);
BOOL const isBooking = [data isBooking];
if (isBooking)
buttons.push_back(EButton::Booking);
buttons.push_back(MWMActionBarButtonTypeBooking);
BOOL const isOpentable = [data isOpentable];
if (isOpentable)
buttons.push_back(EButton::Opentable);
buttons.push_back(MWMActionBarButtonTypeOpentable);
BOOL const isPartner = [data isPartner] && [data sponsoredURL] != nil;
if (isPartner)
buttons.push_back(EButton::Partner);
buttons.push_back(MWMActionBarButtonTypePartner);
BOOL const isBookingSearch = [data isBookingSearch];
if (isBookingSearch)
buttons.push_back(EButton::BookingSearch);
buttons.push_back(MWMActionBarButtonTypeBookingSearch);
BOOL const isPhoneCallAvailable =
[AppInfo sharedInfo].canMakeCalls && [data phoneNumber].length > 0;
if (isPhoneCallAvailable)
buttons.push_back(EButton::Call);
buttons.push_back(MWMActionBarButtonTypeCall);
if (!isRoutePlanning)
buttons.push_back(EButton::RouteFrom);
buttons.push_back(MWMActionBarButtonTypeRouteFrom);
}
NSAssert(!buttons.empty(), @"Missing first action bar button");
@ -93,14 +93,14 @@
- (void)setSecondButton:(MWMPlacePageData *)data
{
std::vector<EButton> buttons;
std::vector<MWMActionBarButtonType> buttons;
BOOL const isCanAddIntermediatePoint = [MWMRouter canAddIntermediatePoint];
BOOL const isNavigationReady =
[MWMNavigationDashboardManager manager].state == MWMNavigationDashboardStateReady;
if (isCanAddIntermediatePoint && isNavigationReady)
buttons.push_back(EButton::RouteAddStop);
buttons.push_back(MWMActionBarButtonTypeRouteAddStop);
buttons.push_back(EButton::Bookmark);
buttons.push_back(MWMActionBarButtonTypeBookmark);
auto begin = buttons.begin();
m_visibleButtons.push_back(*begin);
@ -108,18 +108,18 @@
std::copy(begin, buttons.end(), std::back_inserter(m_additionalButtons));
}
- (void)setThirdButton { m_visibleButtons.push_back(EButton::RouteTo); }
- (void)setThirdButton { m_visibleButtons.push_back(MWMActionBarButtonTypeRouteTo); }
- (void)setFourthButton
{
if (m_additionalButtons.empty())
{
m_visibleButtons.push_back(EButton::Share);
m_visibleButtons.push_back(MWMActionBarButtonTypeShare);
}
else
{
m_visibleButtons.push_back(EButton::More);
m_additionalButtons.push_back(EButton::Share);
m_visibleButtons.push_back(MWMActionBarButtonTypeMore);
m_additionalButtons.push_back(MWMActionBarButtonTypeShare);
}
}
@ -130,8 +130,8 @@
for (auto const buttonType : m_visibleButtons)
{
auto const isSelected = (buttonType == EButton::Bookmark ? [data isBookmark] : NO);
auto const isDisabled = (buttonType == EButton::Bookmark && [data isBookmark] && !data.isBookmarkEditable);
auto const isSelected = (buttonType == MWMActionBarButtonTypeBookmark ? [data isBookmark] : NO);
auto const isDisabled = (buttonType == MWMActionBarButtonTypeBookmark && [data isBookmark] && !data.isBookmarkEditable);
auto button = [MWMActionBarButton buttonWithDelegate:self
buttonType:buttonType
partnerIndex:partnerIndex
@ -141,7 +141,7 @@
}
}
- (void)setSingleButton { m_visibleButtons.push_back(EButton::RouteRemoveStop); }
- (void)setSingleButton { m_visibleButtons.push_back(MWMActionBarButtonTypeRouteRemoveStop); }
- (void)setButtons:(MWMPlacePageData *)data
{
@ -152,13 +152,13 @@
} else if (roadType != RoadWarningMarkType::Count) {
switch (roadType) {
case RoadWarningMarkType::Toll:
m_visibleButtons.push_back(EButton::AvoidToll);
m_visibleButtons.push_back(MWMActionBarButtonTypeAvoidToll);
break;
case RoadWarningMarkType::Ferry:
m_visibleButtons.push_back(EButton::AvoidFerry);
m_visibleButtons.push_back(MWMActionBarButtonTypeAvoidFerry);
break;
case RoadWarningMarkType::Dirty:
m_visibleButtons.push_back(EButton::AvoidDirty);
m_visibleButtons.push_back(MWMActionBarButtonTypeAvoidDirty);
break;
default:
break;
@ -198,7 +198,7 @@
{
for (MWMActionBarButton * button in self.barButtons.subviews)
{
if ([button type] == EButton::Download)
if ([button type] == MWMActionBarButtonTypeDownload)
return button.mapDownloadProgress;
}
}
@ -218,34 +218,34 @@
#pragma mark - MWMActionBarButtonDelegate
- (void)tapOnButtonWithType:(EButton)type
- (void)tapOnButtonWithType:(MWMActionBarButtonType)type
{
id<MWMActionBarProtocol> delegate = self.delegate;
auto data = self.data;
switch (type)
{
case EButton::Download: [delegate downloadSelectedArea]; break;
case EButton::Opentable:
case EButton::Booking: [delegate book]; break;
case EButton::BookingSearch: [delegate searchBookingHotels]; break;
case EButton::Call: [delegate call]; break;
case EButton::Bookmark:
case MWMActionBarButtonTypeDownload: [delegate downloadSelectedArea]; break;
case MWMActionBarButtonTypeOpentable:
case MWMActionBarButtonTypeBooking: [delegate book]; break;
case MWMActionBarButtonTypeBookingSearch: [delegate searchBookingHotels]; break;
case MWMActionBarButtonTypeCall: [delegate call]; break;
case MWMActionBarButtonTypeBookmark:
if ([data isBookmark])
[delegate removeBookmark];
else
[delegate addBookmark];
break;
case EButton::RouteFrom: [delegate routeFrom]; break;
case EButton::RouteTo: [delegate routeTo]; break;
case EButton::Share: [delegate share]; break;
case EButton::More: [self showActionSheet]; break;
case EButton::RouteAddStop: [delegate routeAddStop]; break;
case EButton::RouteRemoveStop: [delegate routeRemoveStop]; break;
case EButton::AvoidToll: [delegate avoidToll]; break;
case EButton::AvoidDirty: [delegate avoidDirty]; break;
case EButton::AvoidFerry: [delegate avoidFerry]; break;
case EButton::Partner: [delegate openPartner]; break;
case MWMActionBarButtonTypeRouteFrom: [delegate routeFrom]; break;
case MWMActionBarButtonTypeRouteTo: [delegate routeTo]; break;
case MWMActionBarButtonTypeShare: [delegate share]; break;
case MWMActionBarButtonTypeMore: [self showActionSheet]; break;
case MWMActionBarButtonTypeRouteAddStop: [delegate routeAddStop]; break;
case MWMActionBarButtonTypeRouteRemoveStop: [delegate routeRemoveStop]; break;
case MWMActionBarButtonTypeAvoidToll: [delegate avoidToll]; break;
case MWMActionBarButtonTypeAvoidDirty: [delegate avoidDirty]; break;
case MWMActionBarButtonTypeAvoidFerry: [delegate avoidFerry]; break;
case MWMActionBarButtonTypePartner: [delegate openPartner]; break;
}
}
@ -263,7 +263,7 @@
NSMutableArray<NSString *> * titles = [@[] mutableCopy];
for (auto const buttonType : m_additionalButtons)
{
BOOL const isSelected = buttonType == EButton::Bookmark ? [data isBookmark] : NO;
BOOL const isSelected = buttonType == MWMActionBarButtonTypeBookmark ? [data isBookmark] : NO;
if (NSString * title = titleForButton(buttonType, [data partnerIndex], isSelected))
[titles addObject:title];
else

View file

@ -1,22 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UGCAddReviewCell" id="KGk-i7-Jjw" customClass="MWMUGCAddReviewCell" propertyAccessControl="all">
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UGCAddReviewCell" id="KGk-i7-Jjw" customClass="MWMUGCAddReviewCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="127.5"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="128"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="O6m-tq-AL7">
@ -26,10 +23,10 @@
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OWZ-cu-RdT">
<rect key="frame" x="16" y="52" width="288" height="59.5"/>
<rect key="frame" x="16" y="52" width="288" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="stA-xC-5jb">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D4Q-0A-Efb">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
@ -45,7 +42,7 @@
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Horrible" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7eh-cZ-bQ2">
<rect key="frame" x="0.0" y="47.5" width="40" height="12"/>
<rect key="frame" x="0.0" y="48" width="40" height="12"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -55,7 +52,7 @@
</userDefinedRuntimeAttributes>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JsA-OK-Evh">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<inset key="imageEdgeInsets" minX="0.0" minY="-19" maxX="0.0" maxY="0.0"/>
<state key="normal" image="ic_24px_rating_horrible"/>
<connections>
@ -78,10 +75,10 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="02P-Ht-B8E">
<rect key="frame" x="40" y="0.0" width="84" height="59.5"/>
<rect key="frame" x="40" y="0.0" width="84" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FR5-Ym-AgZ">
<rect key="frame" x="22" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="22" y="0.0" width="40" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZfD-kJ-Q3m">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
@ -97,13 +94,13 @@
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bad" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HDt-VE-NRp">
<rect key="frame" x="10.5" y="47.5" width="19" height="12"/>
<rect key="frame" x="10.5" y="48" width="19" height="12"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ep2-Ms-SEh">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<inset key="imageEdgeInsets" minX="0.0" minY="-19" maxX="0.0" maxY="0.0"/>
<state key="normal" image="ic_24px_rating_bad"/>
<connections>
@ -134,7 +131,7 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IvZ-jc-I5F">
<rect key="frame" x="124" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="124" y="0.0" width="40" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3W8-Mg-bTw">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
@ -150,13 +147,13 @@
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Normal" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vds-hI-dsi">
<rect key="frame" x="2" y="47.5" width="36" height="12"/>
<rect key="frame" x="2" y="48" width="36" height="12"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1kJ-GS-ar5">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<inset key="imageEdgeInsets" minX="0.0" minY="-19" maxX="0.0" maxY="0.0"/>
<state key="normal" image="ic_24px_rating_normal"/>
<connections>
@ -179,10 +176,10 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="H26-KC-z3X">
<rect key="frame" x="164" y="0.0" width="84" height="59.5"/>
<rect key="frame" x="164" y="0.0" width="84" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ADD-eW-XeA">
<rect key="frame" x="22" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="22" y="0.0" width="40" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lPm-nd-4qs">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
@ -198,13 +195,13 @@
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Good" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ST3-Um-4dH">
<rect key="frame" x="7" y="47.5" width="26.5" height="12"/>
<rect key="frame" x="7" y="48" width="26.5" height="12"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TJy-zt-WQZ">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<inset key="imageEdgeInsets" minX="0.0" minY="-19" maxX="0.0" maxY="0.0"/>
<state key="normal" image="ic_24px_rating_good"/>
<connections>
@ -235,7 +232,7 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gRX-L4-fra">
<rect key="frame" x="248" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="248" y="0.0" width="40" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="U5X-iD-KyI">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
@ -251,13 +248,13 @@
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Excellent" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jqs-rm-LpL">
<rect key="frame" x="-2.5" y="47.5" width="45" height="12"/>
<rect key="frame" x="-2.5" y="48" width="45" height="12"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OEs-63-qBj">
<rect key="frame" x="0.0" y="0.0" width="40" height="59.5"/>
<rect key="frame" x="0.0" y="0.0" width="40" height="60"/>
<inset key="imageEdgeInsets" minX="0.0" minY="-19" maxX="0.0" maxY="0.0"/>
<state key="normal" image="ic_24px_rating_excellent"/>
<connections>
@ -328,6 +325,7 @@
<outlet property="normalLabel" destination="vds-hI-dsi" id="gEX-i3-cw4"/>
<outlet property="titleLabel" destination="O6m-tq-AL7" id="VZ0-JQ-m6d"/>
</connections>
<point key="canvasLocation" x="139" y="154"/>
</tableViewCell>
</objects>
<resources>

View file

@ -0,0 +1,168 @@
class DirectionView: UIView {
@IBOutlet var button: UIButton!
}
protocol PlacePagePreviewViewControllerDelegate: AnyObject {
func previewDidPressAddReview()
func previewDidPressSimilarHotels()
}
class PlacePagePreviewViewController: UIViewController {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var titleContainerView: UIStackView!
@IBOutlet var popularView: UIView!
@IBOutlet var subtitleLabel: UILabel!
@IBOutlet var subtitleContainerView: UIStackView!
@IBOutlet var scheduleLabel: UILabel!
@IBOutlet var ratingSummaryView: RatingSummaryView!
@IBOutlet var reviewsLabel: UILabel!
@IBOutlet var addReviewButton: UIButton! {
didSet {
addReviewButton.setTitle("+ \(L("leave_a_review"))", for: .normal)
}
}
@IBOutlet var priceLabel: UILabel!
@IBOutlet var discountView: UIView!
@IBOutlet var discountLabel: UILabel!
@IBOutlet var ugcContainerView: UIStackView!
@IBOutlet var addressLabel: UILabel!
@IBOutlet var addressContainerView: UIStackView!
@IBOutlet var searchSimilarButton: UIButton!
@IBOutlet var titleDirectionView: DirectionView!
@IBOutlet var subtitleDirectionView: DirectionView!
@IBOutlet var addressDirectionView: DirectionView!
var directionView: DirectionView?
var placePagePreviewData: PlacePagePreviewData!
weak var delegate: PlacePagePreviewViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
if let title = placePagePreviewData.title {
titleLabel.text = title
directionView = titleDirectionView
} else {
titleContainerView.isHidden = true
}
if let subtitle = placePagePreviewData.subtitle {
subtitleLabel.text = subtitle
directionView = subtitleDirectionView
} else {
subtitleContainerView.isHidden = true
}
if let address = placePagePreviewData.address {
addressLabel.text = address
directionView = addressDirectionView
} else {
addressContainerView.isHidden = true
}
if let pricing = placePagePreviewData.pricing {
priceLabel.text = pricing
} else {
priceLabel.isHidden = true
}
popularView.isHidden = !placePagePreviewData.isPopular
searchSimilarButton.isHidden = placePagePreviewData.hotelType == .none
configSchedule()
configUgc()
ugcContainerView.isHidden = !placePagePreviewData.isBookingPlace
directionView?.isHidden = false
// directionView?.button.imageView?.transform = CGAffineTransform(rotationAngle: 0.2)
}
func updateUgc(_ ugcData: UgcData) {
ugcContainerView.isHidden = false
if let summaryRating = ugcData.summaryRating {
ratingSummaryView.defaultConfig()
ratingSummaryView.value = summaryRating.ratingString
let r = summaryRating.ratingType.rawValue
ratingSummaryView.type = MWMRatingSummaryViewValueType(rawValue: UInt(r))!
reviewsLabel.text = String(format:L("placepage_summary_rating_description"), ugcData.ratingsCount)
} else {
if ugcData.isUpdateEmpty {
ratingSummaryView.noValueImage = UIImage(named: "ic_12px_rating_normal")
ratingSummaryView.noValueColor = UIColor.blackSecondaryText()
reviewsLabel.text = ugcData.reviews.count == 0 ? L("placepage_no_reviews") : ""
} else {
ratingSummaryView.noValueImage = UIImage(named: "ic_12px_radio_on")
ratingSummaryView.noValueColor = UIColor.linkBlue()
reviewsLabel.text = L("placepage_reviewed")
addReviewButton.isHidden = true
}
}
addReviewButton.isHidden = !ugcData.isUpdateEmpty
}
func updateBooking(_ bookingData: HotelBookingData, rooms: HotelRooms?) {
ugcContainerView.isHidden = false
ratingSummaryView.defaultConfig()
ratingSummaryView.value = NSNumber(value: bookingData.score).stringValue
let rawRating = UInt(bookingData.score / 2) + 1
ratingSummaryView.type = MWMRatingSummaryViewValueType(rawValue: rawRating) ?? .noValue
guard let rooms = rooms else { return }
priceLabel.text = String(coreFormat: L("place_page_starting_from"), arguments: [rooms.minPrice])
priceLabel.isHidden = false
if rooms.discount > 0 {
discountLabel.text = "-\(rooms.discount)%"
discountView.isHidden = false
} else if rooms.isSmartDeal {
discountLabel.text = "%"
discountView.isHidden = false
}
}
func updateDistance(_ distance: String) {
directionView?.button.setTitle(distance, for: .normal)
}
func updateHeading(_ angle: CGFloat) {
UIView.animate(withDuration: kDefaultAnimationDuration, delay: 0, options: [.beginFromCurrentState, .curveEaseInOut], animations: {
self.directionView?.button.transform = CGAffineTransform(rotationAngle: angle)
})
}
@IBAction func onAddReview(_ sender: UIButton) {
delegate?.previewDidPressAddReview()
}
@IBAction func onSimilarHotels(_ sender: UIButton) {
delegate?.previewDidPressSimilarHotels()
}
// MARK: private
private func configSchedule() {
switch placePagePreviewData.schedule {
case .openingHoursAllDay:
scheduleLabel.text = L("twentyfour_seven")
case .openingHoursOpen:
scheduleLabel.text = L("editor_time_open")
case .openingHoursClosed:
scheduleLabel.text = L("closed_now")
scheduleLabel.textColor = UIColor.red
case .openingHoursUnknown:
scheduleLabel.isHidden = true
@unknown default:
fatalError()
}
}
private func configUgc() {
ratingSummaryView.textFont = UIFont.bold12()
ratingSummaryView.backgroundOpacity = 0.05
ratingSummaryView.value = "-"
if placePagePreviewData.isBookingPlace {
reviewsLabel.isHidden = true
addReviewButton.isHidden = true
} else {
priceLabel.isHidden = true
discountView.isHidden = true
}
}
}

View file

@ -0,0 +1,29 @@
class PlacePageReviewViewController: UIViewController {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var dateLabel: UILabel!
@IBOutlet var expandableLabel: ExpandableLabel! {
didSet {
expandableLabel.textLabel.font = UIFont.regular14()
expandableLabel.textLabel.textColor = UIColor.blackPrimaryText()
expandableLabel.expandButton.setTitleColor(UIColor.linkBlue(), for: .normal)
expandableLabel.expandButton.titleLabel?.font = UIFont.regular14()
expandableLabel.expandButton.setTitle(L("placepage_more_button"), for: .normal)
}
}
var review: UgcReview!
lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
return formatter
} ()
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = review.author
dateLabel.text = dateFormatter.string(from: review.date)
expandableLabel.textLabel.text = review.text
}
}

View file

@ -0,0 +1,69 @@
protocol PlacePageReviewsViewControllerDelegate: AnyObject {
func didPressMoreReviews()
}
class PlacePageReviewsViewController: UIViewController {
@IBOutlet var stackView: UIStackView!
var ugcData: UgcData? {
didSet {
updateReviews()
}
}
weak var delegate: PlacePageReviewsViewControllerDelegate?
lazy var myReviewViewController: MyReviewViewController = {
let vc = storyboard!.instantiateViewController(ofType: MyReviewViewController.self)
return vc
} ()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: private
private func updateReviews() {
guard let ugcData = ugcData else { return }
if let myReview = ugcData.myReview {
myReviewViewController.myReview = myReview
addToStack(myReviewViewController)
}
for i in 0..<3 {
if i < ugcData.reviews.count {
let review = ugcData.reviews[i]
let vc = storyboard!.instantiateViewController(ofType: PlacePageReviewViewController.self)
vc.review = review
addToStack(vc)
} else {
break
}
}
if ugcData.reviews.count > 3 {
createMoreReviewsButton()
}
}
@objc private func onMoreReviewsButton(_ sender: UIButton) {
delegate?.didPressMoreReviews()
}
private func createMoreReviewsButton() {
let button = UIButton()
button.setTitle(L("placepage_more_reviews_button"), for: .normal)
button.titleLabel?.font = UIFont.regular17()
button.setTitleColor(UIColor.linkBlue(), for: .normal)
button.heightAnchor.constraint(equalToConstant: 44).isActive = true
stackView.addArrangedSubview(button)
button.addTarget(self, action: #selector(onMoreReviewsButton), for: .touchUpInside)
}
private func addToStack(_ viewController: UIViewController) {
addChild(viewController)
stackView.addArrangedSubview(viewController.view)
viewController.didMove(toParent: self)
}
}

View file

@ -1,30 +1,432 @@
//
// PlacePageViewController.swift
// MAPS.ME
//
// Created by aleksey.belousov on 06/11/2019.
// Copyright © 2019 MapsWithMe. All rights reserved.
//
import UIKit
class PlacePageViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
class PlacePageScrollView: UIScrollView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return point.y > 0
}
}
@objc class PlacePageViewController: UIViewController {
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var stackView: UIStackView!
@IBOutlet var actionBarContainerView: UIView!
@objc var placePageData: PlacePageData!
var rootViewController: MapViewController {
MapViewController.shared()
}
lazy var previewViewController: PlacePagePreviewViewController = {
let vc = storyboard!.instantiateViewController(ofType: PlacePagePreviewViewController.self)
vc.placePagePreviewData = placePageData.previewData
vc.delegate = self
return vc
} ()
lazy var catalogSingleItemViewController: CatalogSingleItemViewController = {
let vc = storyboard!.instantiateViewController(ofType: CatalogSingleItemViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var catalogGalleryViewController: CatalogGalleryViewController = {
let vc = storyboard!.instantiateViewController(ofType: CatalogGalleryViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var wikiDescriptionViewController: WikiDescriptionViewController = {
let vc = storyboard!.instantiateViewController(ofType: WikiDescriptionViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var bookmarkViewController: PlacePageBookmarkViewController = {
let vc = storyboard!.instantiateViewController(ofType: PlacePageBookmarkViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var infoViewController: PlacePageInfoViewController = {
let vc = storyboard!.instantiateViewController(ofType: PlacePageInfoViewController.self)
vc.placePageInfoData = placePageData.infoData
vc.delegate = self
return vc
} ()
lazy var taxiViewController: TaxiViewController = {
let vc = storyboard!.instantiateViewController(ofType: TaxiViewController.self)
vc.taxiProvider = placePageData.taxiProvider
vc.delegate = self
return vc
} ()
lazy var ratingSummaryViewController: RatingSummaryViewController = {
let vc = storyboard!.instantiateViewController(ofType: RatingSummaryViewController.self)
vc.view.isHidden = true
return vc
} ()
lazy var addReviewViewController: AddReviewViewController = {
let vc = storyboard!.instantiateViewController(ofType: AddReviewViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var reviewsViewController: PlacePageReviewsViewController = {
let vc = storyboard!.instantiateViewController(ofType: PlacePageReviewsViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var buttonsViewController: PlacePageButtonsViewController = {
let vc = storyboard!.instantiateViewController(ofType: PlacePageButtonsViewController.self)
vc.buttonsData = placePageData.buttonsData!
vc.delegate = self
return vc
} ()
lazy var hotelPhotosViewController: HotelPhotosViewController = {
let vc = storyboard!.instantiateViewController(ofType: HotelPhotosViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var hotelDescriptionViewController: HotelDescriptionViewController = {
let vc = storyboard!.instantiateViewController(ofType: HotelDescriptionViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var hotelFacilitiesViewController: HotelFacilitiesViewController = {
let vc = storyboard!.instantiateViewController(ofType: HotelFacilitiesViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var hotelReviewsViewController: HotelReviewsViewController = {
let vc = storyboard!.instantiateViewController(ofType: HotelReviewsViewController.self)
vc.view.isHidden = true
vc.delegate = self
return vc
} ()
lazy var actionBarViewController: ActionBarViewController = {
let vc = storyboard!.instantiateViewController(ofType: ActionBarViewController.self)
vc.placePageData = placePageData
// vc.delegate = self
return vc
} ()
override func viewDidLoad() {
super.viewDidLoad()
addToStack(previewViewController)
if placePageData.isPromoCatalog {
addToStack(catalogSingleItemViewController)
addToStack(catalogGalleryViewController)
placePageData.loadCatalogPromo { [weak self] in
guard let self = self else { return }
guard let catalogPromo = self.placePageData.catalogPromo else {
if self.placePageData.wikiDescriptionHtml != nil {
self.wikiDescriptionViewController.view.isHidden = false
}
return
}
if catalogPromo.promoItems.count == 1 {
self.catalogSingleItemViewController.promoItem = catalogPromo.promoItems.first!
self.catalogSingleItemViewController.view.isHidden = false
} else {
self.catalogGalleryViewController.promoData = catalogPromo
self.catalogGalleryViewController.view.isHidden = false
if self.placePageData.wikiDescriptionHtml != nil {
self.wikiDescriptionViewController.view.isHidden = false
}
}
}
}
addToStack(wikiDescriptionViewController)
if let wikiDescriptionHtml = placePageData.wikiDescriptionHtml {
wikiDescriptionViewController.descriptionHtml = wikiDescriptionHtml
if placePageData.bookmarkData?.bookmarkDescription == nil && !placePageData.isPromoCatalog {
wikiDescriptionViewController.view.isHidden = false
}
}
addToStack(bookmarkViewController)
if let bookmarkData = placePageData.bookmarkData {
bookmarkViewController.bookmarkData = bookmarkData
bookmarkViewController.view.isHidden = false
}
addToStack(hotelPhotosViewController)
addToStack(hotelDescriptionViewController)
addToStack(hotelFacilitiesViewController)
addToStack(hotelReviewsViewController)
addToStack(infoViewController)
if placePageData.taxiProvider != .none {
addToStack(taxiViewController)
}
if placePageData.previewData.showUgc {
addToStack(ratingSummaryViewController)
addToStack(addReviewViewController)
addToStack(reviewsViewController)
placePageData.loadUgc { [weak self] in
if let self = self, let ugcData = self.placePageData.ugcData {
self.previewViewController.updateUgc(ugcData)
if !ugcData.isTotalRatingEmpty {
self.ratingSummaryViewController.ugcData = ugcData
self.ratingSummaryViewController.view.isHidden = false
}
if ugcData.isUpdateEmpty {
self.addReviewViewController.view.isHidden = false
}
if !ugcData.isEmpty {
self.reviewsViewController.ugcData = ugcData
self.reviewsViewController.view.isHidden = false
}
self.view.layoutIfNeeded()
let previewFrame = self.scrollView.convert(self.previewViewController.view.bounds, from: self.previewViewController.view)
UIView.animate(withDuration: kDefaultAnimationDuration) {
self.scrollView.contentOffset = CGPoint(x: 0, y: previewFrame.maxY - self.scrollView.height)
}
}
}
}
if placePageData.buttonsData != nil {
addToStack(buttonsViewController)
}
placePageData.loadOnlineData { [weak self] in
if let self = self, let bookingData = self.placePageData.hotelBooking {
self.previewViewController.updateBooking(bookingData, rooms: self.placePageData.hotelRooms)
self.stackView.layoutIfNeeded()
UIView.animate(withDuration: kDefaultAnimationDuration) {
if !bookingData.photos.isEmpty {
self.hotelPhotosViewController.photos = bookingData.photos
self.hotelPhotosViewController.view.isHidden = false
}
self.hotelDescriptionViewController.hotelDescription = bookingData.hotelDescription
self.hotelDescriptionViewController.view.isHidden = false
if bookingData.facilities.count > 0 {
self.hotelFacilitiesViewController.facilities = bookingData.facilities
self.hotelFacilitiesViewController.view.isHidden = false
}
if bookingData.reviews.count > 0 {
self.hotelReviewsViewController.reviewCount = bookingData.scoreCount
self.hotelReviewsViewController.totalScore = bookingData.score
self.hotelReviewsViewController.reviews = bookingData.reviews
self.hotelReviewsViewController.view.isHidden = false
}
self.stackView.layoutIfNeeded()
}
}
}
actionBarViewController.view.translatesAutoresizingMaskIntoConstraints = false
actionBarContainerView.addSubview(actionBarViewController.view)
NSLayoutConstraint.activate([
actionBarViewController.view.leadingAnchor.constraint(equalTo: actionBarContainerView.leadingAnchor),
actionBarViewController.view.topAnchor.constraint(equalTo: actionBarContainerView.topAnchor),
actionBarViewController.view.trailingAnchor.constraint(equalTo: actionBarContainerView.trailingAnchor),
actionBarViewController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
MWMLocationManager.add(observer: self)
if let lastLocation = MWMLocationManager.lastLocation() {
onLocationUpdate(lastLocation)
}
if let lastHeading = MWMLocationManager.lastHeading() {
onHeadingUpdate(lastHeading)
}
let bgView = UIView()
bgView.backgroundColor = UIColor.white()
stackView.insertSubview(bgView, at: 0)
bgView.alignToSuperview()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentInset = UIEdgeInsets(top: scrollView.height, left: 0, bottom: 0, right: 0)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// let previewFrame = scrollView.convert(previewViewController.view.bounds, from: previewViewController.view)
// UIView.animate(withDuration: kDefaultAnimationDuration) {
// self.scrollView.contentOffset = CGPoint(x: 0, y: previewFrame.maxY - self.scrollView.height)
// }
}
// MARK: private
private func addToStack(_ viewController: UIViewController) {
addChild(viewController)
stackView.addArrangedSubview(viewController.view)
viewController.didMove(toParent: self)
}
}
extension PlacePageViewController: PlacePagePreviewViewControllerDelegate {
func previewDidPressAddReview() {
}
func previewDidPressSimilarHotels() {
}
}
extension PlacePageViewController: PlacePageInfoViewControllerDelegate {
func didPressCall() {
guard let phoneUrl = placePageData.infoData.phoneUrl,
UIApplication.shared.canOpenURL(phoneUrl) else { return }
UIApplication.shared.open(phoneUrl, options: [:])
}
func didPressWebsite() {
guard let website = placePageData.infoData.website,
let url = URL(string: website) else { return }
UIApplication.shared.open(url, options: [:])
}
func didPressEmail() {
}
func didPressLocalAd() {
}
}
extension PlacePageViewController: WikiDescriptionViewControllerDelegate {
func didPressMore() {
}
}
extension PlacePageViewController: TaxiViewControllerDelegate {
func didPressOrder() {
}
}
extension PlacePageViewController: AddReviewViewControllerDelegate {
func didRate(_ rating: UgcSummaryRatingType) {
}
}
extension PlacePageViewController: PlacePageReviewsViewControllerDelegate {
func didPressMoreReviews() {
}
}
extension PlacePageViewController: PlacePageButtonsViewControllerDelegate {
func didPressHotels() {
}
func didPressAddPlace() {
}
func didPressEditPlace() {
}
func didPressAddBusiness() {
}
}
extension PlacePageViewController: HotelPhotosViewControllerDelegate {
func didSelectItemAt(_ index: Int) {
}
}
extension PlacePageViewController: HotelDescriptionViewControllerDelegate {
func hotelDescriptionDidPressMore() {
}
}
extension PlacePageViewController: HotelFacilitiesViewControllerDelegate {
func facilitiesDidPressMore() {
}
}
extension PlacePageViewController: HotelReviewsViewControllerDelegate {
func hotelReviewsDidPressMore() {
}
}
extension PlacePageViewController: CatalogSingleItemViewControllerDelegate {
func catalogPromoItemDidPressView() {
}
func catalogPromoItemDidPressMore() {
}
}
extension PlacePageViewController: CatalogGalleryViewControllerDelegate {
func promoGalleryDidPressMore() {
}
func promoGalleryDidSelectItemAtIndex(_ index: Int) {
}
}
extension PlacePageViewController: PlacePageBookmarkViewControllerDelegate {
func bookmarkDidPressEdit() {
}
}
extension PlacePageViewController: MWMLocationObserver {
func onHeadingUpdate(_ heading: CLHeading) {
if heading.trueHeading < 0 {
return
}
let rad = heading.trueHeading * Double.pi / 180
previewViewController.updateHeading(CGFloat(rad))
}
func onLocationUpdate(_ location: CLLocation) {
let ppLocation = CLLocation(latitude: placePageData.locationCoordinate.latitude,
longitude: placePageData.locationCoordinate.longitude)
let distance = location.distance(from: ppLocation)
let distanceFormatter = MKDistanceFormatter()
distanceFormatter.unitStyle = .abbreviated
let formattedDistance = distanceFormatter.string(fromDistance: distance)
previewViewController.updateDistance(formattedDistance)
}
func onLocationError(_ locationError: MWMLocationStatus) {
}
}

View file

@ -0,0 +1,56 @@
class RatingSummaryViewController: UIViewController {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var countLabel: UILabel!
@IBOutlet var ratingSummaryView: RatingSummaryView! {
didSet {
ratingSummaryView.horribleColor = UIColor.ratingRed()
ratingSummaryView.badColor = UIColor.ratingOrange()
ratingSummaryView.normalColor = UIColor.ratingYellow()
ratingSummaryView.goodColor = UIColor.ratingLightGreen()
ratingSummaryView.excellentColor = UIColor.ratingGreen()
ratingSummaryView.textFont = UIFont.bold28()
ratingSummaryView.textSize = 28
}
}
@IBOutlet var ratingViews: [UIView]!
@IBOutlet var ratingLabels: [UILabel]!
@IBOutlet var starViews: [StarRatingView]! {
didSet {
starViews.forEach {
$0.activeColor = UIColor.ratingYellow()
$0.inactiveColor = UIColor.blackDividers()
}
}
}
var ugcData: UgcData? {
didSet {
updateRating()
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateRating()
}
private func updateRating() {
guard let ugcData = ugcData else { return }
ratingSummaryView.value = ugcData.summaryRating!.ratingString
let r = ugcData.summaryRating!.ratingType.rawValue
ratingSummaryView.type = MWMRatingSummaryViewValueType(rawValue: UInt(r))!
countLabel.text = String(format:L("placepage_summary_rating_description"), ugcData.ratingsCount)
for i in 0..<3 {
if ugcData.starRatings.count > i {
let starRating = ugcData.starRatings[i]
ratingLabels[i].text = L(starRating.title)
starViews[i].rating = Int(round(starRating.value))
} else {
ratingViews[i].isHidden = true
}
}
}
}

View file

@ -0,0 +1,38 @@
protocol TaxiViewControllerDelegate: AnyObject {
func didPressOrder()
}
class TaxiViewController: UIViewController {
@IBOutlet var taxiImageView: UIImageView!
@IBOutlet var taxiNameLabel: UILabel!
var taxiProvider: PlacePageTaxiProvider = .none
weak var delegate: TaxiViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
switch taxiProvider {
case .none:
assertionFailure()
case .uber:
taxiImageView.image = UIImage(named: "icTaxiUber")
taxiNameLabel.text = L("uber")
case .yandex:
taxiImageView.image = UIImage(named: "ic_taxi_logo_yandex")
taxiNameLabel.text = L("yandex_taxi_title")
case .maxim:
taxiImageView.image = UIImage(named: "ic_taxi_logo_maksim")
taxiNameLabel.text = L("maxim_taxi_title")
case .rutaxi:
taxiImageView.image = UIImage(named: "ic_taxi_logo_vezet")
taxiNameLabel.text = L("vezet_taxi")
@unknown default:
fatalError()
}
}
@IBAction func onOrder(_ sender: UIButton) {
delegate?.didPressOrder()
}
}

View file

@ -0,0 +1,58 @@
class ExpandableLabel: UIView {
private var stackView = UIStackView()
var textLabel = UILabel()
var expandButton = UIButton()
var expanded = false
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.alignment = .leading
textLabel.numberOfLines = 2
textLabel.contentMode = .topLeft
expandButton.clipsToBounds = true
expandButton.addTarget(self, action: #selector(onExpand(_:)), for: .touchUpInside)
addSubview(stackView)
stackView.addArrangedSubview(textLabel)
stackView.addArrangedSubview(expandButton)
NSLayoutConstraint.activate([
stackView.leftAnchor.constraint(equalTo: leftAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.rightAnchor.constraint(equalTo: rightAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
}
@objc func onExpand(_ sender: UIButton) {
UIView.animate(withDuration: kDefaultAnimationDuration) {
self.textLabel.numberOfLines = 0
self.expandButton.isHidden = true
self.stackView.layoutIfNeeded()
}
}
override func layoutSubviews() {
super.layoutSubviews()
guard let s = textLabel.text as NSString? else { return }
let textRect = s.boundingRect(with: size,
options: .usesLineFragmentOrigin,
attributes: [.font: textLabel.font!],
context: nil)
let lineHeight = textLabel.font.lineHeight
if Int(lineHeight * CGFloat(textLabel.numberOfLines)) >= Int(textRect.height) {
expandButton.isHidden = true
}
}
}

View file

@ -0,0 +1,113 @@
fileprivate class StarView: UIView {
private static let points: [CGPoint] = [
CGPoint(x: 49.5, y: 0.0),
CGPoint(x: 60.5, y: 35.0),
CGPoint(x: 99.0, y: 35.0),
CGPoint(x: 67.5, y: 58.0),
CGPoint(x: 78.5, y: 92.0),
CGPoint(x: 49.5, y: 71.0),
CGPoint(x: 20.5, y: 92.0),
CGPoint(x: 31.5, y: 58.0),
CGPoint(x: 0.0, y: 35.0),
CGPoint(x: 38.5, y: 35.0),
]
private var path: UIBezierPath = {
let path = UIBezierPath()
path.move(to: StarView.points[0])
StarView.points.suffix(from: 1).forEach {
path.addLine(to: $0)
}
path.close()
return path
} ()
private var starLayer: CAShapeLayer {
layer as! CAShapeLayer
}
var color: UIColor = UIColor.orange {
didSet {
starLayer.fillColor = color.cgColor
}
}
override class var layerClass: AnyClass {
CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
starLayer.fillRule = .evenOdd
starLayer.fillColor = color.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
let offset: CGFloat = 0.05
let sx = width / 100 * CGFloat(1.0 - offset * 2)
let sy = height / 100 * CGFloat(1.0 - offset * 2)
guard let newPath = path.copy() as? UIBezierPath else { return }
let scale = CGAffineTransform(scaleX: sx, y: sy)
let translate = CGAffineTransform(translationX: width * offset, y: height * offset)
newPath.apply(scale.concatenating(translate))
let boxPath = UIBezierPath(rect: bounds)
boxPath.append(newPath)
boxPath.usesEvenOddFillRule = true
starLayer.path = boxPath.cgPath
}
}
class StarRatingView: UIView {
private var starViews: [StarView] = []
var rating: Int = 3
var activeColor: UIColor = UIColor.orange
var inactiveColor: UIColor = UIColor.lightGray
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func layoutSubviews() {
super.layoutSubviews()
for i in 0..<starViews.count {
let sv = starViews[i]
sv.color = i >= rating ? inactiveColor : activeColor
sv.frame = CGRect(x: 18 * i, y: 0, width: 15, height: 15)
sv.layer.cornerRadius = 3
}
}
override var intrinsicContentSize: CGSize {
return CGSize(width: 18 * 5 - 3, height: 15)
}
private func commonInit() {
for _ in 0..<5 {
let sv = StarView()
sv.color = inactiveColor
sv.clipsToBounds = true
starViews.append(sv)
addSubview(sv)
}
}
}

View file

@ -0,0 +1,59 @@
protocol WikiDescriptionViewControllerDelegate: AnyObject {
func didPressMore()
}
class WikiDescriptionViewController: UIViewController {
@IBOutlet var descriptionTextView: UITextView!
@IBOutlet var moreButton: UIButton!
var descriptionHtml: String? {
didSet{
updateDescription()
}
}
weak var delegate: WikiDescriptionViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
descriptionTextView.textContainerInset = .zero
updateDescription()
}
private func updateDescription() {
guard let descriptionHtml = descriptionHtml else { return }
DispatchQueue.global().async {
let font = UIFont.regular14()
let color = UIColor.blackPrimaryText()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 4
let attributedString: NSAttributedString
if let str = NSMutableAttributedString(htmlString: descriptionHtml, baseFont: font, paragraphStyle: paragraphStyle) {
str.addAttribute(NSAttributedString.Key.foregroundColor,
value: color,
range: NSRange(location: 0, length: str.length))
attributedString = str;
} else {
attributedString = NSAttributedString(string: descriptionHtml,
attributes: [NSAttributedString.Key.font : font,
NSAttributedString.Key.foregroundColor: color,
NSAttributedString.Key.paragraphStyle: paragraphStyle])
}
DispatchQueue.main.async {
if attributedString.length > 500 {
self.descriptionTextView.attributedText = attributedString.attributedSubstring(from: NSRange(location: 0,
length: 500))
} else {
self.descriptionTextView.attributedText = attributedString
}
}
}
}
@IBAction func onMore(_ sender: UIButton) {
delegate?.didPressMore()
}
}

View file

@ -12,6 +12,7 @@ enum Storyboard: Int {
case categorySettings
case drivingOptions
case carPlay
case placePage
}
extension UIStoryboard {
@ -28,6 +29,7 @@ extension UIStoryboard {
case .categorySettings: name = "CategorySettings"
case .drivingOptions: name = "DrivingOptions"
case .carPlay: name = "CarPlayStoryboard"
case .placePage: name = "PlacePage"
}
return UIStoryboard(name: name, bundle: nil)
}