mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Add "add more" button to image picker. Provide caption editing continuity.
This commit is contained in:
parent
2efbf1f432
commit
8b24fba095
14 changed files with 277 additions and 84 deletions
23
Signal/Images.xcassets/album_add_more.imageset/Contents.json
vendored
Normal file
23
Signal/Images.xcassets/album_add_more.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@1x.png
vendored
Normal file
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@1x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@2x.png
vendored
Normal file
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@3x.png
vendored
Normal file
BIN
Signal/Images.xcassets/album_add_more.imageset/album_add_more@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -2676,7 +2676,7 @@ typedef enum : NSUInteger {
|
|||
- (void)imagePicker:(OWSImagePickerGridController *)imagePicker
|
||||
didPickImageAttachments:(NSArray<SignalAttachment *> *)attachments
|
||||
{
|
||||
[self tryToSendAttachmentsIfApproved:attachments];
|
||||
[self tryToSendAttachmentsIfApproved:attachments skipApprovalDialog:YES];
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -139,6 +139,8 @@ typedef UITableViewCell *_Nonnull (^OWSTableCustomCellBlock)(void);
|
|||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController;
|
||||
|
||||
- (void)applyTheme;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue