diff --git a/Classes/Constants/KanvasDesign.swift b/Classes/Constants/KanvasDesign.swift index 4cd142897..360ce90e4 100644 --- a/Classes/Constants/KanvasDesign.swift +++ b/Classes/Constants/KanvasDesign.swift @@ -263,7 +263,7 @@ public struct KanvasDesign { mediaClipsEditorViewTopPadding: 6, mediaClipsEditorViewBottomPadding: 6 + (Device.belongsToIPhoneXGroup ? 28 : 0), mediaClipsEditorViewNextButtonCenterYOffset: 3, - mediaClipsEditorViewNextImage: UIImage.imageFromCameraBundle(named: "next"), + mediaClipsEditorViewNextImage: KanvasImages.shared.nextImage, mediaClipsCollectionCellClipHeight: 60, mediaClipsCollectionCellClipWidth: 40, mediaClipsCollectionCellBorderWidth: 1.1, diff --git a/Classes/Constants/KanvasEditorDesign.swift b/Classes/Constants/KanvasEditorDesign.swift index 815ac2615..c80e0bfd9 100644 --- a/Classes/Constants/KanvasEditorDesign.swift +++ b/Classes/Constants/KanvasEditorDesign.swift @@ -111,7 +111,7 @@ public struct KanvasEditorDesign { public static var original: KanvasEditorDesign = { return KanvasEditorDesign( isVerticalMenu: false, - checkmarkImage: UIImage.imageFromCameraBundle(named: "editorConfirm"), + checkmarkImage: KanvasImages.shared.editorConfirmImage, buttonBackgroundColor: .clear, buttonInvertedBackgroundColor: .clear, optionBackgroundColor: .clear, diff --git a/Classes/Constants/KanvasImages.swift b/Classes/Constants/KanvasImages.swift index f39093b5c..0881388ce 100644 --- a/Classes/Constants/KanvasImages.swift +++ b/Classes/Constants/KanvasImages.swift @@ -7,7 +7,7 @@ import Foundation // the images used throughout the module -struct KanvasImages { +public struct KanvasImages { // MARK: - Mode Selection static let photoModeImage: UIImage? = .none static let loopModeImage: UIImage? = .none @@ -43,7 +43,6 @@ struct KanvasImages { // MARK: - General static let closeImage = UIImage.imageFromCameraBundle(named: "whiteCloseIcon") static let crossImage = UIImage.imageFromCameraBundle(named: "cross") - static let confirmImage = UIImage.imageFromCameraBundle(named: "confirm") static let longCheckmarkImage = UIImage.imageFromCameraBundle(named: "longCheckmark") static let backImage = UIImage.imageFromCameraBundle(named: "back") static let backArrowImage = UIImage.imageFromCameraBundle(named: "backArrow") @@ -54,7 +53,6 @@ struct KanvasImages { static let trashBinClosed = UIImage.imageFromCameraBundle(named: "trashBinClosed") static let trashBinOpened = UIImage.imageFromCameraBundle(named: "trashBinOpened") static let circleImage = UIImage.imageFromCameraBundle(named: "circleIcon") - static let nextImage = UIImage.imageFromCameraBundle(named: "next") static let nextArrowImage = UIImage.imageFromCameraBundle(named: "nextArrow") static let saveImage = UIImage.imageFromCameraBundle(named: "save") static let cogImage = UIImage.imageFromCameraBundle(named: "cog") @@ -82,9 +80,6 @@ struct KanvasImages { .manga: nil, .toon: nil, ] - - // MARK: - Editor - static let editorConfirmImage = UIImage.imageFromCameraBundle(named: "editorConfirm") static let editIcons: [EditionOption: [UIImage?]] = [ .gif: [ @@ -173,4 +168,20 @@ struct KanvasImages { // MARK: - Camera Permissions static let permissionCheckmark = UIImage.imageFromCameraBundle(named: "checkmark") + + let nextImage: UIImage? + let confirmImage: UIImage? + let editorConfirmImage: UIImage? + + public static var shared = KanvasImages(confirmImage: UIImage.imageFromCameraBundle(named: "confirm"), + editorConfirmImage: UIImage.imageFromCameraBundle(named: "editorConfirm"), + nextImage: UIImage.imageFromCameraBundle(named: "next")) + + public init(confirmImage: UIImage?, + editorConfirmImage: UIImage?, + nextImage: UIImage?) { + self.confirmImage = confirmImage + self.editorConfirmImage = editorConfirmImage + self.nextImage = nextImage + } } diff --git a/Classes/Editor/EditorView.swift b/Classes/Editor/EditorView.swift index 51030b6a4..9862fe4ca 100644 --- a/Classes/Editor/EditorView.swift +++ b/Classes/Editor/EditorView.swift @@ -149,14 +149,6 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega private let showMuteButton: Bool private let showCrossIcon: Bool private let postButton = UIButton() - private lazy var publishButton: UIButton = { - let button = UIButton(type: .custom) - button.accessibilityIdentifier = "Media Clips Next Button" - button.accessibilityLabel = "Next Button" - button.setImage(KanvasImages.nextImage, for: .normal) - button.translatesAutoresizingMaskIntoConstraints = false - return button - }() private let postLabel = UILabel() private let tagButton = UIButton() private let fakeOptionCell = UIImageView() @@ -166,6 +158,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega private let showTagCollection: Bool private let showQuickPostButton: Bool private let showBlogSwitcher: Bool + private let confirmAtTop: Bool private let metalContext: MetalContext? private let filterSelectionCircle = UIImageView() private let navigationContainer = IgnoreTouchesView() @@ -245,6 +238,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega showTagCollection: Bool, showQuickPostButton: Bool, showBlogSwitcher: Bool, + confirmAtTop: Bool, quickBlogSelectorCoordinator: KanvasQuickBlogSelectorCoordinating?, tagCollection: UIView?, metalContext: MetalContext?, @@ -260,6 +254,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega self.showCrossIcon = showCrossIcon self.showQuickPostButton = showQuickPostButton self.showBlogSwitcher = showBlogSwitcher + self.confirmAtTop = confirmAtTop self.quickBlogSelectorCoordinator = quickBlogSelectorCoordinator self.tagCollection = tagCollection self.metalContext = metalContext @@ -425,16 +420,27 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega private func setupConfirmButton() { confirmButton.accessibilityLabel = "Confirm Button" navigationContainer.addSubview(confirmButton) - confirmButton.setImage(KanvasImages.nextImage, for: .normal) + confirmButton.setImage(KanvasImages.shared.nextImage, for: .normal) confirmButton.addTarget(self, action: #selector(confirmButtonPressed), for: .touchUpInside) confirmButton.translatesAutoresizingMaskIntoConstraints = false - + + let positioningConstraints: [NSLayoutConstraint] + if confirmAtTop { + positioningConstraints = [ + confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin), + confirmButton.centerYAnchor.constraint(equalTo: closeButton.centerYAnchor) + ] + } else { + positioningConstraints = [ + confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin), + confirmButton.bottomAnchor.constraint(equalTo: safeLayoutGuide.bottomAnchor, constant: -EditorViewConstants.buttonBottomMargin) + ] + } + NSLayoutConstraint.activate([ - confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin), confirmButton.heightAnchor.constraint(equalToConstant: EditorViewConstants.confirmButtonSize), confirmButton.widthAnchor.constraint(equalToConstant: EditorViewConstants.confirmButtonSize), - confirmButton.bottomAnchor.constraint(equalTo: safeLayoutGuide.bottomAnchor, constant: -EditorViewConstants.buttonBottomMargin) - ]) + ] + positioningConstraints) } private func setupPostOptionsButton() { @@ -457,7 +463,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega ]) } else { - confirmButton.setImage(KanvasImages.nextImage, for: .normal) + confirmButton.setImage(KanvasImages.shared.nextImage, for: .normal) NSLayoutConstraint.activate([ confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin), @@ -474,28 +480,6 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega collectionContainer.accessibilityIdentifier = "Edition Menu Collection Container" collectionContainer.clipsToBounds = false collectionContainer.translatesAutoresizingMaskIntoConstraints = false - let leftButton: UIView? - let rightButton: UIView? - let trailingMargin: CGFloat - let leadingMargin: CGFloat - - if showMuteButton { - leftButton = muteButton - leadingMargin = EditorViewConstants.saveButtonHorizontalMargin - } else { - leftButton = nil - leadingMargin = 0 - } - - if showSaveButton { - rightButton = saveButton - trailingMargin = EditorViewConstants.saveButtonHorizontalMargin - } - else { - rightButton = confirmOrPostButton() - trailingMargin = confirmOrPostButtonHorizontalMargin() - } - if KanvasEditorDesign.shared.isVerticalMenu { NSLayoutConstraint.activate([ @@ -507,21 +491,49 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega } else { - let verticalConstraint: NSLayoutConstraint + let leftButton: UIView? + let leadingMargin: CGFloat + let xAnchor: NSLayoutXAxisAnchor + let trailingMargin: CGFloat - if let button = rightButton { - verticalConstraint = collectionContainer.centerYAnchor.constraint(equalTo: button.centerYAnchor) + if showMuteButton { + leftButton = muteButton + leadingMargin = EditorViewConstants.saveButtonHorizontalMargin } else { - verticalConstraint = collectionContainer.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor) + leftButton = nil + leadingMargin = 0 } + if confirmAtTop { + xAnchor = safeAreaLayoutGuide.trailingAnchor + trailingMargin = 0 + } else { + if showSaveButton { + xAnchor = saveButton.leadingAnchor + trailingMargin = EditorViewConstants.saveButtonHorizontalMargin + } + else { + xAnchor = confirmOrPostButton().leadingAnchor + trailingMargin = confirmOrPostButtonHorizontalMargin() + } + } + + let verticalPositioning: [NSLayoutConstraint] + if confirmAtTop { + verticalPositioning = [collectionContainer.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)] + } else { + verticalPositioning = [collectionContainer.centerYAnchor.constraint(equalTo: confirmOrPostButton().centerYAnchor)] + } + + let leftButtonConstraints = [ + leftButton?.centerYAnchor.constraint(equalTo: collectionContainer.centerYAnchor) + ].compactMap { $0 } + NSLayoutConstraint.activate([ collectionContainer.leadingAnchor.constraint(equalTo: leftButton?.trailingAnchor ?? safeAreaLayoutGuide.leadingAnchor, constant: leadingMargin), - collectionContainer.trailingAnchor.constraint(equalTo: rightButton?.leadingAnchor ?? trailingAnchor, constant: -trailingMargin / 2), - verticalConstraint, + collectionContainer.trailingAnchor.constraint(equalTo: xAnchor, constant: -trailingMargin / 2), collectionContainer.heightAnchor.constraint(equalToConstant: EditionMenuCollectionView.height), - leftButton?.centerYAnchor.constraint(equalTo: collectionContainer.centerYAnchor) - ].compactMap { $0 }) + ] + verticalPositioning + leftButtonConstraints) } } @@ -632,7 +644,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega updatePostButton(avatarView: avatarView) } else { - postButton.setImage(KanvasImages.nextImage, for: .normal) + postButton.setImage(KanvasImages.shared.nextImage, for: .normal) } postButton.contentHorizontalAlignment = .fill postButton.contentVerticalAlignment = .fill diff --git a/Classes/Editor/EditorViewController.swift b/Classes/Editor/EditorViewController.swift index 43145e98a..a4c39ee23 100644 --- a/Classes/Editor/EditorViewController.swift +++ b/Classes/Editor/EditorViewController.swift @@ -240,6 +240,7 @@ public final class EditorViewController: UIViewController, MediaPlayerController showTagCollection: settings.showTagCollectionInEditor, showQuickPostButton: settings.showQuickPostButtonInEditor, showBlogSwitcher: settings.showBlogSwitcherInEditor, + confirmAtTop: settings.features.editorConfirmAtTop, quickBlogSelectorCoordinator: quickBlogSelectorCoordinator, tagCollection: tagCollection, metalContext: metalContext, diff --git a/Classes/Preview/CameraPreviewView.swift b/Classes/Preview/CameraPreviewView.swift index d5aa93606..9d846b574 100644 --- a/Classes/Preview/CameraPreviewView.swift +++ b/Classes/Preview/CameraPreviewView.swift @@ -97,7 +97,7 @@ final class CameraPreviewView: UIView { confirmButton.accessibilityLabel = "Confirm Button" confirmButton.layer.applyShadows(offset: CGSize(width: 0.0, height: 2.0), radius: 0.0) addSubview(confirmButton) - confirmButton.setImage(KanvasImages.confirmImage, for: .normal) + confirmButton.setImage(KanvasImages.shared.confirmImage, for: .normal) confirmButton.addTarget(self, action: #selector(confirmButtonPressed), for: .touchUpInside) confirmButton.translatesAutoresizingMaskIntoConstraints = false diff --git a/Classes/Settings/CameraSettings.swift b/Classes/Settings/CameraSettings.swift index 01d7f316b..f34a65697 100644 --- a/Classes/Settings/CameraSettings.swift +++ b/Classes/Settings/CameraSettings.swift @@ -135,6 +135,10 @@ public struct CameraFeatures { public var editorPostOptions: Bool = false + /// Editor Confirm Button + /// Moves the editor confirm button to the top right + public var editorConfirmAtTop: Bool = false + /// The Editor Saving feature /// This enables the UI to save media from the editor. public var editorSaving: Bool = false diff --git a/Kanvas.podspec b/Kanvas.podspec index cd38665d9..5fb38009e 100644 --- a/Kanvas.podspec +++ b/Kanvas.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Kanvas" - spec.version = "1.2.1" + spec.version = "1.2.2" spec.summary = "A custom camera built for iOS." spec.homepage = "https://github.com/tumblr/kanvas-ios" spec.license = "MPLv2" diff --git a/KanvasExample/KanvasExample/FeatureTableView.swift b/KanvasExample/KanvasExample/FeatureTableView.swift index bc4b6b868..0aebbf763 100644 --- a/KanvasExample/KanvasExample/FeatureTableView.swift +++ b/KanvasExample/KanvasExample/FeatureTableView.swift @@ -32,6 +32,7 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat case editorSaving(Bool) case editorPosting(Bool) case editorPostOptions(Bool) + case editorConfirmAtTop(Bool) case newCameraModes(Bool) case gifs(Bool) case modeSelectorTooltip(Bool) @@ -82,6 +83,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat return "New Camera Modes" case .editorPostOptions(_): return "Editor Post Options" + case .editorConfirmAtTop(_): + return "Editor Confirm At Top" case .gifs(_): return "GIF support" case .modeSelectorTooltip(_): @@ -143,6 +146,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat return enabled case .editorPostOptions(let enabled): return enabled + case .editorConfirmAtTop(let enabled): + return enabled case .gifs(let enabled): return enabled case .modeSelectorTooltip(let enabled): @@ -241,6 +246,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat featuresData[indexPath.row] = .newCameraModes(value) case .editorPostOptions(_): featuresData[indexPath.row] = .editorPostOptions(value) + case .editorConfirmAtTop(_): + featuresData[indexPath.row] = .editorConfirmAtTop(value) case .gifs(_): featuresData[indexPath.row] = .gifs(value) case .modeSelectorTooltip(_): diff --git a/KanvasExample/KanvasExample/KanvasExampleViewController.swift b/KanvasExample/KanvasExample/KanvasExampleViewController.swift index ee515b0c9..3c19d8b77 100644 --- a/KanvasExample/KanvasExample/KanvasExampleViewController.swift +++ b/KanvasExample/KanvasExample/KanvasExampleViewController.swift @@ -271,6 +271,7 @@ extension KanvasExampleViewController: FeatureTableViewDelegate { .editorSaving(settings.features.editorSaving), .editorPosting(settings.features.editorPosting), .editorPostOptions(settings.features.editorPostOptions), + .editorConfirmAtTop(settings.features.editorConfirmAtTop), .newCameraModes(settings.features.newCameraModes), .modeSelectorTooltip(settings.features.modeSelectorTooltip), .shutterButtonTooltip(settings.features.shutterButtonTooltip), @@ -324,6 +325,8 @@ extension KanvasExampleViewController: FeatureTableViewDelegate { settings.defaultMode = settings.features.newCameraModes ? Constants.defaultNewMode : Constants.defaultStandardMode case .editorPostOptions(_): settings.features.editorPostOptions = value + case .editorConfirmAtTop(_): + settings.features.editorConfirmAtTop = value case .modeSelectorTooltip(_): settings.features.modeSelectorTooltip = value case .shutterButtonTooltip(_): diff --git a/KanvasExample/KanvasExampleTests/Camera/ImagePreviewControllerTests.swift b/KanvasExample/KanvasExampleTests/Camera/ImagePreviewControllerTests.swift index 69c6ac170..644ee32a9 100644 --- a/KanvasExample/KanvasExampleTests/Camera/ImagePreviewControllerTests.swift +++ b/KanvasExample/KanvasExampleTests/Camera/ImagePreviewControllerTests.swift @@ -12,7 +12,7 @@ import XCTest final class ImagePreviewControllerTests: FBSnapshotTestCase { - private let testImage = KanvasImages.confirmImage + private let testImage = KanvasImages.shared.confirmImage private let secondTestImage = KanvasImages.flashOnImage override func setUp() { diff --git a/KanvasExample/KanvasExampleTests/Constants/KanvasImagesTests.swift b/KanvasExample/KanvasExampleTests/Constants/KanvasImagesTests.swift index bd48f5d5d..c5c2bb3b2 100644 --- a/KanvasExample/KanvasExampleTests/Constants/KanvasImagesTests.swift +++ b/KanvasExample/KanvasExampleTests/Constants/KanvasImagesTests.swift @@ -66,7 +66,7 @@ final class KanvasImagesTests: FBSnapshotTestCase { func testConfirmImage() { let imageView = newImageView() - let image = KanvasImages.confirmImage + let image = KanvasImages.shared.confirmImage XCTAssert(image != nil, "Image not found") imageView.image = image FBSnapshotVerifyView(imageView) diff --git a/KanvasExample/KanvasExampleTests/Editor/EditorViewTests.swift b/KanvasExample/KanvasExampleTests/Editor/EditorViewTests.swift index 16566004a..4861947f4 100644 --- a/KanvasExample/KanvasExampleTests/Editor/EditorViewTests.swift +++ b/KanvasExample/KanvasExampleTests/Editor/EditorViewTests.swift @@ -31,6 +31,7 @@ final class EditorViewTests: FBSnapshotTestCase { showTagCollection: false, showQuickPostButton: false, showBlogSwitcher: false, + confirmAtTop: false, quickBlogSelectorCoordinator: nil, tagCollection: nil, metalContext: nil, diff --git a/KanvasExample/KanvasExampleTests/Extensions/UIImage+DominantColorsTests.swift b/KanvasExample/KanvasExampleTests/Extensions/UIImage+DominantColorsTests.swift index 487cca12b..889722a42 100644 --- a/KanvasExample/KanvasExampleTests/Extensions/UIImage+DominantColorsTests.swift +++ b/KanvasExample/KanvasExampleTests/Extensions/UIImage+DominantColorsTests.swift @@ -10,7 +10,7 @@ import XCTest final class UIImageDominantColorsTests: XCTestCase { func testDominantColors() { - guard let image = KanvasImages.confirmImage else { return } + guard let image = KanvasImages.shared.confirmImage else { return } let colors = image.getDominantColors(count: 3) let expectedColors = [UIColor(hex: "#24bbfa"), diff --git a/KanvasExample/KanvasExampleTests/Utility/ColorThief/ColorThiefTests.swift b/KanvasExample/KanvasExampleTests/Utility/ColorThief/ColorThiefTests.swift index 75a69478c..3a691a787 100644 --- a/KanvasExample/KanvasExampleTests/Utility/ColorThief/ColorThiefTests.swift +++ b/KanvasExample/KanvasExampleTests/Utility/ColorThief/ColorThiefTests.swift @@ -11,7 +11,7 @@ import XCTest final class ColorThieftTests: XCTestCase { - private let testImage = KanvasImages.confirmImage + private let testImage = KanvasImages.shared.confirmImage func testGetPalette() { guard let image = testImage, diff --git a/KanvasExample/KanvasExampleTests/Utility/ColorThief/MMCQTests.swift b/KanvasExample/KanvasExampleTests/Utility/ColorThief/MMCQTests.swift index 0384d9bf4..0182e501f 100644 --- a/KanvasExample/KanvasExampleTests/Utility/ColorThief/MMCQTests.swift +++ b/KanvasExample/KanvasExampleTests/Utility/ColorThief/MMCQTests.swift @@ -11,7 +11,7 @@ import XCTest final class MMCQTests: XCTestCase { - private let testImage = KanvasImages.confirmImage + private let testImage = KanvasImages.shared.confirmImage func testQuantize() { guard let image = testImage, diff --git a/KanvasExample/Podfile.lock b/KanvasExample/Podfile.lock index 9c84706ec..481241bf2 100644 --- a/KanvasExample/Podfile.lock +++ b/KanvasExample/Podfile.lock @@ -4,7 +4,7 @@ PODS: - FBSnapshotTestCase/Core (2.1.4) - FBSnapshotTestCase/SwiftSupport (2.1.4): - FBSnapshotTestCase/Core - - Kanvas (1.2.1) + - Kanvas (1.2.2) DEPENDENCIES: - FBSnapshotTestCase (= 2.1.4) @@ -20,7 +20,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a - Kanvas: 257eab9c9e3666f990a202e73ff793f399d8dd13 + Kanvas: 412d5b7502809153a6acac98f57923ad5d0251f8 PODFILE CHECKSUM: 14b28dd726149c0d01dba9154d5bb095d9ba6a18