Skip to content

Commit

Permalink
Merge pull request #91 from tumblr/stories/confirmAtTop
Browse files Browse the repository at this point in the history
Adds customization points for Confirm + Next buttons
  • Loading branch information
bjtitus authored Feb 22, 2021
2 parents e6cf498 + 57276ec commit 0bdd05a
Show file tree
Hide file tree
Showing 17 changed files with 101 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Classes/Constants/KanvasDesign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Classes/Constants/KanvasEditorDesign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 17 additions & 6 deletions Classes/Constants/KanvasImages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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: [
Expand Down Expand Up @@ -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
}
}
102 changes: 57 additions & 45 deletions Classes/Editor/EditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -245,6 +238,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
showTagCollection: Bool,
showQuickPostButton: Bool,
showBlogSwitcher: Bool,
confirmAtTop: Bool,
quickBlogSelectorCoordinator: KanvasQuickBlogSelectorCoordinating?,
tagCollection: UIView?,
metalContext: MetalContext?,
Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand All @@ -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),
Expand All @@ -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([
Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions Classes/Editor/EditorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Classes/Preview/CameraPreviewView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions Classes/Settings/CameraSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Kanvas.podspec
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
7 changes: 7 additions & 0 deletions KanvasExample/KanvasExample/FeatureTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(_):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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(_):
Expand Down
3 changes: 3 additions & 0 deletions KanvasExample/KanvasExample/KanvasExampleViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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(_):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ final class EditorViewTests: FBSnapshotTestCase {
showTagCollection: false,
showQuickPostButton: false,
showBlogSwitcher: false,
confirmAtTop: false,
quickBlogSelectorCoordinator: nil,
tagCollection: nil,
metalContext: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 0bdd05a

Please sign in to comment.