FUIAttachmentsFormCell

@IBDesignable
open class FUIAttachmentsFormCell : FUIInlineValidationTableViewCell
  • The reusable UI component implemented as an UITableViewCell to manage selecting attachments.

FUIAttachmentsFormCell uses a FUIAttachmentsViewController to display the title of the cell and a collection of icons to represent the attachments. The attachment icon size may change, depends on the system font size settings. The controller arranges the attachment icons in such a manner that as many icons to be fitted in a row, and as many rows to display all the attachment icons. It will also try to make the row spacing equal to the spacing between icons. However, the row spacing is limited to 20 pixels maximum.

Developers should use the property attachmentsController to provide attachment information; the delegate, the dataSource and the list of FUIAttachmentAction implementations for the desired type of attachments. The app can use the built-in types or implement additional types as desired.

Important

the cell’s parent UITableViewController should subclass FUIFormTableViewController.

Color settings:

Setting tintColor for add button for a state using setTintColor(_:for:) api. Currently normal and .selected are supported.

 cell.setTintColor(UIColor.red, for: .normal)

There are three built-in FUIAttachmentAction:

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: FUIAttachmentsFormCell.reuseIdentifier, for: indexPath) as! FUIAttachmentsFormCell
     cell.attachmentsController.delegate = self
     cell.attachmentsController.dataSource = self

     let addPhotoAction = FUIAddPhotoAttachmentAction()
     addPhotoAction.delegate = self
     cell.attachmentsController.addAttachmentAction(addPhotoAction)

     let takePhotoAction = FUITakePhotoAttachmentAction()
     takePhotoAction.delegate = self
     cell.attachmentsController.addAttachmentAction(takePhotoAction)

     let filePickerAction = FUIDocumentPickerAttachmentAction()
     filePickerAction.delegate = self
     cell.attachmentsController.addAttachmentAction(filePickerAction)

     return cell
 }

 var attachmentURLs: [URL] = [URL]()

// MARK: FUIAttachmentsViewControllerDataSource methods
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, iconForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
    let urlString = self.attachmentURLs[index].absoluteString
    guard let image = self.attachmentThumbnails[urlString] else {
        return nil
    }
    return (image!, .scaleAspectFill)
}

func numberOfAttachments(in attachmentsViewController: FUIAttachmentsViewController) -> Int {
    return attachmentURLs.count
}

func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, urlForAttachmentAtIndex index: Int) -> URL? {
    return attachmentURLs[index]
}

 func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, titleForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
     return "attachment title"
 }

 func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, subtitleForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
     return "attachment subtitle"
 }

 func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, footnoteForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
     return "attachment footnote"
 }

// MARK:  FUIAttachmentsViewControllerDelegateMethods
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, couldNotPresentAttachmentAtIndex index: Int) {

}

func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, didPressDeleteAtIndex index: Int) {
    self.attachmentURLs.remove(at: index)
    self.tableView.reloadSections(IndexSet(integer:attachmentSection), with: .automatic)
}

 func focusOnNewAttachment() {
     DispatchQueue.main.async {
         if let cell = self.tableView.visibleCells.last as? FUIAttachmentsFormCell { // find the attachment cell
             if let newDoc = cell.accessibilityElements?.last {
                 UIAccessibility.post(notification: .layoutChanged, argument: newDoc)
             }
         }
     }
 }

//MARK: FUIAddPhotoAttachmentActionDelegate
 func addPhotoAttachmentAction(_ action: FUIAddPhotoAttachmentAction, didSelectPhoto asset: PHAsset, at url: URL) {
    setupThumbnails(url, with: asset)
    self.addAttachmentURL(url)
}

//MARK: FUITakePhotoAttachmentActionDelegate

func takePhotoAttachmentAction(_ action: FUITakePhotoAttachmentAction, didTakePhoto asset: PHAsset, at url: URL) {
    setupThumbnails(url, with: asset)
    self.addAttachmentURL(url)
}


func addAttachmentURL(_ url: URL) {
    self.attachmentURLs.append(url)
    DispatchQueue.main.async {
        self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
        self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.attachmentSection) , at: .middle, animated: true)
        if UIAccessibility.isVoiceOverRunning {
            focusOnNewAttachment()
        }
    }
}

 func setupThumbnails(_ url: URL, with asset: PHAsset) {
     let imageManager = PHImageManager.default()
     imageManager.requestImage(for: asset, targetSize: CGSize(width: 80, height: 80), contentMode: .default, options: nil, resultHandler: { image, array in
         self.attachmentThumbnails[url.absoluteString] = image
         DispatchQueue.main.async {
             self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
             self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.attachmentSection) , at: .middle, animated: true)
         }
     })
 }

 //MARK: FUIDocumentPickerAttachmentActionDelegate {
 var documentPicker: UIDocumentPickerViewController {
     return UIDocumentPickerViewController(documentTypes: ["public.data"], in: .import)
 }

 func documentPickerAttachmentAction(_ action: FUIDocumentPickerAttachmentAction, didPickFileAt url: URL) {
     if let savedUrl = saveFileToTempFolder(url) {
         self.addAttachmentURL(savedUrl)
     }
     self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
     if UIAccessibility.isVoiceOverRunning {
        focusOnNewAttachment()
     }
 }

## Theming

Supported TEXT class paths:

 fdlFUIAttachmentsFormView_attachmentTitleLabel {}
 fdlFUIAttachmentsViewController_alertActionTitle {}
 fdlFUIFileThumbnailCollectionItemView_titleLabel {}
 fdlFUIThumbnailCollectionItemView_subtitle {}
 fdlFUIThumbnailCollectionItemView_footnote {}

Supported TEXT properties:

 font-color: Color;
 font-style: UIFontTextStyle;

Supported IMAGE class paths:

 fdlFUIFileThumbnailCollectionItemView_detailImageView {}

Supported IMAGE properties:

 tint-color: Color;

Supported BUTTON class paths:

fdlFUIAddButtonCell_addButton {}

Supported BUTTON properties:

 image: Image;
 tint-color: Color;

Supported CELL class paths:

 fdlFUIAttachmentsFormCell_thumbnailCell {}
 fdlFUIAttachmentsFormCell_addButtonCell {}

Supported CELL properties:

 border-color: Color;
 border-width: Integer;
 corner-radius: Integer;

Supported style classes

  • The default cell reuse identifier.

    Declaration

    Swift

    open class var reuseIdentifier: String { get }
  • The controller managing the attachments displayed by this cell.

    Declaration

    Swift

    open private(set) var attachmentsController: FUIAttachmentsViewController { get }
  • Indicates if user can add attachment or not. If this is true, there will be a “+” button shown. When user tapped that button, it will bring up the “Add Attachment” pop-up for user to select additional attachment. Otherwise, the “+” button will not be shown. The default is true.

    Declaration

    Swift

    public var isEditable: Bool { get set }
  • isEnabled and isEditable are in sync.

    Declaration

    Swift

    override public var isEnabled: Bool { get set }
  • Open the item of the specified attachment at the given index.

    Declaration

    Swift

    public func openAttachmentItem(index: Int)

    Parameters

    index

    The index of the item.