/* * Copyright 2018 Google * * 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 #if TARGET_OS_IOS #import "FirebaseInAppMessaging/Sources/DefaultUI/FIRCore+InAppMessagingDisplay.h" #import "FirebaseInAppMessaging/Sources/DefaultUI/ImageOnly/FIRIAMImageOnlyViewController.h" @interface FIRIAMImageOnlyViewController () @property(nonatomic, readwrite) FIRInAppMessagingImageOnlyDisplay *imageOnlyMessage; @property(weak, nonatomic) IBOutlet UIImageView *imageView; @property(weak, nonatomic) IBOutlet UIButton *closeButton; @property(nonatomic, assign) CGSize imageOriginalSize; @end @implementation FIRIAMImageOnlyViewController + (FIRIAMImageOnlyViewController *) instantiateViewControllerWithResourceBundle:(NSBundle *)resourceBundle displayMessage: (FIRInAppMessagingImageOnlyDisplay *)imageOnlyMessage displayDelegate: (id)displayDelegate timeFetcher:(id)timeFetcher { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"FIRInAppMessageDisplayStoryboard" bundle:resourceBundle]; if (storyboard == nil) { FIRLogError(kFIRLoggerInAppMessagingDisplay, @"I-FID300002", @"Storyboard '" "FIRInAppMessageDisplayStoryboard' not found in bundle %@", resourceBundle); return nil; } FIRIAMImageOnlyViewController *imageOnlyVC = (FIRIAMImageOnlyViewController *)[storyboard instantiateViewControllerWithIdentifier:@"image-only-vc"]; imageOnlyVC.displayDelegate = displayDelegate; imageOnlyVC.imageOnlyMessage = imageOnlyMessage; imageOnlyVC.timeFetcher = timeFetcher; return imageOnlyVC; } - (FIRInAppMessagingDisplayMessage *)inAppMessage { return self.imageOnlyMessage; } - (IBAction)closeButtonClicked:(id)sender { [self dismissView:FIRInAppMessagingDismissTypeUserTapClose]; } - (void)setupRecognizers { UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(messageTapped:)]; tapGestureRecognizer.delaysTouchesBegan = YES; tapGestureRecognizer.numberOfTapsRequired = 1; self.imageView.userInteractionEnabled = YES; [self.imageView addGestureRecognizer:tapGestureRecognizer]; } - (void)messageTapped:(UITapGestureRecognizer *)recognizer { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" FIRInAppMessagingAction *action = [[FIRInAppMessagingAction alloc] initWithActionText:nil actionURL:self.imageOnlyMessage.actionURL]; #pragma clang diagnostic pop [self followAction:action]; } - (void)viewDidLoad { [super viewDidLoad]; [self.view setBackgroundColor:[UIColor.grayColor colorWithAlphaComponent:0.5]]; // Close button should be announced last for better VoiceOver experience. self.view.accessibilityElements = @[ self.imageView, self.closeButton ]; if (self.imageOnlyMessage.imageData) { UIImage *image = [UIImage imageWithData:self.imageOnlyMessage.imageData.imageRawData]; self.imageOriginalSize = image.size; [self.imageView setImage:image]; self.imageView.contentMode = UIViewContentModeScaleAspectFit; self.imageView.accessibilityLabel = self.inAppMessage.campaignInfo.campaignName; } else { self.imageView.isAccessibilityElement = NO; } [self setupRecognizers]; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if (!self.imageOnlyMessage.imageData) { return; } // do the calculation in viewDidLayoutSubViews since self.view.window.frame is only // reliable at this time // Calculate the size of the image view under the constraints: // 1 Retain the image ratio // 2 Have at least 30 point of margines around four sides of the image view CGFloat minimalMargine = 30; // 30 points CGFloat maxImageViewWidth = self.view.window.frame.size.width - minimalMargine * 2; CGFloat maxImageViewHeight = self.view.window.frame.size.height - minimalMargine * 2; // Factor in space for the top notch on iPhone X*. #if defined(__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 if (@available(iOS 11.0, *)) { maxImageViewHeight -= self.view.safeAreaInsets.top; } #endif // defined(__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 CGFloat adjustedImageViewHeight = self.imageOriginalSize.height; CGFloat adjustedImageViewWidth = self.imageOriginalSize.width; if (adjustedImageViewWidth > maxImageViewWidth || adjustedImageViewHeight > maxImageViewHeight) { if (maxImageViewHeight / maxImageViewWidth > self.imageOriginalSize.height / self.imageOriginalSize.width) { // the image is relatively too wide compared against displayable area adjustedImageViewWidth = maxImageViewWidth; adjustedImageViewHeight = adjustedImageViewWidth * self.imageOriginalSize.height / self.imageOriginalSize.width; FIRLogDebug(kFIRLoggerInAppMessagingDisplay, @"I-FID110002", @"Use max available image display width as %lf", adjustedImageViewWidth); } else { // the image is relatively too narrow compared against displayable area adjustedImageViewHeight = maxImageViewHeight; adjustedImageViewWidth = adjustedImageViewHeight * self.imageOriginalSize.width / self.imageOriginalSize.height; FIRLogDebug(kFIRLoggerInAppMessagingDisplay, @"I-FID110003", @"Use max avilable image display height as %lf", adjustedImageViewHeight); } } else { // image can be rendered fully at its original size FIRLogDebug(kFIRLoggerInAppMessagingDisplay, @"I-FID110001", @"Image can be fully displayed in image only mode"); } CGRect rect = CGRectMake(0, 0, adjustedImageViewWidth, adjustedImageViewHeight); self.imageView.frame = rect; self.imageView.center = self.view.center; CGFloat closeButtonCenterX = CGRectGetMaxX(self.imageView.frame); CGFloat closeButtonCenterY = CGRectGetMinY(self.imageView.frame); self.closeButton.center = CGPointMake(closeButtonCenterX, closeButtonCenterY); [self.view bringSubviewToFront:self.closeButton]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // close any potential keyboard, which would conflict with the modal in-app messagine view [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; if (self.imageOnlyMessage.campaignInfo.renderAsTestMessage) { FIRLogDebug(kFIRLoggerInAppMessagingDisplay, @"I-FID110004", @"Flashing the close button since this is a test message."); [self flashCloseButton:self.closeButton]; } } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Announce via VoiceOver that the image-only message has appeared. Highlight the image. UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.imageView); } - (void)flashCloseButton:(UIButton *)closeButton { closeButton.alpha = 1.0f; [UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction animations:^{ closeButton.alpha = 0.1f; } completion:^(BOOL finished){ // Do nothing }]; } @end #endif // TARGET_OS_IOS