diff --git a/CHANGELOG.md b/CHANGELOG.md index 3780cd20..56ef3dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Changes for users of the library currently on `develop`: +## [5.0.0](https://github.com/nytimes/NYTPhotoViewer/releases/tag/5.0.0) + +Changes for users of the library in 5.0.0: + +- Changed `NYTPhotosViewControllerDelegate` protocol so that `- photosViewController:interstitialViewAtIndex:` can return nil. If it does, that index is skipped and the following (or preceding) photo or interstitial view is displayed. + ## [4.0.1](https://github.com/nytimes/NYTPhotoViewer/releases/tag/4.0.1) Changes for users of the library in 4.0.1: diff --git a/Example-Swift/AppDelegate.swift b/Example-Swift/AppDelegate.swift index 8736b564..d9e0a220 100755 --- a/Example-Swift/AppDelegate.swift +++ b/Example-Swift/AppDelegate.swift @@ -13,7 +13,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey:Any]?) -> Bool { return true } } diff --git a/Example-Swift/PhotoBox.swift b/Example-Swift/PhotoBox.swift index 3523e78f..ff427274 100644 --- a/Example-Swift/PhotoBox.swift +++ b/Example-Swift/PhotoBox.swift @@ -35,13 +35,13 @@ final class NYTPhotoBox: NSObject, NYTPhoto { var attributedCaptionTitle: NSAttributedString? var attributedCaptionSummary: NSAttributedString? { - let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white, + let attributes = [NSAttributedString.Key.foregroundColor:UIColor.white, NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body)] return NSAttributedString(string: value.summary, attributes: attributes) } var attributedCaptionCredit: NSAttributedString? { - let attributes = [NSAttributedString.Key.foregroundColor: UIColor.gray, + let attributes = [NSAttributedString.Key.foregroundColor:UIColor.gray, NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .footnote)] return NSAttributedString(string: value.credit, attributes: attributes) } diff --git a/Example-Swift/ViewController.swift b/Example-Swift/ViewController.swift index 816fea8f..efc20750 100755 --- a/Example-Swift/ViewController.swift +++ b/Example-Swift/ViewController.swift @@ -46,8 +46,8 @@ extension ViewController: NYTPhotosViewControllerDelegate { return false } - let shareActivityViewController = UIActivityViewController(activityItems: [photoImage], applicationActivities: nil) - shareActivityViewController.completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, items: [Any]?, error: Error?) in + let shareActivityViewController = UIActivityViewController(activityItems: [photoImage], applicationActivities:nil) + shareActivityViewController.completionWithItemsHandler = {(activityType:UIActivity.ActivityType?, completed:Bool, items:[Any]?, error:Error?) in if completed { photosViewController.delegate?.photosViewController!(photosViewController, actionCompletedWithActivityType: activityType?.rawValue) } @@ -69,7 +69,7 @@ extension ViewController: NYTPhotosViewControllerDelegate { photoViewerCoordinator = nil } - func photosViewController(_ photosViewController: NYTPhotosViewController, interstitialViewAt index: UInt) -> UIView { + func photosViewController(_ photosViewController: NYTPhotosViewController, interstitialViewAt index: UInt) -> UIView? { let redView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: photosViewController.view.frame.width, height: 200))) redView.backgroundColor = .red redView.autoresizingMask = [.flexibleWidth] diff --git a/Example/NYTViewController.m b/Example/NYTViewController.m index 6a504027..8f7ba720 100644 --- a/Example/NYTViewController.m +++ b/Example/NYTViewController.m @@ -55,7 +55,7 @@ - (void)updateImagesOnPhotosViewController:(NYTPhotosViewController *)photosView for (NYTExamplePhoto *photo in dataSource.photos) { if (!photo.image && !photo.imageData) { photo.image = [UIImage imageNamed:@"NYTimesBuilding"]; - photo.attributedCaptionSummary = [[NSAttributedString alloc] initWithString:@"Photo which previously had a loading spinner (to see the spinner, reopen the photo viewer and scroll to this photo)" attributes:@{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; + photo.attributedCaptionSummary = [[NSAttributedString alloc] initWithString:@"Photo which previously had a loading spinner (to see the spinner, reopen the photo viewer and scroll to this photo)" attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; [photosViewController updatePhoto:photo]; } } @@ -228,15 +228,15 @@ + (NYTPhotoViewerArrayDataSource *)newVariedDataSourceIncludingPhoto:(NYTExample } + (NSAttributedString *)attributedTitleFromString:(NSString *)caption { - return [[NSAttributedString alloc] initWithString:caption attributes:@{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; + return [[NSAttributedString alloc] initWithString:caption attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; } + (NSAttributedString *)attributedSummaryFromString:(NSString *)summary { - return [[NSAttributedString alloc] initWithString:summary attributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; + return [[NSAttributedString alloc] initWithString:summary attributes:@{NSForegroundColorAttributeName:[UIColor lightGrayColor], NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]}]; } + (NSAttributedString *)attributedCreditFromString:(NSString *)credit { - return [[NSAttributedString alloc] initWithString:credit attributes:@{NSForegroundColorAttributeName: [UIColor grayColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]}]; + return [[NSAttributedString alloc] initWithString:credit attributes:@{NSForegroundColorAttributeName:[UIColor grayColor], NSFontAttributeName:[UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]}]; } @end diff --git a/NYTPhotoViewer.podspec b/NYTPhotoViewer.podspec index 7c7334ba..809b07eb 100644 --- a/NYTPhotoViewer.podspec +++ b/NYTPhotoViewer.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "NYTPhotoViewer" - s.version = "4.0.1" + s.version = "5.0.0" s.description = <<-DESC NYTPhotoViewer is a slideshow and image viewer that includes double tap to zoom, captions, support for multiple images, interactive flick to dismiss, animated zooming presentation, and more. diff --git a/NYTPhotoViewer/Info.plist b/NYTPhotoViewer/Info.plist index 331a2dac..e6771905 100644 --- a/NYTPhotoViewer/Info.plist +++ b/NYTPhotoViewer/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.2.0 + 5.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/NYTPhotoViewer/NYTPhotosViewController.h b/NYTPhotoViewer/NYTPhotosViewController.h index 18dd30fd..11cbca67 100644 --- a/NYTPhotoViewer/NYTPhotosViewController.h +++ b/NYTPhotoViewer/NYTPhotosViewController.h @@ -222,7 +222,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * * @return A view to display as the caption for the photo. Return `nil` to show a default view generated from the caption properties on the photo object. */ -- (UIView * _Nullable)photosViewController:(NYTPhotosViewController *)photosViewController captionViewForPhoto:(id )photo; +- (nullable UIView *)photosViewController:(NYTPhotosViewController *)photosViewController captionViewForPhoto:(id )photo; /** * Returns whether the caption view should respect the safe area. @@ -248,7 +248,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * * @return The text to display as the navigation-item title for the given photo. Return `nil` to show a default title like "1 of 4" indicating progress in a slideshow, or an empty string to hide this text entirely. */ -- (NSString * _Nullable)photosViewController:(NYTPhotosViewController *)photosViewController titleForPhoto:(id )photo atIndex:(NSInteger)photoIndex totalPhotoCount:(nullable NSNumber *)totalPhotoCount; +- (nullable NSString *)photosViewController:(NYTPhotosViewController *)photosViewController titleForPhoto:(id )photo atIndex:(NSInteger)photoIndex totalPhotoCount:(nullable NSNumber *)totalPhotoCount; /** * Returns a view to display while a photo is loading. Can be any `UIView` object, but is expected to respond to `sizeToFit` appropriately. This view will be sized and centered in the blank area, and hidden when the photo image or its placeholder is loaded. @@ -258,7 +258,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * * @return A view to display while the photo is loading. Return `nil` to show a default white `UIActivityIndicatorView`. */ -- (UIView * _Nullable)photosViewController:(NYTPhotosViewController *)photosViewController loadingViewForPhoto:(id )photo; +- (nullable UIView *)photosViewController:(NYTPhotosViewController *)photosViewController loadingViewForPhoto:(id )photo; /** * Returns the view from which to animate for a given object conforming to the `NYTPhoto` protocol. @@ -268,7 +268,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * * @return The view to animate out of or into for the given photo. */ -- (UIView * _Nullable)photosViewController:(NYTPhotosViewController *)photosViewController referenceViewForPhoto:(id )photo; +- (nullable UIView *)photosViewController:(NYTPhotosViewController *)photosViewController referenceViewForPhoto:(id )photo; /** * Returns the maximum zoom scale for a given object conforming to the `NYTPhoto` protocol. @@ -307,7 +307,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * @param photosViewController The `NYTPhotosViewController` instance that sent the delegate message. * @param activityType The activity type that was successfully shared. */ -- (void)photosViewController:(NYTPhotosViewController *)photosViewController actionCompletedWithActivityType:(NSString * _Nullable)activityType; +- (void)photosViewController:(NYTPhotosViewController *)photosViewController actionCompletedWithActivityType:(nullable NSString *)activityType; /** * called when an `NYTInterstitialViewController` is created but before it is displayed. Returns the view to display as an interstitial view. @@ -317,7 +317,7 @@ extern NSString * const NYTPhotosViewControllerDidDismissNotification; * * @return A `UIView`. */ -- (UIView *)photosViewController:(NYTPhotosViewController *)photosViewController interstitialViewAtIndex:(NSUInteger)index; +- (nullable UIView *)photosViewController:(NYTPhotosViewController *)photosViewController interstitialViewAtIndex:(NSUInteger)index; @end diff --git a/NYTPhotoViewer/NYTPhotosViewController.m b/NYTPhotoViewer/NYTPhotosViewController.m index f3555dab..e0dabdd1 100644 --- a/NYTPhotoViewer/NYTPhotosViewController.m +++ b/NYTPhotoViewer/NYTPhotosViewController.m @@ -174,7 +174,7 @@ - (instancetype)initWithDataSource:(id )dataSource ini return [self initWithDataSource:dataSource initialPhoto:initialPhoto delegate:delegate]; } -- (instancetype)initWithDataSource:(id )dataSource initialPhoto:(id _Nullable)initialPhoto delegate:(nullable id )delegate { +- (instancetype)initWithDataSource:(id )dataSource initialPhoto:(nullable id )initialPhoto delegate:(nullable id )delegate { self = [super initWithNibName:nil bundle:nil]; if (self) { @@ -184,7 +184,7 @@ - (instancetype)initWithDataSource:(id )dataSource ini return self; } -- (void)commonInitWithDataSource:(id )dataSource initialPhoto:(id _Nullable)initialPhoto delegate:(nullable id )delegate { +- (void)commonInitWithDataSource:(id )dataSource initialPhoto:(nullable id )initialPhoto delegate:(nullable id )delegate { _dataSource = dataSource; _delegate = delegate; _initialPhoto = initialPhoto; @@ -207,7 +207,7 @@ - (void)commonInitWithDataSource:(id )dataSource initi _notificationCenter = [NSNotificationCenter new]; - self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:@{UIPageViewControllerOptionInterPageSpacingKey: @(NYTPhotosViewControllerInterPhotoSpacing)}]; + self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:@{UIPageViewControllerOptionInterPageSpacingKey:@(NYTPhotosViewControllerInterPhotoSpacing)}]; self.pageViewController.delegate = self; self.pageViewController.dataSource = self; @@ -579,63 +579,36 @@ - (NSInteger)totalItemCount { return self.dataSource.numberOfPhotos.integerValue + numberOfInterstitialViews; } -#pragma mark - NYTPhotoViewControllerDelegate +#pragma mark - UIPageViewControllerDataSource -- (void)photoViewController:(NYTPhotoViewController *)photoViewController didLongPressWithGestureRecognizer:(UILongPressGestureRecognizer *)longPressGestureRecognizer { - self.shouldHandleLongPress = NO; - - BOOL clientDidHandle = NO; - if ([self.delegate respondsToSelector:@selector(photosViewController:handleLongPressForPhoto:withGestureRecognizer:)]) { - clientDidHandle = [self.delegate photosViewController:self handleLongPressForPhoto:photoViewController.photo withGestureRecognizer:longPressGestureRecognizer]; - } - - self.shouldHandleLongPress = !clientDidHandle; - - if (self.shouldHandleLongPress) { - UIMenuController *menuController = [UIMenuController sharedMenuController]; - CGRect targetRect = CGRectZero; - targetRect.origin = [longPressGestureRecognizer locationInView:longPressGestureRecognizer.view]; - [menuController setTargetRect:targetRect inView:longPressGestureRecognizer.view]; - [menuController setMenuVisible:YES animated:YES]; - } -} +/// internal helper method for the following two delegate methods -#pragma mark - UIPageViewControllerDataSource +- (UIViewController *)nextViewControllerFromIndex:(NSInteger)startingIndex delta:(NSInteger)delta stopBeforeIndex:(NSInteger)stopBeforeIndex { + NSInteger itemIndex = startingIndex; + while (itemIndex + delta != stopBeforeIndex) { + itemIndex += delta; -- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { - NSUInteger itemIndex = viewController.photoViewItemIndex; - if (itemIndex == 0) { - return nil; + BOOL isPhotoAvailableAtIndex = true; + if ([self.dataSource respondsToSelector:@selector(isPhotoAtIndex:)]) { + isPhotoAvailableAtIndex = [self.dataSource isPhotoAtIndex:itemIndex]; + } + if (isPhotoAvailableAtIndex) { + return [self newPhotoViewControllerForPhoto:[self.dataSource photoAtIndex:itemIndex] atIndex:itemIndex]; + } + UIViewController *possibleVC = [self newViewControllerAtIndex:itemIndex]; + if (possibleVC != nil) { + return possibleVC; + } } + return nil; +} - NSUInteger beforeIndex = itemIndex - 1; - BOOL isPhotoAvailableAtIndex = true; - if ([self.dataSource respondsToSelector:@selector(isPhotoAtIndex:)]) { - isPhotoAvailableAtIndex = [self.dataSource isPhotoAtIndex:beforeIndex]; - } - if (isPhotoAvailableAtIndex) { - return [self newPhotoViewControllerForPhoto:[self.dataSource photoAtIndex:beforeIndex] atIndex:beforeIndex]; - } else { - return [self newViewControllerAtIndex:beforeIndex]; - } +- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { + return [self nextViewControllerFromIndex:viewController.photoViewItemIndex delta:-1 stopBeforeIndex:-1]; } - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { - NSUInteger itemIndex = viewController.photoViewItemIndex; - NSUInteger afterIndex = itemIndex + 1; - if (afterIndex >= [self totalItemCount]) { - return nil; - } - - BOOL isPhotoAvailableAtIndex = true; - if ([self.dataSource respondsToSelector:@selector(isPhotoAtIndex:)]) { - isPhotoAvailableAtIndex = [self.dataSource isPhotoAtIndex:afterIndex]; - } - if (isPhotoAvailableAtIndex) { - return [self newPhotoViewControllerForPhoto:[self.dataSource photoAtIndex:afterIndex] atIndex:afterIndex]; - } else { - return [self newViewControllerAtIndex:afterIndex]; - } + return [self nextViewControllerFromIndex:viewController.photoViewItemIndex delta:1 stopBeforeIndex:self.totalItemCount]; } #pragma mark - UIPageViewControllerDelegate diff --git a/README.md b/README.md index 06966967..5408c52e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ NYTPhotosViewController *photosViewController = [[NYTPhotosViewController alloc] The Example project uses [Carthage](https://github.com/Carthage/Carthage) to integrate its dependencies. If you don’t have Carthage installed, you can install it via [Homebrew](http://brew.sh) with `brew install carthage`. -Then, in your checkout of the `NYTPhotoViewer` repo, run `carthage checkout --use-submodules`. +Then, in your local workspace of the `NYTPhotoViewer` repo, run `./scripts/bootstrap`. ## Installation diff --git a/scripts/lint b/scripts/lint index 5dbfa902..c1bcd1ce 100755 --- a/scripts/lint +++ b/scripts/lint @@ -7,6 +7,6 @@ if ! command -v carthage > /dev/null; then fi -carthage build --platform iOS --no-use-binaries --use-submodules --no-skip-current +carthage build --platform iOS --no-use-binaries --no-skip-current pod lib lint