diff --git a/Gallery.podspec b/Gallery.podspec index 0100c191..d09466f8 100644 --- a/Gallery.podspec +++ b/Gallery.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Gallery" s.summary = "Something good about gallery" - s.version = "2.4.0" + s.version = "2.5.0" s.homepage = "https://github.com/hyperoslo/Gallery" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } diff --git a/Gallery.xcodeproj/project.pbxproj b/Gallery.xcodeproj/project.pbxproj index f21d7731..60842ce8 100644 --- a/Gallery.xcodeproj/project.pbxproj +++ b/Gallery.xcodeproj/project.pbxproj @@ -56,9 +56,11 @@ 3605647F25837D3F00B9F493 /* Permission.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644A25837D3F00B9F493 /* Permission.swift */; }; 3605648025837D3F00B9F493 /* PermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644B25837D3F00B9F493 /* PermissionView.swift */; }; 3605648125837D3F00B9F493 /* PermissionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644C25837D3F00B9F493 /* PermissionController.swift */; }; - 3605648225837D3F00B9F493 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644D25837D3F00B9F493 /* LocationManager.swift */; }; 3605648325837D3F00B9F493 /* PagesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605644F25837D3F00B9F493 /* PagesController.swift */; }; 3605648425837D3F00B9F493 /* PageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3605645025837D3F00B9F493 /* PageIndicator.swift */; }; + 5346BEF825DC00D7008494CE /* LocationProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF425DC00D7008494CE /* LocationProviding.swift */; }; + 5346BEFA25DC00D7008494CE /* LocationManaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF625DC00D7008494CE /* LocationManaging.swift */; }; + 5346BEFB25DC00D7008494CE /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5346BEF725DC00D7008494CE /* LocationManager.swift */; }; D27B72ED1D6EEEC80093318F /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27B72EC1D6EEEC80093318F /* Tests.swift */; }; D2D1A6F41F84F4DB0083D4C5 /* GalleryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D1A6C31F84F4DB0083D4C5 /* GalleryController.swift */; }; D5B2E8AA1C3A780C00C0327D /* Gallery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5B2E89F1C3A780C00C0327D /* Gallery.framework */; }; @@ -124,9 +126,11 @@ 3605644A25837D3F00B9F493 /* Permission.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permission.swift; sourceTree = ""; }; 3605644B25837D3F00B9F493 /* PermissionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionView.swift; sourceTree = ""; }; 3605644C25837D3F00B9F493 /* PermissionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionController.swift; sourceTree = ""; }; - 3605644D25837D3F00B9F493 /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; 3605644F25837D3F00B9F493 /* PagesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagesController.swift; sourceTree = ""; }; 3605645025837D3F00B9F493 /* PageIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageIndicator.swift; sourceTree = ""; }; + 5346BEF425DC00D7008494CE /* LocationProviding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationProviding.swift; sourceTree = ""; }; + 5346BEF625DC00D7008494CE /* LocationManaging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManaging.swift; sourceTree = ""; }; + 5346BEF725DC00D7008494CE /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; D27B72EC1D6EEEC80093318F /* Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; D27B730C1D6EF04D0093318F /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = ""; }; D2D1A6C31F84F4DB0083D4C5 /* GalleryController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryController.swift; sourceTree = ""; }; @@ -228,8 +232,8 @@ 3605644625837D3F00B9F493 /* Fetcher.swift */, 3605644725837D3F00B9F493 /* Utils.swift */, 3605644825837D3F00B9F493 /* OrientationMan.swift */, + 5346BEF325DC00D7008494CE /* Location */, 3605644925837D3F00B9F493 /* Permission */, - 3605644D25837D3F00B9F493 /* LocationManager.swift */, 3605644E25837D3F00B9F493 /* Pages */, ); path = Utils; @@ -299,6 +303,16 @@ path = Pages; sourceTree = ""; }; + 5346BEF325DC00D7008494CE /* Location */ = { + isa = PBXGroup; + children = ( + 5346BEF425DC00D7008494CE /* LocationProviding.swift */, + 5346BEF625DC00D7008494CE /* LocationManaging.swift */, + 5346BEF725DC00D7008494CE /* LocationManager.swift */, + ); + path = Location; + sourceTree = ""; + }; D27B730E1D6EF0640093318F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -481,9 +495,9 @@ files = ( 3605647B25837D3F00B9F493 /* GridView.swift in Sources */, 3605647C25837D3F00B9F493 /* Fetcher.swift in Sources */, - 3605648225837D3F00B9F493 /* LocationManager.swift in Sources */, 3605646725837D3F00B9F493 /* DropdownController.swift in Sources */, 3605648425837D3F00B9F493 /* PageIndicator.swift in Sources */, + 5346BEF825DC00D7008494CE /* LocationProviding.swift in Sources */, 3605648025837D3F00B9F493 /* PermissionView.swift in Sources */, 3605647725837D3F00B9F493 /* EmptyView.swift in Sources */, 3605646B25837D3F00B9F493 /* VideoEditor.swift in Sources */, @@ -519,6 +533,7 @@ 3605647125837D3F00B9F493 /* UIImageView+Extensions.swift in Sources */, 3605646225837D3F00B9F493 /* ImageCell.swift in Sources */, 3605645425837D3F00B9F493 /* VideoBox.swift in Sources */, + 5346BEFA25DC00D7008494CE /* LocationManaging.swift in Sources */, 3605646125837D3F00B9F493 /* Cart.swift in Sources */, 3605646525837D3F00B9F493 /* UIBlurEffect+Style.swift in Sources */, 3605648325837D3F00B9F493 /* PagesController.swift in Sources */, @@ -528,6 +543,7 @@ 3605647925837D3F00B9F493 /* AlbumCell.swift in Sources */, 3605647A25837D3F00B9F493 /* ArrowButton.swift in Sources */, 3605645A25837D3F00B9F493 /* CameraMan.swift in Sources */, + 5346BEFB25DC00D7008494CE /* LocationManager.swift in Sources */, 3605645825837D3F00B9F493 /* CameraController.swift in Sources */, 3605645225837D3F00B9F493 /* VideosLibrary.swift in Sources */, 3605647625837D3F00B9F493 /* UIScrollView+Extensions.swift in Sources */, diff --git a/README.md b/README.md index 8e50ac8c..4b553f49 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ The delegate methods give you `Image` and `Video`, which are just wrappers aroun `Gallery` handles permissions for you. It checks and askes for photo and camera usage permissions at first launch. As of iOS 10, we need to explicitly declare usage descriptions in plist files +### Madatory ```xml NSCameraUsageDescription This app requires access to camera @@ -71,6 +72,14 @@ The delegate methods give you `Image` and `Video`, which are just wrappers aroun This app requires access to photo library ``` +### Optional +If defining the `GALLERY_USE_LOCATION` compiler flag for the purposes of recording location information then the following usage string is required: + +```xml +NSLocationWhenInUseUsageDescription +This app requires location when in use +``` + ### Configuration There are lots of customization points in `Config` structs. For example @@ -82,6 +91,20 @@ Config.Camera.recordLocation = true Config.tabsToShow = [.imageTab, .cameraTab] ``` +Note: When utilising the `recordLocation` property, `GALLERY_USE_LOCATION` needs defining first in order to expose this functionality. If using Cocoapods this can be done with the usage of post install hook as follows: + +```ruby +post_install do |installer| + installer.pods_project.targets.each do |target| + if target.name == 'Gallery' + target.build_configurations.each do |config| + config.build_settings['OTHER_SWIFT_FLAGS'] = '-DGALLERY_USE_LOCATION' + end + end + end +end +``` + ### Video Editor `Gallery` cares more about video with its editing functionalities. We have `VideoEditor` and `AdvancedVideoEditor` to trim, resize, scale and define quality of the selected video diff --git a/Sources/Gallery/Camera/CameraController.swift b/Sources/Gallery/Camera/CameraController.swift index a89bda95..3c255154 100644 --- a/Sources/Gallery/Camera/CameraController.swift +++ b/Sources/Gallery/Camera/CameraController.swift @@ -3,7 +3,7 @@ import AVFoundation class CameraController: UIViewController { - var locationManager: LocationManager? + var locationManager: LocationManaging? lazy var cameraMan: CameraMan = self.makeCameraMan() lazy var cameraView: CameraView = self.makeCameraView() let once = Once() @@ -68,9 +68,11 @@ class CameraController: UIViewController { } func setupLocation() { + #if GALLERY_USE_LOCATION if Config.Camera.recordLocation { locationManager = LocationManager() } + #endif } // MARK: - Action @@ -117,7 +119,8 @@ class CameraController: UIViewController { }) self.cameraView.stackView.startLoading() - cameraMan.takePhoto(previewLayer, location: locationManager?.latestLocation) { [weak self] asset in + + self.cameraMan.takePhoto(previewLayer, locationProvider: locationManager?.latestLocationProvider) { [weak self] asset in guard let strongSelf = self else { return } diff --git a/Sources/Gallery/Camera/CameraMan.swift b/Sources/Gallery/Camera/CameraMan.swift index 46af5e1b..99676a4d 100644 --- a/Sources/Gallery/Camera/CameraMan.swift +++ b/Sources/Gallery/Camera/CameraMan.swift @@ -15,7 +15,6 @@ class CameraMan { let session = AVCaptureSession() let queue = DispatchQueue(label: "no.hyper.Gallery.Camera.SessionQueue", qos: .background) let savingQueue = DispatchQueue(label: "no.hyper.Gallery.Camera.SavingQueue", qos: .background) - let orientationMan = OrientationMan() var backCamera: AVCaptureDeviceInput? var frontCamera: AVCaptureDeviceInput? @@ -127,11 +126,10 @@ class CameraMan { } } - func takePhoto(_ previewLayer: AVCaptureVideoPreviewLayer, location: CLLocation?, completion: @escaping ((PHAsset?) -> Void)) { + func takePhoto(_ previewLayer: AVCaptureVideoPreviewLayer, locationProvider: LocationProviding?, completion: @escaping ((PHAsset?) -> Void)) { guard let connection = stillImageOutput?.connection(with: .video) else { return } - // It should be set the image orientation with the device current orientation - connection.videoOrientation = self.orientationMan.videoOrientation() + connection.videoOrientation = Utils.videoOrientation() queue.async { self.stillImageOutput?.captureStillImageAsynchronously(from: connection) { @@ -147,12 +145,12 @@ class CameraMan { return } - self.savePhoto(image, location: location, completion: completion) + self.savePhoto(image, locationProvider: locationProvider, completion: completion) } } } - func savePhoto(_ image: UIImage, location: CLLocation?, completion: @escaping ((PHAsset?) -> Void)) { + func savePhoto(_ image: UIImage, locationProvider: LocationProviding?, completion: @escaping ((PHAsset?) -> Void)) { var localIdentifier: String? savingQueue.async { @@ -162,7 +160,9 @@ class CameraMan { localIdentifier = request.placeholderForCreatedAsset?.localIdentifier request.creationDate = Date() - request.location = location + #if GALLERY_USE_LOCATION + request.location = locationProvider?.location + #endif } DispatchQueue.main.async { diff --git a/Sources/Gallery/Utils/Config.swift b/Sources/Gallery/Utils/Config.swift index 081f41e1..095d20d0 100644 --- a/Sources/Gallery/Utils/Config.swift +++ b/Sources/Gallery/Utils/Config.swift @@ -39,7 +39,9 @@ public struct Config { public struct Camera { + #if GALLERY_USE_LOCATION public static var recordLocation: Bool = false + #endif public struct ShutterButton { public static var numberColor: UIColor = UIColor(red: 54/255, green: 56/255, blue: 62/255, alpha: 1) diff --git a/Sources/Gallery/Utils/LocationManager.swift b/Sources/Gallery/Utils/Location/LocationManager.swift similarity index 74% rename from Sources/Gallery/Utils/LocationManager.swift rename to Sources/Gallery/Utils/Location/LocationManager.swift index dae86fb0..30dadaf9 100644 --- a/Sources/Gallery/Utils/LocationManager.swift +++ b/Sources/Gallery/Utils/Location/LocationManager.swift @@ -1,9 +1,10 @@ +#if GALLERY_USE_LOCATION import Foundation import CoreLocation -class LocationManager: NSObject, CLLocationManagerDelegate { +class LocationManager: NSObject, LocationManaging, CLLocationManagerDelegate { var locationManager = CLLocationManager() - var latestLocation: CLLocation? + var latestLocationProvider: LocationProviding? override init() { super.init() @@ -24,7 +25,9 @@ class LocationManager: NSObject, CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // Pick the location with best (= smallest value) horizontal accuracy - latestLocation = locations.sorted { $0.horizontalAccuracy < $1.horizontalAccuracy }.first + if let location = locations.sorted { $0.horizontalAccuracy < $1.horizontalAccuracy }.first { + latestLocationProvider = LocationProvider(location: location) + } } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { @@ -35,3 +38,5 @@ class LocationManager: NSObject, CLLocationManagerDelegate { } } } + +#endif diff --git a/Sources/Gallery/Utils/Location/LocationManaging.swift b/Sources/Gallery/Utils/Location/LocationManaging.swift new file mode 100644 index 00000000..298a5cb6 --- /dev/null +++ b/Sources/Gallery/Utils/Location/LocationManaging.swift @@ -0,0 +1,6 @@ +protocol LocationManaging { + + func start() + func stop() + var latestLocationProvider: LocationProviding? { get } +} diff --git a/Sources/Gallery/Utils/Location/LocationProviding.swift b/Sources/Gallery/Utils/Location/LocationProviding.swift new file mode 100644 index 00000000..794f4784 --- /dev/null +++ b/Sources/Gallery/Utils/Location/LocationProviding.swift @@ -0,0 +1,15 @@ +#if GALLERY_USE_LOCATION +import CoreLocation +#endif + +protocol LocationProviding { + #if GALLERY_USE_LOCATION + var location: CLLocation { get } + #endif +} + +struct LocationProvider: LocationProviding { + #if GALLERY_USE_LOCATION + let location: CLLocation + #endif +}