Skip to content

Commit 0bdd05a

Browse files
authored
Merge pull request #91 from tumblr/stories/confirmAtTop
Adds customization points for Confirm + Next buttons
2 parents e6cf498 + 57276ec commit 0bdd05a

17 files changed

+101
-62
lines changed

Classes/Constants/KanvasDesign.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public struct KanvasDesign {
263263
mediaClipsEditorViewTopPadding: 6,
264264
mediaClipsEditorViewBottomPadding: 6 + (Device.belongsToIPhoneXGroup ? 28 : 0),
265265
mediaClipsEditorViewNextButtonCenterYOffset: 3,
266-
mediaClipsEditorViewNextImage: UIImage.imageFromCameraBundle(named: "next"),
266+
mediaClipsEditorViewNextImage: KanvasImages.shared.nextImage,
267267
mediaClipsCollectionCellClipHeight: 60,
268268
mediaClipsCollectionCellClipWidth: 40,
269269
mediaClipsCollectionCellBorderWidth: 1.1,

Classes/Constants/KanvasEditorDesign.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public struct KanvasEditorDesign {
111111
public static var original: KanvasEditorDesign = {
112112
return KanvasEditorDesign(
113113
isVerticalMenu: false,
114-
checkmarkImage: UIImage.imageFromCameraBundle(named: "editorConfirm"),
114+
checkmarkImage: KanvasImages.shared.editorConfirmImage,
115115
buttonBackgroundColor: .clear,
116116
buttonInvertedBackgroundColor: .clear,
117117
optionBackgroundColor: .clear,

Classes/Constants/KanvasImages.swift

+17-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Foundation
88

99
// the images used throughout the module
10-
struct KanvasImages {
10+
public struct KanvasImages {
1111
// MARK: - Mode Selection
1212
static let photoModeImage: UIImage? = .none
1313
static let loopModeImage: UIImage? = .none
@@ -43,7 +43,6 @@ struct KanvasImages {
4343
// MARK: - General
4444
static let closeImage = UIImage.imageFromCameraBundle(named: "whiteCloseIcon")
4545
static let crossImage = UIImage.imageFromCameraBundle(named: "cross")
46-
static let confirmImage = UIImage.imageFromCameraBundle(named: "confirm")
4746
static let longCheckmarkImage = UIImage.imageFromCameraBundle(named: "longCheckmark")
4847
static let backImage = UIImage.imageFromCameraBundle(named: "back")
4948
static let backArrowImage = UIImage.imageFromCameraBundle(named: "backArrow")
@@ -54,7 +53,6 @@ struct KanvasImages {
5453
static let trashBinClosed = UIImage.imageFromCameraBundle(named: "trashBinClosed")
5554
static let trashBinOpened = UIImage.imageFromCameraBundle(named: "trashBinOpened")
5655
static let circleImage = UIImage.imageFromCameraBundle(named: "circleIcon")
57-
static let nextImage = UIImage.imageFromCameraBundle(named: "next")
5856
static let nextArrowImage = UIImage.imageFromCameraBundle(named: "nextArrow")
5957
static let saveImage = UIImage.imageFromCameraBundle(named: "save")
6058
static let cogImage = UIImage.imageFromCameraBundle(named: "cog")
@@ -82,9 +80,6 @@ struct KanvasImages {
8280
.manga: nil,
8381
.toon: nil,
8482
]
85-
86-
// MARK: - Editor
87-
static let editorConfirmImage = UIImage.imageFromCameraBundle(named: "editorConfirm")
8883

8984
static let editIcons: [EditionOption: [UIImage?]] = [
9085
.gif: [
@@ -173,4 +168,20 @@ struct KanvasImages {
173168

174169
// MARK: - Camera Permissions
175170
static let permissionCheckmark = UIImage.imageFromCameraBundle(named: "checkmark")
171+
172+
let nextImage: UIImage?
173+
let confirmImage: UIImage?
174+
let editorConfirmImage: UIImage?
175+
176+
public static var shared = KanvasImages(confirmImage: UIImage.imageFromCameraBundle(named: "confirm"),
177+
editorConfirmImage: UIImage.imageFromCameraBundle(named: "editorConfirm"),
178+
nextImage: UIImage.imageFromCameraBundle(named: "next"))
179+
180+
public init(confirmImage: UIImage?,
181+
editorConfirmImage: UIImage?,
182+
nextImage: UIImage?) {
183+
self.confirmImage = confirmImage
184+
self.editorConfirmImage = editorConfirmImage
185+
self.nextImage = nextImage
186+
}
176187
}

Classes/Editor/EditorView.swift

+57-45
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,6 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
149149
private let showMuteButton: Bool
150150
private let showCrossIcon: Bool
151151
private let postButton = UIButton()
152-
private lazy var publishButton: UIButton = {
153-
let button = UIButton(type: .custom)
154-
button.accessibilityIdentifier = "Media Clips Next Button"
155-
button.accessibilityLabel = "Next Button"
156-
button.setImage(KanvasImages.nextImage, for: .normal)
157-
button.translatesAutoresizingMaskIntoConstraints = false
158-
return button
159-
}()
160152
private let postLabel = UILabel()
161153
private let tagButton = UIButton()
162154
private let fakeOptionCell = UIImageView()
@@ -166,6 +158,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
166158
private let showTagCollection: Bool
167159
private let showQuickPostButton: Bool
168160
private let showBlogSwitcher: Bool
161+
private let confirmAtTop: Bool
169162
private let metalContext: MetalContext?
170163
private let filterSelectionCircle = UIImageView()
171164
private let navigationContainer = IgnoreTouchesView()
@@ -245,6 +238,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
245238
showTagCollection: Bool,
246239
showQuickPostButton: Bool,
247240
showBlogSwitcher: Bool,
241+
confirmAtTop: Bool,
248242
quickBlogSelectorCoordinator: KanvasQuickBlogSelectorCoordinating?,
249243
tagCollection: UIView?,
250244
metalContext: MetalContext?,
@@ -260,6 +254,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
260254
self.showCrossIcon = showCrossIcon
261255
self.showQuickPostButton = showQuickPostButton
262256
self.showBlogSwitcher = showBlogSwitcher
257+
self.confirmAtTop = confirmAtTop
263258
self.quickBlogSelectorCoordinator = quickBlogSelectorCoordinator
264259
self.tagCollection = tagCollection
265260
self.metalContext = metalContext
@@ -425,16 +420,27 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
425420
private func setupConfirmButton() {
426421
confirmButton.accessibilityLabel = "Confirm Button"
427422
navigationContainer.addSubview(confirmButton)
428-
confirmButton.setImage(KanvasImages.nextImage, for: .normal)
423+
confirmButton.setImage(KanvasImages.shared.nextImage, for: .normal)
429424
confirmButton.addTarget(self, action: #selector(confirmButtonPressed), for: .touchUpInside)
430425
confirmButton.translatesAutoresizingMaskIntoConstraints = false
431-
426+
427+
let positioningConstraints: [NSLayoutConstraint]
428+
if confirmAtTop {
429+
positioningConstraints = [
430+
confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin),
431+
confirmButton.centerYAnchor.constraint(equalTo: closeButton.centerYAnchor)
432+
]
433+
} else {
434+
positioningConstraints = [
435+
confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin),
436+
confirmButton.bottomAnchor.constraint(equalTo: safeLayoutGuide.bottomAnchor, constant: -EditorViewConstants.buttonBottomMargin)
437+
]
438+
}
439+
432440
NSLayoutConstraint.activate([
433-
confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin),
434441
confirmButton.heightAnchor.constraint(equalToConstant: EditorViewConstants.confirmButtonSize),
435442
confirmButton.widthAnchor.constraint(equalToConstant: EditorViewConstants.confirmButtonSize),
436-
confirmButton.bottomAnchor.constraint(equalTo: safeLayoutGuide.bottomAnchor, constant: -EditorViewConstants.buttonBottomMargin)
437-
])
443+
] + positioningConstraints)
438444
}
439445

440446
private func setupPostOptionsButton() {
@@ -457,7 +463,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
457463
])
458464
}
459465
else {
460-
confirmButton.setImage(KanvasImages.nextImage, for: .normal)
466+
confirmButton.setImage(KanvasImages.shared.nextImage, for: .normal)
461467

462468
NSLayoutConstraint.activate([
463469
confirmButton.trailingAnchor.constraint(equalTo: safeLayoutGuide.trailingAnchor, constant: -EditorViewConstants.confirmButtonHorizontalMargin),
@@ -474,28 +480,6 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
474480
collectionContainer.accessibilityIdentifier = "Edition Menu Collection Container"
475481
collectionContainer.clipsToBounds = false
476482
collectionContainer.translatesAutoresizingMaskIntoConstraints = false
477-
let leftButton: UIView?
478-
let rightButton: UIView?
479-
let trailingMargin: CGFloat
480-
let leadingMargin: CGFloat
481-
482-
if showMuteButton {
483-
leftButton = muteButton
484-
leadingMargin = EditorViewConstants.saveButtonHorizontalMargin
485-
} else {
486-
leftButton = nil
487-
leadingMargin = 0
488-
}
489-
490-
if showSaveButton {
491-
rightButton = saveButton
492-
trailingMargin = EditorViewConstants.saveButtonHorizontalMargin
493-
}
494-
else {
495-
rightButton = confirmOrPostButton()
496-
trailingMargin = confirmOrPostButtonHorizontalMargin()
497-
}
498-
499483
if KanvasEditorDesign.shared.isVerticalMenu {
500484

501485
NSLayoutConstraint.activate([
@@ -507,21 +491,49 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
507491
}
508492
else {
509493

510-
let verticalConstraint: NSLayoutConstraint
494+
let leftButton: UIView?
495+
let leadingMargin: CGFloat
496+
let xAnchor: NSLayoutXAxisAnchor
497+
let trailingMargin: CGFloat
511498

512-
if let button = rightButton {
513-
verticalConstraint = collectionContainer.centerYAnchor.constraint(equalTo: button.centerYAnchor)
499+
if showMuteButton {
500+
leftButton = muteButton
501+
leadingMargin = EditorViewConstants.saveButtonHorizontalMargin
514502
} else {
515-
verticalConstraint = collectionContainer.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)
503+
leftButton = nil
504+
leadingMargin = 0
516505
}
517506

507+
if confirmAtTop {
508+
xAnchor = safeAreaLayoutGuide.trailingAnchor
509+
trailingMargin = 0
510+
} else {
511+
if showSaveButton {
512+
xAnchor = saveButton.leadingAnchor
513+
trailingMargin = EditorViewConstants.saveButtonHorizontalMargin
514+
}
515+
else {
516+
xAnchor = confirmOrPostButton().leadingAnchor
517+
trailingMargin = confirmOrPostButtonHorizontalMargin()
518+
}
519+
}
520+
521+
let verticalPositioning: [NSLayoutConstraint]
522+
if confirmAtTop {
523+
verticalPositioning = [collectionContainer.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)]
524+
} else {
525+
verticalPositioning = [collectionContainer.centerYAnchor.constraint(equalTo: confirmOrPostButton().centerYAnchor)]
526+
}
527+
528+
let leftButtonConstraints = [
529+
leftButton?.centerYAnchor.constraint(equalTo: collectionContainer.centerYAnchor)
530+
].compactMap { $0 }
531+
518532
NSLayoutConstraint.activate([
519533
collectionContainer.leadingAnchor.constraint(equalTo: leftButton?.trailingAnchor ?? safeAreaLayoutGuide.leadingAnchor, constant: leadingMargin),
520-
collectionContainer.trailingAnchor.constraint(equalTo: rightButton?.leadingAnchor ?? trailingAnchor, constant: -trailingMargin / 2),
521-
verticalConstraint,
534+
collectionContainer.trailingAnchor.constraint(equalTo: xAnchor, constant: -trailingMargin / 2),
522535
collectionContainer.heightAnchor.constraint(equalToConstant: EditionMenuCollectionView.height),
523-
leftButton?.centerYAnchor.constraint(equalTo: collectionContainer.centerYAnchor)
524-
].compactMap { $0 })
536+
] + verticalPositioning + leftButtonConstraints)
525537
}
526538
}
527539

@@ -632,7 +644,7 @@ final class EditorView: UIView, MovableViewCanvasDelegate, MediaPlayerViewDelega
632644
updatePostButton(avatarView: avatarView)
633645
}
634646
else {
635-
postButton.setImage(KanvasImages.nextImage, for: .normal)
647+
postButton.setImage(KanvasImages.shared.nextImage, for: .normal)
636648
}
637649
postButton.contentHorizontalAlignment = .fill
638650
postButton.contentVerticalAlignment = .fill

Classes/Editor/EditorViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ public final class EditorViewController: UIViewController, MediaPlayerController
240240
showTagCollection: settings.showTagCollectionInEditor,
241241
showQuickPostButton: settings.showQuickPostButtonInEditor,
242242
showBlogSwitcher: settings.showBlogSwitcherInEditor,
243+
confirmAtTop: settings.features.editorConfirmAtTop,
243244
quickBlogSelectorCoordinator: quickBlogSelectorCoordinator,
244245
tagCollection: tagCollection,
245246
metalContext: metalContext,

Classes/Preview/CameraPreviewView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ final class CameraPreviewView: UIView {
9797
confirmButton.accessibilityLabel = "Confirm Button"
9898
confirmButton.layer.applyShadows(offset: CGSize(width: 0.0, height: 2.0), radius: 0.0)
9999
addSubview(confirmButton)
100-
confirmButton.setImage(KanvasImages.confirmImage, for: .normal)
100+
confirmButton.setImage(KanvasImages.shared.confirmImage, for: .normal)
101101
confirmButton.addTarget(self, action: #selector(confirmButtonPressed), for: .touchUpInside)
102102
confirmButton.translatesAutoresizingMaskIntoConstraints = false
103103

Classes/Settings/CameraSettings.swift

+4
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ public struct CameraFeatures {
135135

136136
public var editorPostOptions: Bool = false
137137

138+
/// Editor Confirm Button
139+
/// Moves the editor confirm button to the top right
140+
public var editorConfirmAtTop: Bool = false
141+
138142
/// The Editor Saving feature
139143
/// This enables the UI to save media from the editor.
140144
public var editorSaving: Bool = false

Kanvas.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |spec|
22
spec.name = "Kanvas"
3-
spec.version = "1.2.1"
3+
spec.version = "1.2.2"
44
spec.summary = "A custom camera built for iOS."
55
spec.homepage = "https://github.com/tumblr/kanvas-ios"
66
spec.license = "MPLv2"

KanvasExample/KanvasExample/FeatureTableView.swift

+7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat
3232
case editorSaving(Bool)
3333
case editorPosting(Bool)
3434
case editorPostOptions(Bool)
35+
case editorConfirmAtTop(Bool)
3536
case newCameraModes(Bool)
3637
case gifs(Bool)
3738
case modeSelectorTooltip(Bool)
@@ -82,6 +83,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat
8283
return "New Camera Modes"
8384
case .editorPostOptions(_):
8485
return "Editor Post Options"
86+
case .editorConfirmAtTop(_):
87+
return "Editor Confirm At Top"
8588
case .gifs(_):
8689
return "GIF support"
8790
case .modeSelectorTooltip(_):
@@ -143,6 +146,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat
143146
return enabled
144147
case .editorPostOptions(let enabled):
145148
return enabled
149+
case .editorConfirmAtTop(let enabled):
150+
return enabled
146151
case .gifs(let enabled):
147152
return enabled
148153
case .modeSelectorTooltip(let enabled):
@@ -241,6 +246,8 @@ class FeatureTableView: UIView, UITableViewDelegate, UITableViewDataSource, Feat
241246
featuresData[indexPath.row] = .newCameraModes(value)
242247
case .editorPostOptions(_):
243248
featuresData[indexPath.row] = .editorPostOptions(value)
249+
case .editorConfirmAtTop(_):
250+
featuresData[indexPath.row] = .editorConfirmAtTop(value)
244251
case .gifs(_):
245252
featuresData[indexPath.row] = .gifs(value)
246253
case .modeSelectorTooltip(_):

KanvasExample/KanvasExample/KanvasExampleViewController.swift

+3
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ extension KanvasExampleViewController: FeatureTableViewDelegate {
271271
.editorSaving(settings.features.editorSaving),
272272
.editorPosting(settings.features.editorPosting),
273273
.editorPostOptions(settings.features.editorPostOptions),
274+
.editorConfirmAtTop(settings.features.editorConfirmAtTop),
274275
.newCameraModes(settings.features.newCameraModes),
275276
.modeSelectorTooltip(settings.features.modeSelectorTooltip),
276277
.shutterButtonTooltip(settings.features.shutterButtonTooltip),
@@ -324,6 +325,8 @@ extension KanvasExampleViewController: FeatureTableViewDelegate {
324325
settings.defaultMode = settings.features.newCameraModes ? Constants.defaultNewMode : Constants.defaultStandardMode
325326
case .editorPostOptions(_):
326327
settings.features.editorPostOptions = value
328+
case .editorConfirmAtTop(_):
329+
settings.features.editorConfirmAtTop = value
327330
case .modeSelectorTooltip(_):
328331
settings.features.modeSelectorTooltip = value
329332
case .shutterButtonTooltip(_):

KanvasExample/KanvasExampleTests/Camera/ImagePreviewControllerTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import XCTest
1212

1313
final class ImagePreviewControllerTests: FBSnapshotTestCase {
1414

15-
private let testImage = KanvasImages.confirmImage
15+
private let testImage = KanvasImages.shared.confirmImage
1616
private let secondTestImage = KanvasImages.flashOnImage
1717

1818
override func setUp() {

KanvasExample/KanvasExampleTests/Constants/KanvasImagesTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ final class KanvasImagesTests: FBSnapshotTestCase {
6666

6767
func testConfirmImage() {
6868
let imageView = newImageView()
69-
let image = KanvasImages.confirmImage
69+
let image = KanvasImages.shared.confirmImage
7070
XCTAssert(image != nil, "Image not found")
7171
imageView.image = image
7272
FBSnapshotVerifyView(imageView)

KanvasExample/KanvasExampleTests/Editor/EditorViewTests.swift

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ final class EditorViewTests: FBSnapshotTestCase {
3131
showTagCollection: false,
3232
showQuickPostButton: false,
3333
showBlogSwitcher: false,
34+
confirmAtTop: false,
3435
quickBlogSelectorCoordinator: nil,
3536
tagCollection: nil,
3637
metalContext: nil,

KanvasExample/KanvasExampleTests/Extensions/UIImage+DominantColorsTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import XCTest
1010
final class UIImageDominantColorsTests: XCTestCase {
1111

1212
func testDominantColors() {
13-
guard let image = KanvasImages.confirmImage else { return }
13+
guard let image = KanvasImages.shared.confirmImage else { return }
1414
let colors = image.getDominantColors(count: 3)
1515

1616
let expectedColors = [UIColor(hex: "#24bbfa"),

KanvasExample/KanvasExampleTests/Utility/ColorThief/ColorThiefTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import XCTest
1111

1212
final class ColorThieftTests: XCTestCase {
1313

14-
private let testImage = KanvasImages.confirmImage
14+
private let testImage = KanvasImages.shared.confirmImage
1515

1616
func testGetPalette() {
1717
guard let image = testImage,

KanvasExample/KanvasExampleTests/Utility/ColorThief/MMCQTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import XCTest
1111

1212
final class MMCQTests: XCTestCase {
1313

14-
private let testImage = KanvasImages.confirmImage
14+
private let testImage = KanvasImages.shared.confirmImage
1515

1616
func testQuantize() {
1717
guard let image = testImage,

0 commit comments

Comments
 (0)