linphone-ios/Classes/Swift/Chat/Views/ChatConversationTableViewSwift.swift

801 lines
33 KiB
Swift

/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* 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 <http://www.gnu.org/licenses/>.
*/
import UIKit
import Foundation
import linphonesw
import DropDown
import QuickLook
import SwipeCellKit
class ChatConversationTableViewSwift: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, QLPreviewControllerDelegate, QLPreviewControllerDataSource, SwipeCollectionViewCellDelegate {
static let compositeDescription = UICompositeViewDescription(ChatConversationTableViewSwift.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription }
lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
return collectionView
}()
var menu: DropDown? = nil
var basic :Bool = false
var floatingScrollButton : UIButton?
var scrollBadge : UILabel?
var floatingScrollBackground : UIButton?
var previewItems : [QLPreviewItem?] = []
var afterPreviewIndex = -1
override func viewDidLoad() {
super.viewDidLoad()
self.initView()
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
self.collectionView.backgroundColor = VoipTheme.backgroundWhiteBlack.get()
self.collectionView.reloadData()
}
ChatConversationTableViewModel.sharedModel.refreshIndexPath.observe { index in
self.collectionView.reloadData()
}
ChatConversationTableViewModel.sharedModel.onClickIndexPath.observe { index in
self.onGridClick(indexMessage: ChatConversationTableViewModel.sharedModel.onClickMessageIndexPath, index: index!)
}
ChatConversationTableViewModel.sharedModel.editModeOn.observe { mode in
self.collectionView.reloadData()
}
collectionView.isUserInteractionEnabled = true
collectionView.keyboardDismissMode = .interactive
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func initView(){
basic = isBasicChatRoom(ChatConversationTableViewModel.sharedModel.chatRoom?.getCobject)
view.addSubview(collectionView)
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MultilineMessageCell.self, forCellWithReuseIdentifier: MultilineMessageCell.reuseId)
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).estimatedItemSize = UICollectionViewFlowLayout.automaticSize
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).minimumLineSpacing = 2
collectionView.transform = CGAffineTransform(scaleX: 1, y: -1)
}
override func viewDidAppear(_ animated: Bool) {
createFloatingButton()
if ChatConversationTableViewModel.sharedModel.getNBMessages() > 0 {
scrollToBottom(animated: false)
}
NotificationCenter.default.addObserver(self, selector: #selector(self.receivePresenceNotification(notification:)), name: Notification.Name("LinphoneFriendPresenceUpdate"), object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
if ChatConversationTableViewModel.sharedModel.getNBMessages() > 0 {
scrollToBottom(animated: false, async:false)
}
NotificationCenter.default.removeObserver(self, name: Notification.Name("LinphoneFriendPresenceUpdate"), object: nil)
NotificationCenter.default.removeObserver(self)
}
@objc func receivePresenceNotification(notification: NSNotification) {
if (notification.name.rawValue == "LinphoneFriendPresenceUpdate"){
collectionView.reloadData()
}
}
func scrollToMessage(message: ChatMessage){
let messageIndex = ChatConversationTableViewModel.sharedModel.getIndexMessage(message: message)
self.collectionView.scrollToItem(at: IndexPath(row: messageIndex, section: 0), at: .bottom, animated: false)
}
func scrollToBottom(animated: Bool, async: Bool = true){
if (async) {
DispatchQueue.main.async{
self.collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: animated)
}
} else {
self.collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: animated)
}
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
if self.floatingScrollButton != nil && self.floatingScrollBackground != nil {
self.floatingScrollButton!.isHidden = true
self.floatingScrollBackground!.isHidden = true
}
if scrollBadge != nil {
scrollBadge!.text = "0"
}
}
func refreshDataAfterForeground(){
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
func refreshData(isOutgoing: Bool){
if (ChatConversationTableViewModel.sharedModel.getNBMessages() > 1){
let isDisplayingBottomOfTable = collectionView.contentOffset.y <= 20
if ChatConversationTableViewModel.sharedModel.getNBMessages() < 4 {
collectionView.reloadData()
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
} else if isDisplayingBottomOfTable {
if self.collectionView.numberOfItems(inSection: 0) > 2 {
self.collectionView.scrollToItem(at: IndexPath(item: 1, section: 0), at: .top, animated: false)
}
collectionView.reloadData()
self.scrollToBottom(animated: true)
} else if !isOutgoing {
if !collectionView.indexPathsForVisibleItems.isEmpty {
let selectedCellIndex = collectionView.indexPathsForVisibleItems.sorted().first!
let selectedCell = collectionView.cellForItem(at: selectedCellIndex)
let visibleRect = collectionView.convert(collectionView.bounds, to: selectedCell)
UIView.performWithoutAnimation {
collectionView.reloadData()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2){
let newSelectedCell = self.collectionView.cellForItem(at: IndexPath(row: selectedCellIndex.row + 1, section: 0))
let updatedVisibleRect = self.collectionView.convert(self.collectionView.bounds, to: newSelectedCell)
var contentOffset = self.collectionView.contentOffset
contentOffset.y = contentOffset.y + (visibleRect.origin.y - updatedVisibleRect.origin.y)
self.collectionView.contentOffset = contentOffset
}
}
scrollBadge!.isHidden = false
scrollBadge!.text = "\(ChatConversationViewModel.sharedModel.chatRoom?.unreadMessagesCount ?? 0)"
}
} else {
collectionView.reloadData()
self.scrollToBottom(animated: false)
}
if ChatConversationTableViewModel.sharedModel.editModeOn.value! {
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.insert(false, at: 0)
}
}else{
collectionView.reloadData()
if(ChatConversationViewModel.sharedModel.chatRoom != nil){
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
}
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffsetY = scrollView.contentOffset.y
if contentOffsetY <= 20{
if floatingScrollButton != nil && floatingScrollBackground != nil {
floatingScrollButton?.isHidden = true
floatingScrollBackground?.isHidden = true
scrollBadge?.text = "0"
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
}
} else {
if floatingScrollButton != nil && floatingScrollBackground != nil {
floatingScrollButton?.isHidden = false
floatingScrollBackground?.isHidden = false;
if(scrollBadge?.text == "0"){
scrollBadge?.isHidden = true
}
}
}
}
// MARK: - UICollectionViewDataSource -
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MultilineMessageCell.reuseId, for: indexPath) as! MultilineMessageCell
cell.delegate = self
if let event = ChatConversationTableViewModel.sharedModel.getMessage(index: indexPath.row){
if(ChatConversationTableViewModel.sharedModel.editModeOn.value! && indexPath.row >= ChatConversationTableViewModel.sharedModel.messageListSelected.value!.count){
for _ in ChatConversationTableViewModel.sharedModel.messageListSelected.value!.count...indexPath.row {
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.append(false)
}
}
cell.configure(event: event, selfIndexPathConfigure: indexPath, editMode: ChatConversationTableViewModel.sharedModel.editModeOn.value!, selected: ChatConversationTableViewModel.sharedModel.editModeOn.value! ? ChatConversationTableViewModel.sharedModel.messageListSelected.value![indexPath.row] : false)
if (event.chatMessage != nil && ChatConversationViewModel.sharedModel.chatRoom != nil){
cell.onLongClickOneClick {
if(cell.chatMessage != nil && ChatConversationViewModel.sharedModel.chatRoom != nil){
self.initDataSource(message: cell.chatMessage!)
self.tapChooseMenuItemMessage(contentViewBubble: cell.contentViewBubble, event: cell.eventMessage!, preContentSize: cell.preContentViewBubble.frame.size.height)
}
}
}
if (!cell.replyContent.isHidden && event.chatMessage?.replyMessage != nil){
cell.replyContent.onClick {
self.scrollToMessage(message: (cell.chatMessage?.replyMessage)!)
}
}
cell.imageViewBubble.onClick {
if (!cell.imageViewBubble.isHidden || !cell.imageVideoViewBubble.isHidden) && cell.chatMessage != nil && !cell.chatMessage!.isFileTransferInProgress {
self.onImageClick(chatMessage: cell.chatMessage!, index: indexPath.row)
}
}
cell.imageVideoViewBubble.onClick {
if (!cell.imageViewBubble.isHidden || !cell.imageVideoViewBubble.isHidden) && cell.chatMessage != nil && !cell.chatMessage!.isFileTransferInProgress {
self.onImageClick(chatMessage: cell.chatMessage!, index: indexPath.row)
}
}
}
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
return cell
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let customCell = cell as! MultilineMessageCell
if customCell.isPlayingVoiceRecording {
AudioPlayer.stopSharedPlayer()
}
if customCell.ephemeralTimer != nil {
customCell.ephemeralTimer?.invalidate()
}
if customCell.chatMessageDelegate != nil {
customCell.chatMessage?.removeDelegate(delegate: customCell.chatMessageDelegate!)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ChatConversationTableViewModel.sharedModel.getNBMessages()
}
func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
let message = ChatConversationTableViewModel.sharedModel.getMessage(index: indexPath.row)
if orientation == .left {
if message?.chatMessage != nil {
let replyAction = SwipeAction(style: .default, title: "Reply") { action, indexPath in
self.replyMessage(message: (message?.chatMessage)!)
}
return [replyAction]
} else {
return nil
}
} else {
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
self.deleteMessage(message: message!)
}
return [deleteAction]
}
}
func collectionView(_ collectionView: UICollectionView, editActionsOptionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
var options = SwipeOptions()
if orientation == .left {
options.expansionStyle = .selection
}
return options
}
func isBasicChatRoom(_ room: OpaquePointer?) -> Bool {
if room == nil {
return true
}
let charRoomBasic = ChatRoom.getSwiftObject(cObject: room!)
let isBasic = charRoomBasic.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesBasic.rawValue))
return isBasic
}
func tapChooseMenuItemMessage(contentViewBubble: UIView, event: EventLog, preContentSize: CGFloat) {
menu!.anchorView = view
menu!.width = 240
let coordinateMin = contentViewBubble.convert(contentViewBubble.frame.origin, to: view)
let coordinateMax = contentViewBubble.convert(CGPoint(x: contentViewBubble.frame.maxX - 40, y: contentViewBubble.frame.maxY), to: view)
if (coordinateMax.y + CGFloat(menu!.dataSource.count * 44) - preContentSize < view.frame.maxY) {
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: coordinateMax.y - preContentSize)
} else if ((coordinateMax.y + CGFloat(menu!.dataSource.count * 44) > view.frame.maxY) && coordinateMin.y > CGFloat(menu!.dataSource.count * 44) + (preContentSize * 2)) {
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: coordinateMin.y - (preContentSize * 2) - CGFloat(menu!.dataSource.count * 44))
} else {
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: 0)
}
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
view.contentMessageView.messageView.endEditing(true)
menu!.show()
menu!.selectionAction = { [weak self] (index: Int, item: String) in
guard let _ = self else { return }
switch item {
case VoipTexts.bubble_chat_dropDown_emojis:
self!.copyMessage(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_resend:
self!.resendMessage(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_copy_text:
self!.copyMessage(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_forward:
self!.forwardMessage(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_reply:
self!.replyMessage(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_infos:
if !event.chatMessage!.isFileTransferInProgress && !(event.chatMessage!.state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue || event.chatMessage!.state.rawValue == LinphoneChatMessageStateFileTransferError.rawValue) {
self!.infoMessage(event: event)
}
case VoipTexts.bubble_chat_dropDown_add_to_contact:
self!.addToContacts(message: event.chatMessage!)
case VoipTexts.bubble_chat_dropDown_delete:
self!.deleteMessage(message: event)
default:
Log.e("Error Default tapChooseMenuItemMessage ChatConversationTableViewSwift")
}
self!.menu!.clearSelection()
}
}
func initDataSource(message: ChatMessage) {
menu = {
let menu = DropDown()
menu.dataSource = [""]
let images = [
"menu_resend_default",
"menu_copy_text_default",
"menu_forward_default",
"menu_reply_default",
"menu_info",
"contact_add_default",
"menu_delete",
"menu_info"
]
menu.cellNib = UINib(nibName: "DropDownCell", bundle: nil)
menu.customCellConfiguration = { index, title, cell in
guard let cell = cell as? MyCell else {
return
}
if(index < images.count){
switch menu.dataSource[index] {
case VoipTexts.bubble_chat_dropDown_emojis:
cell.myImageView.image = UIImage(named: images[7])
cell.myEmojisView.isHidden = false
cell.myImageView.isHidden = true
cell.optionLabel.isHidden = true
switch message.ownReaction?.body {
case "❤️":
cell.myEmojiButton1.layer.cornerRadius = 10
cell.myEmojiButton1.backgroundColor = VoipTheme.light_grey_color
case "👍":
cell.myEmojiButton2.layer.cornerRadius = 10
cell.myEmojiButton2.backgroundColor = VoipTheme.light_grey_color
case "😂":
cell.myEmojiButton3.layer.cornerRadius = 10
cell.myEmojiButton3.backgroundColor = VoipTheme.light_grey_color
case "😮":
cell.myEmojiButton4.layer.cornerRadius = 10
cell.myEmojiButton4.backgroundColor = VoipTheme.light_grey_color
case "😢":
cell.myEmojiButton5.layer.cornerRadius = 10
cell.myEmojiButton5.backgroundColor = VoipTheme.light_grey_color
default:
print("No reaction")
}
cell.myEmojiButton1.onClick {
do {
let messageReaction = try message.ownReaction?.body != "❤️" ? message.createReaction(utf8Reaction: "❤️") : message.createReaction(utf8Reaction: "")
messageReaction.send()
self.menu!.clearSelection()
self.menu?.removeFromSuperview()
} catch {
Log.e(error.localizedDescription)
}
}
cell.myEmojiButton2.onClick {
do {
let messageReaction = try message.ownReaction?.body != "👍" ? message.createReaction(utf8Reaction: "👍") : message.createReaction(utf8Reaction: "")
messageReaction.send()
self.menu!.clearSelection()
self.menu?.removeFromSuperview()
} catch {
Log.e(error.localizedDescription)
}
}
cell.myEmojiButton3.onClick {
do {
let messageReaction = try message.ownReaction?.body != "😂" ? message.createReaction(utf8Reaction: "😂") : message.createReaction(utf8Reaction: "")
messageReaction.send()
self.menu!.clearSelection()
self.menu?.removeFromSuperview()
} catch {
Log.e(error.localizedDescription)
}
}
cell.myEmojiButton4.onClick {
do {
let messageReaction = try message.ownReaction?.body != "😮" ? message.createReaction(utf8Reaction: "😮") : message.createReaction(utf8Reaction: "")
messageReaction.send()
self.menu!.clearSelection()
self.menu?.removeFromSuperview()
} catch {
Log.e(error.localizedDescription)
}
}
cell.myEmojiButton5.onClick {
do {
let messageReaction = try message.ownReaction?.body != "😢" ? message.createReaction(utf8Reaction: "😢") : message.createReaction(utf8Reaction: "")
messageReaction.send()
self.menu!.clearSelection()
self.menu?.removeFromSuperview()
} catch {
Log.e(error.localizedDescription)
}
}
case VoipTexts.bubble_chat_dropDown_resend:
if #available(iOS 13.0, *) {
cell.myImageView.image = UIImage(named: images[0])!.withTintColor(.darkGray)
} else {
cell.myImageView.image = UIImage(named: images[0])
}
case VoipTexts.bubble_chat_dropDown_copy_text:
cell.myImageView.image = UIImage(named: images[1])
case VoipTexts.bubble_chat_dropDown_forward:
cell.myImageView.image = UIImage(named: images[2])
case VoipTexts.bubble_chat_dropDown_reply:
cell.myImageView.image = UIImage(named: images[3])
case VoipTexts.bubble_chat_dropDown_infos:
cell.myImageView.image = UIImage(named: images[4])
case VoipTexts.bubble_chat_dropDown_add_to_contact:
cell.myImageView.image = UIImage(named: images[5])
case VoipTexts.bubble_chat_dropDown_delete:
cell.myImageView.image = UIImage(named: images[6])
default:
cell.myImageView.image = UIImage(named: images[7])
}
}
}
return menu
}()
menu!.dataSource.removeAll()
let state = message.state
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_emojis)
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue || state.rawValue == LinphoneChatMessageStateFileTransferError.rawValue) {
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_resend)
}
if (message.utf8Text != "" && !ICSBubbleView.isConferenceInvitationMessage(cmessage: message.getCobject!)) {
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_copy_text)
}
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_forward)
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_reply)
let chatroom = ChatConversationViewModel.sharedModel.chatRoom
if chatroom != nil {
if (chatroom!.nbParticipants > 1) {
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_infos)
}
let isOneToOneChat = ChatConversationViewModel.sharedModel.chatRoom!.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesOneToOne.rawValue))
if (!message.isOutgoing && FastAddressBook.getContactWith(message.fromAddress?.getCobject) == nil
&& !isOneToOneChat && !ConfigManager.instance().lpConfigBoolForKey(key: "read_only_native_address_book")) {
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_add_to_contact)
}
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_delete)
}
}
func resendMessage(message: ChatMessage){
if ((linphone_core_is_network_reachable(LinphoneManager.getLc()) == 0)) {
PhoneMainView.instance().present(LinphoneUtils.networkErrorView("send a message"), animated: true)
return;
}else{
message.send()
}
}
func copyMessage(message: ChatMessage){
UIPasteboard.general.string = message.utf8Text
}
func forwardMessage(message: ChatMessage){
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
view.pendingForwardMessage = message.getCobject
let viewtoGo: ChatsListView = self.VIEW(ChatsListView.compositeViewDescription())
PhoneMainView.instance().changeCurrentView(viewtoGo.compositeViewDescription())
}
func replyMessage(message: ChatMessage){
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
if (view.contentMessageView.messageView.messageText.textColor == UIColor.lightGray && view.contentMessageView.stackView.arrangedSubviews[3].isHidden && view.contentMessageView.stackView.arrangedSubviews[4].isHidden){
view.contentMessageView.messageView.messageText.becomeFirstResponder()
}
view.initiateReplyView(forMessage: message.getCobject)
}
func infoMessage(event: EventLog){
let view: ChatConversationImdnView = self.VIEW(ChatConversationImdnView.compositeViewDescription())
view.event = event.getCobject
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
}
func addToContacts(message: ChatMessage) {
let addr = message.fromAddress
addr?.clean()
if let lAddress = addr?.asStringUriOnly() {
var normSip = String(utf8String: lAddress)
normSip = normSip?.hasPrefix("sip:") ?? false ? (normSip as NSString?)?.substring(from: 4) : normSip
normSip = normSip?.hasPrefix("sips:") ?? false ? (normSip as NSString?)?.substring(from: 5) : normSip
ContactSelection.setAddAddress(normSip)
ContactSelection.setSelectionMode(ContactSelectionModeEdit)
ContactSelection.enableSipFilter(false)
PhoneMainView.instance().changeCurrentView(ContactsListView.compositeViewDescription())
}
}
func deleteMessage(message: EventLog){
let messageChat = message.chatMessage
if messageChat != nil {
if ChatConversationTableViewModel.sharedModel.editModeOn.value! {
let indexDeletedMessage = ChatConversationTableViewModel.sharedModel.getIndexMessage(message: messageChat!)
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.remove(at: indexDeletedMessage)
ChatConversationTableViewModel.sharedModel.messageSelected.value! -= 1
}
let chatRoom = ChatConversationViewModel.sharedModel.chatRoom
if chatRoom != nil {
chatRoom!.deleteMessage(message: messageChat!)
}
} else {
message.deleteFromDatabase()
}
collectionView.reloadData()
}
func getPreviewItem(filePath: String) -> NSURL{
let url = NSURL(fileURLWithPath: filePath)
return url
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return previewItems.count
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return (previewItems[index] as QLPreviewItem?)!
}
func previewControllerDidDismiss(_ controller: QLPreviewController) {
collectionView.scrollToItem(at: IndexPath(item: afterPreviewIndex, section: 0), at: .centeredVertically, animated: false)
afterPreviewIndex = -1
}
func onImageClick(chatMessage: ChatMessage, index: Int) {
let state = chatMessage.state
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue) {
Log.i("Messsage not delivered")
} else {
if (VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) || ConfigManager.instance().lpConfigBoolForKey(key: "use_in_app_file_viewer_for_non_encrypted_files", section: "app")){
var viewer: MediaViewer = VIEW(MediaViewer.compositeViewDescription())
var image = UIImage()
if chatMessage.contents.filter({$0.isFile}).first!.type == "image" {
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
var plainFile = chatMessage.contents.filter({$0.isFile}).first!.exportPlainFile()
image = UIImage(contentsOfFile: plainFile)!
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
plainFile = ""
}else {
image = UIImage(contentsOfFile: chatMessage.contents.filter({$0.isFile}).first!.filePath!)!
}
}
viewer.imageViewer = image
viewer.imageNameViewer = (chatMessage.contents.filter({$0.isFile}).first!.name!.isEmpty ? "" : chatMessage.contents.filter({$0.isFile}).first!.name)!
viewer.imagePathViewer = chatMessage.contents.filter({$0.isFile}).first!.exportPlainFile()
viewer.contentType = chatMessage.contents.filter({$0.isFile}).first!.type
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
} else {
let previewController = QLPreviewController()
self.previewItems = []
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
var plainFile = chatMessage.contents.filter({$0.isFile}).first?.exportPlainFile()
self.previewItems.append(self.getPreviewItem(filePath: plainFile!))
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
plainFile = ""
}else if chatMessage.contents.filter({$0.isFile}).first?.filePath != nil {
self.previewItems.append(self.getPreviewItem(filePath: (chatMessage.contents.filter({$0.isFile}).first?.filePath)!))
}
afterPreviewIndex = index
previewController.currentPreviewItemIndex = 0
previewController.dataSource = self
previewController.delegate = self
previewController.reloadData()
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
}
}
}
func onGridClick(indexMessage: Int, index: Int) {
let chatMessage = ChatConversationTableViewModel.sharedModel.getMessage(index: indexMessage)?.chatMessage
let state = chatMessage!.state
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue) {
Log.i("Messsage not delivered")
} else {
if (VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) || ConfigManager.instance().lpConfigBoolForKey(key: "use_in_app_file_viewer_for_non_encrypted_files", section: "app")){
var text = ""
var filePathString = VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) ? chatMessage!.contents.filter({$0.isFile})[index].exportPlainFile() : chatMessage!.contents.filter({$0.isFile})[index].filePath
if let urlEncoded = filePathString!.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed){
if !urlEncoded.isEmpty {
if let urlFile = URL(string: "file://" + urlEncoded){
do {
text = try String(contentsOf: urlFile, encoding: .utf8)
let viewer: TextViewer = VIEW(TextViewer.compositeViewDescription())
if chatMessage != nil {
viewer.textViewer = text
viewer.textNameViewer = (chatMessage!.contents.filter({$0.isFile})[index].name!.isEmpty ? "" : chatMessage!.contents.filter({$0.isFile})[index].name)!
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
}
} catch {
var extensionFile = ""
if chatMessage!.contents.filter({$0.isFile})[index].name != nil {
extensionFile = chatMessage!.contents.filter({$0.isFile})[index].name!.lowercased().components(separatedBy: ".").last ?? ""
}
if text == "" && (chatMessage!.contents.filter({$0.isFile})[index].type == "image" || chatMessage!.contents.filter({$0.isFile})[index].type == "video" || chatMessage!.contents.filter({$0.isFile})[index].name!.lowercased().components(separatedBy: ".").last == "pdf" || (["mkv", "avi", "mov", "mp4"].contains(extensionFile))){
let viewer: MediaViewer = VIEW(MediaViewer.compositeViewDescription())
var image = UIImage()
if chatMessage != nil {
if chatMessage!.contents.filter({$0.isFile})[index].type == "image" {
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
var plainFile = chatMessage!.contents.filter({$0.isFile})[index].exportPlainFile()
image = UIImage(contentsOfFile: plainFile)!
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
plainFile = ""
}else {
image = UIImage(contentsOfFile: chatMessage!.contents.filter({$0.isFile})[index].filePath!)!
}
}
viewer.imageViewer = image
viewer.imageNameViewer = (chatMessage!.contents.filter({$0.isFile})[index].name!.isEmpty ? "" : chatMessage!.contents.filter({$0.isFile})[index].name)!
viewer.imagePathViewer = chatMessage!.contents.filter({$0.isFile})[index].exportPlainFile()
viewer.contentType = chatMessage!.contents.filter({$0.isFile})[index].type
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
}
} else {
let exportView = UIAlertController(
title: VoipTexts.chat_message_cant_open_file_in_app_dialog_title,
message: VoipTexts.chat_message_cant_open_file_in_app_dialog_message,
preferredStyle: .alert)
let cancelAction = UIAlertAction(
title: VoipTexts.cancel,
style: .default,
handler: { action in
})
let exportAction = UIAlertAction(
title: VoipTexts.chat_message_cant_open_file_in_app_dialog_export_button,
style: .destructive,
handler: { action in
let previewController = QLPreviewController()
self.previewItems = []
self.previewItems.append(self.getPreviewItem(filePath: filePathString!))
self.afterPreviewIndex = indexMessage
previewController.dataSource = self
previewController.currentPreviewItemIndex = index
previewController.delegate = self
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
})
exportView.addAction(cancelAction)
exportView.addAction(exportAction)
PhoneMainView.instance()!.present(exportView, animated: true)
}
}
}
}
}
/*
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: filePathString)
filePathString = ""
}
*/
} else {
let previewController = QLPreviewController()
self.previewItems = []
chatMessage?.contents.forEach({ content in
if(content.isFile && !content.isVoiceRecording){
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
var plainFile = content.exportPlainFile()
self.previewItems.append(self.getPreviewItem(filePath: plainFile))
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
plainFile = ""
}else {
self.previewItems.append(self.getPreviewItem(filePath: (content.filePath!)))
}
}
})
afterPreviewIndex = indexMessage
previewController.dataSource = self
previewController.currentPreviewItemIndex = index
previewController.delegate = self
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
}
}
}
}