diff --git a/BFRImageViewController/BFRImageContainerViewController.h b/BFRImageViewController/BFRImageContainerViewController.h index 4a4270b..a5aed3e 100644 --- a/BFRImageViewController/BFRImageContainerViewController.h +++ b/BFRImageViewController/BFRImageContainerViewController.h @@ -8,12 +8,23 @@ #import +typedef NS_ENUM(NSUInteger, BFRImageAssetType) { + BFRImageAssetTypeImage, + BFRImageAssetTypeRemoteImage, + BFRImageAssetTypeGIF, + BFRImageAssetTypeLivePhoto, + BFRImageAssetTypeUnknown +}; + /*! This class holds an image to view, if you need an image viewer alloc @C BFRImageViewController instead. This class isn't meant to instanitated outside of it. */ @interface BFRImageContainerViewController : UIViewController /*! Source of the image, which should either be @c NSURL or @c UIIimage. */ @property (strong, nonatomic, nonnull) id imgSrc; +/*! The type of asset that is being represented by the given @p imgSrc. */ +@property (nonatomic, assign) BFRImageAssetType assetType; + /*! This will determine whether to change certain behaviors for 3D touch considerations based on its value. */ @property (nonatomic, getter=isBeingUsedFor3DTouch) BOOL usedFor3DTouch; @@ -29,4 +40,7 @@ /*! If there is more than one image in the containing @c BFRImageViewController - this property is set to YES to make swiping from image to image easier. */ @property (nonatomic, getter=shouldDisableHorizontalDrag) BOOL disableHorizontalDrag; +/*! Assigning YES to this property will disable autoplay for live photos when it used with 3DTouch peek feature */ +@property (nonatomic, getter=shouldDisableAutoplayForLivePhoto) BOOL disableAutoplayForLivePhoto; + @end diff --git a/BFRImageViewController/BFRImageContainerViewController.m b/BFRImageViewController/BFRImageContainerViewController.m index afd017b..0cbf8f6 100644 --- a/BFRImageViewController/BFRImageContainerViewController.m +++ b/BFRImageViewController/BFRImageContainerViewController.m @@ -10,6 +10,7 @@ #import "BFRBackLoadedImageSource.h" #import "BFRImageViewerConstants.h" #import +#import #import #import #import @@ -22,9 +23,15 @@ @interface BFRImageContainerViewController () 1); + imgVC.disableAutoplayForLivePhoto = self.shouldDisableAutoplayForLivePhoto; [self.imageViewControllers addObject:imgVC]; } diff --git a/BFRImageViewerDemo/BFRImageViewer.xcodeproj/project.pbxproj b/BFRImageViewerDemo/BFRImageViewer.xcodeproj/project.pbxproj index 65d20d3..66f3c0c 100644 --- a/BFRImageViewerDemo/BFRImageViewer.xcodeproj/project.pbxproj +++ b/BFRImageViewerDemo/BFRImageViewer.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 944B4DC11BFFC0C000B9BF87 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 944B4DBF1BFFC0C000B9BF87 /* LaunchScreen.storyboard */; }; 944B4DE91BFFC0E300B9BF87 /* BFRImageContainerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 944B4DE61BFFC0E300B9BF87 /* BFRImageContainerViewController.m */; }; 944B4DEA1BFFC0E300B9BF87 /* BFRImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 944B4DE81BFFC0E300B9BF87 /* BFRImageViewController.m */; }; + 95D4797D1F97C348001E54D4 /* FifthViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 95D4797C1F97C348001E54D4 /* FifthViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -61,6 +62,8 @@ 944B4DE61BFFC0E300B9BF87 /* BFRImageContainerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BFRImageContainerViewController.m; sourceTree = ""; }; 944B4DE71BFFC0E300B9BF87 /* BFRImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BFRImageViewController.h; sourceTree = ""; }; 944B4DE81BFFC0E300B9BF87 /* BFRImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BFRImageViewController.m; sourceTree = ""; }; + 95D4797B1F97C348001E54D4 /* FifthViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FifthViewController.h; sourceTree = ""; }; + 95D4797C1F97C348001E54D4 /* FifthViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FifthViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -130,6 +133,8 @@ 944B4DAE1BFFC0C000B9BF87 /* Supporting Files */, 171F4AD11E96C31400F4AF01 /* FourthViewController.h */, 171F4AD21E96C31400F4AF01 /* FourthViewController.m */, + 95D4797B1F97C348001E54D4 /* FifthViewController.h */, + 95D4797C1F97C348001E54D4 /* FifthViewController.m */, ); path = BFRImageViewer; sourceTree = ""; @@ -299,6 +304,7 @@ 944B4DB91BFFC0C000B9BF87 /* SecondViewController.m in Sources */, 1797CB8E1E81BB4F00D9F729 /* BFRImageTransitionAnimator.m in Sources */, 1797CB911E81BBB200D9F729 /* ThirdViewController.m in Sources */, + 95D4797D1F97C348001E54D4 /* FifthViewController.m in Sources */, 944B4DEA1BFFC0E300B9BF87 /* BFRImageViewController.m in Sources */, 944B4DB31BFFC0C000B9BF87 /* AppDelegate.m in Sources */, 171F4AD01E96BE0500F4AF01 /* BFRBackLoadedImageSource.m in Sources */, diff --git a/BFRImageViewerDemo/BFRImageViewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/BFRImageViewerDemo/BFRImageViewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/BFRImageViewerDemo/BFRImageViewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/BFRImageViewerDemo/BFRImageViewer/AppDelegate.m b/BFRImageViewerDemo/BFRImageViewer/AppDelegate.m index ee3d10b..82b1ecd 100644 --- a/BFRImageViewerDemo/BFRImageViewer/AppDelegate.m +++ b/BFRImageViewerDemo/BFRImageViewer/AppDelegate.m @@ -11,6 +11,7 @@ #import "SecondViewController.h" #import "ThirdViewController.h" #import "FourthViewController.h" +#import "FifthViewController.h" @interface AppDelegate () @@ -24,7 +25,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UITabBarController *tabVC = [UITabBarController new]; tabVC.view.backgroundColor = [UIColor whiteColor]; - tabVC.viewControllers = @[[FirstViewController new], [SecondViewController new], [ThirdViewController new], [FourthViewController new]]; + tabVC.viewControllers = @[[FirstViewController new], + [SecondViewController new], + [ThirdViewController new], + [FourthViewController new], + [FifthViewController new]]; self.window.rootViewController = tabVC; [self.window makeKeyAndVisible]; diff --git a/BFRImageViewerDemo/BFRImageViewer/FifthViewController.h b/BFRImageViewerDemo/BFRImageViewer/FifthViewController.h new file mode 100644 index 0000000..77de02c --- /dev/null +++ b/BFRImageViewerDemo/BFRImageViewer/FifthViewController.h @@ -0,0 +1,13 @@ +// +// FifthViewController.h +// BFRImageViewer +// +// Created by Omer Emre Aslan on 18.10.2017. +// Copyright © 2017 Andrew Yates. All rights reserved. +// + +#import + +@interface FifthViewController : UIViewController + +@end diff --git a/BFRImageViewerDemo/BFRImageViewer/FifthViewController.m b/BFRImageViewerDemo/BFRImageViewer/FifthViewController.m new file mode 100644 index 0000000..2617e34 --- /dev/null +++ b/BFRImageViewerDemo/BFRImageViewer/FifthViewController.m @@ -0,0 +1,164 @@ +// +// FifthViewController.m +// BFRImageViewer +// +// Created by Omer Emre Aslan on 18.10.2017. +// Copyright © 2017 Andrew Yates. All rights reserved. +// + +#import +#import "FifthViewController.h" +#import "BFRImageViewController.h" + +@interface FifthViewController () + +@end + +@implementation FifthViewController + +- (instancetype) init { + if (self = [super init]) { + self.title = @"Live Photo"; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self check3DTouch]; + + [self addImageButtonToView]; +} + +#pragma mark - 3D Touch +- (void)check3DTouch { + if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { + [self registerForPreviewingWithDelegate:self sourceView:self.view]; + } +} + +- (UIViewController *)previewingContext:(id)previewingContext viewControllerForLocation:(CGPoint)location { + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; + + if (status == PHAuthorizationStatusAuthorized) { + return [self imageViewControllerForLivePhotoDisableAutoplay:NO]; + } else { + [self showAuthorizationAlertViewControllerAnimated:YES]; + return nil; + } +} + +- (void)previewingContext:(id)previewingContext commitViewController:(UIViewController *)viewControllerToCommit { + [self presentViewController:viewControllerToCommit animated:YES completion:nil]; +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { + if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { + [self check3DTouch]; + } +} + +#pragma mark - Misc +- (void)addImageButtonToView { + UIButton *openImageFromURL = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + openImageFromURL.translatesAutoresizingMaskIntoConstraints = NO; + [openImageFromURL setTitle:@"Open Image" forState:UIControlStateNormal]; + [openImageFromURL addTarget:self + action:@selector(openImage:) + forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:openImageFromURL]; + [openImageFromURL.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; + [openImageFromURL.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES; +} + +#pragma mark - Actions + +- (void)openImage:(UIButton *)sender { + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; + + if (status == PHAuthorizationStatusAuthorized) { + BFRImageViewController *imageViewController = [self + imageViewControllerForLivePhotoDisableAutoplay:YES]; + [self presentViewController:imageViewController + animated:YES + completion:nil]; + } else { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + if (status == PHAuthorizationStatusAuthorized) { + BFRImageViewController *imageViewController = [self imageViewControllerForLivePhotoDisableAutoplay:YES]; + [self presentViewController:imageViewController + animated:YES + completion:nil]; + } else { + [self showAuthorizationAlertViewControllerAnimated:YES]; + } + }]; + } + +} + +- (void)showAuthorizationAlertViewControllerAnimated:(BOOL)isAnimated { + UIAlertController *controller = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"Authorization Failed!", nil) + message:NSLocalizedString(@"In order to access live photo feature, please allow authorization on Settings.", nil) + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *closeAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"Close", nil) + style:UIAlertActionStyleDefault + handler:nil]; + [controller addAction:closeAction]; + + [self presentViewController:controller + animated:isAnimated + completion:nil]; +} + +- (BFRImageViewController *)imageViewControllerForLivePhotoDisableAutoplay:(BOOL)shouldDisableAutoPlay { + PHFetchOptions *options = [[PHFetchOptions alloc] init]; + options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; + options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeImage]; + options.predicate = [NSPredicate predicateWithFormat:@"mediaSubtype == %d", PHAssetMediaSubtypePhotoLive]; + options.includeAllBurstAssets = NO; + PHFetchResult *allLivePhotos = [PHAsset fetchAssetsWithOptions:options]; + + NSMutableArray *livePhotosToShow = [NSMutableArray new]; + + if (allLivePhotos.count > 0) { + NSInteger maxResults = 4; + NSInteger currentFetchCount = 0; + + for (PHFetchResult *result in allLivePhotos) { + if (currentFetchCount == maxResults) { + break; + } + + [livePhotosToShow addObject:result]; + currentFetchCount++; + } + + BFRImageViewController *viewController = [[BFRImageViewController alloc] + initWithImageSource:[livePhotosToShow copy]]; + viewController.disableAutoplayForLivePhoto = shouldDisableAutoPlay; + return viewController; + } else { + UIAlertController *controller = [UIAlertController + alertControllerWithTitle:@"No Live Photos" + message:@"There doesn't appear to be any live photos on your device." + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *closeAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"Close", nil) + style:UIAlertActionStyleDefault + handler:nil]; + [controller addAction:closeAction]; + + [self presentViewController:controller + animated:YES + completion:nil]; + + return nil; + } +} + +@end diff --git a/BFRImageViewerDemo/BFRImageViewer/Info.plist b/BFRImageViewerDemo/BFRImageViewer/Info.plist index 7bfe257..a0e47a9 100644 --- a/BFRImageViewerDemo/BFRImageViewer/Info.plist +++ b/BFRImageViewerDemo/BFRImageViewer/Info.plist @@ -2,6 +2,8 @@ + NSPhotoLibraryUsageDescription + The app will open an image from your library. CFBundleDevelopmentRegion en CFBundleExecutable