[ios] New place page

This commit is contained in:
VladiMihaylenko 2016-10-05 13:54:11 +03:00
parent c3b17e75f7
commit 54798069b3
52 changed files with 3158 additions and 182 deletions

View file

@ -219,7 +219,7 @@
}
else
{
BookmarksVC * bvc = [[BookmarksVC alloc] initWithCategory:indexPath.row];
BookmarksVC * bvc = [[BookmarksVC alloc] initWithCategory:static_cast<int>(indexPath.row)];
[self.navigationController pushViewController:bvc animated:YES];
}
}

View file

@ -2,9 +2,9 @@
@interface BookmarksVC : MWMTableViewController <UITextFieldDelegate>
{
size_t m_categoryIndex;
int m_categoryIndex;
}
- (instancetype)initWithCategory:(size_t)index;
- (instancetype)initWithCategory:(int)index;
@end

View file

@ -38,7 +38,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
@implementation BookmarksVC
- (instancetype)initWithCategory:(size_t)index
- (instancetype)initWithCategory:(int)index
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
@ -236,7 +236,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
// Same as "Close".
MapViewController * mapVC = self.navigationController.viewControllers.firstObject;
mapVC.controlsManager.searchHidden = YES;
f.ShowBookmark(BookmarkAndCategory(m_categoryIndex, indexPath.row));
f.ShowBookmark({static_cast<int>(indexPath.row), m_categoryIndex});
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
@ -294,7 +294,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
}
else
{
BookmarkAndCategory bookmarkAndCategory = BookmarkAndCategory(m_categoryIndex, indexPath.row);
BookmarkAndCategory bookmarkAndCategory{static_cast<int>(indexPath.row), m_categoryIndex};
NSValue * value = [NSValue valueWithBytes:&bookmarkAndCategory objCType:@encode(BookmarkAndCategory)];
[[NSNotificationCenter defaultCenter] postNotificationName:BOOKMARK_DELETED_NOTIFICATION object:value];
BookmarkCategory::Guard guard(*cat);

View file

@ -35,7 +35,7 @@
[super viewDidLoad];
NSAssert(self.category, @"Category can't be nil!");
NSAssert(self.delegate, @"Delegate can't be nil!");
NSAssert(IsValid(m_bac), @"Invalid BookmarkAndCategory's instance!");
NSAssert(m_bac.IsValid(), @"Invalid BookmarkAndCategory's instance!");
self.title = L(@"bookmark_sets");
}
@ -67,7 +67,7 @@
if (cat)
cell.textLabel.text = @(cat->GetName().c_str());
if (m_bac.first == indexPath.row)
if (m_bac.m_categoryIndex == indexPath.row)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
@ -85,11 +85,11 @@
- (void)moveBookmarkToSetWithIndex:(int)setIndex
{
BookmarkAndCategory bac;
bac.second = static_cast<int>(GetFramework().MoveBookmark(m_bac.second, m_bac.first, setIndex));
bac.first = setIndex;
bac.m_bookmarkIndex = static_cast<int>(GetFramework().MoveBookmark(m_bac.m_bookmarkIndex, m_bac.m_categoryIndex, setIndex));
bac.m_categoryIndex = setIndex;
m_bac = bac;
BookmarkCategory const * category = GetFramework().GetBookmarkManager().GetBmCategory(bac.first);
BookmarkCategory const * category = GetFramework().GetBookmarkManager().GetBmCategory(bac.m_categoryIndex);
self.category = @(category->GetName().c_str());
}

View file

@ -9,6 +9,7 @@
@class MapViewController;
@class MWMPlacePageEntity;
@protocol MWMFeatureHolder;
@interface MWMMapViewControlsManager : NSObject
@ -20,8 +21,8 @@
@property(nonatomic) MWMBottomMenuState menuState;
@property(nonatomic) MWMBottomMenuState menuRestoreState;
@property(nonatomic, readonly) MWMNavigationDashboardState navigationState;
@property(nonatomic, readonly) MWMPlacePageEntity * placePageEntity;
@property(nonatomic) BOOL searchHidden;
@property(nonatomic) BOOL isDirectionViewHidden;
- (instancetype)init __attribute__((unavailable("init is not available")));
- (instancetype)initWithParentController:(MapViewController *)controller;
@ -40,8 +41,6 @@
#pragma mark - MWMPlacePageViewManager
@property(nonatomic, readonly) BOOL isDirectionViewShown;
- (void)dismissPlacePage;
- (void)showPlacePage:(place_page::Info const &)info;
- (void)addPlacePageViews:(NSArray *)views;
@ -68,4 +67,8 @@
- (void)searchFrameUpdated:(CGRect)frame;
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale;
#pragma mark - MWMFeatureHolder
- (id<MWMFeatureHolder>)featureHolder;
@end

View file

@ -10,6 +10,7 @@
#import "MWMFrameworkListener.h"
#import "MWMObjectsCategorySelectorController.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageManager.h"
#import "MWMPlacePageViewManager.h"
#import "MWMRoutePreview.h"
#import "MWMRouter.h"
@ -42,7 +43,7 @@ extern NSString * const kAlohalyticsTapEventKey;
@property(nonatomic) MWMSideButtons * sideButtons;
@property(nonatomic) MWMBottomMenuViewController * menuController;
@property(nonatomic) MWMPlacePageViewManager * placePageManager;
@property(nonatomic) id<MWMPlacePageProtocol> placePageManager;
@property(nonatomic) MWMNavigationDashboardManager * navigationManager;
@property(nonatomic) MWMSearchManager * searchManager;
@ -84,7 +85,7 @@ extern NSString * const kAlohalyticsTapEventKey;
searchManagerState != MWMSearchManagerStateHidden) ||
self.navigationState == MWMNavigationDashboardStatePlanning ||
self.navigationState == MWMNavigationDashboardStateReady ||
self.menuState == MWMBottomMenuStateActive || self.isDirectionViewShown ||
self.menuState == MWMBottomMenuStateActive || !self.isDirectionViewHidden ||
(isNightMode && self.navigationState != MWMNavigationDashboardStateHidden) ||
MapsAppDelegate.theApp.routingPlaneMode != MWMRoutingPlaneModeNone;
return (isLight || (!isLight && isNightMode)) ? UIStatusBarStyleLightContent
@ -292,12 +293,19 @@ extern NSString * const kAlohalyticsTapEventKey;
{
if (IPAD)
return;
CGSize const ownerViewSize = self.ownerController.view.size;
if (ownerViewSize.width > ownerViewSize.height)
if (isIOS7)
{
CGFloat const leftBound = frame.origin.x + frame.size.width;
self.menuController.leftBound = leftBound;
[MWMNavigationDashboardManager manager].leftBound = leftBound;
CGSize const ownerViewSize = self.ownerController.view.size;
if (ownerViewSize.width > ownerViewSize.height)
{
CGFloat const leftBound = frame.origin.x + frame.size.width;
self.menuController.leftBound = leftBound;
[MWMNavigationDashboardManager manager].leftBound = leftBound;
}
else
{
[self.sideButtons setBottomBound:frame.origin.y];
}
}
else
{
@ -459,11 +467,13 @@ extern NSString * const kAlohalyticsTapEventKey;
return _menuController;
}
- (MWMPlacePageViewManager *)placePageManager
- (id)placePageManager
{
auto const PlacePageClass = isIOS7 || IPAD ? [MWMPlacePageViewManager class] : [MWMPlacePageManager class];
if (!_placePageManager)
_placePageManager =
[[MWMPlacePageViewManager alloc] initWithViewController:self.ownerController];
[[PlacePageClass alloc] initWithViewController:self.ownerController];
return _placePageManager;
}
@ -526,12 +536,6 @@ extern NSString * const kAlohalyticsTapEventKey;
}
- (MWMNavigationDashboardState)navigationState { return self.navigationManager.state; }
- (MWMPlacePageEntity *)placePageEntity { return self.placePageManager.entity; }
- (BOOL)isDirectionViewShown
{
return _placePageManager ? _placePageManager.isDirectionViewShown : NO;
}
- (void)setTopBound:(CGFloat)topBound
{
if (IPAD)
@ -558,4 +562,11 @@ extern NSString * const kAlohalyticsTapEventKey;
searchHidden ? MWMSearchManagerStateHidden : MWMSearchManagerStateDefault;
}
#pragma mark - MWMFeatureHolder
- (id<MWMFeatureHolder>)featureHolder
{
return self.placePageManager;
}
@end

View file

@ -57,7 +57,7 @@
- (IBAction)openBookmarks
{
BookmarksVC * bvc = [[BookmarksVC alloc] initWithCategory:self.index];
BookmarksVC * bvc = [[BookmarksVC alloc] initWithCategory:static_cast<int>(self.index)];
UINavigationController * rootVC = (UINavigationController *)UIApplication.sharedApplication.delegate.window.rootViewController;
[rootVC pushViewController:bvc animated:YES];
}

View file

@ -1,3 +1,4 @@
#import "Common.h"
#import "MWMActionBarButton.h"
#import "MWMButton.h"
#import "UIColor+MapsMeColor.h"
@ -95,7 +96,8 @@ NSString * titleForButton(EButton type, BOOL isSelected)
button.delegate = delegate;
button.type = type;
[view addSubview:button];
button.autoresizingMask = UIViewAutoresizingNone;
if (isIOS7)
button.autoresizingMask = UIViewAutoresizingNone;
[button configButton:isSelected];
}

View file

@ -6,6 +6,7 @@
#import "MWMPlacePage.h"
#import "MWMPlacePageActionBar.h"
#import "MWMPlacePageBookmarkCell.h"
#import "MWMPlacePageBookmarkDelegate.h"
#import "MWMPlacePageButtonCell.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageInfoCell.h"

View file

@ -0,0 +1,12 @@
#import "MWMTableViewCell.h"
@protocol MWMPlacePageButtonsProtocol, MWMPlacePageCellUpdateProtocol;
@interface MWMBookmarkCell : MWMTableViewCell
- (void)configureWithText:(NSString *)text
updateCellDelegate:(id<MWMPlacePageCellUpdateProtocol>)updateCellDelegate
editBookmarkDelegate:(id<MWMPlacePageButtonsProtocol>)editBookmarkDelegate
isHTML:(BOOL)isHTML;
@end

View file

@ -0,0 +1,216 @@
#import "MWMPlacePageCellUpdateProtocol.h"
#import "MWMBookmarkCell.h"
#import "MWMPlacePageProtocol.h"
#import "UIColor+MapsMeColor.h"
#import "UIFont+MapsMeFonts.h"
namespace
{
void * kContext = &kContext;
NSString * const kTextViewContentSizeKeyPath = @"contentSize";
} // namespace
@interface MWMBookmarkCell ()
@property(weak, nonatomic) IBOutlet UITextView * textView;
@property(weak, nonatomic) IBOutlet UIImageView * spinner;
@property(weak, nonatomic) IBOutlet UIButton * editButton;
@property(weak, nonatomic) IBOutlet UIImageView * gradientView;
@property(nonatomic) IBOutlet NSLayoutConstraint * textViewHeight;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * moreButtonHeight;
@property(nonatomic) IBOutlet NSLayoutConstraint * textViewZeroHeight;
@property(weak, nonatomic) id<MWMPlacePageCellUpdateProtocol> updateCellDelegate;
@property(weak, nonatomic) id<MWMPlacePageButtonsProtocol> editBookmarkDelegate;
@property(copy, nonatomic) NSAttributedString * attributedHTML;
@property (nonatomic) BOOL isOpen;
@end
@implementation MWMBookmarkCell
- (void)awakeFromNib
{
[super awakeFromNib];
[self registerObserver];
}
- (void)dealloc
{
[self unregisterObserver];
}
- (void)unregisterObserver
{
[self.textView removeObserver:self forKeyPath:kTextViewContentSizeKeyPath context:kContext];
}
- (void)registerObserver
{
[self.textView addObserver:self forKeyPath:kTextViewContentSizeKeyPath options:NSKeyValueObservingOptionNew context:kContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == kContext)
{
NSValue * s = change[@"new"];
CGFloat const height = s.CGSizeValue.height;
auto const boundedHeight = self.textViewHeight.constant;
if (height < boundedHeight || self.isOpen)
[self stateOpen:YES];
else if (height > boundedHeight && !self.isOpen)
[self stateOpen:NO];
[self setNeedsLayout];
[self.updateCellDelegate updateCellWithForceReposition:NO];
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (void)configureWithText:(NSString *)text
updateCellDelegate:(id<MWMPlacePageCellUpdateProtocol>)updateCellDelegate
editBookmarkDelegate:(id<MWMPlacePageButtonsProtocol>)editBookmarkDelegate
isHTML:(BOOL)isHTML
{
self.attributedHTML = nil;
self.isOpen = NO;
self.textViewHeight.active = NO;
self.textViewZeroHeight.active = NO;
self.updateCellDelegate = updateCellDelegate;
self.editBookmarkDelegate = editBookmarkDelegate;
if (!text.length)
{
[self configWithEmptyDescription];
}
else if (isHTML)
{
[self configHTML:text];
}
else
{
[self configPlain:text];
}
}
- (void)configWithEmptyDescription
{
[self stopSpinner];
[self stateOpen:YES];
self.textViewZeroHeight.active = YES;
}
- (void)configHTML:(NSString *)text
{
if (self.attributedHTML)
{
[self stopSpinner];
self.textViewZeroHeight.active = NO;
self.textView.attributedText = self.attributedHTML;
if (fabs(self.textView.contentSize.height - 0.5) < 1)
[self.textView sizeToFit];
}
else
{
self.textViewZeroHeight.active = YES;
[self startSpinner];
[self stateOpen:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSDictionary<NSString *, id> * attr = @{
NSForegroundColorAttributeName : [UIColor blackPrimaryText],
NSFontAttributeName : [UIFont regular16]
};
NSError * error = nil;
NSMutableAttributedString * str = [[NSMutableAttributedString alloc]
initWithData:[text dataUsingEncoding:NSUnicodeStringEncoding]
options:@{
NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType
}
documentAttributes:nil
error:&error];
if (error)
{
// If we failed while attempting to render html than just show plain text in bookmark.
// Ussualy there is a problem only in iOS7.
self.attributedHTML = [[NSAttributedString alloc] initWithString:text attributes:attr];
}
else
{
[str addAttributes:attr range:{0, str.length}];
self.attributedHTML = str;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self configHTML:nil];
});
});
}
}
- (void)configPlain:(NSString *)text
{
[self stopSpinner];
self.textView.text = text;
}
- (void)stateOpen:(BOOL)isOpen
{
self.moreButtonHeight.constant = isOpen ? 0 : 33;
self.textViewHeight.active = !isOpen;
self.gradientView.hidden = isOpen;
}
- (void)startSpinner
{
// self.textViewZeroHeight.active = YES;
self.editButton.hidden = YES;
NSUInteger const animationImagesCount = 12;
NSMutableArray * animationImages = [NSMutableArray arrayWithCapacity:animationImagesCount];
NSString * postfix = [UIColor isNightMode] ? @"dark" : @"light";
for (NSUInteger i = 0; i < animationImagesCount; ++i)
animationImages[i] =
[UIImage imageNamed:[NSString stringWithFormat:@"Spinner_%@_%@", @(i + 1), postfix]];
self.spinner.animationDuration = 0.8;
self.spinner.animationImages = animationImages;
self.spinner.hidden = NO;
[self.spinner startAnimating];
}
- (void)stopSpinner
{
[self.spinner stopAnimating];
self.editButton.hidden = NO;
self.spinner.hidden = YES;
}
- (IBAction)moreTap
{
self.isOpen = YES;
[self stateOpen:YES];
[self setNeedsLayout];
// [self.delegate updateCellWithForceReposition:NO];
}
- (IBAction)editTap
{
[self.editBookmarkDelegate editBookmark];
}
@end

View file

@ -13,6 +13,8 @@
- (instancetype)initWithManager:(MWMPlacePageViewManager *)manager;
- (void)setDirectionArrowTransform:(CGAffineTransform)transform;
- (void)show;
- (instancetype)initWithCoder:(NSCoder *)aDecoder __attribute__((unavailable("initWithCoder is not available")));
- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("initWithFrame is not available")));
- (instancetype)init __attribute__((unavailable("init is not available")));

View file

@ -1,3 +1,6 @@
#import "MapsAppDelegate.h"
#import "MapViewController.h"
#import "MWMMapViewControlsManager.h"
#import "MWMDirectionView.h"
#import "MWMPlacePageViewManager.h"
#import "UIFont+MapsMeFonts.h"
@ -34,6 +37,36 @@ static CGFloat const kDirectionArrowSide = IPAD ? 260. : 160.;
self.directionArrow.autoresizingMask = UIViewAutoresizingNone;
}
- (void)show
{
UIView * superview = [MapsAppDelegate theApp].mapViewController.view;
[superview addSubview:self];
[superview endEditing:YES];
[self setNeedsLayout];
}
- (void)didMoveToSuperview
{
[super didMoveToSuperview];
MapsAppDelegate * app = [MapsAppDelegate theApp];
MWMMapViewControlsManager * manager = [MWMMapViewControlsManager manager];
if (self.superview)
{
[app disableStandby];
manager.isDirectionViewHidden = NO;
}
else
{
[app enableStandby];
manager.isDirectionViewHidden = YES;
}
[app.mapViewController updateStatusBarStyle];
}
- (void)layoutSubviews
{
UIView * superview = self.superview;
@ -122,7 +155,7 @@ static CGFloat const kDirectionArrowSide = IPAD ? 260. : 160.;
{
// Prevent super call to stop event propagation
// [super touchesBegan:touches withEvent:event];
[self.manager hideDirectionView];
[self removeFromSuperview];
}
@end

View file

@ -1,9 +1,11 @@
#import "MWMTableViewController.h"
@class MWMPlacePageViewManager;
@class MWMPlacePageData;
@interface MWMEditBookmarkController : MWMTableViewController
@property (weak, nonatomic) MWMPlacePageData * data;
@property (nonatomic) MWMPlacePageViewManager * manager;
@end

View file

@ -1,8 +1,10 @@
#import "Common.h"
#import "MWMBookmarkTitleCell.h"
#import "MWMButtonCell.h"
#import "MWMBookmarkColorViewController.h"
#import "MWMEditBookmarkController.h"
#import "MWMNoteCell.h"
#import "MWMPlacePageData.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageViewManager.h"
#import "SelectSetVC.h"
@ -50,13 +52,23 @@ enum RowInMetaInfo
- (void)viewDidLoad
{
[super viewDidLoad];
NSAssert(self.manager, @"Entity can't be nil!");
MWMPlacePageEntity * en = self.manager.entity;
self.cachedDescription = en.bookmarkDescription;
self.cachedTitle = en.bookmarkTitle;
self.cachedCategory = en.bookmarkCategory;
self.cachedColor = en.bookmarkColor;
m_cachedBac = en.bac;
NSAssert(self.manager || self.data, @"Entity and data can't be nil both!");
if (isIOS7 || IPAD)
{
MWMPlacePageEntity * en = self.manager.entity;
self.cachedDescription = en.bookmarkDescription;
self.cachedTitle = en.bookmarkTitle;
self.cachedCategory = en.bookmarkCategory;
self.cachedColor = en.bookmarkColor;
m_cachedBac = en.bac;
}
else
{
self.cachedDescription = self.data.bookmarkDescription;
self.cachedTitle = self.data.externalTitle ? self.data.externalTitle : self.data.title;
self.cachedCategory = self.data.bookmarkCategory;
self.cachedColor = self.data.bookmarkColor;
}
[self configNavBar];
[self registerCells];
@ -95,14 +107,40 @@ enum RowInMetaInfo
- (void)onSave
{
[self.view endEditing:YES];
MWMPlacePageEntity * en = self.manager.entity;
en.bookmarkDescription = self.cachedDescription;
en.bookmarkColor = self.cachedColor;
en.bookmarkCategory = self.cachedCategory;
en.bookmarkTitle = self.cachedTitle;
en.bac = m_cachedBac;
[en synchronize];
[self.manager reloadBookmark];
if (isIOS7 || IPAD)
{
MWMPlacePageEntity * en = self.manager.entity;
en.bookmarkDescription = self.cachedDescription;
en.bookmarkColor = self.cachedColor;
en.bookmarkCategory = self.cachedCategory;
en.bookmarkTitle = self.cachedTitle;
en.bac = m_cachedBac;
[en synchronize];
[self.manager reloadBookmark];
}
else
{
Framework & f = GetFramework();
auto const bac = self.data.bac;
BookmarkCategory * category = f.GetBmCategory(bac.m_categoryIndex);
if (!category)
return;
{
BookmarkCategory::Guard guard(*category);
Bookmark * bookmark =
static_cast<Bookmark *>(guard.m_controller.GetUserMarkForEdit(bac.m_bookmarkIndex));
if (!bookmark)
return;
bookmark->SetType(self.cachedColor.UTF8String);
bookmark->SetDescription(self.cachedDescription.UTF8String);
bookmark->SetName(self.cachedTitle.UTF8String);
}
category->SaveToKMLFile();
f.UpdatePlacePageInfoForCurrentSelection();
}
[self backTap];
}

View file

@ -0,0 +1,32 @@
namespace osmoh
{
struct Day
{
Day(NSString * workingDays, NSString * workingTimes, NSString * breaks) : m_workingDays(workingDays),
m_workingTimes(workingTimes),
m_breaks(breaks) {}
explicit Day(NSString * workingDays) : m_workingDays(workingDays),
m_isOpen(false) {}
NSString * TodayTime() const
{
return m_workingTimes ? [NSString stringWithFormat:@"%@ %@", m_workingDays, m_workingTimes] : m_workingDays;
}
NSString * m_workingDays;
NSString * m_workingTimes;
NSString * m_breaks;
bool m_isOpen = true;
};
} // namespace osmoh
#include "std/string.hpp"
#include "std/vector.hpp"
@interface MWMOpeningHours : NSObject
+ (vector<osmoh::Day>)processRawString:(NSString *)str;
@end

View file

@ -0,0 +1,128 @@
#import "MWMOpeningHours.h"
#import "MWMOpeningHoursCommon.h"
#include "3party/opening_hours/opening_hours.hpp"
#include "editor/opening_hours_ui.hpp"
#include "editor/ui2oh.hpp"
using namespace editor;
using namespace osmoh;
namespace
{
NSString * stringFromTimeSpan(Timespan const & timeSpan)
{
return [NSString stringWithFormat:@"%@-%@", stringFromTime(timeSpan.GetStart()),
stringFromTime(timeSpan.GetEnd())];
}
NSString * breaksFromClosedTime(TTimespans const & closedTimes)
{
NSMutableString * breaks = [@"" mutableCopy];
for (auto & ct : closedTimes)
{
[breaks appendString:@"\n"];
[breaks appendString:stringFromTimeSpan(ct)];
}
return breaks.copy;
}
void addToday(ui::TimeTable const & tt, vector<Day> & allDays)
{
NSString * workingDays;
NSString * workingTimes;
NSString * breaks;
if (tt.IsTwentyFourHours())
{
workingDays = L(@"twentyfour_seven");
workingTimes = @"";
breaks = @"";
}
else
{
BOOL const everyDay = (tt.GetOpeningDays().size() == 7);
workingDays = everyDay ? L(@"daily") : L(@"today");
workingTimes = stringFromTimeSpan(tt.GetOpeningTime());
breaks = breaksFromClosedTime(tt.GetExcludeTime());
}
allDays.emplace(allDays.begin(), workingDays, workingTimes, breaks);
}
void addClosedToday(vector<Day> & allDays)
{
allDays.emplace(allDays.begin(), L(@"day_off_today"));
}
void addDay(ui::TimeTable const & tt, vector<Day> & allDays)
{
NSString * workingDays = stringFromOpeningDays(tt.GetOpeningDays());
NSString * workingTimes;
NSString * breaks;
if (tt.IsTwentyFourHours())
{
workingTimes = L(@"twentyfour_seven");
}
else
{
workingTimes = stringFromTimeSpan(tt.GetOpeningTime());
breaks = breaksFromClosedTime(tt.GetExcludeTime());
}
allDays.emplace_back(workingDays, workingTimes, breaks);
}
void addUnhandledDays(ui::TOpeningDays const & days, vector<Day> & allDays)
{
if (days.empty())
return;
allDays.emplace_back(stringFromOpeningDays(days));
}
} // namespace
@implementation MWMOpeningHours
+ (vector<Day>)processRawString:(NSString *)str
{
ui::TimeTableSet timeTableSet;
osmoh::OpeningHours oh(str.UTF8String);
if (!MakeTimeTableSet(oh, timeTableSet))
return {};
vector<Day> days;
NSCalendar * cal = [NSCalendar currentCalendar];
cal.locale = [NSLocale currentLocale];
auto const timeTablesSize = timeTableSet.Size();
auto const today = static_cast<Weekday>([cal components:NSCalendarUnitWeekday fromDate:[NSDate date]].weekday);
auto const unhandledDays = timeTableSet.GetUnhandledDays();
/// Schedule contains more than one rule for all days or unhandled days.
BOOL const isExtendedSchedule = timeTablesSize != 1 || !unhandledDays.empty();
BOOL hasCurrentDay = NO;
for (auto const & tt : timeTableSet)
{
ui::TOpeningDays const & workingDays = tt.GetOpeningDays();
if (workingDays.find(today) != workingDays.end())
{
hasCurrentDay = YES;
addToday(tt, days);
}
if (isExtendedSchedule)
addDay(tt, days);
}
if (!hasCurrentDay)
addClosedToday(days);
addUnhandledDays(unhandledDays, days);
return days;
}
@end

View file

@ -0,0 +1,10 @@
#import "MWMTableViewCell.h"
@protocol MWMPlacePageCellUpdateProtocol;
@interface MWMOpeningHoursCell : MWMTableViewCell
- (void)configureWithOpeningHours:(NSString *)openningHours
updateLayoutDelegate:(id<MWMPlacePageCellUpdateProtocol>)delegate
isClosedNow:(BOOL)isClosedNow;
@end

View file

@ -0,0 +1,200 @@
#import "Common.h"
#import "MWMOpeningHours.h"
#import "MWMOpeningHoursCell.h"
#import "MWMPlacePageCellUpdateProtocol.h"
#include "std/array.hpp"
namespace
{
array<NSString *, 2> kOHClasses = {{@"_MWMOHHeaderCell", @"_MWMOHSubCell"}};
void * kContext = &kContext;
NSString * const kTableViewContentSizeKeyPath = @"contentSize";
} // namespace
#pragma mark - _MWMOHHeaderCell
@interface _MWMOHHeaderCell : MWMTableViewCell
@property(weak, nonatomic) IBOutlet UILabel * today;
@property(weak, nonatomic) IBOutlet UILabel * breaks;
@property(weak, nonatomic) IBOutlet UILabel * closedNow;
@property(weak, nonatomic) IBOutlet UIImageView * arrowIcon;
@property(weak, nonatomic) IBOutlet UIImageView * separator;
@property(copy, nonatomic) TMWMVoidBlock tapAction;
@end
@implementation _MWMOHHeaderCell
- (IBAction)extendTap
{
if (!self.tapAction)
return;
self.tapAction();
[UIView animateWithDuration:kDefaultAnimationDuration animations:^
{
self.arrowIcon.transform = CGAffineTransformIsIdentity(self.arrowIcon.transform) ?
CGAffineTransformMakeRotation(M_PI) :
CGAffineTransformIdentity;
}];
}
@end
#pragma mark - _MWMOHSubCell
@interface _MWMOHSubCell :MWMTableViewCell
@property(weak, nonatomic) IBOutlet UILabel * days;
@property(weak, nonatomic) IBOutlet UILabel * schedule;
@property(weak, nonatomic) IBOutlet UILabel * breaks;
@property(weak, nonatomic) IBOutlet UIImageView * separator;
@end
@implementation _MWMOHSubCell
@end
@interface MWMOpeningHoursCell () <UITableViewDelegate, UITableViewDataSource>
@property(weak, nonatomic) IBOutlet UITableView * tableView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * tableViewHeight;
@property(weak, nonatomic) id<MWMPlacePageCellUpdateProtocol> delegate;
@property(nonatomic) BOOL isExtended;
@property(nonatomic) BOOL isClosedNow;
@end
@implementation MWMOpeningHoursCell
{
vector<osmoh::Day> m_days;
}
- (void)awakeFromNib
{
[super awakeFromNib];
for (auto s : kOHClasses)
[self.tableView registerNib:[UINib nibWithNibName:s bundle:nil] forCellReuseIdentifier:s];
self.tableView.estimatedRowHeight = 48;
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self registerObserver];
}
- (void)configureWithOpeningHours:(NSString *)openningHours
updateLayoutDelegate:(id<MWMPlacePageCellUpdateProtocol>)delegate
isClosedNow:(BOOL)isClosedNow;
{
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
self.delegate = delegate;
self.isClosedNow = isClosedNow;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
{
self->m_days = [MWMOpeningHours processRawString:openningHours];
dispatch_async(dispatch_get_main_queue(), ^
{
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView reloadData];
});
});
}
#pragma mark - UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.isExtended ? m_days.size() : 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
auto const & day = m_days[indexPath.row];
BOOL const isSeparatorHidden = self.isExtended ? indexPath.row == 0 : indexPath.row == m_days.size() - 1;
if (indexPath.row == 0)
{
_MWMOHHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:[_MWMOHHeaderCell className]];
cell.today.text = day.TodayTime();
cell.breaks.text = day.m_breaks;
cell.closedNow.text = self.isClosedNow ? L(@"closed_now") : nil;;
if (m_days.size() > 1)
{
cell.tapAction = ^
{
self.isExtended = !self.isExtended;
NSMutableArray<NSIndexPath *> * ip = [@[] mutableCopy];
for (auto i = 1; i < self->m_days.size(); i++)
[ip addObject:[NSIndexPath indexPathForRow:i inSection:0]];
if (self.isExtended)
[self.tableView insertRowsAtIndexPaths:ip withRowAnimation:UITableViewRowAnimationAutomatic];
else
[self.tableView deleteRowsAtIndexPaths:ip withRowAnimation:UITableViewRowAnimationAutomatic];
};
cell.arrowIcon.hidden = NO;
}
else
{
cell.tapAction = nil;
cell.arrowIcon.hidden = YES;
}
cell.separator.hidden = isSeparatorHidden;
return cell;
}
else
{
_MWMOHSubCell * cell = [tableView dequeueReusableCellWithIdentifier:[_MWMOHSubCell className]];
cell.days.text = day.m_workingDays;
cell.schedule.text = day.m_workingTimes ? day.m_workingTimes : L(@"closed");
cell.breaks.text = day.m_breaks;
cell.separator.hidden = isSeparatorHidden;
return cell;
}
}
#pragma mark - Observer's methods
- (void)dealloc
{
[self unregisterObserver];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == kContext)
{
NSValue * s = change[@"new"];
CGFloat const height = s.CGSizeValue.height;
self.tableViewHeight.constant = height;
[self setNeedsLayout];
[self.delegate updateCellWithForceReposition:NO];
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (void)unregisterObserver
{
[self.tableView removeObserver:self forKeyPath:kTableViewContentSizeKeyPath context:kContext];
}
- (void)registerObserver
{
[self.tableView addObserver:self forKeyPath:kTableViewContentSizeKeyPath options:NSKeyValueObservingOptionNew context:kContext];
}
@end

View file

@ -0,0 +1,31 @@
#pragma mark - MWMPPScrollView
@protocol MWMPlacePageViewUpdateProtocol <NSObject>
- (void)updateWithHeight:(CGFloat)height;
@end
@interface MWMPPScrollView : UIScrollView
- (instancetype)initWithFrame:(CGRect)frame inactiveView:(UIView *)inactiveView;
@property(weak, nonatomic) UIView * inactiveView;
@end
#pragma mark - MWMPPView
@interface MWMPPView : UIView
@property(weak, nonatomic) IBOutlet UIImageView * top;
@property(weak, nonatomic) IBOutlet UIImageView * spinner;
@property(weak, nonatomic) IBOutlet UITableView * tableView;
@property(nonatomic) CGFloat currentContentHeight;
@property(nonatomic) id<MWMPlacePageViewUpdateProtocol> delegate;
- (void)hideTableView:(BOOL)isHidden;
@end

View file

@ -0,0 +1,101 @@
#import "MWMPPView.h"
#import "UIColor+MapsMeColor.h"
namespace
{
void * kContext = &kContext;
NSString * const kTableViewContentSizeKeyPath = @"contentSize";
} // namespace
#pragma mark - MWMPPScrollView
@implementation MWMPPScrollView
- (instancetype)initWithFrame:(CGRect)frame inactiveView:(UIView *)inactiveView
{
self = [super initWithFrame:frame];
if (self)
_inactiveView = inactiveView;
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (point.y > [self convertRect:self.inactiveView.bounds fromView:self.inactiveView].origin.y)
return YES;
return NO;
}
@end
#pragma mark - MWMPPView
@implementation MWMPPView
- (void)hideTableView:(BOOL)isHidden
{
if (isHidden)
{
self.tableView.alpha = 0.;
self.spinner.hidden = NO;
[self.spinner startAnimating];
}
else
{
self.tableView.alpha = 1.;
self.spinner.hidden = YES;
[self.spinner stopAnimating];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == kContext)
{
NSValue * s = change[@"new"];
CGFloat const height = s.CGSizeValue.height;
if (fabs(height - self.currentContentHeight) > 0.5)
{
self.currentContentHeight = height;
self.height = height + self.top.height;
[self setNeedsLayout];
[self.delegate updateWithHeight:self.height];
}
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self.tableView addObserver:self forKeyPath:kTableViewContentSizeKeyPath options:NSKeyValueObservingOptionNew context:kContext];
self.tableView.estimatedRowHeight = 44.;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.contentInset = {.top = -36};
NSUInteger const animationImagesCount = 12;
NSMutableArray * animationImages = [NSMutableArray arrayWithCapacity:animationImagesCount];
NSString * postfix = [UIColor isNightMode] ? @"dark" : @"light";
for (NSUInteger i = 0; i < animationImagesCount; ++i)
animationImages[i] = [UIImage imageNamed:[NSString stringWithFormat:@"Spinner_%@_%@", @(i+1), postfix]];
self.spinner.animationDuration = 0.8;
self.spinner.animationImages = animationImages;
[self.spinner startAnimating];
}
- (void)dealloc
{
[self.tableView removeObserver:self forKeyPath:kTableViewContentSizeKeyPath context:kContext];
}
@end

View file

@ -10,7 +10,7 @@
static NSString * const kPlacePageNibIdentifier = @"PlacePageView";
static NSString * const kPlacePageViewCenterKeyPath = @"center";
extern NSString * const kPP2BookmarkEditingSegue = @"PP2BookmarkEditing";
static NSString * const kPP2BookmarkEditingSegue = @"PP2BookmarkEditing";
extern NSString * const kPP2BookmarkEditingIPADSegue = @"PP2BookmarkEditingIPAD";
@interface MWMPlacePage ()

View file

@ -1,7 +1,25 @@
@class MWMPlacePageViewManager;
@class MWMPlacePageData;
@protocol MWMActionBarSharedData <NSObject>
- (BOOL)isBookmark;
- (BOOL)isBooking;
- (BOOL)isApi;
- (BOOL)isMyPosition;
- (NSString *)title;
- (NSString *)subtitle;
- (NSString *)phoneNumber;
@end
@protocol MWMActionBarProtocol;
@interface MWMPlacePageActionBar : SolidTouchView
+ (MWMPlacePageActionBar *)actionBarWithDelegate:(id<MWMActionBarProtocol>)delegate;
- (void)configureWithData:(id<MWMActionBarSharedData>)data;
@property (nonatomic) BOOL isBookmark;
- (UIView *)shareAnchor;

View file

@ -3,6 +3,7 @@
#import "MWMActionBarButton.h"
#import "MWMBasePlacePageView.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageProtocol.h"
#import "MWMPlacePageViewManager.h"
#import "MapViewController.h"
#import "MapsAppDelegate.h"
@ -13,12 +14,6 @@
extern NSString * const kAlohalyticsTapEventKey;
namespace
{
NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
} // namespace
@interface MWMPlacePageActionBar ()<MWMActionBarButtonDelegate>
{
vector<EButton> m_visibleButtons;
@ -30,14 +25,34 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
@property(weak, nonatomic) IBOutlet UIImageView * separator;
@property(nonatomic) BOOL isPrepareRouteMode;
@property(weak, nonatomic) id<MWMActionBarSharedData> data;
@property(weak, nonatomic) id<MWMActionBarProtocol> delegate;
@end
@implementation MWMPlacePageActionBar
+ (MWMPlacePageActionBar *)actionBarWithDelegate:(id<MWMActionBarProtocol>)delegate
{
MWMPlacePageActionBar * bar = [[NSBundle.mainBundle loadNibNamed:[self className] owner:nil options:nil]
firstObject];
bar.delegate = delegate;
return bar;
}
- (void)configureWithData:(id<MWMActionBarSharedData>)data
{
self.data = data;
self.isPrepareRouteMode = MapsAppDelegate.theApp.routingPlaneMode != MWMRoutingPlaneModeNone;
self.isBookmark = data.isBookmark;
[self configureButtons];
self.autoresizingMask = UIViewAutoresizingNone;
}
+ (MWMPlacePageActionBar *)actionBarForPlacePageManager:(MWMPlacePageViewManager *)placePageManager
{
MWMPlacePageActionBar * bar =
[[NSBundle.mainBundle loadNibNamed:kPlacePageActionBarNibName owner:nil options:nil]
[[NSBundle.mainBundle loadNibNamed:[self className] owner:nil options:nil]
firstObject];
[bar configureWithPlacePageManager:placePageManager];
return bar;
@ -56,16 +71,16 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
{
m_visibleButtons.clear();
m_additionalButtons.clear();
MWMPlacePageEntity * entity = self.placePageManager.entity;
NSString * phone = [entity getCellValue:MWMPlacePageCellTypePhoneNumber];
auto data = static_cast<id<MWMActionBarSharedData>>(isIOS7 ? self.placePageManager.entity : self.data);
NSString * phone = data.phoneNumber;
BOOL const isIphone = [[UIDevice currentDevice].model isEqualToString:@"iPhone"];
BOOL const isPhoneNotEmpty = phone.length > 0;
BOOL const isBooking = entity.isBooking;
BOOL const isBooking = data.isBooking;
BOOL const itHasPhoneNumber = isIphone && isPhoneNotEmpty;
BOOL const isApi = entity.isApi;
BOOL const isApi = data.isApi;
BOOL const isP2P = self.isPrepareRouteMode;
BOOL const isMyPosition = entity.isMyPosition;
BOOL const isMyPosition = data.isMyPosition;
if (isMyPosition)
{
@ -171,21 +186,24 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
- (void)tapOnButtonWithType:(EButton)type
{
MWMPlacePageViewManager * placePageManager = self.placePageManager;
id<MWMActionBarProtocol> delegate = IPAD ? self.placePageManager : self.delegate;
switch (type)
{
case EButton::Api: [placePageManager apiBack]; break;
case EButton::Booking: [placePageManager book:NO]; break;
case EButton::Call: [placePageManager call]; break;
case EButton::Api: [delegate apiBack]; break;
case EButton::Booking: [delegate book:NO]; break;
case EButton::Call: [delegate call]; break;
case EButton::Bookmark:
if (self.isBookmark)
[placePageManager removeBookmark];
[delegate removeBookmark];
else
[placePageManager addBookmark];
[delegate addBookmark];
self.isBookmark = !self.isBookmark;
break;
case EButton::RouteFrom: [placePageManager routeFrom]; break;
case EButton::RouteTo: [placePageManager routeTo]; break;
case EButton::Share: [placePageManager share]; 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::Spacer: break;
}
@ -196,16 +214,16 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
- (void)showActionSheet
{
NSString * cancel = L(@"cancel");
MWMPlacePageEntity * entity = self.placePageManager.entity;
BOOL const isTitleNotEmpty = entity.title.length > 0;
NSString * title = isTitleNotEmpty ? entity.title : entity.subtitle;
NSString * subtitle = isTitleNotEmpty ? entity.subtitle : nil;
auto data = static_cast<id<MWMActionBarSharedData>>(IPAD ? self.placePageManager.entity : self.data);
BOOL const isTitleNotEmpty = data.title.length > 0;
NSString * title = isTitleNotEmpty ? data.title : data.subtitle;
NSString * subtitle = isTitleNotEmpty ? data.subtitle : nil;
UIViewController * vc = static_cast<UIViewController *>([MapViewController controller]);
NSMutableArray<NSString *> * titles = [@[] mutableCopy];
for (auto const buttonType : m_additionalButtons)
{
BOOL const isSelected = buttonType == EButton::Bookmark ? self.isBookmark : NO;
BOOL const isSelected = buttonType == EButton::Bookmark ? data.isBookmark : NO;
if (NSString * title = titleForButton(buttonType, isSelected))
[titles addObject:title];
else
@ -246,6 +264,10 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
- (void)layoutSubviews
{
[super layoutSubviews];
self.width = self.superview.width;
if (IPAD)
self.origin = {0, self.superview.height - 48};
self.separator.width = self.width;
CGFloat const buttonWidth = self.width / self.buttons.count;
for (UIView * button in self.buttons)
@ -255,6 +277,11 @@ NSString * const kPlacePageActionBarNibName = @"PlacePageActionBar";
}
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
}
#pragma mark - Properties
- (void)setIsBookmark:(BOOL)isBookmark

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>

View file

@ -1,13 +1,6 @@
#import "MWMTableViewCell.h"
@protocol MWMPlacePageBookmarkDelegate <NSObject>
- (void)reloadBookmark;
- (void)editBookmarkTap;
- (void)moreTap;
@end
@protocol MWMPlacePageBookmarkDelegate;
@class MWMPlacePage;
@interface MWMPlacePageBookmarkCell : MWMTableViewCell

View file

@ -1,4 +1,5 @@
#import "MWMPlacePageBookmarkCell.h"
#import "MWMPlacePageBookmarkDelegate.h"
#import "Common.h"
#import "MapViewController.h"
#import "Statistics.h"

View file

@ -0,0 +1,8 @@
@protocol MWMPlacePageBookmarkDelegate <NSObject>
@required
- (void)editBookmarkTap;
- (void)reloadBookmark;
- (void)moreTap;
@end

View file

@ -1,10 +1,19 @@
#import "MWMTableViewCell.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageData.h"
@class MWMPlacePageViewManager;
@protocol MWMPlacePageButtonsProtocol;
@interface MWMPlacePageButtonCell : MWMTableViewCell
- (void)config:(MWMPlacePageViewManager *)manager forType:(MWMPlacePageCellType)type;
- (void)config:(MWMPlacePageViewManager *)manager forType:(MWMPlacePageCellType)type NS_DEPRECATED_IOS(7_0, 8_0);
- (void)configForRow:(place_page::ButtonsRows)row
withDelegate:(id<MWMPlacePageButtonsProtocol>)delegate NS_AVAILABLE_IOS(8_0);
- (void)setEnabled:(BOOL)enabled NS_AVAILABLE_IOS(8_0);
- (BOOL)isEnabled NS_AVAILABLE_IOS(8_0);
@end

View file

@ -1,7 +1,9 @@
#import "Common.h"
#import "MWMPlacePageButtonCell.h"
#import "MWMFrameworkListener.h"
#import "MWMPlacePageViewManager.h"
#import "UIColor+MapsMeColor.h"
#import "MWMPlacePageProtocol.h"
@interface MWMPlacePageButtonCell ()<MWMFrameworkStorageObserver>
@ -10,6 +12,8 @@
@property(nonatomic) MWMPlacePageCellType type;
@property(nonatomic) storage::TCountryId countryId;
@property(weak, nonatomic) id<MWMPlacePageButtonsProtocol> delegate;
@property(nonatomic) place_page::ButtonsRows rowType;
@end
@implementation MWMPlacePageButtonCell
@ -22,16 +26,59 @@
[self refreshButtonEnabledState];
}
- (void)setEnabled:(BOOL)enabled
{
self.titleButton.enabled = enabled;
}
- (BOOL)isEnabled
{
return self.titleButton.isEnabled;
}
- (void)configForRow:(place_page::ButtonsRows)row withDelegate:(id<MWMPlacePageButtonsProtocol>)delegate
{
self.delegate = delegate;
self.rowType = row;
switch(row)
{
case place_page::ButtonsRows::AddPlace:
[self.titleButton setTitle:L(@"placepage_add_place_button") forState:UIControlStateNormal];
break;
case place_page::ButtonsRows::EditPlace:
[self.titleButton setTitle:L(@"edit_place") forState:UIControlStateNormal];
break;
case place_page::ButtonsRows::AddBusiness:
[self.titleButton setTitle:L(@"placepage_add_business_button") forState:UIControlStateNormal];
break;
case place_page::ButtonsRows::HotelDescription:
[self.titleButton setTitle:L(@"details") forState:UIControlStateNormal];
break;
}
}
- (IBAction)buttonTap
{
MWMPlacePageViewManager * manager = self.manager;
switch (self.type)
if (IPAD)
{
case MWMPlacePageCellTypeEditButton: [manager editPlace]; break;
case MWMPlacePageCellTypeAddBusinessButton: [manager addBusiness]; break;
case MWMPlacePageCellTypeAddPlaceButton: [manager addPlace]; break;
case MWMPlacePageCellTypeBookingMore: [manager book:YES]; break;
default: NSAssert(false, @"Incorrect cell type!"); break;
switch (self.type)
{
case MWMPlacePageCellTypeEditButton: [self.manager editPlace]; break;
case MWMPlacePageCellTypeAddBusinessButton: [self.manager addBusiness]; break;
case MWMPlacePageCellTypeAddPlaceButton: [self.manager addPlace]; break;
case MWMPlacePageCellTypeBookingMore: [self.manager book:YES]; break;
default: NSAssert(false, @"Incorrect cell type!"); break;
}
return;
}
using namespace place_page;
switch (self.rowType)
{
case ButtonsRows::AddPlace: [self.delegate addPlace]; break;
case ButtonsRows::EditPlace: [self.delegate editPlace]; break;
case ButtonsRows::AddBusiness: [self.delegate addBusiness]; break;
case ButtonsRows::HotelDescription: [self.delegate book:YES]; break;
}
}

View file

@ -0,0 +1,5 @@
@protocol MWMPlacePageCellUpdateProtocol <NSObject>
- (void)updateCellWithForceReposition:(BOOL)isForceReposition;
@end

View file

@ -0,0 +1,103 @@
#include "map/place_page_info.hpp"
#include "std/vector.hpp"
namespace place_page
{
enum class Sections
{
Preview,
Bookmark,
Metainfo,
Buttons
};
enum class MetainfoRows
{
OpeningHours,
Phone,
Address,
Website,
Email,
Cuisine,
Operator,
Internet,
Coordinate
};
enum class ButtonsRows
{
AddBusiness,
EditPlace,
AddPlace,
HotelDescription
};
enum class OpeningHours
{
AllDay,
Open,
Closed,
Unknown
};
} // namespace place_page_data
/// ViewModel for place page.
@interface MWMPlacePageData : NSObject
// ready callback will be called from main queue.
- (instancetype)initWithPlacePageInfo:(place_page::Info const &)info;
- (void)updateBookmarkStatus:(BOOL)isBookmark;
/// Country id for changing place page's fields which depend on application state.
- (storage::TCountryId const &)countryId;
- (FeatureID const &)featureId;
// Regular
- (NSString *)title;
- (NSString *)subtitle;
- (place_page::OpeningHours)schedule;
- (NSString *)address;
// Booking
- (NSString *)bookingRating;
- (NSString *)bookingApproximatePricing;
- (NSURL *)bookingURL;
- (NSURL *)bookingDescriptionURL;
- (NSString *)hotelId;
- (void)assignOnlinePriceToLabel:(UILabel *)label;
// API
- (NSString *)apiURL;
// Bookmark
- (NSString *)externalTitle;
- (NSString *)bookmarkColor;
- (NSString *)bookmarkDescription;
- (NSString *)bookmarkCategory;
- (BookmarkAndCategory)bac;
// Table view's data
- (vector<place_page::Sections> const &)sections;
- (vector<place_page::MetainfoRows> const &)metainfoRows;
- (vector<place_page::ButtonsRows> const &)buttonsRows;
// Table view metainfo rows
- (NSString *)stringForRow:(place_page::MetainfoRows)row;
// Helpers
- (NSString *)phoneNumber;
- (BOOL)isBookmark;
- (BOOL)isApi;
- (BOOL)isBooking;
- (BOOL)isHTMLDescription;
- (BOOL)isMyPosition;
// Coordinates
- (m2::PointD const &)mercator;
- (ms::LatLon)latLon;
+ (void)toggleCoordinateSystem;
@end

View file

@ -0,0 +1,406 @@
#import "MWMPlacePageData.h"
#include "Framework.h"
#include "base/string_utils.hpp"
#include "3party/opening_hours/opening_hours.hpp"
namespace
{
NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
} // namespace
using namespace place_page;
@implementation MWMPlacePageData
{
Info m_info;
vector<Sections> m_sections;
vector<MetainfoRows> m_metainfoRows;
vector<ButtonsRows> m_buttonsRows;
}
- (instancetype)initWithPlacePageInfo:(Info const &)info
{
self = [super init];
if (self)
{
m_info = info;
[self fillSections];
}
return self;
}
- (void)fillSections
{
m_sections.clear();
m_metainfoRows.clear();
m_buttonsRows.clear();
m_sections.push_back(Sections::Preview);
// It's bookmark.
if (m_info.IsBookmark())
m_sections.push_back(Sections::Bookmark);
// There is always at least coordinate meta field.
m_sections.push_back(Sections::Metainfo);
[self fillMetaInfoSection];
// There is at least one of these buttons.
if (m_info.ShouldShowAddPlace() || m_info.ShouldShowEditPlace() || m_info.ShouldShowAddBusiness() || m_info.IsSponsoredHotel())
{
m_sections.push_back(Sections::Buttons);
[self fillButtonsSection];
}
}
- (void)fillMetaInfoSection
{
using namespace osm;
auto const availableProperties = m_info.AvailableProperties();
// We can't match each metadata property to its UI field and thats why we need to use our own enum.
for (auto const p : availableProperties)
{
switch (p)
{
case Props::OpeningHours:
m_metainfoRows.push_back(MetainfoRows::OpeningHours);
break;
case Props::Phone:
m_metainfoRows.push_back(MetainfoRows::Phone);
break;
case Props::Website:
m_metainfoRows.push_back(MetainfoRows::Website);
break;
case Props::Email:
m_metainfoRows.push_back(MetainfoRows::Email);
break;
case Props::Cuisine:
m_metainfoRows.push_back(MetainfoRows::Cuisine);
break;
case Props::Operator:
m_metainfoRows.push_back(MetainfoRows::Operator);
break;
case Props::Internet:
m_metainfoRows.push_back(MetainfoRows::Internet);
break;
case Props::Wikipedia:
case Props::Elevation:
case Props::Stars:
case Props::Flats:
case Props::BuildingLevels:
case Props::Fax:
break;
}
}
auto const address = m_info.GetAddress();
if (!address.empty())
m_metainfoRows.push_back(MetainfoRows::Address);
m_metainfoRows.push_back(MetainfoRows::Coordinate);
}
- (void)fillButtonsSection
{
// We don't have to show edit, add place or business if it's booking object.
if (m_info.IsSponsoredHotel())
{
m_buttonsRows.push_back(ButtonsRows::HotelDescription);
return;
}
if (m_info.ShouldShowAddPlace())
m_buttonsRows.push_back(ButtonsRows::AddPlace);
if (m_info.ShouldShowEditPlace())
m_buttonsRows.push_back(ButtonsRows::EditPlace);
if (m_info.ShouldShowAddBusiness())
m_buttonsRows.push_back(ButtonsRows::AddBusiness);
}
- (void)updateBookmarkStatus:(BOOL)isBookmark
{
auto & f = GetFramework();
auto & bmManager = f.GetBookmarkManager();
if (isBookmark)
{
auto const categoryIndex = static_cast<int>(f.LastEditedBMCategory());
BookmarkData bmData{m_info.FormatNewBookmarkName(), f.LastEditedBMType()};
auto const bookmarkIndex =
static_cast<int>(bmManager.AddBookmark(categoryIndex,self.mercator, bmData));
auto category = f.GetBmCategory(categoryIndex);
NSAssert(category, @"Category can't be nullptr!");
{
BookmarkCategory::Guard guard(*category);
Bookmark * bookmark =
static_cast<Bookmark *>(guard.m_controller.GetUserMarkForEdit(bookmarkIndex));
f.FillBookmarkInfo(*bookmark, {bookmarkIndex, categoryIndex}, m_info);
}
m_sections.insert(m_sections.begin() + 1, Sections::Bookmark);
}
else
{
auto const bac = m_info.GetBookmarkAndCategory();
auto category = bmManager.GetBmCategory(bac.m_categoryIndex);
NSAssert(category, @"Category can't be nullptr!");
{
BookmarkCategory::Guard guard(*category);
guard.m_controller.DeleteUserMark(bac.m_bookmarkIndex);
}
category->SaveToKMLFile();
m_info.m_bac = {};
m_sections.erase(remove(m_sections.begin(), m_sections.end(), Sections::Bookmark));
}
}
#pragma mark - Getters
- (storage::TCountryId const &)countryId
{
return m_info.m_countryId;
}
- (FeatureID const &)featureId
{
return m_info.GetID();
}
- (NSString *)title
{
return @(m_info.GetTitle().c_str());
}
- (NSString *)subtitle
{
return @(m_info.GetSubtitle().c_str());
}
- (place_page::OpeningHours)schedule;
{
auto const raw = m_info.GetOpeningHours();
if (raw.empty())
return place_page::OpeningHours::Unknown;
auto const t = time(nullptr);
osmoh::OpeningHours oh(raw);
if (oh.IsValid())
{
if (oh.IsTwentyFourHours())
return place_page::OpeningHours::AllDay;
else if (oh.IsOpen(t))
return place_page::OpeningHours::Open;
else if (oh.IsClosed(t))
return place_page::OpeningHours::Closed;
else
return place_page::OpeningHours::Unknown;
}
else
{
return place_page::OpeningHours::Unknown;
}
}
- (NSString *)bookingRating
{
return m_info.IsHotel() ? @(m_info.GetRatingFormatted().c_str()) : nil;
}
- (NSString *)bookingApproximatePricing
{
return m_info.IsHotel() ? @(m_info.GetApproximatePricing().c_str()) : nil;
}
- (NSURL *)bookingURL
{
return m_info.IsSponsoredHotel() ? [NSURL URLWithString:@(m_info.m_sponsoredBookingUrl.c_str())] : nil;
}
- (NSURL *)bookingDescriptionURL
{
return m_info.IsSponsoredHotel() ? [NSURL URLWithString:@(m_info.m_sponsoredDescriptionUrl.c_str())] : nil;
}
- (NSString *)hotelId
{
return m_info.IsSponsoredHotel() ? @(m_info.GetMetadata().Get(feature::Metadata::FMD_SPONSORED_ID).c_str())
: nil;
}
- (void)assignOnlinePriceToLabel:(UILabel *)label
{
NSAssert(m_info.IsSponsoredHotel(), @"Online price must be assigned to booking object!");
if (Platform::ConnectionStatus() == Platform::EConnectionType::CONNECTION_NONE)
return;
NSNumberFormatter * currencyFormatter = [[NSNumberFormatter alloc] init];
if (currencyFormatter.currencyCode.length != 3)
currencyFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
currencyFormatter.maximumFractionDigits = 0;
string const currency = currencyFormatter.currencyCode.UTF8String;
auto & api = GetFramework().GetBookingApi();
auto const func = [self, label, currency, currencyFormatter](string const & minPrice, string const & priceCurrency)
{
if (currency != priceCurrency)
return;
NSNumberFormatter * decimalFormatter = [[NSNumberFormatter alloc] init];
decimalFormatter.numberStyle = NSNumberFormatterDecimalStyle;
NSString * currencyString = [currencyFormatter stringFromNumber:[decimalFormatter numberFromString:
[@(minPrice.c_str()) stringByReplacingOccurrencesOfString:@"."
withString:decimalFormatter.decimalSeparator]]];
NSString * pattern = [L(@"place_page_starting_from") stringByReplacingOccurrencesOfString:@"%s" withString:@"%@"];
dispatch_async(dispatch_get_main_queue(), ^{
label.text = [NSString stringWithFormat:pattern, currencyString];
});
};
api.GetMinPrice(self.hotelId.UTF8String, currency, func);
}
- (NSString *)address
{
return @(m_info.GetAddress().c_str());
}
- (NSString *)apiURL
{
return @(m_info.GetApiUrl().c_str());
}
- (NSString *)externalTitle
{
return m_info.IsBookmark() && m_info.m_bookmarkTitle != m_info.GetTitle() ?
@(m_info.m_bookmarkTitle.c_str())
: nil;
}
- (NSString *)bookmarkColor
{
return m_info.IsBookmark() ? @(m_info.m_bookmarkColorName.c_str()) : nil;;
}
- (NSString *)bookmarkDescription
{
return m_info.IsBookmark() ? @(m_info.m_bookmarkDescription.c_str()) : nil;
}
- (NSString *)bookmarkCategory
{
return m_info.IsBookmark() ? @(m_info.m_bookmarkCategoryName.c_str()) : nil;;
}
- (BookmarkAndCategory)bac;
{
return m_info.IsBookmark() ? m_info.m_bac : BookmarkAndCategory();
}
- (vector<Sections> const &)sections
{
return m_sections;
}
- (vector<MetainfoRows> const &)metainfoRows
{
return m_metainfoRows;
}
- (vector<ButtonsRows> const &)buttonsRows
{
return m_buttonsRows;
}
- (NSString *)stringForRow:(MetainfoRows)row
{
switch (row)
{
case MetainfoRows::OpeningHours:
return @(m_info.GetOpeningHours().c_str());
case MetainfoRows::Phone:
return @(m_info.GetPhone().c_str());
case MetainfoRows::Address:
return @(m_info.GetAddress().c_str());
case MetainfoRows::Website:
return @(m_info.GetWebsite().c_str());
case MetainfoRows::Email:
return @(m_info.GetEmail().c_str());
case MetainfoRows::Cuisine:
return @(strings::JoinStrings(m_info.GetCuisines(), Info::kSubtitleSeparator).c_str());
case MetainfoRows::Operator:
return @(m_info.GetOperator().c_str());
case MetainfoRows::Internet:
return L(@"WiFi_available");
case MetainfoRows::Coordinate:
return @(m_info.GetFormattedCoordinate([[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsLatLonAsDMSKey]).c_str());
}
}
#pragma mark - Helpres
- (NSString *)phoneNumber
{
return @(m_info.GetPhone().c_str());
}
- (BOOL)isBookmark
{
return m_info.IsBookmark();
}
- (BOOL)isApi
{
return m_info.HasApiUrl();
}
- (BOOL)isBooking
{
return m_info.IsHotel();
}
- (BOOL)isMyPosition
{
return m_info.IsMyPosition();
}
- (BOOL)isHTMLDescription
{
return strings::IsHTML(m_info.m_bookmarkDescription);
}
#pragma mark - Coordinates
- (m2::PointD const &)mercator
{
return m_info.GetMercator();
}
- (ms::LatLon)latLon
{
return m_info.GetLatLon();
}
+ (void)toggleCoordinateSystem
{
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
[ud setBool:![ud boolForKey:kUserDefaultsLatLonAsDMSKey] forKey:kUserDefaultsLatLonAsDMSKey];
[ud synchronize];
}
@end

View file

@ -61,12 +61,13 @@ using MWMPlacePageCellTypeValueMap = map<MWMPlacePageCellType, string>;
- (BOOL)isBookmark;
- (BOOL)isApi;
- (BOOL)isBooking;
- (ms::LatLon)latlon;
- (ms::LatLon)latLon;
- (m2::PointD const &)mercator;
- (NSString *)apiURL;
- (NSURL *)bookingUrl;
- (NSURL *)bookingDescriptionUrl;
- (NSURL *)bookingURL;
- (NSURL *)bookingDescriptionURL;
- (NSString * )hotelId;
- (NSString *)phoneNumber;
- (string)titleForNewBookmark;
- (instancetype)initWithInfo:(place_page::Info const &)info;

View file

@ -14,7 +14,7 @@
using feature::Metadata;
extern NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
static NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
namespace
{
@ -162,9 +162,9 @@ void initFieldsMap()
- (void)configureBookmark
{
auto const bac = m_info.GetBookmarkAndCategory();
BookmarkCategory * cat = GetFramework().GetBmCategory(bac.first);
BookmarkCategory * cat = GetFramework().GetBmCategory(bac.m_categoryIndex);
BookmarkData const & data =
static_cast<Bookmark const *>(cat->GetUserMark(bac.second))->GetData();
static_cast<Bookmark const *>(cat->GetUserMark(bac.m_bookmarkIndex))->GetData();
self.bookmarkTitle = @(data.GetName().c_str());
self.bookmarkCategory = @(m_info.GetBookmarkCategoryName().c_str());
@ -214,11 +214,11 @@ void initFieldsMap()
return haveField ? @(it->second.c_str()) : nil;
}
- (NSURL *)bookingUrl
- (NSURL *)bookingURL
{
return [self sponsoredUrl:NO];
}
- (NSURL *)bookingDescriptionUrl { return [self sponsoredUrl:YES]; }
- (NSURL *)bookingDescriptionURL { return [self sponsoredUrl:YES]; }
- (NSURL *)sponsoredUrl:(BOOL)isDescription
{
auto const & url =
@ -238,7 +238,12 @@ void initFieldsMap()
return self.isBooking ? @(m_info.GetMetadata().Get(Metadata::FMD_SPONSORED_ID).c_str()) : nil;
}
- (ms::LatLon)latlon { return m_info.GetLatLon(); }
- (NSString *)phoneNumber
{
return [self getCellValue:MWMPlacePageCellTypePhoneNumber];
}
- (ms::LatLon)latLon { return m_info.GetLatLon(); }
- (m2::PointD const &)mercator { return m_info.GetMercator(); }
- (NSString *)apiURL { return @(m_info.GetApiUrl().c_str()); }
- (string)titleForNewBookmark { return m_info.FormatNewBookmarkName(); }
@ -246,7 +251,7 @@ void initFieldsMap()
{
BOOL const useDMSFormat =
[[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsLatLonAsDMSKey];
ms::LatLon const latlon = self.latlon;
ms::LatLon const latlon = self.latLon;
return @((useDMSFormat ? measurement_utils::FormatLatLon(latlon.lat, latlon.lon)
: measurement_utils::FormatLatLonAsDMS(latlon.lat, latlon.lon, 2))
.c_str());
@ -295,14 +300,14 @@ void initFieldsMap()
- (void)synchronize
{
Framework & f = GetFramework();
BookmarkCategory * category = f.GetBmCategory(self.bac.first);
BookmarkCategory * category = f.GetBmCategory(self.bac.m_categoryIndex);
if (!category)
return;
{
BookmarkCategory::Guard guard(*category);
Bookmark * bookmark =
static_cast<Bookmark *>(guard.m_controller.GetUserMarkForEdit(self.bac.second));
static_cast<Bookmark *>(guard.m_controller.GetUserMarkForEdit(self.bac.m_bookmarkIndex));
if (!bookmark)
return;

View file

@ -1,9 +1,13 @@
#import "MWMPlacePageEntity.h"
#import "MWMTableViewCell.h"
#import "MWMPlacePageData.h"
@interface MWMPlacePageInfoCell : MWMTableViewCell
- (void)configureWithType:(MWMPlacePageCellType)type info:(NSString *)info;
- (void)configureWithType:(MWMPlacePageCellType)type info:(NSString *)info NS_DEPRECATED_IOS(7_0, 8_0);
- (void)configWithRow:(place_page::MetainfoRows)row data:(MWMPlacePageData *)data NS_AVAILABLE_IOS(8_0);
@property(weak, nonatomic, readonly) IBOutlet UIImageView * icon;
@property(weak, nonatomic, readonly) IBOutlet id textContainer;

View file

@ -19,7 +19,9 @@
@property(weak, nonatomic) IBOutlet UIButton * upperButton;
@property(weak, nonatomic) IBOutlet UIImageView * toggleImage;
@property(nonatomic) MWMPlacePageCellType type;
@property(nonatomic) MWMPlacePageCellType type NS_DEPRECATED_IOS(7_0, 8_0);
@property(nonatomic) place_page::MetainfoRows rowType NS_AVAILABLE_IOS(8_0);
@property(weak, nonatomic) MWMPlacePageData * data NS_AVAILABLE_IOS(8_0);
@end
@ -37,8 +39,55 @@
}
}
- (void)configWithRow:(place_page::MetainfoRows)row data:(MWMPlacePageData *)data;
{
self.rowType = row;
self.data = data;
NSString * name;
switch (row)
{
case place_page::MetainfoRows::Address:
self.toggleImage.hidden = YES;
name = @"address";
break;
case place_page::MetainfoRows::Phone:
self.toggleImage.hidden = YES;
name = @"phone_number";
break;
case place_page::MetainfoRows::Website:
self.toggleImage.hidden = YES;
name = @"website";
break;
case place_page::MetainfoRows::Email:
self.toggleImage.hidden = YES;
name = @"email";
break;
case place_page::MetainfoRows::Cuisine:
self.toggleImage.hidden = YES;
name = @"cuisine";
break;
case place_page::MetainfoRows::Operator:
self.toggleImage.hidden = YES;
name = @"operator";
break;
case place_page::MetainfoRows::Internet:
self.toggleImage.hidden = YES;
name = @"wifi";
break;
case place_page::MetainfoRows::Coordinate:
self.toggleImage.hidden = NO;
name = @"coordinate";
break;
case place_page::MetainfoRows::OpeningHours:
NSAssert(false, @"Incorrect cell type!");
break;
}
[self configWithIconName:name data:[self.data stringForRow:row]];
}
- (void)configureWithType:(MWMPlacePageCellType)type info:(NSString *)info;
{
self.type = type;
NSString * typeName;
switch (type)
{
@ -70,14 +119,18 @@
default: NSAssert(false, @"Incorrect type!"); break;
}
[self configWithIconName:typeName data:info];
}
- (void)configWithIconName:(NSString *)name data:(NSString *)data
{
UIImage * image =
[UIImage imageNamed:[NSString stringWithFormat:@"%@%@", @"ic_placepage_", typeName]];
self.type = type;
[UIImage imageNamed:[NSString stringWithFormat:@"%@%@", @"ic_placepage_", name]];
self.icon.image = image;
self.icon.mwm_coloring = [self.textContainer isKindOfClass:[UITextView class]]
? MWMImageColoringBlue
: MWMImageColoringBlack;
[self changeText:info];
[self changeText:data];
UILongPressGestureRecognizer * longTap =
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTap:)];
longTap.minimumPressDuration = 0.3;
@ -123,25 +176,55 @@
- (IBAction)cellTap
{
switch (self.type)
if (isIOS7)
{
case MWMPlacePageCellTypeURL:
case MWMPlacePageCellTypeWebsite:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatOpenSite)];
break;
case MWMPlacePageCellTypeEmail:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatSendEmail)];
break;
case MWMPlacePageCellTypePhoneNumber:
switch (self.type)
{
case MWMPlacePageCellTypeURL:
case MWMPlacePageCellTypeWebsite:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatOpenSite)];
break;
case MWMPlacePageCellTypeEmail:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatSendEmail)];
break;
case MWMPlacePageCellTypePhoneNumber:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatCallPhoneNumber)];
break;
case MWMPlacePageCellTypeCoordinate:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatToggleCoordinates)];
[self.currentEntity toggleCoordinateSystem];
[self changeText:[self.currentEntity getCellValue:MWMPlacePageCellTypeCoordinate]];
break;
default: break;
}
return;
}
switch (self.rowType)
{
case place_page::MetainfoRows::Phone:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatCallPhoneNumber)];
break;
case MWMPlacePageCellTypeCoordinate:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatToggleCoordinates)];
[self.currentEntity toggleCoordinateSystem];
[self changeText:[self.currentEntity getCellValue:MWMPlacePageCellTypeCoordinate]];
case place_page::MetainfoRows::Website:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatOpenSite)];
break;
case place_page::MetainfoRows::Email:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatSendEmail)];
break;
case place_page::MetainfoRows::Coordinate:
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatToggleCoordinates)];
[MWMPlacePageData toggleCoordinateSystem];
[self changeText:[self.data stringForRow:self.rowType]];
break;
case place_page::MetainfoRows::Cuisine:
case place_page::MetainfoRows::Operator:
case place_page::MetainfoRows::OpeningHours:
case place_page::MetainfoRows::Address:
case place_page::MetainfoRows::Internet:
break;
default: break;
}
}
- (void)longTap:(UILongPressGestureRecognizer *)sender

View file

@ -0,0 +1,42 @@
#include "storage/storage_defines.hpp"
@protocol MWMPlacePageLayoutDelegate <NSObject>
- (void)onTopBoundChanged:(CGFloat)bound;
- (void)shouldDestroyLayout;
@end
@protocol MWMPlacePageLayoutDataSource <NSObject>
- (NSString *)distanceToObject;
- (void)downloadSelectedArea;
@end
@class MWMPlacePageData, MWMPPView;
@protocol MWMPlacePageButtonsProtocol, MWMActionBarProtocol;
/// Helps with place page view layout and representation
@interface MWMPlacePageLayout : NSObject
- (instancetype)initWithOwnerView:(UIView *)view
delegate:(id<MWMPlacePageLayoutDelegate, MWMPlacePageButtonsProtocol, MWMActionBarProtocol>)delegate
dataSource:(id<MWMPlacePageLayoutDataSource>)dataSource;
- (void)layoutWithSize:(CGSize const &)size;
- (void)showWithData:(MWMPlacePageData *)data;
- (void)close;
- (void)mwm_refreshUI;
- (UIView *)shareAnchor;
- (void)reloadBookmarkSection:(BOOL)isBookmark;
- (void)rotateDirectionArrowToAngle:(CGFloat)angle;
- (void)setDistanceToObject:(NSString *)distance;
- (void)processDownloaderEventWithStatus:(storage::NodeStatus)status progress:(CGFloat)progress;
@end

View file

@ -0,0 +1,530 @@
#import "MWMCircularProgress.h"
#import "MWMPlacePageActionBar.h"
#import "MWMPlacePageCellUpdateProtocol.h"
#import "MWMPlacePageData.h"
#import "MWMPlacePageLayout.h"
#import "MWMPPView.h"
#import "MWMBookmarkCell.h"
#import "MWMPlacePageBookmarkCell.h"
#import "MWMPlacePageButtonCell.h"
#import "MWMPlacePageInfoCell.h"
#import "MWMOpeningHoursCell.h"
#import "MWMPlacePagePreviewCell.h"
#import "UIColor+MapsMeColor.h"
#include "storage/storage.hpp"
#include "std/array.hpp"
namespace
{
enum class ScrollDirection { Up, Down };
enum class State { Bottom, Top };
CGFloat const kMinOffset = 64;
CGFloat const kOpenPlacePageStopValue = 0.7;
array<NSString *, 1> kPreviewCells = {{@"MWMPlacePagePreviewCell"}};
array<NSString *, 1> kBookmarkCells = {{@"MWMBookmarkCell"}};
array<NSString *, 9> kMetaInfoCells = {{@"MWMOpeningHoursCell", @"PlacePageLinkCell", @"PlacePageInfoCell", @"PlacePageLinkCell", @"PlacePageLinkCell", @"PlacePageInfoCell", @"PlacePageInfoCell", @"PlacePageInfoCell", @"PlacePageInfoCell"}};
array<NSString *, 1> kButtonsCells = {{@"MWMPlacePageButtonCell"}};
NSTimeInterval const kAnimationDuration = 0.15;
void animate(TMWMVoidBlock animate, TMWMVoidBlock completion = nil)
{
[UIView animateWithDuration:kAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
animate();
} completion:^(BOOL finished) {
if (completion)
completion();
}];
}
} // namespace
@interface MWMPlacePageLayout () <UITableViewDelegate, UITableViewDataSource,
MWMPlacePageCellUpdateProtocol, MWMPlacePageViewUpdateProtocol>
@property(weak, nonatomic) MWMPlacePageData * data;
@property(weak, nonatomic) UIView * ownerView;
@property(weak, nonatomic) id<MWMPlacePageLayoutDelegate, MWMPlacePageButtonsProtocol, MWMActionBarProtocol> delegate;
@property(weak, nonatomic) id<MWMPlacePageLayoutDataSource> dataSource;
@property(nonatomic) MWMPPScrollView * scrollView;
@property(nonatomic) IBOutlet MWMPPView * placePageView;
@property(nonatomic) ScrollDirection direction;
@property(nonatomic) State state;
@property(nonatomic) CGFloat portraitOpenContentOffset;
@property(nonatomic) CGFloat landscapeOpenContentOffset;
@property(nonatomic) CGFloat lastContentOffset;
@property(nonatomic) CGFloat expandedContentOffset;
@property(nonatomic) MWMPlacePagePreviewCell * ppPreviewCell;
@property(nonatomic) MWMBookmarkCell * bookmarkCell;
@property(nonatomic) MWMPlacePageActionBar * actionBar;
@property(nonatomic) BOOL isPlacePageButtonsEnabled;
@property(nonatomic) BOOL isDownloaderViewShown;
@end
@implementation MWMPlacePageLayout
- (instancetype)initWithOwnerView:(UIView *)view
delegate:(id<MWMPlacePageLayoutDelegate, MWMPlacePageButtonsProtocol, MWMActionBarProtocol>)delegate
dataSource:(id<MWMPlacePageLayoutDataSource>)dataSource
{
self = [super init];
if (self)
{
_ownerView = view;
_delegate = delegate;
_dataSource = dataSource;
[[NSBundle mainBundle] loadNibNamed:[MWMPPView className] owner:self options:nil];
auto view = self.ownerView;
auto const & size = view.size;
_placePageView.frame = {{0, size.height}, size};
_placePageView.delegate = self;
_scrollView = [[MWMPPScrollView alloc] initWithFrame:view.frame inactiveView:_placePageView];
_portraitOpenContentOffset = MAX(size.width, size.height) * kOpenPlacePageStopValue;
_landscapeOpenContentOffset = MIN(size.width, size.height) * kOpenPlacePageStopValue;
[_ownerView addSubview:_scrollView];
[_scrollView addSubview:_placePageView];
auto tv = _placePageView.tableView;
[tv registerNib:[UINib nibWithNibName:kPreviewCells[0] bundle:nil] forCellReuseIdentifier:kPreviewCells[0]];
[tv registerNib:[UINib nibWithNibName:kButtonsCells[0] bundle:nil] forCellReuseIdentifier:kButtonsCells[0]];
[tv registerNib:[UINib nibWithNibName:kBookmarkCells[0] bundle:nil] forCellReuseIdentifier:kBookmarkCells[0]];
}
return self;
}
- (void)registerCells
{
auto tv = self.placePageView.tableView;
// Register all meta info cells.
for (auto const i : self.data.metainfoRows)
{
auto name = kMetaInfoCells[static_cast<size_t>(i)];
[tv registerNib:[UINib nibWithNibName:name bundle:nil] forCellReuseIdentifier:name];
}
}
- (void)layoutWithSize:(CGSize const &)size
{
self.scrollView.frame = {{}, size};
self.placePageView.origin = {0., size.height};
self.actionBar.frame = {{0., size.height - 48}, {size.width, 48}};
[self.delegate onTopBoundChanged:self.scrollView.contentOffset.y];
}
- (UIView *)shareAnchor
{
return self.actionBar.shareAnchor;
}
- (void)showWithData:(MWMPlacePageData *)data
{
self.isPlacePageButtonsEnabled = YES;
self.data = nil;
self.ppPreviewCell = nil;
self.bookmarkCell = nil;
self.scrollView.delegate = self;
self.state = State::Bottom;
[self collapse];
self.data = data;
[self.actionBar configureWithData:static_cast<id<MWMActionBarSharedData>>(self.data)];
[self registerCells];
[self.placePageView.tableView reloadData];
}
- (void)rotateDirectionArrowToAngle:(CGFloat)angle
{
[self.ppPreviewCell rotateDirectionArrowToAngle:angle];
}
- (void)setDistanceToObject:(NSString *)distance
{
[self.ppPreviewCell setDistanceToObject:distance];
}
- (MWMPlacePageActionBar *)actionBar
{
if (!_actionBar)
{
_actionBar = [MWMPlacePageActionBar actionBarWithDelegate:self.delegate];
UIView * superview = self.ownerView;
_actionBar.origin = {0., superview.height};
[superview addSubview:_actionBar];
}
return _actionBar;
}
- (void)close
{
animate(^ {
self.actionBar.origin = {0., self.ownerView.height};
[self.scrollView setContentOffset:{} animated:YES];
}, ^{
[self.actionBar removeFromSuperview];
self.actionBar = nil;
[self.delegate shouldDestroyLayout];
});
}
- (void)mwm_refreshUI
{
[self.placePageView mwm_refreshUI];
[self.actionBar mwm_refreshUI];
}
- (void)reloadBookmarkSection:(BOOL)isBookmark
{
auto tv = self.placePageView.tableView;
NSIndexSet * set = [NSIndexSet indexSetWithIndex:static_cast<NSInteger>(place_page::Sections::Bookmark)];
if (isBookmark)
{
if (self.bookmarkCell)
[tv reloadSections:set withRowAnimation:UITableViewRowAnimationAutomatic];
else
[tv insertSections:set withRowAnimation:UITableViewRowAnimationAutomatic];
}
else
{
[tv deleteSections:set withRowAnimation:UITableViewRowAnimationAutomatic];
self.bookmarkCell = nil;
}
}
- (void)collapse
{
self.actionBar.hidden = YES;
[self.placePageView hideTableView:YES];
self.scrollView.scrollEnabled = NO;
animate(^{
self.actionBar.origin = {0., self.ownerView.height};
[self.scrollView setContentOffset:{0., kMinOffset} animated:YES];
});
}
- (void)expand
{
self.actionBar.hidden = NO;
self.scrollView.scrollEnabled = YES;
animate(^{
[self.placePageView hideTableView:NO];
self.actionBar.minY = self.actionBar.superview.height - self.actionBar.height;
self.expandedContentOffset = self.ppPreviewCell.height + self.placePageView.top.height + self.actionBar.height;
auto const targetOffset = self.state == State::Bottom ? self.expandedContentOffset : self.topContentOffset;
[self.scrollView setContentOffset:{0, targetOffset} animated:YES];
});
}
- (BOOL)isPortrait
{
auto const & s = self.ownerView.size;
return s.height > s.width;
}
- (CGFloat)topContentOffset
{
auto const target = self.isPortrait ? self.portraitOpenContentOffset : self.landscapeOpenContentOffset;
if (target > self.placePageView.height)
return self.placePageView.height;
return target;
}
#pragma mark - Downloader event
- (void)processDownloaderEventWithStatus:(storage::NodeStatus)status progress:(CGFloat)progress
{
using namespace storage;
switch(status)
{
case NodeStatus::Undefined:
{
self.isPlacePageButtonsEnabled = YES;
auto const & sections = self.data.sections;
auto const it = find(sections.begin(), sections.end(), place_page::Sections::Buttons);
if (it != sections.end())
{
[self.placePageView.tableView reloadSections:[NSIndexSet indexSetWithIndex:distance(sections.begin(), it)]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
if (self.ppPreviewCell)
[self.ppPreviewCell setDownloaderViewHidden:YES animated:NO];
else
self.isDownloaderViewShown = NO;
break;
}
case NodeStatus::Downloading:
self.ppPreviewCell.mapDownloadProgress.progress = progress;
break;
case NodeStatus::InQueue:
self.ppPreviewCell.mapDownloadProgress.state = MWMCircularProgressStateSpinner;
break;
case NodeStatus::Error:
self.ppPreviewCell.mapDownloadProgress.state = MWMCircularProgressStateFailed;
break;
case NodeStatus::Partly:
break;
case NodeStatus::OnDiskOutOfDate:
case NodeStatus::OnDisk:
{
self.isPlacePageButtonsEnabled = YES;
auto const & sections = self.data.sections;
auto const it = find(sections.begin(), sections.end(), place_page::Sections::Buttons);
if (it != sections.end())
{
[self.placePageView.tableView reloadSections:[NSIndexSet indexSetWithIndex:distance(sections.begin(), it)]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.ppPreviewCell setDownloaderViewHidden:YES animated:NO];
break;
}
case NodeStatus::NotDownloaded:
self.isPlacePageButtonsEnabled = NO;
if (self.ppPreviewCell)
[self.ppPreviewCell setDownloaderViewHidden:NO animated:NO];
else
self.isDownloaderViewShown = YES;
break;
}
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(MWMPPScrollView *)scrollView
{
if ([scrollView isEqual:self.placePageView.tableView])
return;
auto const offset = scrollView.contentOffset;
if (offset.y <= 0)
{
[self.scrollView removeFromSuperview];
[self.actionBar removeFromSuperview];
[self.delegate shouldDestroyLayout];
return;
}
if (offset.y > self.placePageView.height + 30)
{
auto const bounded = self.placePageView.height + 30;
[scrollView setContentOffset:{0, bounded}];
[self.delegate onTopBoundChanged:bounded];
}
else
{
[self.delegate onTopBoundChanged:offset.y];
}
self.direction = self.lastContentOffset < offset.y ? ScrollDirection::Up : ScrollDirection::Down;
self.lastContentOffset = offset.y;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
auto const actualOffset = scrollView.contentOffset.y;
auto const openOffset = self.isPortrait ? self.portraitOpenContentOffset : self.landscapeOpenContentOffset;
auto const targetOffset = (*targetContentOffset).y;
if (actualOffset > self.expandedContentOffset && actualOffset < openOffset)
{
self.state = self.direction == ScrollDirection::Up ? State::Top : State::Bottom;
(*targetContentOffset).y = self.direction == ScrollDirection::Up ? openOffset : self.expandedContentOffset;
}
else if (actualOffset > openOffset && targetOffset < openOffset)
{
self.state = State::Top;
(*targetContentOffset).y = openOffset;
}
else if (actualOffset < self.expandedContentOffset)
{
(*targetContentOffset).y = 0;
animate(^{
self.actionBar.origin = {0., self.ownerView.height};
});
}
else
{
self.state = State::Top;
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (decelerate)
return;
auto const actualOffset = scrollView.contentOffset.y;
auto const openOffset = self.isPortrait ? self.portraitOpenContentOffset : self.landscapeOpenContentOffset;
if (actualOffset < self.expandedContentOffset + 30)
{
self.state = State::Bottom;
animate(^{
[scrollView setContentOffset:{0, self.expandedContentOffset} animated:YES];
});
}
else if (actualOffset < openOffset)
{
self.state = self.direction == ScrollDirection::Up ? State::Top : State::Bottom;
animate(^{
[scrollView setContentOffset:{0, self.direction == ScrollDirection::Up ? openOffset : self.expandedContentOffset}
animated:YES];
});
}
else
{
self.state = State::Top;
}
}
#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (!self.data)
return 0;
return self.data.sections.size();
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
using namespace place_page;
switch (self.data.sections[section])
{
case Sections::Preview:
case Sections::Bookmark: return 1;
case Sections::Metainfo: return self.data.metainfoRows.size();
case Sections::Buttons: return self.data.buttonsRows.size();
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
using namespace place_page;
switch (self.data.sections[indexPath.section])
{
case Sections::Preview:
{
if (!self.ppPreviewCell)
self.ppPreviewCell = [tableView dequeueReusableCellWithIdentifier:[MWMPlacePagePreviewCell className]];
[self.ppPreviewCell configure:self.data updateLayoutDelegate:self dataSource:self.dataSource];
[self.ppPreviewCell setDownloaderViewHidden:!self.isDownloaderViewShown animated:NO];
return self.ppPreviewCell;
}
case Sections::Bookmark:
{
MWMBookmarkCell * c = [tableView dequeueReusableCellWithIdentifier:kBookmarkCells[0]];
[c configureWithText:self.data.bookmarkDescription
updateCellDelegate:self
editBookmarkDelegate:self.delegate
isHTML:self.data.isHTMLDescription];
return c;
}
case Sections::Metainfo:
{
auto const row = self.data.metainfoRows[indexPath.row];
auto cellName = kMetaInfoCells[static_cast<size_t>(row)];
UITableViewCell * c = [tableView dequeueReusableCellWithIdentifier:cellName];
switch (row)
{
case MetainfoRows::OpeningHours:
[static_cast<MWMOpeningHoursCell *>(c) configureWithOpeningHours:[self.data stringForRow:row]
updateLayoutDelegate:self
isClosedNow:self.data.schedule == OpeningHours::Closed];
break;
case MetainfoRows::Phone:
case MetainfoRows::Address:
case MetainfoRows::Website:
case MetainfoRows::Email:
case MetainfoRows::Cuisine:
case MetainfoRows::Operator:
case MetainfoRows::Internet:
case MetainfoRows::Coordinate:
[static_cast<MWMPlacePageInfoCell *>(c) configWithRow:row data:self.data];
break;
}
return c;
}
case Sections::Buttons:
{
MWMPlacePageButtonCell * c = [tableView dequeueReusableCellWithIdentifier:kButtonsCells[0]];
auto const row = self.data.buttonsRows[indexPath.row];
[c configForRow:row withDelegate:self.delegate];
if (row != ButtonsRows::HotelDescription)
[c setEnabled:self.isPlacePageButtonsEnabled];
return c;
}
}
}
#pragma mark - MWMPlacePageCellUpdateProtocol
- (void)updateCellWithForceReposition:(BOOL)isForceReposition
{
auto const update = isForceReposition ? @selector(updateWithExpand) : @selector(update);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:update object:nil];
[self performSelector:update withObject:nil afterDelay:0.5];
}
- (void)update
{
auto tableView = self.placePageView.tableView;
[tableView beginUpdates];
[tableView endUpdates];
}
- (void)updateWithExpand
{
[self update];
[self expand];
}
#pragma mark - MWMPlacePageViewUpdateProtocol
- (void)updateWithHeight:(CGFloat)height
{
auto const & size = self.ownerView.size;
self.scrollView.contentSize = {size.width, size.height + height};
}
@end

View file

@ -0,0 +1,5 @@
#import "MWMPlacePageProtocol.h"
@interface MWMPlacePageManager : NSObject <MWMPlacePageProtocol>
@end

View file

@ -0,0 +1,335 @@
#import "MapViewController.h"
#import "MWMActivityViewController.h"
#import "MWMAPIBar.h"
#import "MWMCircularProgress.h"
#import "MWMPlacePageManager.h"
#import "MWMViewController.h"
#import "MWMPlacePageLayout.h"
#import "MWMPlacePageData.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h"
#import "MWMLocationManager.h"
#import "MWMRouter.h"
#import "MWMStorage.h"
#import "MWMEditBookmarkController.h"
#import "Statistics.h"
#import <Pushwoosh/PushNotificationManager.h>
#include "geometry/distance_on_sphere.hpp"
#include "platform/measurement_utils.hpp"
@interface MWMPlacePageManager() <MWMFrameworkStorageObserver, MWMPlacePageLayoutDelegate,
MWMPlacePageLayoutDataSource, MWMLocationObserver>
@property(weak, nonatomic) MWMViewController * ownerViewController;
@property(nonatomic) MWMPlacePageEntity * entity;
@property(nonatomic) MWMPlacePageLayout * layout;
@property(nonatomic) MWMPlacePageData * data;
@property(nonatomic) storage::NodeStatus currentDownloaderStatus;
@end
@implementation MWMPlacePageManager
- (instancetype)initWithViewController:(MWMViewController *)viewController
{
self = [super init];
if (self)
_ownerViewController = viewController;
return self;
}
- (void)showPlacePage:(place_page::Info const &)info
{
self.currentDownloaderStatus = storage::NodeStatus::Undefined;
[MWMFrameworkListener addObserver:self];
self.data = [[MWMPlacePageData alloc] initWithPlacePageInfo:info];
[self.layout showWithData:self.data];
// Call for the first time to produce changes
[self processCountryEvent:self.data.countryId];
if (![MWMLocationManager lastHeading])
return;
[MWMLocationManager addObserver:self];
[self.layout setDistanceToObject:self.distanceToObject];
}
- (void)closePlacePage
{
[_layout close];
[MWMLocationManager removeObserver:self];
[MWMFrameworkListener removeObserver:self];
}
#pragma mark - MWMPlacePageLayoutDataSource
- (void)downloadSelectedArea
{
auto const & countryId = self.data.countryId;
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(countryId, nodeAttrs);
MWMAlertViewController * avc = [MapViewController controller].alertController;
switch (nodeAttrs.m_status)
{
case NodeStatus::NotDownloaded:
case NodeStatus::Partly:
[MWMStorage downloadNode:countryId alertController:avc onSuccess:nil];
break;
case NodeStatus::Undefined:
case NodeStatus::Error: [MWMStorage retryDownloadNode:countryId]; break;
case NodeStatus::OnDiskOutOfDate: [MWMStorage updateNode:countryId alertController:avc]; break;
case NodeStatus::Downloading:
case NodeStatus::InQueue: [MWMStorage cancelDownloadNode:countryId]; break;
case NodeStatus::OnDisk: break;
}
}
- (NSString *)distanceToObject
{
CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (!lastLocation)
return @"";
string distance;
CLLocationCoordinate2D const coord = lastLocation.coordinate;
ms::LatLon const target = self.data.latLon;
measurement_utils::FormatDistance(
ms::DistanceOnEarth(coord.latitude, coord.longitude, target.lat, target.lon), distance);
return @(distance.c_str());
}
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(TCountryId const &)countryId
{
if (countryId == kInvalidCountryId)
{
[_layout processDownloaderEventWithStatus:storage::NodeStatus::Undefined progress:0];
return;
}
if (self.data.countryId != countryId)
return;
NodeStatuses statuses;
GetFramework().GetStorage().GetNodeStatuses(countryId, statuses);
auto const status = statuses.m_status;
if (status == self.currentDownloaderStatus)
return;
self.currentDownloaderStatus = status;
[_layout processDownloaderEventWithStatus:status progress:0];
}
- (void)processCountry:(TCountryId const &)countryId progress:(MapFilesDownloader::TProgress const &)progress
{
if (countryId == kInvalidCountryId || self.data.countryId != countryId)
return;
[_layout processDownloaderEventWithStatus:storage::NodeStatus::Downloading
progress:static_cast<CGFloat>(progress.first) / progress.second];
}
#pragma mark - MWMPlacePageLayout
- (MWMPlacePageLayout *)layout
{
if (!_layout)
{
_layout = [[MWMPlacePageLayout alloc] initWithOwnerView:self.ownerViewController.view
delegate:self
dataSource:self];
}
return _layout;
}
- (void)onTopBoundChanged:(CGFloat)bound
{
[[MWMMapViewControlsManager manager] dragPlacePage:{{0, self.ownerViewController.view.height - bound}, {}}];
}
- (void)shouldDestroyLayout
{
self.layout = nil;
GetFramework().DeactivateMapSelection(false);
}
#pragma mark - MWMLocationObserver
- (void)onHeadingUpdate:(location::CompassInfo const &)info
{
CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (!lastLocation)
return;
CGFloat const angle = ang::AngleTo(lastLocation.mercator, self.data.mercator) + info.m_bearing;
[_layout rotateDirectionArrowToAngle:angle];
}
- (void)onLocationUpdate:(location::GpsInfo const &)locationInfo
{
[_layout setDistanceToObject:self.distanceToObject];
}
- (void)mwm_refreshUI
{
[_layout mwm_refreshUI];
}
- (void)dismissPlacePage
{
[self closePlacePage];
}
- (void)hidePlacePage
{
[self closePlacePage];
}
- (void)routeFrom
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatBuildRoute)
withParameters:@{kStatValue : kStatSource}];
[[MWMRouter router] buildFromPoint:self.target bestRouter:YES];
[self closePlacePage];
}
- (void)routeTo
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatBuildRoute)
withParameters:@{kStatValue : kStatDestination}];
[[MWMRouter router] buildToPoint:self.target bestRouter:YES];
[self closePlacePage];
}
- (MWMRoutePoint)target
{
NSString * name = nil;
if (self.data.title.length > 0)
name = self.data.title;
else if (self.data.address.length > 0)
name = self.data.address;
else if (self.data.subtitle.length > 0)
name = self.data.subtitle;
else if (self.data.isBookmark)
name = self.data.externalTitle;
else
name = L(@"placepage_unknown_place");
m2::PointD const & org = self.data.mercator;
return self.data.isMyPosition ? MWMRoutePoint(org) : MWMRoutePoint(org, name);
}
- (void)share
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatShare)];
MWMActivityViewController * shareVC =
[MWMActivityViewController shareControllerForPlacePageObject:static_cast<id<MWMPlacePageObject>>(self.data)];
[shareVC presentInParentViewController:self.ownerViewController
anchorView:self.layout.shareAnchor];
}
- (void)editPlace
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatEdit)];
[[PushNotificationManager pushManager] setTags:@{ @"editor_edit_discovered" : @YES }];
[(MapViewController *)self.ownerViewController openEditor];
}
- (void)addBusiness
{
[Statistics logEvent:kStatEditorAddClick withParameters:@{kStatValue : kStatPlacePage}];
[[MWMMapViewControlsManager manager] addPlace:YES hasPoint:NO point:m2::PointD()];
}
- (void)addPlace
{
[Statistics logEvent:kStatEditorAddClick
withParameters:@{kStatValue : kStatPlacePageNonBuilding}];
[[MWMMapViewControlsManager manager] addPlace:NO hasPoint:YES point:self.data.mercator];
}
- (void)addBookmark
{
[self.data updateBookmarkStatus:YES];
[self.layout reloadBookmarkSection:YES];
}
- (void)removeBookmark
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatBookmarks)
withParameters:@{kStatValue : kStatRemove}];
[self.data updateBookmarkStatus:NO];
[self.layout reloadBookmarkSection:NO];
}
- (void)editBookmark
{
[[MapViewController controller] openBookmarkEditorWithData:self.data];
}
- (void)book:(BOOL)isDescription
{
NSMutableDictionary * stat = [@{ kStatProvider : kStatBooking } mutableCopy];
MWMPlacePageData * data = self.data;
auto const latLon = data.latLon;
stat[kStatHotel] = data.hotelId;
stat[kStatHotelLat] = @(latLon.lat);
stat[kStatHotelLon] = @(latLon.lon);
[Statistics logEvent:isDescription ? kPlacePageHotelDetails : kPlacePageHotelBook
withParameters:stat
atLocation:[MWMLocationManager lastLocation]];
UIViewController * vc = static_cast<UIViewController *>([MapViewController controller]);
NSURL * url = isDescription ? self.data.bookingDescriptionURL : self.data.bookingURL;
NSAssert(url, @"Booking url can't be nil!");
[vc openUrl:url];
}
- (void)call
{
NSAssert(self.data.phoneNumber, @"Phone number can't be nil!");
NSString * phoneNumber = [[@"telprompt:" stringByAppendingString:self.data.phoneNumber]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
}
- (void)apiBack
{
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatAPI)];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.data.apiURL]];
[[MapViewController controller].apiBar back];
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self->_layout layoutWithSize:size];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { }];
}
#pragma mark - MWMFeatureHolder
- (FeatureID const &)featureId
{
return self.data.featureId;
}
#pragma mark - Deprecated
@synthesize leftBound = _leftBound;
@synthesize topBound = _topBound;
- (void)setTopBound:(CGFloat)topBound {_topBound = 0;}
- (void)setLeftBound:(CGFloat)leftBound {_leftBound = 0;}
- (void)addSubviews:(NSArray *)views withNavigationController:(UINavigationController *)controller {}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {}
@end

View file

@ -0,0 +1,24 @@
#import "MWMTableViewCell.h"
@class MWMPlacePageData;
@class MWMCircularProgress;
@protocol MWMPlacePageCellUpdateProtocol;
@protocol MWMPlacePageLayoutDataSource;
@interface MWMPlacePagePreviewCell : MWMTableViewCell
- (void)setDistanceToObject:(NSString *)distance;
- (void)rotateDirectionArrowToAngle:(CGFloat)angle;
- (void)setDownloaderViewHidden:(BOOL)isHidden animated:(BOOL)isAnimated;
- (void)setDownloadingProgress:(CGFloat)progress;
- (void)configure:(MWMPlacePageData *)data
updateLayoutDelegate:(id<MWMPlacePageCellUpdateProtocol>)delegate
dataSource:(id<MWMPlacePageLayoutDataSource>)dataSource;
- (MWMCircularProgress *)mapDownloadProgress;
@end

View file

@ -0,0 +1,426 @@
#import "Common.h"
#import "MWMDirectionView.h"
#import "MWMPlacePageCellUpdateProtocol.h"
#import "MWMPlacePageData.h"
#import "MWMPlacePageLayout.h"
#import "MWMPlacePagePreviewCell.h"
#import "MWMCircularProgress.h"
#import "UIColor+MapsmeColor.h"
#include "std/array.hpp"
#include "std/vector.hpp"
namespace
{
array<NSString *, 6> kPPPClasses = {{@"_MWMPPPTitle",
@"_MWMPPPExternalTitle",
@"_MWMPPPSubtitle",
@"_MWMPPPSchedule",
@"_MWMPPPBooking",
@"_MWMPPPAddress"}};
enum class Labels
{
Title,
ExternalTitle,
Subtitle,
Schedule,
Booking,
Address
};
void * kContext = &kContext;
NSString * const kTableViewContentSizeKeyPath = @"contentSize";
CGFloat const kDefaultTableViewLeading = 16;
CGFloat const kCompressedTableViewLeading = 56;
} // namespace
#pragma mark - Base
// Base class for avoiding copy-paste in inheriting cells.
@interface _MWMPPPCellBase : MWMTableViewCell
@property(weak, nonatomic) IBOutlet UILabel * distance;
@property(weak, nonatomic) IBOutlet UIImageView * compass;
@property(weak, nonatomic) IBOutlet UIView * distanceView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * trailing;
@property(copy, nonatomic) TMWMVoidBlock tapOnDistance;
@end
@implementation _MWMPPPCellBase
- (IBAction)tap
{
if (self.tapOnDistance)
self.tapOnDistance();
}
@end
#pragma mark - Title
@interface _MWMPPPTitle : _MWMPPPCellBase
@property(weak, nonatomic) IBOutlet UILabel * title;
@end
@implementation _MWMPPPTitle
@end
#pragma mark - External Title
@interface _MWMPPPExternalTitle : _MWMPPPCellBase
@property(weak, nonatomic) IBOutlet UILabel * externalTitle;
@end
@implementation _MWMPPPExternalTitle
@end
#pragma mark - Subtitle
@interface _MWMPPPSubtitle : _MWMPPPCellBase
@property(weak, nonatomic) IBOutlet UILabel * subtitle;
@end
@implementation _MWMPPPSubtitle
@end
#pragma mark - Schedule
@interface _MWMPPPSchedule : _MWMPPPCellBase
@property(weak, nonatomic) IBOutlet UILabel * schedule;
@end
@implementation _MWMPPPSchedule
@end
#pragma mark - Booking
@interface _MWMPPPBooking : MWMTableViewCell
@property(weak, nonatomic) IBOutlet UILabel * rating;
@property(weak, nonatomic) IBOutlet UILabel * pricing;
@end
@implementation _MWMPPPBooking
@end
#pragma mark - Address
@interface _MWMPPPAddress : _MWMPPPCellBase
@property(weak, nonatomic) IBOutlet UILabel * address;
@end
@implementation _MWMPPPAddress
@end
#pragma mark - Public
@interface MWMPlacePagePreviewCell () <UITableViewDelegate, UITableViewDataSource, MWMCircularProgressProtocol>
{
vector<Labels> m_cells;
}
@property(weak, nonatomic) IBOutlet UITableView * tableView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * tableViewHeight;
@property(weak, nonatomic) NSLayoutConstraint * trailing;
@property(weak, nonatomic) UIView * distanceView;
@property(weak, nonatomic) IBOutlet UIView * downloaderParentView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * tableViewLeading;
@property(nonatomic) MWMCircularProgress * mapDownloadProgress;
@property(nonatomic) BOOL isDirectionViewAvailable;
@property(weak, nonatomic) MWMPlacePageData * data;
@property(weak, nonatomic) id<MWMPlacePageCellUpdateProtocol> delegate;
@property(weak, nonatomic) id<MWMPlacePageLayoutDataSource> dataSource;
@property(copy, nonatomic) NSString * distance;
@property(weak, nonatomic) UIImageView * compass;
@property(nonatomic) CGFloat currentContentHeight;
@property(nonatomic) MWMDirectionView * directionView;
@end
@implementation MWMPlacePagePreviewCell
- (void)awakeFromNib
{
[super awakeFromNib];
for (auto const s : kPPPClasses)
[self.tableView registerNib:[UINib nibWithNibName:s bundle:nil] forCellReuseIdentifier:s];
self.tableView.estimatedRowHeight = 20;
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self registerObserver];
}
- (void)dealloc
{
[self unregisterObserver];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == kContext)
{
NSValue * s = change[@"new"];
CGFloat const height = s.CGSizeValue.height;
if (abs(height - self.currentContentHeight) > 0.5)
{
self.currentContentHeight = height;
self.tableViewHeight.constant = height;
[self setNeedsLayout];
[self.delegate updateCellWithForceReposition:YES];
}
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (MWMDirectionView *)directionView
{
if (!_directionView)
_directionView = [[MWMDirectionView alloc] initWithManager:nil];
return _directionView;
}
- (void)setIsDirectionViewAvailable:(BOOL)isDirectionViewAvailable
{
if (_isDirectionViewAvailable == isDirectionViewAvailable)
return;
_isDirectionViewAvailable = isDirectionViewAvailable;
[self setNeedsLayout];
}
- (void)rotateDirectionArrowToAngle:(CGFloat)angle
{
self.compass.layer.transform = CATransform3DMakeRotation(M_PI_2 - angle, 0, 0, 1);
self.directionView.directionArrow.layer.transform = CATransform3DMakeRotation(M_PI_2 - angle, 0, 0, 1);
}
- (void)setDistanceToObject:(NSString *)distance
{
if (!distance.length)
{
self.isDirectionViewAvailable = NO;
[self setNeedsLayout];
return;
}
if ([self.distance isEqualToString:distance])
return;
self.distance = distance;
self.directionView.distanceLabel.text = distance;
self.isDirectionViewAvailable = YES;
}
- (void)unregisterObserver
{
[self.tableView removeObserver:self forKeyPath:kTableViewContentSizeKeyPath context:kContext];
}
- (void)registerObserver
{
[self.tableView addObserver:self forKeyPath:kTableViewContentSizeKeyPath options:NSKeyValueObservingOptionNew context:kContext];
}
- (void)setDownloadingProgress:(CGFloat)progress
{
self.mapDownloadProgress.progress = progress;
}
- (void)setDownloaderViewHidden:(BOOL)isHidden animated:(BOOL)isAnimated
{
self.downloaderParentView.hidden = isHidden;
self.tableViewLeading.constant = isHidden ? kDefaultTableViewLeading : kCompressedTableViewLeading;
[self setNeedsLayout];
if (!isHidden)
self.mapDownloadProgress.state = MWMCircularProgressStateNormal;
if (!isAnimated)
return;
[UIView animateWithDuration:kDefaultAnimationDuration animations:^{
[self layoutIfNeeded];
}];
}
- (void)configure:(MWMPlacePageData *)data
updateLayoutDelegate:(id<MWMPlacePageCellUpdateProtocol>)delegate
dataSource:(id<MWMPlacePageLayoutDataSource>)dataSource
{
self.data = data;
self.delegate = delegate;
self.dataSource = dataSource;
[self setDistanceToObject:dataSource.distanceToObject];
m_cells.clear();
if (data.title.length)
m_cells.push_back(Labels::Title);
if (data.externalTitle.length)
m_cells.push_back(Labels::ExternalTitle);
if (data.subtitle.length)
m_cells.push_back(Labels::Subtitle);
if (data.schedule != place_page::OpeningHours::Unknown)
m_cells.push_back(Labels::Schedule);
if (data.bookingRating.length)
m_cells.push_back(Labels::Booking);
if (data.address.length)
m_cells.push_back(Labels::Address);
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return m_cells.size();
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
auto data = self.data;
_MWMPPPCellBase * c = nil;
BOOL const isNeedToShowDistance = self.isDirectionViewAvailable && (indexPath.row == m_cells.size() - 1);
switch (m_cells[indexPath.row])
{
case Labels::Title:
{
c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPTitle className]];
static_cast<_MWMPPPTitle *>(c).title.text = data.title;
break;
}
case Labels::ExternalTitle:
{
c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPExternalTitle className]];
static_cast<_MWMPPPExternalTitle *>(c).externalTitle.text = data.externalTitle;
break;
}
case Labels::Subtitle:
{
c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPSubtitle className]];
static_cast<_MWMPPPSubtitle *>(c).subtitle.text = data.subtitle;
break;
}
case Labels::Schedule:
{
c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPSchedule className]];
auto castedCell = static_cast<_MWMPPPSchedule *>(c);
switch(data.schedule)
{
case place_page::OpeningHours::AllDay:
castedCell.schedule.text = L(@"twentyfour_seven");
castedCell.schedule.textColor = [UIColor blackSecondaryText];
break;
case place_page::OpeningHours::Open:
castedCell.schedule.text = L(@"editor_time_open");
castedCell.schedule.textColor = [UIColor blackSecondaryText];
break;
case place_page::OpeningHours::Closed:
castedCell.schedule.text = L(@"closed_now");
castedCell.schedule.textColor = [UIColor red];
break;
case place_page::OpeningHours::Unknown:
NSAssert(false, @"Incorrect schedule!");
break;
}
break;
}
case Labels::Booking:
{
_MWMPPPBooking * c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPBooking className]];
c.rating.text = data.bookingRating;
c.pricing.text = data.bookingApproximatePricing;
[data assignOnlinePriceToLabel:c.pricing];
return c;
}
case Labels::Address:
{
c = [tableView dequeueReusableCellWithIdentifier:[_MWMPPPAddress className]];
static_cast<_MWMPPPAddress *>(c).address.text = data.address;
break;
}
}
if (isNeedToShowDistance)
[self showDistanceOnCell:c];
else
[self hideDistanceOnCell:c];
return c;
}
- (void)showDistanceOnCell:(_MWMPPPCellBase *)cell
{
cell.trailing.priority = UILayoutPriorityDefaultLow;
cell.distance.text = self.distance;
cell.tapOnDistance = ^{ [self.directionView show]; };
[cell.contentView setNeedsLayout];
self.compass = cell.compass;
self.trailing = cell.trailing;
self.distanceView = cell.distanceView;
cell.distanceView.hidden = NO;
}
- (void)hideDistanceOnCell:(_MWMPPPCellBase *)cell
{
cell.trailing.priority = UILayoutPriorityDefaultHigh;
[cell.contentView setNeedsLayout];
cell.distanceView.hidden = YES;
}
#pragma mark - MWMCircularProgressProtocol
- (void)progressButtonPressed:(MWMCircularProgress *)progress
{
[self.dataSource downloadSelectedArea];
}
#pragma mark - Properties
- (MWMCircularProgress *)mapDownloadProgress
{
if (!_mapDownloadProgress)
{
_mapDownloadProgress =
[MWMCircularProgress downloaderProgressForParentView:self.downloaderParentView];
_mapDownloadProgress.delegate = self;
MWMCircularProgressStateVec const affectedStates = {MWMCircularProgressStateNormal,
MWMCircularProgressStateSelected};
[_mapDownloadProgress setImage:[UIImage imageNamed:@"ic_download"] forStates:affectedStates];
[_mapDownloadProgress setColoring:MWMButtonColoringBlue forStates:affectedStates];
}
return _mapDownloadProgress;
}
@end

View file

@ -0,0 +1,58 @@
#import "MWMMapViewControlsManager.h"
#include "Framework.h"
@class MWMPlacePageEntity, MWMViewController;
@protocol MWMActionBarProtocol <NSObject>
- (void)routeFrom;
- (void)routeTo;
- (void)share;
- (void)addBookmark;
- (void)removeBookmark;
- (void)call;
- (void)book:(BOOL)isDecription;
- (void)apiBack;
@end
@protocol MWMPlacePageButtonsProtocol <NSObject>
- (void)editPlace;
- (void)addPlace;
- (void)addBusiness;
- (void)book:(BOOL)isDescription;
- (void)editBookmark;
@end
struct FeatureID;
@protocol MWMFeatureHolder <NSObject>
- (FeatureID const &)featureId;
@end
@protocol MWMPlacePageProtocol <MWMActionBarProtocol, MWMPlacePageButtonsProtocol, MWMFeatureHolder>
@property(weak, nonatomic, readonly) MWMViewController * ownerViewController;
@property(nonatomic) CGFloat topBound;
@property(nonatomic) CGFloat leftBound;
- (instancetype)initWithViewController:(MWMViewController *)viewController;
- (void)showPlacePage:(place_page::Info const &)info;
- (void)mwm_refreshUI;
- (void)dismissPlacePage;
- (void)hidePlacePage;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation;
- (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
- (void)addSubviews:(NSArray *)views withNavigationController:(UINavigationController *)controller;
@end

View file

@ -2,16 +2,16 @@
#include "Framework.h"
#include "MWMPlacePageProtocol.h"
@class MWMPlacePageEntity, MWMPlacePageNavigationBar, MWMViewController;
@interface MWMPlacePageViewManager : NSObject
@interface MWMPlacePageViewManager : NSObject <MWMPlacePageProtocol>
@property(weak, nonatomic, readonly) MWMViewController * ownerViewController;
@property(nonatomic, readonly) MWMPlacePageEntity * entity;
@property(nonatomic) MWMPlacePageNavigationBar * iPhoneNavigationBar;
@property(nonatomic) CGFloat topBound;
@property(nonatomic) CGFloat leftBound;
@property(nonatomic, readonly) BOOL isDirectionViewShown;
- (instancetype)initWithViewController:(MWMViewController *)viewController;
- (void)showPlacePage:(place_page::Info const &)info;
@ -37,7 +37,6 @@
- (void)reloadBookmark;
- (void)dragPlacePage:(CGRect)frame;
- (void)showDirectionViewWithTitle:(NSString *)title type:(NSString *)type;
- (void)hideDirectionView;
- (void)addSubviews:(NSArray *)views withNavigationController:(UINavigationController *)controller;
- (void)changeHeight:(CGFloat)height;

View file

@ -70,6 +70,11 @@ extern NSString * const kBookmarksChangedNotification;
[self configPlacePage];
}
- (FeatureID const &)featureId
{
return self.entity.featureID;
}
#pragma mark - Layout
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
@ -211,7 +216,7 @@ extern NSString * const kBookmarksChangedNotification;
[Alohalytics logEvent:kAlohalyticsTapEventKey withValue:@"ppShare"];
MWMPlacePageEntity * entity = self.entity;
MWMActivityViewController * shareVC =
[MWMActivityViewController shareControllerForPlacePageObject:entity];
[MWMActivityViewController shareControllerForPlacePageObject:static_cast<id<MWMPlacePageObject>>(entity)];
[shareVC presentInParentViewController:self.ownerViewController
anchorView:self.placePage.actionBar.shareAnchor];
}
@ -220,7 +225,7 @@ extern NSString * const kBookmarksChangedNotification;
{
NSMutableDictionary * stat = [@{ kStatProvider : kStatBooking } mutableCopy];
MWMPlacePageEntity * en = self.entity;
auto const latLon = en.latlon;
auto const latLon = en.latLon;
stat[kStatHotel] = en.hotelId;
stat[kStatHotelLat] = @(latLon.lat);
stat[kStatHotelLon] = @(latLon.lon);
@ -229,7 +234,7 @@ extern NSString * const kBookmarksChangedNotification;
atLocation:[MWMLocationManager lastLocation]];
UIViewController * vc = static_cast<UIViewController *>([MapViewController controller]);
NSURL * url = isDescription ? self.entity.bookingDescriptionUrl : self.entity.bookingUrl;
NSURL * url = isDescription ? self.entity.bookingDescriptionURL : self.entity.bookingURL;
NSAssert(url, @"Booking url can't be nil!");
[vc openUrl:url];
}
@ -276,10 +281,10 @@ extern NSString * const kBookmarksChangedNotification;
withParameters:@{kStatValue : kStatAdd}];
Framework & f = GetFramework();
BookmarkData bmData = {self.entity.titleForNewBookmark, f.LastEditedBMType()};
size_t const categoryIndex = f.LastEditedBMCategory();
size_t const bookmarkIndex =
f.GetBookmarkManager().AddBookmark(categoryIndex, self.entity.mercator, bmData);
self.entity.bac = {categoryIndex, bookmarkIndex};
auto const categoryIndex = static_cast<int>(f.LastEditedBMCategory());
auto const bookmarkIndex =
static_cast<int>(f.GetBookmarkManager().AddBookmark(categoryIndex, self.entity.mercator, bmData));
self.entity.bac = {bookmarkIndex, categoryIndex};
self.entity.bookmarkTitle = @(bmData.GetName().c_str());
self.entity.bookmarkCategory = @(f.GetBmCategory(categoryIndex)->GetName().c_str());
[NSNotificationCenter.defaultCenter postNotificationName:kBookmarksChangedNotification
@ -294,16 +299,16 @@ extern NSString * const kBookmarksChangedNotification;
[Statistics logEvent:kStatEventName(kStatPlacePage, kStatBookmarks)
withParameters:@{kStatValue : kStatRemove}];
Framework & f = GetFramework();
BookmarkCategory * bookmarkCategory = f.GetBookmarkManager().GetBmCategory(self.entity.bac.first);
BookmarkCategory * bookmarkCategory = f.GetBookmarkManager().GetBmCategory(self.entity.bac.m_categoryIndex);
if (bookmarkCategory)
{
{
BookmarkCategory::Guard guard(*bookmarkCategory);
guard.m_controller.DeleteUserMark(self.entity.bac.second);
guard.m_controller.DeleteUserMark(self.entity.bac.m_bookmarkIndex);
}
bookmarkCategory->SaveToKMLFile();
}
self.entity.bac = MakeEmptyBookmarkAndCategory();
self.entity.bac = {};
self.entity.bookmarkTitle = nil;
self.entity.bookmarkCategory = nil;
[NSNotificationCenter.defaultCenter postNotificationName:kBookmarksChangedNotification
@ -335,7 +340,7 @@ extern NSString * const kBookmarksChangedNotification;
return @"";
string distance;
CLLocationCoordinate2D const coord = lastLocation.coordinate;
ms::LatLon const target = self.entity.latlon;
ms::LatLon const target = self.entity.latLon;
measurement_utils::FormatDistance(
ms::DistanceOnEarth(coord.latitude, coord.longitude, target.lat, target.lon), distance);
return @(distance.c_str());
@ -344,26 +349,12 @@ extern NSString * const kBookmarksChangedNotification;
- (void)showDirectionViewWithTitle:(NSString *)title type:(NSString *)type
{
MWMDirectionView * directionView = self.directionView;
UIView * ownerView = self.ownerViewController.view;
directionView.titleLabel.text = title;
directionView.typeLabel.text = type;
[ownerView addSubview:directionView];
[ownerView endEditing:YES];
[directionView setNeedsLayout];
MapsAppDelegate * app = [MapsAppDelegate theApp];
[app.mapViewController updateStatusBarStyle];
[app disableStandby];
[directionView show];
[self updateDistance];
}
- (void)hideDirectionView
{
[self.directionView removeFromSuperview];
MapsAppDelegate * app = [MapsAppDelegate theApp];
[app.mapViewController updateStatusBarStyle];
[app enableStandby];
}
- (void)changeHeight:(CGFloat)height
{
if (!IPAD)
@ -399,7 +390,7 @@ extern NSString * const kBookmarksChangedNotification;
return _directionView;
}
- (BOOL)isDirectionViewShown { return self.directionView.superview != nil; }
- (void)setTopBound:(CGFloat)topBound { _topBound = self.placePage.topBound = topBound; }
- (void)setLeftBound:(CGFloat)leftBound { _leftBound = self.placePage.leftBound = leftBound; }
- (void)editBookmark {}
@end

View file

@ -12,6 +12,7 @@ struct AddressInfo;
@class MWMMapViewControlsManager;
@class MWMAPIBar;
@class MWMPlacePageData;
@interface MapViewController : MWMViewController
@ -31,6 +32,7 @@ struct AddressInfo;
- (void)openBookmarks;
- (void)openMapsDownloader:(mwm::DownloaderMode)mode;
- (void)openEditor;
- (void)openBookmarkEditorWithData:(MWMPlacePageData *)data;
- (void)initialize;

View file

@ -19,7 +19,9 @@
#import "MWMMapDownloaderViewController.h"
#import "MWMMapViewControlsManager.h"
#import "MWMPageController.h"
#import "MWMPlacePageData.h"
#import "MWMPlacePageEntity.h"
#import "MWMPlacePageProtocol.h"
#import "MWMRouter.h"
#import "MWMRouterSavedState.h"
#import "MWMSettings.h"
@ -70,6 +72,8 @@ NSString * const kDownloaderSegue = @"Map2MapDownloaderSegue";
NSString * const kMigrationSegue = @"Map2MigrationSegue";
NSString * const kEditorSegue = @"Map2EditorSegue";
NSString * const kUDViralAlertWasShown = @"ViralAlertWasShown";
NSString * const kPP2BookmarkEditingSegue = @"PP2BookmarkEditing";
// The first launch after process started. Used to skip "Not follow, no position" state and to run
// locator.
@ -416,7 +420,8 @@ BOOL gIsFirstMyPositionMode = YES;
- (void)openEditor
{
using namespace osm_auth_ios;
auto const & featureID = self.controlsManager.placePageEntity.info.GetID();
auto const & featureID = self.controlsManager.featureHolder.featureId;
[Statistics logEvent:kStatEditorEditStart
withParameters:@{
@ -425,7 +430,12 @@ BOOL gIsFirstMyPositionMode = YES;
kStatEditorMWMName : @(featureID.GetMwmName().c_str()),
kStatEditorMWMVersion : @(featureID.GetMwmVersion())
}];
[self performSegueWithIdentifier:kEditorSegue sender:self.controlsManager.placePageEntity];
[self performSegueWithIdentifier:kEditorSegue sender:self.controlsManager.featureHolder];
}
- (void)openBookmarkEditorWithData:(MWMPlacePageData *)data
{
[self performSegueWithIdentifier:kPP2BookmarkEditingSegue sender:data];
}
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode
@ -552,7 +562,12 @@ BOOL gIsFirstMyPositionMode = YES;
if ([segue.identifier isEqualToString:kEditorSegue])
{
MWMEditorViewController * dvc = segue.destinationViewController;
[dvc setFeatureToEdit:static_cast<MWMPlacePageEntity *>(sender).featureID];
[dvc setFeatureToEdit:static_cast<id<MWMFeatureHolder>>(sender).featureId];
}
else if ([segue.identifier isEqualToString:kPP2BookmarkEditingSegue])
{
MWMEditBookmarkController * dvc = segue.destinationViewController;
dvc.data = static_cast<MWMPlacePageData *>(sender);
}
else if ([segue.identifier isEqualToString:kDownloaderSegue])
{

View file

@ -1,4 +1,4 @@
@class MWMPlacePageEntity;
@protocol MWMPlacePageObject;
@interface MWMActivityViewController : UIActivityViewController
@ -6,7 +6,7 @@
+ (instancetype)shareControllerForMyPosition:(CLLocationCoordinate2D const &)location;
+ (instancetype)shareControllerForPlacePageObject:(MWMPlacePageEntity *)entity;
+ (instancetype)shareControllerForPlacePageObject:(id<MWMPlacePageObject>)object;
- (void)presentInParentViewController:(UIViewController *)parentVC anchorView:(UIView *)anchorView;

View file

@ -32,10 +32,10 @@
return [[self alloc] initWithActivityItem:item];
}
+ (instancetype)shareControllerForPlacePageObject:(MWMPlacePageEntity *)entity
+ (instancetype)shareControllerForPlacePageObject:(id<MWMPlacePageObject>)object;
{
MWMShareActivityItem * item =
[[MWMShareActivityItem alloc] initForPlacePageObjectWithEntity:entity];
[[MWMShareActivityItem alloc] initForPlacePageObject:object];
return [[self alloc] initWithActivityItem:item];
}

View file

@ -1,8 +1,25 @@
@class MWMPlacePageEntity;
namespace ms
{
class LatLon;
} // namespace ms
@protocol MWMPlacePageObject <NSObject>
- (BOOL)isMyPosition;
- (BOOL)isBooking;
- (NSString *)title;
- (NSString *)subtitle;
- (NSString *)address;
- (NSURL *)bookingDescriptionURL;
- (NSString *)phoneNumber;
- (ms::LatLon)latLon;
@end
@interface MWMShareActivityItem : NSObject<UIActivityItemSource>
- (instancetype)initForMyPositionAtLocation:(CLLocationCoordinate2D const &)location;
- (instancetype)initForPlacePageObjectWithEntity:(MWMPlacePageEntity *)entity;
- (instancetype)initForPlacePageObject:(id<MWMPlacePageObject>)object;
@end

View file

@ -15,7 +15,7 @@ NSString * httpGe0Url(NSString * shortUrl)
@interface MWMShareActivityItem ()
@property(nonatomic) MWMPlacePageEntity * entity;
@property(nonatomic) id<MWMPlacePageObject> object;
@property(nonatomic) CLLocationCoordinate2D location;
@property(nonatomic) BOOL isMyPosition;
@ -34,16 +34,16 @@ NSString * httpGe0Url(NSString * shortUrl)
return self;
}
- (instancetype)initForPlacePageObjectWithEntity:(MWMPlacePageEntity *)entity
- (instancetype)initForPlacePageObject:(id<MWMPlacePageObject>)object
{
self = [super init];
if (self)
{
NSAssert(entity, @"Entity can't be nil!");
BOOL const isMyPosition = entity.isMyPosition;
NSAssert(object, @"Entity can't be nil!");
BOOL const isMyPosition = object.isMyPosition;
_isMyPosition = isMyPosition;
if (!isMyPosition)
_entity = entity;
_object = object;
}
return self;
}
@ -52,22 +52,22 @@ NSString * httpGe0Url(NSString * shortUrl)
{
auto & f = GetFramework();
auto const title = ^NSString *(MWMPlacePageEntity * entity)
auto const title = ^NSString *(id<MWMPlacePageObject> obj)
{
if (!entity || entity.isMyPosition)
if (!obj || obj.isMyPosition)
return L(@"my_position");
else if (entity.title.length)
return entity.title;
else if (entity.subtitle.length)
return entity.subtitle;
else if (entity.address.length)
return entity.address;
else if (obj.title.length)
return obj.title;
else if (obj.subtitle.length)
return obj.subtitle;
else if (obj.address.length)
return obj.address;
else
return @"";
};
ms::LatLon const ll = self.entity ? self.entity.latlon : ms::LatLon(self.location.latitude, self.location.longitude);
string const s = f.CodeGe0url(ll.lat, ll.lon, f.GetDrawScale(), title(self.entity).UTF8String);
ms::LatLon const ll = self.object ? self.object.latLon : ms::LatLon(self.location.latitude, self.location.longitude);
string const s = f.CodeGe0url(ll.lat, ll.lon, f.GetDrawScale(), title(self.object).UTF8String);
NSString * url = @(s.c_str());
if (!isShort)
@ -108,7 +108,7 @@ NSString * httpGe0Url(NSString * shortUrl)
NSString * shortUrl = [self url:YES];
return [NSString stringWithFormat:@"%@\n%@", httpGe0Url(shortUrl),
self.isMyPosition ? L(@"my_position_share_email_subject")
: self.entity.title];
: self.object.title];
}
- (NSString *)itemDefaultWithActivityType:(NSString *)activityType
@ -123,13 +123,13 @@ NSString * httpGe0Url(NSString * shortUrl)
}
NSMutableString * result = [L(@"sharing_call_action_look") mutableCopy];
vector<NSString *> strings{self.entity.title, self.entity.subtitle, self.entity.address,
[self.entity getCellValue:MWMPlacePageCellTypePhoneNumber], url};
vector<NSString *> strings{self.object.title, self.object.subtitle, self.object.address,
self.object.phoneNumber, url};
if (self.entity.isBooking)
if (self.object.isBooking)
{
strings.push_back(L(@"sharing_booking"));
strings.push_back(self.entity.bookingDescriptionUrl.absoluteString);
strings.push_back(self.object.bookingDescriptionURL.absoluteString);
}
for (auto const str : strings)