You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
9.9 KiB

2 years ago
/*
* Copyright 2019 Google LLC. All rights reserved.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#import "GooglePlacesDemos/Samples/FindPlaceLikelihoodListViewController.h"
#import <GooglePlaces/GooglePlaces.h>
static NSString *const kCellIdentifier = @"LikelihoodCellIdentifier";
#pragma mark - ButtonCoordinateView
@interface ButtonCoordinateView : UIView
// The button used to trigger the fetch likelihoods from coordinate action.
@property(nonatomic, strong) UIButton *button;
@end
@implementation ButtonCoordinateView {
}
- (instancetype)init {
if (self = [super init]) {
[self setupUI];
}
return self;
}
- (void)setupUI {
self.layer.cornerRadius = 3;
self.layer.masksToBounds = YES;
self.layer.borderColor = [UIColor clearColor].CGColor;
self.layer.borderWidth = 1;
UIStackView *stackView = [[UIStackView alloc] init];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 15;
stackView.layoutMargins = UIEdgeInsetsMake(5, 0, 5, 0);
stackView.layoutMarginsRelativeArrangement = YES;
[self addSubview:stackView];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"Retrieve location" forState:UIControlStateNormal];
[stackView addArrangedSubview:button];
_button = button;
UIStackView *labelsStackView = [[UIStackView alloc] init];
labelsStackView.axis = UILayoutConstraintAxisVertical;
[stackView addArrangedSubview:labelsStackView];
[stackView setTranslatesAutoresizingMaskIntoConstraints:NO];
[NSLayoutConstraint activateConstraints:@[
[stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
[stackView.topAnchor constraintEqualToAnchor:self.topAnchor],
[stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor]
]];
}
// Sets the title and target for the button.
- (void)fillWithButtonTitle:(NSString *)title
target:(id)target
action:(SEL)action
forControlEvents:(UIControlEvents)controlEvents {
[_button setTitle:title forState:UIControlStateNormal];
[_button addTarget:target action:action forControlEvents:controlEvents];
}
@end
#pragma mark - FindPlaceLikelihoodListViewController
@interface FindPlaceLikelihoodListViewController ()
@property(nonatomic, strong) UITableView *tableView;
@property(nonatomic, strong) NSArray<GMSPlaceLikelihood *> *placeLikelihoods;
@property(nonatomic, strong) UILabel *errorLabel;
@property(nonatomic, strong) ButtonCoordinateView *currentButtonCoordinateView;
@end
@implementation FindPlaceLikelihoodListViewController {
CLLocationManager *_locationManager;
GMSPlacesClient *_placesClient;
}
+ (NSString *)demoTitle {
return @"Find Place Likelihoods";
}
- (void)viewDidLoad {
[super viewDidLoad];
_placesClient = [GMSPlacesClient sharedClient];
// Initializes the location manager to be used for current location.
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
_locationManager = locationManager;
self.title = [NSString stringWithFormat:@"Find place likelihoods from location"];
#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
if (@available(iOS 13.0, *)) {
self.view.backgroundColor = [UIColor systemBackgroundColor];
} else {
self.view.backgroundColor = [UIColor whiteColor];
}
#else
self.view.backgroundColor = [UIColor whiteColor];
#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
UIStackView *mainStackView = [[UIStackView alloc] init];
mainStackView.axis = UILayoutConstraintAxisVertical;
[self.view addSubview:mainStackView];
// Adds the location input section.
UIStackView *locationInputStackView = [[UIStackView alloc] initWithFrame:CGRectZero];
locationInputStackView.axis = UILayoutConstraintAxisVertical;
locationInputStackView.layoutMargins = UIEdgeInsetsMake(20, 15, 0, 15);
locationInputStackView.layoutMarginsRelativeArrangement = YES;
locationInputStackView.distribution = UIStackViewDistributionFill;
locationInputStackView.alignment = UIStackViewAlignmentFill;
locationInputStackView.spacing = 10;
[mainStackView addArrangedSubview:locationInputStackView];
ButtonCoordinateView *currentView = [[ButtonCoordinateView alloc] init];
[currentView fillWithButtonTitle:@"Find from current location"
target:self
action:@selector(onCurrentLocationTap)
forControlEvents:UIControlEventTouchUpInside];
[locationInputStackView addArrangedSubview:currentView];
_currentButtonCoordinateView = currentView;
UILabel *errorLabel = [[UILabel alloc] init];
errorLabel.textColor = [UIColor redColor];
errorLabel.numberOfLines = 0;
[locationInputStackView addArrangedSubview:errorLabel];
_errorLabel = errorLabel;
// Adds the likelihood list table.
UITableView *tableView = [[UITableView alloc] init];
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kCellIdentifier];
tableView.delegate = self;
tableView.dataSource = self;
[mainStackView addArrangedSubview:tableView];
_tableView = tableView;
mainStackView.translatesAutoresizingMaskIntoConstraints = NO;
NSArray<NSLayoutConstraint *> *stackViewConstraints = @[
[mainStackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[mainStackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[mainStackView.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor],
[mainStackView.bottomAnchor constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor]
];
stackViewConstraints = @[
[mainStackView.leadingAnchor
constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor],
[mainStackView.trailingAnchor
constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor],
[mainStackView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[mainStackView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor]
];
[NSLayoutConstraint activateConstraints:stackViewConstraints];
[self onCurrentLocationTap];
}
#pragma mark - Button Handlers
// Requests location services authorization if needed, and starts updating location.
- (void)onCurrentLocationTap {
if (![FindPlaceLikelihoodListViewController areLocationServicesEnabledAndAuthorized]) {
[_locationManager requestWhenInUseAuthorization];
return;
}
[_locationManager startUpdatingLocation];
__block FindPlaceLikelihoodListViewController *weakSelf = self;
GMSPlaceLikelihoodsCallback fetcherCallback =
^(NSArray<GMSPlaceLikelihood *> *_Nullable likelihoods, NSError *_Nullable error) {
[weakSelf handleFindPlaceLikelihoodsResponse:likelihoods error:error];
};
[_placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:GMSPlaceFieldAll
callback:fetcherCallback];
}
#pragma mark - CLLocationManagerDelegate
// Retries retrieving current location if user has granted location services permission.
- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
// Retry current location fetch once user enables Location Services.
[self onCurrentLocationTap];
} else {
_errorLabel.text = @"Please make sure location services are enabled.";
}
}
#pragma mark - UITableViewDataSource/Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (_placeLikelihoods == nil) {
return 0;
}
return _placeLikelihoods.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier
forIndexPath:indexPath];
cell.textLabel.numberOfLines = 0;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSInteger row = indexPath.row;
NSInteger likelihoodCount = _placeLikelihoods.count;
if (likelihoodCount > 0 && row < likelihoodCount) {
GMSPlaceLikelihood *likelihood = _placeLikelihoods[row];
cell.textLabel.text = likelihood.place.name;
}
return cell;
}
#pragma mark - Helpers
// Checks if user has authorized location services required for retrieving device location.
+ (BOOL)areLocationServicesEnabledAndAuthorized {
if (![CLLocationManager locationServicesEnabled]) {
return NO;
}
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
return status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusAuthorizedWhenInUse;
}
- (void)handleFindPlaceLikelihoodsResponse:(NSArray<GMSPlaceLikelihood *> *)likelihoods
error:(NSError *)error {
if (error != nil) {
_errorLabel.text = @"There was an error fetching likelihoods.";
return;
}
// Filters out Places that don't have a valid name.
NSPredicate *predicate = [NSPredicate
predicateWithBlock:^BOOL(GMSPlaceLikelihood *likelihood, NSDictionary<NSString *, id> *b) {
return likelihood.place.name != nil && [likelihood.place.name length] > 0;
}];
_placeLikelihoods = [likelihoods filteredArrayUsingPredicate:predicate];
_errorLabel.text = nil;
[_tableView reloadData];
[self resignFirstResponder];
}
@end