Add "add more" button to image picker. Provide caption editing continuity.

This commit is contained in:
Matthew Chen 2018-11-15 10:25:48 -05:00
parent 2efbf1f432
commit 8b24fba095
14 changed files with 277 additions and 84 deletions

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "album_add_more@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "album_add_more@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "album_add_more@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -2676,7 +2676,7 @@ typedef enum : NSUInteger {
- (void)imagePicker:(OWSImagePickerGridController *)imagePicker
didPickImageAttachments:(NSArray<SignalAttachment *> *)attachments
{
[self tryToSendAttachmentsIfApproved:attachments];
[self tryToSendAttachmentsIfApproved:attachments skipApprovalDialog:YES];
}
/*

View File

@ -12,7 +12,7 @@ protocol ImagePickerControllerDelegate {
}
@objc(OWSImagePickerGridController)
class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegate, PhotoCollectionPickerDelegate {
class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegate, PhotoCollectionPickerDelegate, AttachmentApprovalViewControllerDelegate {
@objc
weak var delegate: ImagePickerControllerDelegate?
@ -26,6 +26,11 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
private let titleLabel = UILabel()
private var selectedIds = Set<String>()
// This variable should only be accessed on the main thread.
private var assetIdToCommentMap = [String: String]()
init() {
collectionViewFlowLayout = type(of: self).buildLayout()
photoCollection = library.defaultPhotoCollection()
@ -38,7 +43,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
fatalError("init(coder:) has not been implemented")
}
// MARK: View Lifecycle
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
@ -52,17 +57,27 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
collectionView.register(PhotoGridViewCell.self, forCellWithReuseIdentifier: PhotoGridViewCell.reuseIdentifier)
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(didPressCancel))
view.backgroundColor = .ows_gray95
if let navBar = self.navigationController?.navigationBar as? OWSNavigationBar {
navBar.makeClear()
} else {
owsFailDebug("Invalid nav bar.")
}
let cancelButton = UIBarButtonItem(barButtonSystemItem: .stop,
target: self,
action: #selector(didPressCancel))
cancelButton.tintColor = .ows_gray05
navigationItem.leftBarButtonItem = cancelButton
if #available(iOS 11, *) {
titleLabel.text = photoCollection.localizedTitle()
titleLabel.textColor = Theme.primaryColor
titleLabel.textColor = .ows_gray05
titleLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight()
let titleIconView = UIImageView()
titleIconView.tintColor = Theme.primaryColor
titleIconView.tintColor = .ows_gray05
titleIconView.image = UIImage(named: "navbar_disclosure_down")?.withRenderingMode(.alwaysTemplate)
let titleView = UIStackView(arrangedSubviews: [titleLabel, titleIconView])
@ -81,7 +96,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
updateSelectButton()
}
collectionView.backgroundColor = Theme.backgroundColor
collectionView.backgroundColor = .ows_gray95
}
override func viewWillLayoutSubviews() {
@ -96,16 +111,38 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let scale = UIScreen.main.scale
let cellSize = collectionViewFlowLayout.itemSize
photoMediaSize.thumbnailSize = CGSize(width: cellSize.width * scale, height: cellSize.height * scale)
reloadDataAndRestoreSelection()
}
// MARK: Actions
private func reloadDataAndRestoreSelection() {
guard let collectionView = collectionView else {
owsFailDebug("Missing collectionView.")
return
}
collectionView.reloadData()
collectionView.layoutIfNeeded()
let count = photoCollectionContents.count
for index in 0..<count {
let asset = photoCollectionContents.asset(at: index)
let assetId = asset.localIdentifier
if selectedIds.contains(assetId) {
collectionView.selectItem(at: IndexPath(row: index, section: 0),
animated: false, scrollPosition: [])
}
}
}
// MARK: - Actions
@objc
func didPressCancel(sender: UIBarButtonItem) {
self.dismiss(animated: true)
}
// MARK: Layout
// MARK: - Layout
static let kInterItemSpacing: CGFloat = 2
private class func buildLayout() -> UICollectionViewFlowLayout {
@ -146,7 +183,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
}
// MARK: Batch Selection
// MARK: - Batch Selection
lazy var doneButton: UIBarButtonItem = {
return UIBarButtonItem(barButtonSystemItem: .done,
@ -184,12 +221,39 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
let assets: [PHAsset] = indexPaths.compactMap { return photoCollectionContents.asset(at: $0.row) }
let promises = assets.map { return photoCollectionContents.outgoingAttachment(for: $0) }
when(fulfilled: promises).map { attachments in
self.dismiss(animated: true) {
self.delegate?.imagePicker(self, didPickImageAttachments: attachments)
complete(withAssets: assets)
}
func complete(withAssets assets: [PHAsset]) {
let attachmentPromises: [Promise<SignalAttachment>] = assets.map({
return photoCollectionContents.outgoingAttachment(for: $0)
})
when(fulfilled: attachmentPromises)
.map { attachments in
self.didComplete(withAttachments: attachments)
}.retainUntilComplete()
}
private func didComplete(withAttachments attachments: [SignalAttachment]) {
AssertIsOnMainThread()
// If we re-enter image picking, do so in batch mode.
isInBatchSelectMode = true
for attachment in attachments {
guard let assetId = attachment.sourceId else {
owsFailDebug("Attachment is missing asset id.")
continue
}
}.retainUntilComplete()
// Link the attachment with its asset to ensure caption continuity.
attachment.sourceId = assetId
// Restore any existing caption for this attachment.
attachment.captionText = assetIdToCommentMap[assetId]
}
let vc = AttachmentApprovalViewController(mode: .sharedNavigation, attachments: attachments)
vc.approvalDelegate = self
navigationController?.pushViewController(vc, animated: true)
}
func updateDoneButton() {
@ -206,7 +270,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
func updateSelectButton() {
navigationItem.rightBarButtonItem = isInBatchSelectMode ? doneButton : selectButton
let button = isInBatchSelectMode ? doneButton : selectButton
button.tintColor = .ows_gray05
navigationItem.rightBarButtonItem = button
}
@objc
@ -234,13 +300,17 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
collectionView.indexPathsForSelectedItems?.forEach { collectionView.deselectItem(at: $0, animated: false)}
}
// MARK: PhotoLibraryDelegate
// MARK: - PhotoLibraryDelegate
func photoLibraryDidChange(_ photoLibrary: PhotoLibrary) {
collectionView?.reloadData()
// We only want to let users select assets
// from a single collection.
selectedIds.removeAll()
reloadDataAndRestoreSelection()
}
// MARK: PhotoCollectionPickerDelegate
// MARK: - PhotoCollectionPickerDelegate
func photoCollectionPicker(_ photoCollectionPicker: PhotoCollectionPickerController, didPickCollection collection: PhotoCollection) {
photoCollection = collection
@ -252,7 +322,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
navigationItem.title = photoCollection.localizedTitle()
}
collectionView?.reloadData()
reloadDataAndRestoreSelection()
}
// MARK: - Event Handlers
@ -264,30 +334,33 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let view = PhotoCollectionPickerController(library: library,
previousPhotoCollection: photoCollection,
collectionDelegate: self)
let nav = UINavigationController(rootViewController: view)
let nav = OWSNavigationController(rootViewController: view)
self.present(nav, animated: true, completion: nil)
}
// MARK: UICollectionView
// MARK: - UICollectionView
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let asset = photoCollectionContents.asset(at: indexPath.item)
let assetId = asset.localIdentifier
selectedIds.insert(assetId)
if isInBatchSelectMode {
updateDoneButton()
} else {
let asset = photoCollectionContents.asset(at: indexPath.row)
firstly {
photoCollectionContents.outgoingAttachment(for: asset)
}.map { attachment in
self.dismiss(animated: true) {
self.delegate?.imagePicker(self, didPickImageAttachments: [attachment])
}
}.retainUntilComplete()
complete(withAssets: [asset])
}
}
public override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
Logger.debug("")
let asset = photoCollectionContents.asset(at: indexPath.item)
let assetId = asset.localIdentifier
selectedIds.remove(assetId)
if isInBatchSelectMode {
updateDoneButton()
}
@ -301,10 +374,44 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PhotoGridViewCell.reuseIdentifier, for: indexPath) as? PhotoGridViewCell else {
owsFail("cell was unexpectedly nil")
}
cell.loadingColor = UIColor(white: 0.2, alpha: 1)
let assetItem = photoCollectionContents.assetItem(at: indexPath.item, photoMediaSize: photoMediaSize)
cell.configure(item: assetItem)
let assetId = assetItem.asset.localIdentifier
let isSelected = selectedIds.contains(assetId)
cell.isSelected = isSelected
return cell
}
// MARK: - AttachmentApprovalViewControllerDelegate
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment]) {
self.dismiss(animated: true) {
self.delegate?.imagePicker(self, didPickImageAttachments: attachments)
}
}
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didCancelAttachments attachments: [SignalAttachment]) {
navigationController?.popToViewController(self, animated: true)
}
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, addMoreToAttachments attachments: [SignalAttachment]) {
navigationController?.popToViewController(self, animated: true)
}
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, changedCaptionOfAttachment attachment: SignalAttachment) {
AssertIsOnMainThread()
guard let assetId = attachment.sourceId else {
owsFailDebug("Attachment missing source id.")
return
}
guard let captionText = attachment.captionText, captionText.count > 0 else {
assetIdToCommentMap.removeValue(forKey: assetId)
return
}
assetIdToCommentMap[assetId] = captionText
}
}

View File

@ -37,14 +37,22 @@ class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDeleg
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .ows_gray95
if let navBar = self.navigationController?.navigationBar as? OWSNavigationBar {
navBar.makeClear()
} else {
owsFailDebug("Invalid nav bar.")
}
if #available(iOS 11, *) {
let titleLabel = UILabel()
titleLabel.text = previousPhotoCollection.localizedTitle()
titleLabel.textColor = Theme.primaryColor
titleLabel.textColor = .ows_gray05
titleLabel.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight()
let titleIconView = UIImageView()
titleIconView.tintColor = Theme.primaryColor
titleIconView.tintColor = .ows_gray05
titleIconView.image = UIImage(named: "navbar_disclosure_up")?.withRenderingMode(.alwaysTemplate)
let titleView = UIStackView(arrangedSubviews: [titleLabel, titleIconView])
@ -60,9 +68,11 @@ class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDeleg
library.add(delegate: self)
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(didPressCancel))
let cancelButton = UIBarButtonItem(barButtonSystemItem: .stop,
target: self,
action: #selector(didPressCancel))
cancelButton.tintColor = .ows_gray05
navigationItem.leftBarButtonItem = cancelButton
updateContents()
}
@ -75,6 +85,10 @@ class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDeleg
section.add(OWSTableItem.init(customCellBlock: { () -> UITableViewCell in
let cell = OWSTableItem.newCell()
cell.backgroundColor = .ows_gray95
cell.contentView.backgroundColor = .ows_gray95
cell.selectedBackgroundView?.backgroundColor = UIColor(white: 0.2, alpha: 1)
let imageView = UIImageView()
let kImageSize = 50
imageView.autoSetDimensions(to: CGSize(width: kImageSize, height: kImageSize))
@ -97,7 +111,7 @@ class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDeleg
let titleLabel = UILabel()
titleLabel.text = collection.localizedTitle()
titleLabel.font = UIFont.ows_dynamicTypeBody
titleLabel.textColor = Theme.primaryColor
titleLabel.textColor = .ows_gray05
let stackView = UIStackView(arrangedSubviews: [imageView, titleLabel])
stackView.axis = .horizontal
@ -120,6 +134,12 @@ class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDeleg
self.contents = contents
}
@objc
public override func applyTheme() {
view.backgroundColor = .ows_gray95
tableView.backgroundColor = .ows_gray95
}
// MARK: Actions
@objc

View File

@ -150,11 +150,15 @@ class PhotoCollectionContents {
switch asset.mediaType {
case .image:
return requestImageDataSource(for: asset).map { (dataSource: DataSource, dataUTI: String) in
return SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .medium)
let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI, imageQuality: .medium)
attachment.sourceId = asset.localIdentifier
return attachment
}
case .video:
return requestVideoDataSource(for: asset).map { (dataSource: DataSource, dataUTI: String) in
return SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI)
let attachment = SignalAttachment.attachment(dataSource: dataSource, dataUTI: dataUTI)
attachment.sourceId = asset.localIdentifier
return attachment
}
default:
return Promise(error: PhotoLibraryError.unsupportedMediaType)

View File

@ -29,6 +29,8 @@ public class PhotoGridViewCell: UICollectionViewCell {
private static let animatedBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_gif")
private static let selectedBadgeImage = #imageLiteral(resourceName: "selected_blue_circle")
public var loadingColor = Theme.offBackgroundColor
override public var isSelected: Bool {
didSet {
self.selectedBadgeView.isHidden = !self.isSelected
@ -99,7 +101,7 @@ public class PhotoGridViewCell: UICollectionViewCell {
get { return imageView.image }
set {
imageView.image = newValue
imageView.backgroundColor = newValue == nil ? Theme.offBackgroundColor : .clear
imageView.backgroundColor = newValue == nil ? loadingColor : .clear
}
}

View File

@ -11,6 +11,8 @@ import PromiseKit
public protocol AttachmentApprovalViewControllerDelegate: class {
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment])
func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didCancelAttachments attachments: [SignalAttachment])
@objc optional func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, addMoreToAttachments attachments: [SignalAttachment])
@objc optional func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, changedCaptionOfAttachment attachment: SignalAttachment)
}
class AttachmentItemCollection {
@ -91,16 +93,24 @@ class SignalAttachmentItem: Hashable {
}
}
@objc
public enum AttachmentApprovalViewControllerMode: UInt {
case modal
case sharedNavigation
}
@objc
public class AttachmentApprovalViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, CaptioningToolbarDelegate {
// MARK: Properties
// MARK: - Properties
weak var approvalDelegate: AttachmentApprovalViewControllerDelegate?
private let mode: AttachmentApprovalViewControllerMode
public weak var approvalDelegate: AttachmentApprovalViewControllerDelegate?
private(set) var captioningToolbar: CaptioningToolbar!
// MARK: Initializers
// MARK: - Initializers
@available(*, unavailable, message:"use attachment: constructor instead.")
required public init?(coder aDecoder: NSCoder) {
@ -110,8 +120,10 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
let kSpacingBetweenItems: CGFloat = 20
@objc
required public init(attachments: [SignalAttachment]) {
required public init(mode: AttachmentApprovalViewControllerMode,
attachments: [SignalAttachment]) {
assert(attachments.count > 0)
self.mode = mode
let attachmentItems = attachments.map { SignalAttachmentItem(attachment: $0 )}
self.attachmentItemCollection = AttachmentItemCollection(attachmentItems: attachmentItems)
super.init(transitionStyle: .scroll,
@ -123,7 +135,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
@objc
public class func wrappedInNavController(attachments: [SignalAttachment], approvalDelegate: AttachmentApprovalViewControllerDelegate) -> OWSNavigationController {
let vc = AttachmentApprovalViewController(attachments: attachments)
let vc = AttachmentApprovalViewController(mode: .modal, attachments: attachments)
vc.approvalDelegate = approvalDelegate
let navController = OWSNavigationController(rootViewController: vc)
@ -136,7 +148,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return navController
}
// MARK: View Lifecycle
// MARK: - View Lifecycle
let galleryRailView = GalleryRailView()
let railContainerView = UIView()
@ -171,7 +183,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// Bottom Toolbar
let captioningToolbar = CaptioningToolbar()
let isAddMoreVisible = mode == .sharedNavigation
let captioningToolbar = CaptioningToolbar(isAddMoreVisible: isAddMoreVisible)
captioningToolbar.captioningToolbarDelegate = self
self.captioningToolbar = captioningToolbar
@ -179,9 +192,12 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
self.navigationItem.title = nil
let cancelButton = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(cancelPressed))
cancelButton.tintColor = .white
self.navigationItem.leftBarButtonItem = cancelButton
if mode != .sharedNavigation {
let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self, action: #selector(cancelPressed))
cancelButton.tintColor = .white
self.navigationItem.leftBarButtonItem = cancelButton
}
guard let firstItem = attachmentItems.first else {
owsFailDebug("firstItem was unexpectedly nil")
@ -189,6 +205,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
self.setCurrentItem(firstItem, direction: .forward, animated: false)
captioningToolbar.captionText = currentViewController.attachment.captionText
}
override public func viewWillAppear(_ animated: Bool) {
@ -263,8 +281,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
let button = OWSButton { [weak self] in
guard let self = self else { return }
self.remove(attachmentItem: attachmentItem)
guard let strongSelf = self else { return }
strongSelf.remove(attachmentItem: attachmentItem)
}
button.setImage(#imageLiteral(resourceName: "ic_small_x"), for: .normal)
@ -300,21 +318,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
pagerScrollView.isScrollEnabled = attachmentItems.count > 1
}
private func makeClearToolbar() -> UIToolbar {
let toolbar = UIToolbar()
toolbar.backgroundColor = UIColor.clear
// Making a toolbar transparent requires setting an empty uiimage
toolbar.setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: .default)
// hide 1px top-border
toolbar.clipsToBounds = true
return toolbar
}
// MARK: UIPageViewControllerDelegate
// MARK: - UIPageViewControllerDelegate
public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
Logger.debug("")
@ -356,7 +360,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
// MARK: UIPageViewControllerDataSource
// MARK: - UIPageViewControllerDataSource
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let currentViewController = viewController as? AttachmentPrepViewController else {
@ -493,7 +497,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
self.approvalDelegate?.attachmentApproval(self, didCancelAttachments: attachments)
}
// MARK: CaptioningToolbarDelegate
// MARK: - CaptioningToolbarDelegate
var currentPageController: AttachmentPrepViewController {
return viewControllers!.first as! AttachmentPrepViewController
@ -520,6 +524,12 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
func captioningToolbar(_ captioningToolbar: CaptioningToolbar, textViewDidChange textView: UITextView) {
currentItem.attachment.captionText = textView.text
self.approvalDelegate?.attachmentApproval?(self, changedCaptionOfAttachment: currentItem.attachment)
}
func captioningToolbarDidAddMore(_ captioningToolbar: CaptioningToolbar) {
self.approvalDelegate?.attachmentApproval?(self, addMoreToAttachments: attachments)
}
}
@ -558,7 +568,7 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate {
return
}
let direction: NavigationDirection = currentIndex < targetIndex ? .forward : .reverse
let direction: UIPageViewControllerNavigationDirection = currentIndex < targetIndex ? .forward : .reverse
self.setCurrentItem(targetItem, direction: direction, animated: true)
}
@ -573,7 +583,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
case fullsize, compact
}
// MARK: Properties
// MARK: - Properties
let attachmentItem: SignalAttachmentItem
var attachment: SignalAttachment {
@ -587,7 +597,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
private(set) var contentContainer: UIView!
private(set) var playVideoButton: UIView?
// MARK: Initializers
// MARK: - Initializers
init(attachmentItem: SignalAttachmentItem) {
self.attachmentItem = attachmentItem
@ -599,7 +609,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
fatalError("init(coder:) has not been implemented")
}
// MARK: View Lifecycle
// MARK: - View Lifecycle
override public func loadView() {
self.view = UIView()
@ -713,7 +723,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
ensureAttachmentViewScale(animated: false)
}
// MARK:
// MARK: -
@objc public func didTapPlayerView(_ gestureRecognizer: UIGestureRecognizer) {
assert(self.videoPlayer != nil)
@ -727,7 +737,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
self.playVideo()
}
// MARK: Video
// MARK: - Video
private func playVideo() {
Logger.info("")
@ -804,7 +814,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
}
}
// MARK: Helpers
// MARK: - Helpers
var isZoomable: Bool {
return attachment.isImage || attachment.isVideo
@ -939,11 +949,13 @@ protocol CaptioningToolbarDelegate: class {
func captioningToolbarDidBeginEditing(_ captioningToolbar: CaptioningToolbar)
func captioningToolbarDidEndEditing(_ captioningToolbar: CaptioningToolbar)
func captioningToolbar(_ captioningToolbar: CaptioningToolbar, textViewDidChange: UITextView)
func captioningToolbarDidAddMore(_ captioningToolbar: CaptioningToolbar)
}
class CaptioningToolbar: UIView, UITextViewDelegate {
weak var captioningToolbarDelegate: CaptioningToolbarDelegate?
private let addMoreButton: UIButton
private let sendButton: UIButton
private let textView: UITextView
@ -984,9 +996,10 @@ class CaptioningToolbar: UIView, UITextViewDelegate {
}
}
// MARK: Initializers
// MARK: - Initializers
init() {
init(isAddMoreVisible: Bool) {
self.addMoreButton = UIButton(type: .custom)
self.sendButton = UIButton(type: .system)
self.textView = MessageTextView()
self.textViewHeight = kMinTextViewHeight
@ -1012,6 +1025,9 @@ class CaptioningToolbar: UIView, UITextViewDelegate {
textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
textView.scrollIndicatorInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 3)
addMoreButton.setImage(UIImage(named: "album_add_more"), for: .normal)
addMoreButton.addTarget(self, action: #selector(didTapAddMore), for: .touchUpInside)
let sendTitle = NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", comment: "Label for 'send' button in the 'attachment approval' dialog.")
sendButton.setTitle(sendTitle, for: .normal)
sendButton.addTarget(self, action: #selector(didTapSend), for: .touchUpInside)
@ -1039,6 +1055,9 @@ class CaptioningToolbar: UIView, UITextViewDelegate {
contentView.addSubview(sendButton)
contentView.addSubview(textView)
contentView.addSubview(lengthLimitLabel)
if isAddMoreVisible {
contentView.addSubview(addMoreButton)
}
addSubview(contentView)
contentView.autoPinEdgesToSuperviewEdges()
@ -1060,9 +1079,17 @@ class CaptioningToolbar: UIView, UITextViewDelegate {
// So it doesn't work as expected with RTL layouts when we explicitly want something
// to be on the right side for both RTL and LTR layouts, like with the send button.
// I believe this is a bug in PureLayout. Filed here: https://github.com/PureLayout/PureLayout/issues/209
textView.autoPinEdge(toSuperviewMargin: .left)
textView.autoPinEdge(toSuperviewMargin: .top)
textView.autoPinEdge(toSuperviewMargin: .bottom)
if isAddMoreVisible {
addMoreButton.autoPinEdge(toSuperviewMargin: .left)
textView.autoPinEdge(.left, to: .right, of: addMoreButton, withOffset: kToolbarMargin)
addMoreButton.autoAlignAxis(.horizontal, toSameAxisOf: sendButton)
addMoreButton.setContentHuggingHigh()
addMoreButton.setCompressionResistanceHigh()
} else {
textView.autoPinEdge(toSuperviewMargin: .left)
}
sendButton.autoPinEdge(.left, to: .right, of: textView, withOffset: kToolbarMargin)
sendButton.autoPinEdge(.bottom, to: .bottom, of: textView, withOffset: -3)
@ -1087,12 +1114,16 @@ class CaptioningToolbar: UIView, UITextViewDelegate {
notImplemented()
}
// MARK:
// MARK: -
@objc func didTapSend() {
self.captioningToolbarDelegate?.captioningToolbarDidTapSend(self)
}
@objc func didTapAddMore() {
self.captioningToolbarDelegate?.captioningToolbarDidAddMore(self)
}
// MARK: - UITextViewDelegate
public func textViewDidChange(_ textView: UITextView) {

View File

@ -139,6 +139,8 @@ typedef UITableViewCell *_Nonnull (^OWSTableCustomCellBlock)(void);
- (void)presentFromViewController:(UIViewController *)fromViewController;
- (void)applyTheme;
@end
NS_ASSUME_NONNULL_END

View File

@ -33,7 +33,7 @@ public class GalleryRailCellView: UIView {
addGestureRecognizer(tapGesture)
}
required init?(coder aDecoder: NSCoder) {
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@ -112,7 +112,7 @@ public class GalleryRailView: UIView, GalleryRailCellViewDelegate {
scrollView.autoPinEdgesToSuperviewMargins()
}
required init?(coder aDecoder: NSCoder) {
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

View File

@ -19,7 +19,7 @@ public class OWSButton: UIButton {
self.addTarget(self, action: #selector(didTap), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

View File

@ -160,6 +160,10 @@ public class SignalAttachment: NSObject {
@objc
public let dataUTI: String
// Can be used by views to link this SignalAttachment with an arbitrary source.
@objc
public var sourceId: String?
var error: SignalAttachmentError? {
didSet {
AssertIsOnMainThread()