diff --git a/Sources/GiniCaptureSDK/Core/Extensions/AVCaptureVideoOrientation.swift b/Sources/GiniCaptureSDK/Core/Extensions/AVCaptureVideoOrientation.swift index dcc37ca..a624489 100644 --- a/Sources/GiniCaptureSDK/Core/Extensions/AVCaptureVideoOrientation.swift +++ b/Sources/GiniCaptureSDK/Core/Extensions/AVCaptureVideoOrientation.swift @@ -20,14 +20,13 @@ extension AVCaptureVideoOrientation { } } - init?(_ device: UIDeviceOrientation?) { - guard let orientation = device else { return nil } - switch orientation { + init(_ device: UIDeviceOrientation) { + switch device { case .portrait: self = .portrait case .portraitUpsideDown: self = .portraitUpsideDown case .landscapeLeft: self = .landscapeRight case .landscapeRight: self = .landscapeLeft - default: return nil + default: self = .portrait } } } diff --git a/Sources/GiniCaptureSDK/Core/Extensions/UIImage.swift b/Sources/GiniCaptureSDK/Core/Extensions/UIImage.swift index 56f3603..3ac52ca 100644 --- a/Sources/GiniCaptureSDK/Core/Extensions/UIImage.swift +++ b/Sources/GiniCaptureSDK/Core/Extensions/UIImage.swift @@ -6,6 +6,7 @@ // import UIKit +import AVFoundation extension UIImage { convenience init?(qrData data: Data) { @@ -157,3 +158,21 @@ extension UIImage { return self } } + + +extension UIImage.Orientation { + init(_ cgOrientation: AVCaptureVideoOrientation) { + switch cgOrientation { + case .portrait: + self = .up + case .landscapeRight: + self = .right + case .landscapeLeft: + self = .left + case .portraitUpsideDown: + self = .down + @unknown default: + fatalError("Unknown AVCaptureVideoOrientation case encountered") + } + } +} diff --git a/Sources/GiniCaptureSDK/Core/Extensions/UIWindow.swift b/Sources/GiniCaptureSDK/Core/Extensions/UIWindow.swift new file mode 100644 index 0000000..237f8c1 --- /dev/null +++ b/Sources/GiniCaptureSDK/Core/Extensions/UIWindow.swift @@ -0,0 +1,21 @@ +// +// UIWindow.swift +// +// +// Copyright © 2023 Gini GmbH. All rights reserved +// + +import UIKit + +extension UIWindow { + static var orientation: UIInterfaceOrientation { + if #available(iOS 13.0, *) { + return UIApplication.shared.windows + .first? + .windowScene? + .interfaceOrientation ?? .portrait + } else { + return UIApplication.shared.statusBarOrientation + } + } +} diff --git a/Sources/GiniCaptureSDK/Core/GiniConfiguration.swift b/Sources/GiniCaptureSDK/Core/GiniConfiguration.swift index 30b1c72..5614bf3 100644 --- a/Sources/GiniCaptureSDK/Core/GiniConfiguration.swift +++ b/Sources/GiniCaptureSDK/Core/GiniConfiguration.swift @@ -206,13 +206,13 @@ import GiniBankAPILibrary @objc public var flashToggleEnabled = false /** - When the flash toggle is enabled, this flag indicates if the flash is on by default. + Set whether the camera flash should be on or off when the SDK starts. The flash is off by default. */ - @objc public var flashOnByDefault = true + @objc public var flashOnByDefault = false /** Sets the close button text in the navigation bar on the camera screen. - */ + */ @objc public var navigationBarCameraTitleCloseButton = "" /** diff --git a/Sources/GiniCaptureSDK/Core/Helpers/DeviceOrientation.swift b/Sources/GiniCaptureSDK/Core/Helpers/DeviceOrientation.swift new file mode 100644 index 0000000..b0aae82 --- /dev/null +++ b/Sources/GiniCaptureSDK/Core/Helpers/DeviceOrientation.swift @@ -0,0 +1,44 @@ +// +// DeviceOrientation.swift +// +// +// Copyright © 2023 Gini GmbH. All rights reserved +// + +import UIKit + +enum Device { + + /** + * This property tries to get 4 orientations: + * landscapeLeft, landscapeRight, portrait, portraitUpsideDown + * as defined by UIDeviceOrientation enum. + * It can return also unknown orientation (which is rare case) + */ + static var orientation: UIDeviceOrientation { + + // otherwise if there is flat (faceUp, faceDown), unknown orientation + // try to get orientation from UIInterfaceOrientation + // Notice that: + // UIDeviceOrientationLandscapeRight => UIInterfaceOrientationLandscapeLeft + // UIDeviceOrientationLandscapeLeft => UIInterfaceOrientationLandscapeRight + + let interfaceOrientation = UIWindow.orientation + switch interfaceOrientation { + case .landscapeLeft: + return UIDeviceOrientation.landscapeRight + case .landscapeRight: + return UIDeviceOrientation.landscapeLeft + case .portrait: + return .portrait + case .portraitUpsideDown: + return .portraitUpsideDown + case .unknown: + break + @unknown default: + break + } + + return .unknown + } +} diff --git a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift index 43ad37b..4f581d1 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift @@ -247,7 +247,7 @@ final class Camera: NSObject, CameraProtocol { // Set the orientation according to the current orientation of the interface DispatchQueue.main.sync { [weak self] in guard let self = self else { return } - connection.videoOrientation = AVCaptureVideoOrientation(self.application.statusBarOrientation) + connection.videoOrientation = AVCaptureVideoOrientation(Device.orientation) } // Trigger photo capturing diff --git a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera/CameraViewController.swift b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera/CameraViewController.swift index 9c9590e..ca0bea9 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera/CameraViewController.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera/CameraViewController.swift @@ -300,8 +300,7 @@ import UIKit if let image = self.cameraButtonsViewModel.didCapture(imageData: data, processedImageData: processedImageData, error: error, - orientation: - UIApplication.shared.statusBarOrientation, + orientation: UIWindow.orientation, giniConfiguration: self.giniConfiguration) { UIImpactFeedbackGenerator(style: .medium).impactOccurred() diff --git a/Sources/GiniCaptureSDK/Core/Screens/Camera/CameraPreviewViewController.swift b/Sources/GiniCaptureSDK/Core/Screens/Camera/CameraPreviewViewController.swift index 406f9fb..5344876 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Camera/CameraPreviewViewController.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Camera/CameraPreviewViewController.swift @@ -45,9 +45,10 @@ final class CameraPreviewViewController: UIViewController { return spinner }() + private let cameraFocusImage = UIImageNamedPreferred(named: "cameraFocus") lazy var cameraFrameView: UIImageView = { let imageView = UIImageView() - imageView.image = UIImageNamedPreferred(named: "cameraFocus") + imageView.image = cameraFocusImage imageView.contentMode = .scaleAspectFit imageView.isHidden = true return imageView @@ -71,12 +72,6 @@ final class CameraPreviewViewController: UIViewController { private var camera: CameraProtocol private var defaultImageView: UIImageView? private var focusIndicatorImageView: UIImageView? - private let interfaceOrientationsMapping: [UIInterfaceOrientation: AVCaptureVideoOrientation] = [ - .portrait: .portrait, - .landscapeRight: .landscapeRight, - .landscapeLeft: .landscapeLeft, - .portraitUpsideDown: .portraitUpsideDown - ] private var cameraFocusSmall: UIImage? { return UIImageNamedPreferred(named: "cameraFocusSmall") @@ -240,20 +235,19 @@ final class CameraPreviewViewController: UIViewController { } private func updateFrameOrientation(with orientation: AVCaptureVideoOrientation) { - if UIDevice.current.isIpad { - NSLayoutConstraint.deactivate([cameraFrameViewHeightAnchorPortrait, cameraFrameViewHeightAnchorLandscape]) - - let isLandscape = orientation == .landscapeRight || orientation == .landscapeLeft - cameraFrameViewHeightAnchorPortrait.isActive = !isLandscape - cameraFrameViewHeightAnchorLandscape.isActive = isLandscape - - if let image = cameraFrameView.image?.cgImage { - if isLandscape { - cameraFrameView.image = UIImage(cgImage: image, scale: 1.0, orientation: .left) - } else { - cameraFrameView.image = UIImage(cgImage: image, scale: 1.0, orientation: .up) - } - + guard UIDevice.current.isIpad else { return } + let isLandscape = orientation == .landscapeRight || orientation == .landscapeLeft + if let image = cameraFocusImage?.cgImage { + NSLayoutConstraint.deactivate([ + cameraFrameViewHeightAnchorPortrait, + cameraFrameViewHeightAnchorLandscape + ]) + if isLandscape { + cameraFrameViewHeightAnchorLandscape.isActive = true + cameraFrameView.image = UIImage(cgImage: image, scale: 1.0, orientation: .left) + } else { + cameraFrameViewHeightAnchorPortrait.isActive = true + cameraFrameView.image = UIImage(cgImage: image, scale: 1.0, orientation: .up) } } } @@ -361,18 +355,10 @@ final class CameraPreviewViewController: UIViewController { func updatePreviewViewOrientation() { - let orientation: AVCaptureVideoOrientation - if UIDevice.current.isIpad { - orientation = interfaceOrientationsMapping[UIApplication.shared.statusBarOrientation] ?? .portrait - currentOrientation = UIApplication.shared.statusBarOrientation - } else { - orientation = .portrait - currentOrientation = .portrait - } - + let videoOrientation = AVCaptureVideoOrientation(Device.orientation) + previewView.videoPreviewLayer.connection?.videoOrientation = videoOrientation setupOrientationAndTransform() - previewView.videoPreviewLayer.connection?.videoOrientation = orientation - updateFrameOrientation(with: orientation) + updateFrameOrientation(with: videoOrientation) } func changeQRFrameColor(to color: UIColor) { @@ -406,18 +392,18 @@ final class CameraPreviewViewController: UIViewController { .scaledBy(x: roi.width, y: roi.height) // Compensate for orientation (buffers always come in the same orientation). - switch currentOrientation { + switch Device.orientation { case .landscapeLeft: - textOrientation = CGImagePropertyOrientation.up + textOrientation = .up uiRotationTransform = CGAffineTransform.identity case .landscapeRight: - textOrientation = CGImagePropertyOrientation.down + textOrientation = .down uiRotationTransform = CGAffineTransform(translationX: 1, y: 1).rotated(by: CGFloat.pi) case .portraitUpsideDown: - textOrientation = CGImagePropertyOrientation.left + textOrientation = .left uiRotationTransform = CGAffineTransform(translationX: 1, y: 0).rotated(by: CGFloat.pi / 2) default: // everything else to .portraitUp - textOrientation = CGImagePropertyOrientation.right + textOrientation = .right uiRotationTransform = CGAffineTransform(translationX: 0, y: 1).rotated(by: -CGFloat.pi / 2) } @@ -425,6 +411,7 @@ final class CameraPreviewViewController: UIViewController { visionToAVFTransform = roiToGlobalTransform.concatenating(bottomToTopTransform) .concatenating(uiRotationTransform) } + } // MARK: - Default and not authorized views diff --git a/Sources/GiniCaptureSDK/Core/Screens/Document picker/Gallery/AlbumsPickerTableViewCell.swift b/Sources/GiniCaptureSDK/Core/Screens/Document picker/Gallery/AlbumsPickerTableViewCell.swift index 7862277..df4b464 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Document picker/Gallery/AlbumsPickerTableViewCell.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Document picker/Gallery/AlbumsPickerTableViewCell.swift @@ -45,7 +45,10 @@ final class AlbumsPickerTableViewCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - accessoryType = .disclosureIndicator + let chevronImage = UIImageNamedPreferred(named: "chevron") + let chevronImageView = UIImageView(image: chevronImage) + chevronImageView.image = chevronImage + accessoryView = chevronImageView contentView.addSubview(albumThumbnailView) contentView.addSubview(albumTitleLabel) contentView.addSubview(albumSubTitleLabel) diff --git a/Sources/GiniCaptureSDK/Core/Screens/Help/DataSources/HelpMenu/HelpMenuDataSource.swift b/Sources/GiniCaptureSDK/Core/Screens/Help/DataSources/HelpMenu/HelpMenuDataSource.swift index aec02ce..28fc2f2 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Help/DataSources/HelpMenu/HelpMenuDataSource.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Help/DataSources/HelpMenu/HelpMenuDataSource.swift @@ -45,7 +45,10 @@ final class HelpMenuDataSource: HelpRoundedCornersDataSource