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

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'iphone/Maps/Classes/MWMPlacePageLayout.mm')
-rw-r--r--iphone/Maps/Classes/MWMPlacePageLayout.mm530
1 files changed, 530 insertions, 0 deletions
diff --git a/iphone/Maps/Classes/MWMPlacePageLayout.mm b/iphone/Maps/Classes/MWMPlacePageLayout.mm
new file mode 100644
index 0000000000..b8e4a55a3c
--- /dev/null
+++ b/iphone/Maps/Classes/MWMPlacePageLayout.mm
@@ -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