// // NCScan.swift // Nextcloud // // Created by Marino Faggiana on 21/08/18. // Copyright (c) 2018 Marino Faggiana. All rights reserved. // // Author Marino Faggiana // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // import UIKit import Photos import EasyTipView class NCScan: UIViewController, NCScanCellCellDelegate { @IBOutlet weak var collectionViewSource: UICollectionView! @IBOutlet weak var collectionViewDestination: UICollectionView! @IBOutlet weak var cancel: UIBarButtonItem! @IBOutlet weak var save: UIBarButtonItem! @IBOutlet weak var add: UIButton! @IBOutlet weak var transferDown: UIButton! @IBOutlet weak var labelTitlePDFzone: UILabel! @IBOutlet weak var segmentControlFilter: UISegmentedControl! // Data Source for collectionViewSource internal var itemsSource: [String] = [] // Data Source for collectionViewDestination internal var imagesDestination: [UIImage] = [] internal var itemsDestination: [String] = [] internal let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! private var tipView: EasyTipView? enum TypeFilter { case document case original } internal var filter: TypeFilter = TypeFilter.document // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .secondarySystemGroupedBackground navigationItem.title = NSLocalizedString("_scanned_images_", comment: "") collectionViewSource.dragInteractionEnabled = true collectionViewSource.dragDelegate = self collectionViewSource.dropDelegate = self collectionViewSource.backgroundColor = .secondarySystemGroupedBackground collectionViewDestination.dragInteractionEnabled = true collectionViewDestination.dropDelegate = self collectionViewDestination.dragDelegate = self collectionViewDestination.reorderingCadence = .fast // default value - .immediate collectionViewDestination.backgroundColor = .secondarySystemGroupedBackground cancel.title = NSLocalizedString("_cancel_", comment: "") save.title = NSLocalizedString("_save_", comment: "") labelTitlePDFzone.text = NSLocalizedString("_scan_label_document_zone_", comment: "") labelTitlePDFzone.backgroundColor = .systemGray6 labelTitlePDFzone.textColor = .label segmentControlFilter.setTitle(NSLocalizedString("_filter_document_", comment: ""), forSegmentAt: 0) segmentControlFilter.setTitle(NSLocalizedString("_filter_original_", comment: ""), forSegmentAt: 1) add.setImage(UIImage(systemName: "plus")?.image(color: .label, size: 25), for: .normal) transferDown.setImage(UIImage(systemName: "arrow.down")?.image(color: .label, size: 25), for: .normal) let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(recognizer:))) collectionViewSource.addGestureRecognizer(longPressRecognizer) let longPressRecognizerPlus = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(recognizer:))) add.addGestureRecognizer(longPressRecognizerPlus) // TIP var preferences = EasyTipView.Preferences() preferences.drawing.foregroundColor = .white preferences.drawing.backgroundColor = NCBrandColor.shared.nextcloud preferences.drawing.textAlignment = .left preferences.drawing.arrowPosition = .left preferences.drawing.cornerRadius = 10 preferences.animating.dismissTransform = CGAffineTransform(translationX: 0, y: 100) preferences.animating.showInitialTransform = CGAffineTransform(translationX: 0, y: -100) preferences.animating.showInitialAlpha = 0 preferences.animating.showDuration = 1.5 preferences.animating.dismissDuration = 1.5 tipView = EasyTipView(text: NSLocalizedString("_tip_addcopyimage_", comment: ""), preferences: preferences, delegate: self) collectionViewSource.reloadData() collectionViewDestination.reloadData() NotificationCenter.default.addObserver(self, selector: #selector(dismiss(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDismissScanDocument), object: nil) loadImage() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) showTip() } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) self.tipView?.dismiss() coordinator.animate(alongsideTransition: nil) { _ in self.showTip() } } // MARK: - Tip func showTip() { if !NCManageDatabase.shared.tipExists(NCGlobal.shared.tipNCScanAddImage) { self.tipView?.show(forView: add, withinSuperview: self.view) } } // MARK: - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) add.setImage(UIImage(systemName: "plus")?.image(color: .label, size: 25), for: .normal) transferDown.setImage(UIImage(systemName: "arrow.down")?.image(color: .label, size: 25), for: .normal) } override var canBecomeFirstResponder: Bool { return true } override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if action == #selector(pasteImage) { return true } return false } @objc func dismiss(_ notification: NSNotification) { self.dismiss(animated: true, completion: nil) } @IBAction func cancelAction(sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } @IBAction func saveAction(sender: UIBarButtonItem) { if !imagesDestination.isEmpty { var images: [UIImage] = [] let serverUrl = appDelegate.activeServerUrl for image in imagesDestination { images.append(filter(image: image)!) } let vc = NCHostingUploadScanDocumentView().makeShipDetailsUI(images: images, userBaseUrl: appDelegate, serverUrl: serverUrl) self.navigationController?.pushViewController(vc, animated: true) } } @IBAction func add(sender: UIButton) { // TIP dismissTip() NCDocumentCamera.shared.openScannerDocument(viewController: self) } @IBAction func transferDown(sender: UIButton) { for fileName in itemsSource where !itemsDestination.contains(fileName) { let fileNamePathAt = CCUtility.getDirectoryScan() + "/" + fileName guard let data = try? Data(contentsOf: URL(fileURLWithPath: fileNamePathAt)), let image = UIImage(data: data) else { return } imagesDestination.append(image) itemsDestination.append(fileName) } // Save button if imagesDestination.isEmpty { save.isEnabled = false } else { save.isEnabled = true } collectionViewDestination.reloadData() } @IBAction func indexChanged(_ sender: AnyObject) { switch segmentControlFilter.selectedSegmentIndex { case 0: filter = .document case 1: filter = .original default: break } collectionViewDestination.reloadData() } func loadImage() { itemsSource.removeAll() do { let atPath = CCUtility.getDirectoryScan()! let directoryContents = try FileManager.default.contentsOfDirectory(atPath: atPath) for fileName in directoryContents where fileName.first != "." { itemsSource.append(fileName) } } catch { print(error.localizedDescription) } itemsSource = itemsSource.sorted() collectionViewSource.reloadData() // Save button if imagesDestination.isEmpty { save.isEnabled = false } else { save.isEnabled = true } } /* func applyGrayScaleFilter(image: UIImage?) -> UIImage? { guard let ciImage = image?.ciImage else { return nil } let filter = CIFilter(name: "CIColorControls", parameters: ["inputImage" : ciImage, "inputContrast": NSNumber(1.0), "inputSaturation": NSNumber(0.0), "inputBrightness": NSNumber(0.0)]) guard let out = filter?.outputImage else { return nil } return UIImage(ciImage: out) } */ func filter(image: UIImage) -> UIImage? { guard let ciImage = CIImage(image: image) else { return image } if filter == .document { let imageFilter = ciImage.applyingFilter("CIColorControls", parameters: ["inputSaturation": 0, "inputContrast": 1.1]).applyingFilter("CIDocumentEnhancer", parameters: ["inputAmount": 5]) let context: CIContext = CIContext(options: nil) let cgImage: CGImage = context.createCGImage(imageFilter, from: imageFilter.extent)! let image: UIImage = UIImage(cgImage: cgImage) return image } return image } // destinationIndexPath: indexpath of the collection view where the user drops the element // collectionView: collectionView in which reordering needs to be done. func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) { let items = coordinator.items if items.count == 1, let item = items.first, let sourceIndexPath = item.sourceIndexPath { var dIndexPath = destinationIndexPath if dIndexPath.row >= collectionView.numberOfItems(inSection: 0) { dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1 } collectionView.performBatchUpdates({ if collectionView === collectionViewDestination { imagesDestination.remove(at: sourceIndexPath.row) imagesDestination.insert((item.dragItem.localObject as? UIImage)!, at: dIndexPath.row) let fileName = itemsDestination[sourceIndexPath.row] itemsDestination.remove(at: sourceIndexPath.row) itemsDestination.insert(fileName, at: dIndexPath.row) } else { itemsSource.remove(at: sourceIndexPath.row) itemsSource.insert((item.dragItem.localObject as? String)!, at: dIndexPath.row) } collectionView.deleteItems(at: [sourceIndexPath]) collectionView.insertItems(at: [dIndexPath]) }) coordinator.drop(items.first!.dragItem, toItemAt: dIndexPath) } } func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) { collectionView.performBatchUpdates({ var indexPaths: [IndexPath] = [] for (index, item) in coordinator.items.enumerated() { let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section) if collectionView === collectionViewDestination { let fileName = (item.dragItem.localObject as? String)! let fileNamePathAt = CCUtility.getDirectoryScan() + "/" + fileName guard let data = try? Data(contentsOf: URL(fileURLWithPath: fileNamePathAt)), let image = UIImage(data: data) else { return } imagesDestination.insert(image, at: indexPath.row) itemsDestination.insert(fileName, at: indexPath.row) } else { // NOT PERMITTED return } indexPaths.append(indexPath) } collectionView.insertItems(at: indexPaths) }) } @objc func handleLongPressGesture(recognizer: UIGestureRecognizer) { if recognizer.state == UIGestureRecognizer.State.began { self.becomeFirstResponder() let pasteboard = UIPasteboard.general if let recognizerView = recognizer.view, let recognizerSuperView = recognizerView.superview, pasteboard.hasImages { UIMenuController.shared.menuItems = [UIMenuItem(title: "Paste", action: #selector(pasteImage))] UIMenuController.shared.showMenu(from: recognizerSuperView, rect: recognizerView.frame) } // TIP dismissTip() } } @objc func pasteImage() { let pasteboard = UIPasteboard.general if pasteboard.hasImages { guard let image = pasteboard.image?.fixedOrientation() else { return } let fileName = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: true)! let fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName do { try image.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic) } catch { return } loadImage() } } func delete(with imageIndex: Int, sender: Any) { imagesDestination.remove(at: imageIndex) itemsDestination.remove(at: imageIndex) // Save button if imagesDestination.isEmpty { save.isEnabled = false } else { save.isEnabled = true } collectionViewDestination.reloadData() } func rotate(with imageIndex: Int, sender: Any) { let indexPath = IndexPath(row: imageIndex, section: 0) if let cell = collectionViewDestination.cellForItem(at: indexPath) as? NCScanCell { var image = imagesDestination[imageIndex] image = image.rotate(radians: .pi / 2)! imagesDestination[imageIndex] = image cell.customImageView.image = image } } } extension NCScan: EasyTipViewDelegate { // TIP func easyTipViewDidTap(_ tipView: EasyTipView) { NCManageDatabase.shared.addTip(NCGlobal.shared.tipNCScanAddImage) } func easyTipViewDidDismiss(_ tipView: EasyTipView) { } func dismissTip() { NCManageDatabase.shared.addTip(NCGlobal.shared.tipNCScanAddImage) self.tipView?.dismiss() } }