123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- //
- // PreviewAttachmentImageVideo.swift
- // Qmera
- //
- // Created by Akhmad Al Qindi Irsyam on 08/09/21.
- //
- import UIKit
- import AVKit
- import AVFoundation
- protocol PreviewAttachmentImageVideoDelegate : NSObjectProtocol {
- func sendChatFromPreviewImage(message_text: String, attachment_flag: String, image_id: String, video_id: String, thumb_id: String, viewController: UIViewController)
- }
- class PreviewAttachmentImageVideo: UIViewController, UIScrollViewDelegate, UITextViewDelegate {
- @IBOutlet var imagePreview: UIImageView!
- @IBOutlet var buttonSend: UIButton!
- @IBOutlet var textFieldSend: UITextView!
- @IBOutlet var buttonCancel: UIButton!
- @IBOutlet var constraintViewTextField: NSLayoutConstraint!
- @IBOutlet var heightTextFieldSend: NSLayoutConstraint!
- @IBOutlet var constraintButtonSend: NSLayoutConstraint!
- @IBOutlet var scrollViewImage: UIScrollView!
- @IBOutlet weak var buttonAckConfidential: UIButton!
- @IBOutlet weak var constraintLeftTextField: NSLayoutConstraint!
- var imageVideoData: [UIImagePickerController.InfoKey: Any]?
- var image: UIImage?
- var currentTextTextField: String?
- var delegate: PreviewAttachmentImageVideoDelegate?
- var isHiddenTextField = false
- var fromCopy = false
- var isConfidential = false
- var isAck = false
- var isGroup = false
- var isCC = false
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- if (imageVideoData != nil) {
- if (imageVideoData![.mediaType] as! String == "public.movie") {
- do {
- let asset = AVURLAsset(url: imageVideoData![.mediaURL] as! URL, options: nil)
- let imgGenerator = AVAssetImageGenerator(asset: asset)
- imgGenerator.appliesPreferredTrackTransform = true
- let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
- let thumbnail = UIImage(cgImage: cgImage)
- imagePreview.image = thumbnail
- let symbolPlay = UIImageView(image: UIImage(systemName: "play.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50, weight: .bold, scale: .default)))
- imagePreview.addSubview(symbolPlay)
- symbolPlay.tintColor = .black.withAlphaComponent(0.5)
- symbolPlay.translatesAutoresizingMaskIntoConstraints = false
- symbolPlay.centerXAnchor.constraint(equalTo: imagePreview.centerXAnchor).isActive = true
- symbolPlay.centerYAnchor.constraint(equalTo: imagePreview.centerYAnchor).isActive = true
- let objectTap = ObjectGesture(target: self, action: #selector(previewImageVideoTapped(_:)))
- scrollViewImage.addGestureRecognizer(objectTap)
- objectTap.videoURL = imageVideoData![.mediaURL] as? NSURL
- } catch let error {
- print("*** Error generating thumbnail: \(error.localizedDescription)")
- }
- } else {
- imagePreview.image = imageVideoData![.originalImage] as? UIImage
- }
- } else {
- imagePreview.image = image
- }
-
- if ((imageVideoData != nil && imageVideoData![.mediaType] as! String == "public.image") || isHiddenTextField) {
- scrollViewImage.maximumZoomScale = 4
- scrollViewImage.minimumZoomScale = 1
- scrollViewImage.delegate = self
- }
-
- if (isHiddenTextField) {
- textFieldSend.removeFromSuperview()
- buttonSend.removeFromSuperview()
- buttonAckConfidential.removeFromSuperview()
- } else {
- buttonSend.setImage(resizeImage(image: UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
-
- buttonSend.circle()
- buttonSend.addTarget(self, action: #selector(sendTapped), for: .touchUpInside)
- if isCC {
- buttonAckConfidential.isHidden = true
- constraintLeftTextField.constant = 20
- } else {
- buttonAckConfidential.circle()
- buttonAckConfidential.addTarget(self, action: #selector(showChooserACKConfidential), for: .touchUpInside)
- let imageConfidential = resizeImage(image: UIImage(named: "confidential_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal)
- let imageAck = resizeImage(image: UIImage(named: "ack_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal)
- if isAck {
- buttonAckConfidential.setImage(imageAck, for: .normal)
- } else if isConfidential {
- buttonAckConfidential.setImage(imageConfidential, for: .normal)
- }
- }
-
- textFieldSend.layer.cornerRadius = textFieldSend.maxCornerRadius()
- textFieldSend.layer.borderWidth = 1.0
- if (currentTextTextField == "" || currentTextTextField == nil) {
- textFieldSend.text = "Send message".localized()
- textFieldSend.textColor = UIColor.lightGray
- } else {
- textFieldSend.text = currentTextTextField
- }
- textFieldSend.textContainerInset = UIEdgeInsets(top: 12, left: 20, bottom: 12, right: 40)
- textFieldSend.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.5).cgColor
- textFieldSend.font = UIFont.systemFont(ofSize: 12)
- textFieldSend.delegate = self
- textFieldSend.allowsEditingTextAttributes = true
-
- let center: NotificationCenter = NotificationCenter.default
- center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
- center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
-
- let dismissKeyboard = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
- view.addGestureRecognizer(dismissKeyboard)
- }
-
- buttonCancel.circle()
- buttonCancel.backgroundColor = .secondaryColor.withAlphaComponent(0.4)
- buttonCancel.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
- }
-
- @objc func showChooserACKConfidential() {
- let alertController = UIAlertController(title: "Message Mode".localized(), message: "Select".localized() + " " + "Message Mode".localized(), preferredStyle: .actionSheet)
- if !self.isGroup {
- let imageConfidential = resizeImage(image: UIImage(named: "confidential_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal)
- let confidentialAction = UIAlertAction(title: "Confidential Message".localized(), style: .default, handler: { (UIAlertAction) in
- if !self.isConfidential {
- self.isConfidential = true
- self.buttonAckConfidential.setImage(imageConfidential, for: .normal)
- }
- if self.isAck {
- self.isAck = false
- }
- self.setPreviousVariableMessageMode()
- })
- confidentialAction.setValue(imageConfidential, forKey: "image")
- alertController.addAction(confidentialAction)
- }
- let imageAck = resizeImage(image: UIImage(named: "ack_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal)
- let ackAction = UIAlertAction(title: "Confirmation Message".localized(), style: .default, handler: { (UIAlertAction) in
- if !self.isAck {
- self.isAck = true
- self.buttonAckConfidential.setImage(imageAck, for: .normal)
- }
- if !self.isGroup {
- if self.isConfidential {
- self.isConfidential = false
- }
- }
- self.setPreviousVariableMessageMode()
- })
- ackAction.setValue(imageAck, forKey: "image")
- alertController.addAction(ackAction)
- alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: { (UIAlertAction) in
- if !self.isGroup {
- self.isConfidential = false
- }
- self.isAck = false
- self.buttonAckConfidential.setImage(UIImage(systemName: "gearshape.fill", withConfiguration: UIImage.SymbolConfiguration(scale: .large))?.withTintColor(.white).withRenderingMode(.alwaysTemplate), for: .normal)
- self.setPreviousVariableMessageMode()
- }))
- self.present(alertController, animated: true, completion: nil)
- }
-
- func setPreviousVariableMessageMode() {
- let stack = self.presentingViewController as! UINavigationController
- let vc = stack.viewControllers[stack.viewControllers.count - 1]
- if vc is EditorPersonal {
- let editorVc = vc as! EditorPersonal
- editorVc.setAckConfidential(isAck: self.isAck, isConfidential: self.isConfidential)
- } else {
- let editorVc = vc as! EditorGroup
- editorVc.setAckConfidential(isAck: self.isAck, isConfidential: self.isConfidential)
- }
- }
-
- func textViewDidChange(_ textView: UITextView) {
- textView.attributedText = textView.text.richText(isEditing: true)
- }
-
- func textViewDidBeginEditing(_ textView: UITextView) {
- if textView.textColor == UIColor.lightGray {
- textView.text = nil
- textView.textColor = UIColor.black
- }
- }
-
- func textViewDidEndEditing(_ textView: UITextView) {
- if textView.text.isEmpty {
- textView.text = "Send message".localized()
- textView.textColor = UIColor.lightGray
- }
- }
-
- func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
- let cursorPosition = textView.caretRect(for: self.textFieldSend.selectedTextRange!.start).origin
- let currentLine = Int(cursorPosition.y / self.textFieldSend.font!.lineHeight)
- UIView.animate(withDuration: 0.3) {
- if currentLine == 0 {
- self.heightTextFieldSend.constant = 40
- } else if currentLine < 4 {
- self.heightTextFieldSend.constant = self.textFieldSend.contentSize.height// Padding
- }
- }
- return true
- }
-
- @objc func previewImageVideoTapped(_ sender: ObjectGesture) {
- let player = AVPlayer(url: sender.videoURL! as URL)
- let playerVC = AVPlayerViewController()
- playerVC.player = player
- playerVC.modalPresentationStyle = .custom
- self.present(playerVC, animated: true, completion: nil)
- }
-
- func viewForZooming(in scrollView: UIScrollView) -> UIView? {
- return imagePreview
- }
-
- func scrollViewDidZoom(_ scrollView: UIScrollView) {
- if scrollViewImage.zoomScale > 1 {
- if let image = imagePreview.image {
- let ratioW = imagePreview.frame.width / image.size.width
- let ratioH = imagePreview.frame.height / image.size.height
-
- let ratio = ratioW < ratioH ? ratioW : ratioH
- let newWidth = image.size.width * ratio
- let newHeight = image.size.height * ratio
-
- let conditionLeft = newWidth*scrollViewImage.zoomScale > imagePreview.frame.width
-
- let left = 0.5 * (conditionLeft ? newWidth - imagePreview.frame.width : (scrollViewImage.frame.width - scrollViewImage.contentSize.width))
-
- let conditionTop = newHeight*scrollViewImage.zoomScale > imagePreview.frame.height
-
- let top = 0.01 * (conditionTop ? newHeight - imagePreview.frame.width : (scrollViewImage.frame.height - scrollViewImage.contentSize.height))
-
- scrollViewImage.contentInset = UIEdgeInsets(top: top, left: left, bottom: top, right: left)
- }
- } else {
- scrollViewImage.contentInset = .zero
- }
- }
-
- @objc func dismissKeyboard() {
- textFieldSend.resignFirstResponder() // dismiss keyoard
- }
-
- @objc func keyboardWillShow(notification: NSNotification) {
- let info:NSDictionary = notification.userInfo! as NSDictionary
- let keyboardSize = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
-
- let keyboardHeight: CGFloat = keyboardSize.height
-
- let _: CGFloat = info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat
-
- UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseInOut, animations: {
- self.constraintViewTextField.constant = keyboardHeight + 10
- self.constraintButtonSend.constant = keyboardHeight + 10
- }, completion: nil)
- }
-
- @objc func keyboardWillHide(notification: NSNotification) {
- UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
- self.constraintViewTextField.constant = 20
- self.constraintButtonSend.constant = 20
- }, completion: nil)
-
- }
-
- @objc func sendTapped() {
- if fromCopy || (imageVideoData![.mediaType] as! String == "public.image") {
- var originalImageName = ""
- if (fromCopy) {
- originalImageName = "\(Date().currentTimeMillis())_copyImage"
- } else if (imageVideoData![.imageURL] == nil) {
- originalImageName = "\(Date().currentTimeMillis())_takeImage"
- } else {
- let urlImage = (imageVideoData![.imageURL] as! NSURL).absoluteString
- originalImageName = (urlImage! as NSString).lastPathComponent
- }
- let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
- let compressedImageName = "THUMB-Qmera_image_\(originalImageName)"
- let thumbName = "THUMB_Qmera_image_\(originalImageName)"
- let fileURL = documentsDirectory.appendingPathComponent(compressedImageName)
- var compressedImage:Data?
- if (fromCopy) {
- compressedImage = image!.jpegData(compressionQuality: 1.0)
- } else {
- compressedImage = (imageVideoData![.originalImage] as! UIImage).jpegData(compressionQuality: 1.0)
- }
- if let data = compressedImage,
- !FileManager.default.fileExists(atPath: fileURL.path) {
- do {
- try data.write(to: fileURL)
- print("file saved")
- } catch {
- print("error saving file:", error)
- }
- }
- let thumbImage = UIImage(data: compressedImage!)
- let fileURLTHUMB = documentsDirectory.appendingPathComponent(thumbName)
- if let dataThumb = thumbImage!.jpegData(compressionQuality: 0.25),
- !FileManager.default.fileExists(atPath: fileURLTHUMB.path) {
- do {
- try dataThumb.write(to: fileURLTHUMB)
- print("thumb saved")
- } catch {
- print("error saving file:", error)
- }
- }
- self.dismiss(animated: true, completion: nil)
- if (textFieldSend.text!.trimmingCharacters(in: .whitespacesAndNewlines) == "Send message".localized() && textFieldSend.textColor == UIColor.lightGray) {
- delegate!.sendChatFromPreviewImage(message_text: "", attachment_flag: "1", image_id: compressedImageName, video_id: "", thumb_id: thumbName, viewController: self)
- } else {
- delegate!.sendChatFromPreviewImage(message_text: textFieldSend.text!, attachment_flag: "1", image_id: compressedImageName, video_id: "", thumb_id: thumbName, viewController: self)
- }
- } else {
- guard var dataVideo = try? Data(contentsOf: imageVideoData![.mediaURL] as! URL) else {
- return
- }
- let sizeOfVideo = Double(dataVideo.count / 1048576)
- if (sizeOfVideo > 10.0) {
- let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + UUID().uuidString + ".mp4")
- compressVideo(inputURL: imageVideoData![.mediaURL] as! URL,
- outputURL: compressedURL) { exportSession in
- guard let session = exportSession else {
- return
- }
-
- switch session.status {
- case .unknown:
- break
- case .waiting:
- break
- case .exporting:
- break
- case .completed:
- guard let compressedData = try? Data(contentsOf: compressedURL) else {
- return
- }
- dataVideo = compressedData
- case .failed:
- break
- case .cancelled:
- break
- @unknown default:
- break
- }
- }
- }
- let urlVideo = (imageVideoData![.mediaURL] as! NSURL).absoluteString
- let originalVideoName = (urlVideo! as NSString).lastPathComponent
- let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
- let renamedVideoName = "Qmera_video_\(originalVideoName)"
- let thumbName = "THUMB_Qmera_video_\(originalVideoName)"
- let fileURL = documentsDirectory.appendingPathComponent(renamedVideoName)
- if !FileManager.default.fileExists(atPath: fileURL.path) {
- do {
- try dataVideo.write(to: fileURL)
- print("file saved")
- } catch {
- print("error saving file:", error)
- }
- }
- let dataThumbVideo = imagePreview.image!.jpegData(compressionQuality: 1.0)
- let fileURLTHUMB = documentsDirectory.appendingPathComponent(thumbName)
- if !FileManager.default.fileExists(atPath: fileURLTHUMB.path) {
- do {
- try dataThumbVideo!.write(to: fileURLTHUMB)
- print("thumb saved")
- } catch {
- print("error saving file:", error)
- }
- }
- self.dismiss(animated: true, completion: nil)
- if (textFieldSend.text!.trimmingCharacters(in: .whitespacesAndNewlines) == "Send message".localized() && textFieldSend.textColor == UIColor.lightGray) {
- delegate!.sendChatFromPreviewImage(message_text: "", attachment_flag: "2", image_id: "", video_id: renamedVideoName, thumb_id: thumbName, viewController: self)
- } else {
- delegate!.sendChatFromPreviewImage(message_text: textFieldSend.text!, attachment_flag: "2", image_id: "", video_id: renamedVideoName, thumb_id: thumbName, viewController: self)
- }
- }
- }
-
- func compressVideo(inputURL: URL,
- outputURL: URL,
- handler:@escaping (_ exportSession: AVAssetExportSession?) -> Void) {
- let urlAsset = AVURLAsset(url: inputURL, options: nil)
- guard let exportSession = AVAssetExportSession(asset: urlAsset,
- presetName: AVAssetExportPresetMediumQuality) else {
- handler(nil)
-
- return
- }
-
- exportSession.outputURL = outputURL
- exportSession.outputFileType = .mp4
- exportSession.exportAsynchronously {
- handler(exportSession)
- }
- }
-
- @objc func cancelTapped() {
- self.dismiss(animated: true, completion: nil)
- }
- }
|