diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.pbxproj b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.pbxproj index 4ca189cc..b6d10fa2 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.pbxproj +++ b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 1E1275C12CAA8DDB0080CB19 /* PSDChatsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1275C02CAA8DDB0080CB19 /* PSDChatsTableView.swift */; }; + 1E1275C32CAA8DEC0080CB19 /* PSDChatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1275C22CAA8DEC0080CB19 /* PSDChatsViewController.swift */; }; + 1E1275C52CAA8E100080CB19 /* PSDCreateChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1275C42CAA8E100080CB19 /* PSDCreateChat.swift */; }; 4B060F2A2732AD8C002E20A7 /* StringHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B060F292732AD8C002E20A7 /* StringHelper.swift */; }; 4B062A832518A8D100B317D3 /* PSDPlaceholderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B062A822518A8D100B317D3 /* PSDPlaceholderMessage.swift */; }; 4B062A882518AC9500B317D3 /* messagePlaceholder@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B062A872518AC9500B317D3 /* messagePlaceholder@3x.png */; }; @@ -293,6 +296,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1E1275C02CAA8DDB0080CB19 /* PSDChatsTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PSDChatsTableView.swift; sourceTree = ""; }; + 1E1275C22CAA8DEC0080CB19 /* PSDChatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PSDChatsViewController.swift; sourceTree = ""; }; + 1E1275C42CAA8E100080CB19 /* PSDCreateChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PSDCreateChat.swift; sourceTree = ""; }; 4B060F292732AD8C002E20A7 /* StringHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringHelper.swift; sourceTree = ""; }; 4B062A822518A8D100B317D3 /* PSDPlaceholderMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSDPlaceholderMessage.swift; sourceTree = ""; }; 4B062A872518AC9500B317D3 /* messagePlaceholder@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "messagePlaceholder@3x.png"; sourceTree = ""; }; @@ -1120,6 +1126,7 @@ 4BB8559E2208559200F7CCE5 /* Requests */ = { isa = PBXGroup; children = ( + 1E1275C42CAA8E100080CB19 /* PSDCreateChat.swift */, 4B5533722264C07B00353941 /* PSDDownloader.swift */, 4B56BE482216CC0E004E6685 /* PSDUploader.swift */, 4BB8559F2208593200F7CCE5 /* URLCreator.swift */, @@ -1139,6 +1146,8 @@ 4BB855A1220865D500F7CCE5 /* chats */ = { isa = PBXGroup; children = ( + 1E1275C22CAA8DEC0080CB19 /* PSDChatsViewController.swift */, + 1E1275C02CAA8DDB0080CB19 /* PSDChatsTableView.swift */, 4BB855B02208741600F7CCE5 /* PSDChatInfoTableViewCell.swift */, ); path = chats; @@ -1455,6 +1464,7 @@ 4B9C205D2451904E004DEF7A /* PSDRowMessage.swift in Sources */, 4B873BB6224BCA8100A96E93 /* PSDPushToken.swift in Sources */, 4B7F139022155F62007C6358 /* String+Date.swift in Sources */, + 1E1275C32CAA8DEC0080CB19 /* PSDChatsViewController.swift in Sources */, 4B66011D223948CE00AA45E6 /* PyrusServiceDeskCustomization.swift in Sources */, 4B9BF878224CBCBC006AD05C /* PSDCopyLabel.swift in Sources */, 4B88C6F722145ACA00BDB304 /* PSDGetChats.swift in Sources */, @@ -1491,6 +1501,7 @@ 7B1E8D58250665F800C1E5AC /* PSDInfoView.swift in Sources */, 4BB6CDC325597E4C004C680A /* PyrusLogger.swift in Sources */, 4B7F350A21F8900A00977C6D /* PSDChatViewController.swift in Sources */, + 1E1275C52CAA8E100080CB19 /* PSDCreateChat.swift in Sources */, 4B6D4A39244E1B6A007C6082 /* AttachmentCollectionView.swift in Sources */, 4B659AFE223FA9E400D79489 /* PSDSpinerTableView.swift in Sources */, 4B82A49A2268B57B00654CE0 /* PSDAttachmentLoadViewControllerInterface.swift in Sources */, @@ -1524,6 +1535,7 @@ 4B7AD4D6250A06C9004E9C48 /* PSDFilesManager.swift in Sources */, 4B7EA884221EB01B009C9B41 /* PSDErrorParser.swift in Sources */, 4BA3FF4022116C1100CE497A /* AttachmentHandler.swift in Sources */, + 1E1275C12CAA8DDB0080CB19 /* PSDChatsTableView.swift in Sources */, 4B56BE4B2216CCC0004E6685 /* PSDAttachment.swift in Sources */, 4B060F2A2732AD8C002E20A7 /* StringHelper.swift in Sources */, 4B6E9DA3225F3B570037462F /* PSDPreviewSetter.swift in Sources */, diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.xcworkspace/xcuserdata/stanislavabobruskina.xcuserdatad/UserInterfaceState.xcuserstate b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.xcworkspace/xcuserdata/stanislavabobruskina.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..a5bc3331 Binary files /dev/null and b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/project.xcworkspace/xcuserdata/stanislavabobruskina.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/xcuserdata/stanislavabobruskina.xcuserdatad/xcschemes/xcschememanagement.plist b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/xcuserdata/stanislavabobruskina.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..e2809256 --- /dev/null +++ b/PyrusServiceDeskIOS/PyrusServiceDesk.xcodeproj/xcuserdata/stanislavabobruskina.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,29 @@ + + + + + SchemeUserState + + PyrusServiceDesk-Universal.xcscheme_^#shared#^_ + + orderHint + 1 + + PyrusServiceDesk.xcscheme_^#shared#^_ + + orderHint + 0 + + PyrusServiceDeskIOS.xcscheme_^#shared#^_ + + orderHint + 2 + + PyrusServiceDeskTests.xcscheme_^#shared#^_ + + orderHint + 3 + + + + diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatTable/PSDChatTableView.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatTable/PSDChatTableView.swift index 2a94fa36..10daed44 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatTable/PSDChatTableView.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatTable/PSDChatTableView.swift @@ -10,6 +10,7 @@ protocol PSDChatTableViewDelegate: NSObjectProtocol { class PSDChatTableView: PSDDetailTableView{ ///The id of chat that is shown in table view weak var chatDelegate: PSDChatTableViewDelegate? + var ticketId = 0 private let footerHeight : CGFloat = 10.0 private let BOTTOM_INFELICITY : CGFloat = 10.0 private var needShowRating : Bool = false @@ -107,6 +108,38 @@ class PSDChatTableView: PSDDetailTableView{ self.keyboardDismissMode = .interactive self.separatorColor = .clear } + + func reload() { + tableMatrix = [[PSDRowMessage]()] + let ticketId = ticketId + DispatchQueue.global().async { + [weak self] in + PSDGetChat.get(needShowError: true, delegate: self, ticketId: ticketId) { + chat in + DispatchQueue.main.async { + if chat != nil { + UnreadMessageManager.removeLastComment() + } + guard let self = self else { + return + } + self.gotData = true + if let chat = chat { + self.storeChat = chat + if !(self.loadingTimer?.isValid ?? false) { + self.drawTableWithData() + } + } else { + self.needShowRating = chat?.showRating ?? false + self.showRateIfNeed() + self.isLoading = false + self.buttonsView.updateWithButtons(nil, width: self.frame.size.width) + } + } + } + } + } + /** Reloads ChatTableView. Creates the new tableMatrix. */ @@ -120,9 +153,10 @@ class PSDChatTableView: PSDDetailTableView{ self.reloadData() self.isLoading = true } + let ticketId = ticketId DispatchQueue.global().async { [weak self] in - PSDGetChat.get(needShowError: true, delegate: self) { + PSDGetChat.get(needShowError: true, delegate: self, ticketId: ticketId) { chat in DispatchQueue.main.async { if chat != nil { @@ -223,93 +257,93 @@ class PSDChatTableView: PSDDetailTableView{ ///update taable matrix ///- parameter needProgress: Determines whether the view should respond to updating(need to show error) func updateChat(needProgress:Bool) { - PSDGetChat.get(needShowError: needProgress, delegate: nil) { [weak self] - (chat : PSDChat?) in - DispatchQueue.main.async { - if let chat = chat{ - UnreadMessageManager.removeLastComment() - self?.needShowRating = chat.showRating - self?.showRateIfNeed() - //compare number of messages it two last sections - guard let self = self else{ - return + PSDGetChat.get(needShowError: needProgress, delegate: nil, ticketId: ticketId) { [weak self] + (chat : PSDChat?) in + DispatchQueue.main.async { + if let chat = chat{ + UnreadMessageManager.removeLastComment() + self?.needShowRating = chat.showRating + self?.showRateIfNeed() + //compare number of messages it two last sections + guard let self = self else{ + return + } + var hasChanges = false + let (removeIndexPaths, removeSections) = self.tableMatrix.removeFakeMessages() + if removeIndexPaths.count > 0 + || removeSections.count > 0, + self.tableMatrix.count > 0 + { + if !hasChanges { + hasChanges = true + PyrusLogger.shared.logEvent("Колличество ячеек до удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") + PyrusLogger.shared.logEvent("Колличество ячеек после удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") } - var hasChanges = false - let (removeIndexPaths, removeSections) = self.tableMatrix.removeFakeMessages() - if removeIndexPaths.count > 0 - || removeSections.count > 0, - self.tableMatrix.count > 0 - { - if !hasChanges { - hasChanges = true - PyrusLogger.shared.logEvent("Колличество ячеек до удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") - PyrusLogger.shared.logEvent("Колличество ячеек после удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") + } + self.tableMatrix.complete(from: chat, startMessage:self.lastMessageFromServer){ + (indexPaths: [IndexPath], sections:IndexSet, _) in + DispatchQueue.main.async { + if indexPaths.count > 0 || + sections.count > 0, + self.tableMatrix.count > 0 + { + if !hasChanges { + hasChanges = true + PyrusLogger.shared.logEvent("Колличество ячеек до удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") + } + PyrusLogger.shared.logEvent("Колличество ячеек после добавления: \(self.tableMatrix[self.tableMatrix.count-1].count)") + PyrusLogger.shared.logEvent("При удалении фейка: ячейки = \(removeIndexPaths), секции \(removeSections)") + PyrusLogger.shared.logEvent("При добавленни нового сообщения: ячейки = \(indexPaths), секции \(sections)") } - } - self.tableMatrix.complete(from: chat, startMessage:self.lastMessageFromServer){ - (indexPaths: [IndexPath], sections:IndexSet, _) in - DispatchQueue.main.async { - if indexPaths.count > 0 || - sections.count > 0, - self.tableMatrix.count > 0 - { - if !hasChanges { - hasChanges = true - PyrusLogger.shared.logEvent("Колличество ячеек до удаления: \(self.tableMatrix[self.tableMatrix.count-1].count)") - } - PyrusLogger.shared.logEvent("Колличество ячеек после добавления: \(self.tableMatrix[self.tableMatrix.count-1].count)") - PyrusLogger.shared.logEvent("При удалении фейка: ячейки = \(removeIndexPaths), секции \(removeSections)") - PyrusLogger.shared.logEvent("При добавленни нового сообщения: ячейки = \(indexPaths), секции \(sections)") + let oldContentOffset = self.contentOffset + let oldContentSize = self.contentSize + self.removeNoConnectionView() + self.lastMessageFromServer = chat.messages.last + self.setLastActivityDate() + if indexPaths.count > 0 + || sections.count > 0 + || removeIndexPaths.count > 0 + || removeSections.count > 0 + { + let (newRemoveIndexPaths, addIndexPaths, reloadIndexPaths, newRemoveSections, addSections, reloadSections) = PSDTableView.compareAddAndRemoveRows(removeIndexPaths: removeIndexPaths, addIndexPaths: indexPaths, removeSections: removeSections, addSections: sections) + PyrusLogger.shared.logEvent("Результат после сопоставления: удалять = \(newRemoveIndexPaths), \(newRemoveSections); \n добавлять = \(addIndexPaths), \(addSections); \n Обновлять = \(reloadIndexPaths), \(reloadSections)") + self.beginUpdates() + if newRemoveIndexPaths.count > 0 { + self.deleteRows(at: newRemoveIndexPaths, with: .none) + } + if newRemoveSections.count > 0 { + self.deleteSections(newRemoveSections, with: .none) + } + if addIndexPaths.count > 0{ + self.insertRows(at: addIndexPaths, with: .none) + } + if addSections.count > 0 { + self.insertSections(addSections, with: .none) + } + if reloadIndexPaths.count > 0 { + self.reloadRows(at: reloadIndexPaths, with: .none) } - let oldContentOffset = self.contentOffset - let oldContentSize = self.contentSize - self.removeNoConnectionView() - self.lastMessageFromServer = chat.messages.last - self.setLastActivityDate() - if indexPaths.count > 0 - || sections.count > 0 - || removeIndexPaths.count > 0 - || removeSections.count > 0 - { - let (newRemoveIndexPaths, addIndexPaths, reloadIndexPaths, newRemoveSections, addSections, reloadSections) = PSDTableView.compareAddAndRemoveRows(removeIndexPaths: removeIndexPaths, addIndexPaths: indexPaths, removeSections: removeSections, addSections: sections) - PyrusLogger.shared.logEvent("Результат после сопоставления: удалять = \(newRemoveIndexPaths), \(newRemoveSections); \n добавлять = \(addIndexPaths), \(addSections); \n Обновлять = \(reloadIndexPaths), \(reloadSections)") - self.beginUpdates() - if newRemoveIndexPaths.count > 0 { - self.deleteRows(at: newRemoveIndexPaths, with: .none) - } - if newRemoveSections.count > 0 { - self.deleteSections(newRemoveSections, with: .none) - } - if addIndexPaths.count > 0{ - self.insertRows(at: addIndexPaths, with: .none) - } - if addSections.count > 0 { - self.insertSections(addSections, with: .none) - } - if reloadIndexPaths.count > 0 { - self.reloadRows(at: reloadIndexPaths, with: .none) - } - if reloadSections.count > 0 { - self.reloadSections(reloadSections, with: .none) - } - self.endUpdates() - self.buttonsView.updateWithButtons(PSDChat.draftAnswers(self.tableMatrix), width: self.frame.size.width) - self.buttonsView.collectionView.collectionViewLayout.invalidateLayout() - self.scrollToBottomAfterRefresh(with: oldContentOffset, oldContentSize: oldContentSize) + if reloadSections.count > 0 { + self.reloadSections(reloadSections, with: .none) } + self.endUpdates() + self.buttonsView.updateWithButtons(PSDChat.draftAnswers(self.tableMatrix), width: self.frame.size.width) + self.buttonsView.collectionView.collectionViewLayout.invalidateLayout() + self.scrollToBottomAfterRefresh(with: oldContentOffset, oldContentSize: oldContentSize) } } - } + } - DispatchQueue.main.async { - if let self = self { - self.buttonsView.updateWithButtons(PSDChat.draftAnswers(self.tableMatrix), width: self.frame.size.width) - self.customRefresh.endRefreshing() - self.bottomRefresh.endRefreshing() - } + } + DispatchQueue.main.async { + if let self = self { + self.buttonsView.updateWithButtons(PSDChat.draftAnswers(self.tableMatrix), width: self.frame.size.width) + self.customRefresh.endRefreshing() + self.bottomRefresh.endRefreshing() } } + } } ///Scrolls table to bottom after refresh, if table view was in bottom scroll position and new messages received private func scrollToBottomAfterRefresh(with oldOffset: CGPoint?, oldContentSize: CGSize?) { @@ -633,7 +667,7 @@ extension PSDChatTableView : PSDChatMessageCellDelegate{ } if let message = self.getMessage(at: indexPath){ message.state = .sending - PSDMessageSend.pass(message, delegate: self) + PSDMessageSend.pass(message, delegate: self, ticketId: ticketId) } } else{ diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatViewController.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatViewController.swift index fc2bba09..7a7909db 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatViewController.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Chat/PSDChatViewController.swift @@ -8,6 +8,7 @@ protocol PSDUpdateInfo{ } class PSDChatViewController: PSDViewController { + var ticketId = 0 private var firstLoad: Bool = true public func updateTitle(){ designNavigation() @@ -16,6 +17,7 @@ class PSDChatViewController: PSDViewController { self.tableView.reloadChat() } private var tableViewTopConstant: NSLayoutConstraint? + override func viewDidLoad() { super.viewDidLoad() presentationController?.delegate = self @@ -131,6 +133,7 @@ class PSDChatViewController: PSDViewController { }() lazy var tableView: PSDChatTableView = { let table = PSDChatTableView(frame: self.view.bounds) + table.ticketId = ticketId table.setupTableView() return table }() @@ -211,7 +214,15 @@ class PSDChatViewController: PSDViewController { self.navigationItem.leftBarButtonItem?.tintColor = color self.navigationItem.rightBarButtonItem?.tintColor = color } - @objc private func closeButtonAction(){ + @objc private func closeButtonAction() { + guard !PyrusServiceDesk.multichats else { + navigationController?.popViewController(animated: true) + EventsLogger.logEvent(.resignFirstResponder, additionalInfo: "hideAllKeyboard() called after press on back button") + UIView.performWithoutAnimation { + hideAllKeyboard() + } + return + } if let mainController = PyrusServiceDesk.mainController { PyrusServiceDesk.mainController?.remove()//with quick opening - closing can be nil } else if let navigationController = self.navigationController as? PyrusServiceDeskController { @@ -266,19 +277,33 @@ class PSDChatViewController: PSDViewController { } } -extension PSDChatViewController : PSDMessageInputViewDelegate{ - func send(_ message:String,_ attachments:[PSDAttachment]){ - let newMessage = PSDObjectsCreator.createMessage(message, attachments: attachments) - prepareMessageForDrawing(newMessage) - tableView.addNewRow(message: newMessage) - PSDMessageSend.pass(newMessage, delegate: self.tableView) +extension PSDChatViewController: PSDMessageInputViewDelegate { + func send(_ message:String, _ attachments: [PSDAttachment]) { + if PyrusServiceDesk.multichats && ticketId == 0 { + PSDCreateChat.create(subject: message, description: message) { [weak self] id in + if let id { + self?.ticketId = id + self?.tableView.ticketId = id + DispatchQueue.main.async { + self?.tableView.reload() + } + } + } + } else { + let newMessage = PSDObjectsCreator.createMessage(message, attachments: attachments) + prepareMessageForDrawing(newMessage) + tableView.addNewRow(message: newMessage) + PSDMessageSend.pass(newMessage, delegate: self.tableView, ticketId: ticketId) + } } + func sendRate(_ rateValue: Int) { let newMessage = PSDObjectsCreator.createMessage(rating: rateValue) prepareMessageForDrawing(newMessage) tableView.addNewRow(message: newMessage) - PSDMessageSend.pass(newMessage, delegate: self.tableView) + PSDMessageSend.pass(newMessage, delegate: self.tableView, ticketId: ticketId) } + private func prepareMessageForDrawing(_ newMessage: PSDMessage) { newMessage.state = .sending if let attachments = newMessage.attachments { diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Helpers/ru.lproj/Localizable.strings b/PyrusServiceDeskIOS/PyrusServiceDesk/Helpers/ru.lproj/Localizable.strings index 9df80117..ed315c65 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Helpers/ru.lproj/Localizable.strings +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Helpers/ru.lproj/Localizable.strings @@ -4,7 +4,7 @@ "Default_User_Name" = "Гость"; "Uploading" = "Загрузка..."; "Empty_Description" = "Пусто"; -"All_Conversations" = "Все обсуждения"; +"All_Conversations" = "Обращения"; "Support_Default_Name" = "Поддержка"; //Buttons' Title diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/ChatListBarButtonItem.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/ChatListBarButtonItem.swift index f7128a4d..a20347d7 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/ChatListBarButtonItem.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/ChatListBarButtonItem.swift @@ -9,7 +9,7 @@ let MESSAGES_NUMBER_NOTIFICATION_NAME = Notification.Name.init("PSDMessagesNumbe ///UIBarButtonItem, that observers number of chats and new messages, and change self view according to its data. If no messages and chats this button is not enabled. class ChatListBarButtonItem: UIBarButtonItem { - private var chatsCount : Int = PyrusServiceDesk.chatsCount + private var chatsCount : Int = 0//PyrusServiceDesk.chatsCount { didSet (oldValue){ if oldValue != chatsCount{ @@ -18,7 +18,7 @@ class ChatListBarButtonItem: UIBarButtonItem { } } - private var newMessagesCount : Int = PyrusServiceDesk.newMessagesCount + private var newMessagesCount : Int = 0//PyrusServiceDesk.newMessagesCount { didSet (oldValue){ if oldValue != newMessagesCount{ @@ -173,10 +173,10 @@ class ChatListBarButtonItem: UIBarButtonItem { object: nil) } private func checkAvailability()->Bool{ - if(PyrusServiceDesk.newMessagesCount == 0 && PyrusServiceDesk.chatsCount==0 && !PyrusServiceDesk.hasInfo){ + //if(PyrusServiceDesk.newMessagesCount == 0 && PyrusServiceDesk.chatsCount==0 && !PyrusServiceDesk.hasInfo){ return false - } - return true +// } +// return true } required init?(coder aDecoder: NSCoder) { diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/PyrusServiceDeskController.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/PyrusServiceDeskController.swift index 07a5014a..ec58695e 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/PyrusServiceDeskController.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Navigation/PyrusServiceDeskController.swift @@ -3,13 +3,15 @@ import UIKit ///The main service desk controller. class PyrusServiceDeskController: PSDNavigationController { - let customization: ServiceDeskConfiguration? + var customization: ServiceDeskConfiguration? required init(_ customization: ServiceDeskConfiguration?, customPresent: Bool) { self.customization = customization - if(PyrusServiceDesk.clientId != nil){ - let pyrusChat = PSDChatViewController() + if(PyrusServiceDesk.clientId != nil) { super.init(nibName: nil, bundle: nil) - pushViewController(pyrusChat, animated: false) + let controller = PyrusServiceDesk.multichats + ? PSDChatsViewController() + : PSDChatViewController() + pushViewController(controller, animated: true) if !customPresent { self.transitioningDelegate = self self.isModalInPopover = true diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/PSDObjects/PSDChat.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/PSDObjects/PSDChat.swift index 62ac5a65..03a4eba4 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/PSDObjects/PSDChat.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/PSDObjects/PSDChat.swift @@ -1,11 +1,15 @@ import UIKit class PSDChat: NSObject { + var chatId: Int? var date: Date? var messages: [PSDMessage] var isRead = true var showRating = false var showRatingText: String? - init(date: Date, messages: [PSDMessage]) { + var subject: String? + + init(chatId: Int?, date: Date, messages: [PSDMessage]) { + self.chatId = chatId self.date = date self.messages = messages } diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCreator.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCreator.swift index 8b673d7c..6a248c37 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCreator.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCreator.swift @@ -19,6 +19,8 @@ import UIKit ///An array with domains. Used to determine if an alert should be shown when a link is clicked. If the user clicked on a link with a domain from the array, then the application will immediately navigate. public static var trustedUrls: [String]? + public static var multichats = false + ///UserId needed for request static private(set) var userId: String = "" { didSet(oldUserId){ @@ -184,8 +186,8 @@ import UIKit ///- parameter clientId: clientId using for all requests. If clientId not setted PyrusServiceDesk Controller will not be created ///- parameter domain: Base domain for network requests. If the [domain] is null, the default pyrus.com will be used. ///- parameter loggingEnabled If true, then the library will write logs, and they can be sent as a file to chat by clicking the "Send Library Logs" button in the menu under the "+" sign. - @objc static public func createWith(_ clientId: String?, domain: String? = nil, loggingEnabled: Bool = false, authorizationToken: String? = nil, fieldsData: [String: String]? = nil) { - createWith(clientId, userId: nil, securityKey: nil, reset: false, domain: domain, loggingEnabled: loggingEnabled, authorizationToken: authorizationToken, fieldsData: fieldsData) + @objc static public func createWith(_ clientId: String?, multichats: Bool = false, domain: String? = nil, loggingEnabled: Bool = false, authorizationToken: String? = nil, fieldsData: [String: String]? = nil) { + createWith(clientId, userId: nil, securityKey: nil, reset: false, domain: domain, loggingEnabled: loggingEnabled, authorizationToken: authorizationToken, fieldsData: fieldsData, multichats: multichats) } ///Init PyrusServiceDesk with new clientId. @@ -203,10 +205,11 @@ import UIKit ///- parameter securityKey: security key of the user for safe initialization //////- parameter domain: Base domain for network requests. If the [domain] is null, the default pyrus.com will be used. ///- parameter loggingEnabled If true, then the library will write logs, and they can be sent as a file to chat by clicking the "Send Library Logs" button in the menu under the "+" sign. - @objc static public func createWith(_ clientId: String?, userId: String?, securityKey: String?, domain: String? = nil, loggingEnabled: Bool = false, authorizationToken: String? = nil, fieldsData: [String: String]? = nil) { - createWith(clientId, userId: userId, securityKey: securityKey, reset: false, domain: domain, loggingEnabled: loggingEnabled, authorizationToken: authorizationToken, fieldsData: fieldsData) + @objc static public func createWith(_ clientId: String?, userId: String?, securityKey: String?, multichats: Bool = false, domain: String? = nil, loggingEnabled: Bool = false, authorizationToken: String? = nil, fieldsData: [String: String]? = nil) { + createWith(clientId, userId: userId, securityKey: securityKey, reset: false, domain: domain, loggingEnabled: loggingEnabled, authorizationToken: authorizationToken, fieldsData: fieldsData, multichats: multichats) } - private static func createWith(_ clientId: String?, userId: String?, securityKey: String?, reset: Bool, domain: String?, loggingEnabled: Bool, authorizationToken: String?, fieldsData: [String: String]?) { + private static func createWith(_ clientId: String?, userId: String?, securityKey: String?, reset: Bool, domain: String?, loggingEnabled: Bool, authorizationToken: String?, fieldsData: [String: String]?, multichats: Bool = false) { + PyrusServiceDesk.multichats = multichats PyrusServiceDesk.loggingEnabled = loggingEnabled guard let clientId = clientId, clientId.count > 0 else { EventsLogger.logEvent(.emptyClientId) diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCustomization.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCustomization.swift index fcf0c94d..d087e447 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCustomization.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/PyrusServiceDeskCustomization.swift @@ -7,6 +7,10 @@ import Foundation ///Chat title using to show in navigation Bar title private(set) var chatTitle: String? + func setChatTitile(_ title: String?) { + chatTitle = title + } + /// Customize color. If not set, the application tint color or blue is used. private(set) var themeColor: UIColor? @@ -32,6 +36,12 @@ import Foundation ///Custom UIBarButtonItem to show in left side of navigation Bar. Default value is nil. If nil there will be drawn back button. If specify custom left button, Pyrus ServiceDesk cannot be closed. private(set) var customLeftBarButtonItem: UIBarButtonItem? + func setCustomLeftBarButtonItem(_ button: UIBarButtonItem?) { + customLeftBarButtonItem = button + } + + private(set) var chatsLeftBarButtonItem: UIBarButtonItem? + ///The view to show additional information under chat private(set) var infoView: PSDInfoView? @@ -147,6 +157,13 @@ import Foundation return self } + @discardableResult + + @objc public func setChatsLeftBarButtonItem(_ customLeftBarButtonItem: UIBarButtonItem?) -> Builder { + configuration.chatsLeftBarButtonItem = customLeftBarButtonItem + return self + } + @discardableResult ///The view to show additional information under chat @objc public func setInfoView(_ infoView: PSDInfoView?) -> Builder { diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDCreateChat.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDCreateChat.swift new file mode 100644 index 00000000..cd862fe3 --- /dev/null +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDCreateChat.swift @@ -0,0 +1,70 @@ +import Foundation + +struct PSDCreateChat { + private static let ATTACHMENTS_KEY = "attachments" + private static let SUBJECT_KEY = "subject" + private static let DESCRIPTION_KEY = "description" + private static let TICKET_KEY = "ticket" + private static let USER_NAME_KEY = "user_name" + private static let TICKET_ID_KEY = "ticket_id" + + private static var sessionTask : URLSessionDataTask? = nil + /** + Create new chat. + On completion returns Int if it was received, or empty nil, if no connection. + */ + static func create(subject: String, description: String, completion: @escaping (_ chatId: Int?) -> Void) + { + //remove old session if it is + remove() + + var ticket = [String: Any]() + ticket[ATTACHMENTS_KEY] = [] + ticket[SUBJECT_KEY] = subject + ticket[DESCRIPTION_KEY] = description + var parameters = [String: Any]() + parameters[TICKET_KEY] = ticket + parameters[USER_NAME_KEY] = PyrusServiceDesk.userName + let request: URLRequest = URLRequest.createRequest(type: .createChat, parameters: parameters) + + PSDCreateChat.sessionTask = PyrusServiceDesk.mainSession.dataTask(with: request) { data, response, error in + guard let data = data, error == nil else { // check for fundamental networking error + completion(nil) + return + } + + if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors + DispatchQueue.main.async { + if httpStatus.statusCode == 403 { + if let onFailed = PyrusServiceDesk.onAuthorizationFailed { + onFailed() + } else { + PyrusServiceDesk.mainController?.closeServiceDesk() + } + } + } + + completion(nil) + } + do { + let chatData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : Any] ?? [String: Any]() + let chatId = chatData[TICKET_ID_KEY] as? Int ?? 0 + completion(chatId) + } catch { + //print("PSDCreateChat error when convert to Integer") + } + + } + PSDCreateChat.sessionTask?.resume() + } + + /** + Cancel session task if its exist + */ + static func remove() { + if PSDCreateChat.sessionTask != nil { + PSDCreateChat.sessionTask?.cancel() + PSDCreateChat.sessionTask = nil + } + } +} diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChat.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChat.swift index c3a16149..c39f37e6 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChat.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChat.swift @@ -9,6 +9,7 @@ struct PSDGetChat { private static let SHOW_RATING_KEY = "show_rating" private static let SHOW_RATING_TEXT_KEY = "show_rating_text" private static let KEEP_UNREAD_RATING_KEY = "keep_unread" + private static let TICKET_ID_KEY = "ticket_id" private static var chatGetters : [Int: ChatGetter] = [Int: ChatGetter]() // private static var sessionTask : URLSessionDataTask? = nil /** @@ -17,9 +18,14 @@ struct PSDGetChat { - parameter delegate: PSDGetDelegate. Works only if showError is true. If not equal to nil - calls showNoConnectionView(), when no internet connection. Else remembers the current ViewController. And if it has not changed when response receive, on it displays an error. On completion returns PSDChat object if it was received. */ - static func get(needShowError: Bool, delegate: PSDGetDelegate?, keepUnread: Bool = false, completion: @escaping (_ chat: PSDChat?) -> Void) { + static func get(needShowError: Bool, delegate: PSDGetDelegate?, keepUnread: Bool = false, ticketId: Int = 0, completion: @escaping (_ chat: PSDChat?) -> Void) { //remove old session if it is remove() + if PyrusServiceDesk.multichats && ticketId == 0 { + let chat = PSDChat(chatId: nil, date: Date(), messages: []) + completion(chat) + return + } var topViewController : UIViewController? = nil DispatchQueue.main.async { //if need show error - remember current top UIViewController @@ -27,7 +33,10 @@ struct PSDGetChat { topViewController = UIApplication.topViewController() } } - let parameters = [KEEP_UNREAD_RATING_KEY: keepUnread, "api_sign": PyrusServiceDesk.apiSign()] as [String : Any] + var parameters = [KEEP_UNREAD_RATING_KEY: keepUnread, "api_sign": PyrusServiceDesk.apiSign()] as [String : Any] + if ticketId != 0 { + parameters[TICKET_ID_KEY] = ticketId + } let request = URLRequest.createRequest(type: .chatFeed, parameters: parameters) let localId = UUID().uuidString @@ -103,7 +112,8 @@ struct PSDGetChat { { var massages : [PSDMessage] = [PSDMessage]() massages = PSDGetChat.generateMessages(from: response["comments"] as? NSArray ?? NSArray()) - let chat = PSDChat(date: Date(), messages: massages) + let ticketId = response[PSDGetChat.TICKET_ID_KEY] as? Int + let chat = PSDChat(chatId: ticketId, date: Date(), messages: massages) chat.showRating = (response[PSDGetChat.SHOW_RATING_KEY] as? Bool) ?? false chat.showRatingText = response[PSDGetChat.SHOW_RATING_TEXT_KEY] as? String return chat diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChats.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChats.swift index 0c9cff1b..e0b98f73 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChats.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDGetChats.swift @@ -37,7 +37,7 @@ struct PSDGetChats { do{ let chatsData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : Any] ?? [String: Any]() let chatsArray = chatsData["tickets"] as? NSArray ?? NSArray() - let chats = generateChats(from:chatsArray) + let chats = generateChats(from: chatsArray) PyrusServiceDesk.chats = chats completion(chats) }catch{ @@ -72,7 +72,9 @@ struct PSDGetChats { let lastMessage :PSDMessage = PSDMessage.init(text: lastComment.stringOfKey("body"), attachments:nil, messageId: lastComment.stringOfKey(commentIdParameter), owner: nil, date: nil) messages.append(lastMessage) } - let chat = PSDChat.init(date: date, messages: messages) + let ticketId = dic["ticket_id"] as? Int + let chat = PSDChat.init(chatId: ticketId, date: date, messages: messages) + chat.subject = dic["subject"] as? String chat.isRead = dic["is_read"] as? Bool ?? true chats.append(chat) } diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSend.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSend.swift index a4037b79..f42edd4c 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSend.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSend.swift @@ -76,7 +76,7 @@ struct PSDMessageSend { - parameter messageToPass: PSDMessage need to be passed. - parameter delegate: PSDMessageSendDelegate object to receive completion or error. */ - static func pass(_ messageToPass: PSDMessage, delegate: PSDMessageSendDelegate?) { + static func pass(_ messageToPass: PSDMessage, delegate: PSDMessageSendDelegate?, ticketId: Int = 0) { if let attachments = messageToPass.attachments { for attachment in attachments{ guard attachment.emptyId() else { @@ -109,7 +109,7 @@ struct PSDMessageSend { } if !hasUnsendAttachments{ let sender = PSDMessageSender() - sender.pass(messageToPass, delegate: delegate, completion: { + sender.pass(messageToPass, ticketId: ticketId, delegate: delegate, completion: { didEndPassMessage(messageToPass, delegate: delegate) }) messageSenders.append(sender) diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSender.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSender.swift index 1209a160..64611575 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSender.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/PSDMessageSender.swift @@ -17,8 +17,8 @@ class PSDMessageSender: NSObject { - parameter delegate: PSDMessageSendDelegate object to receive completion or error. - parameter completion: comptetion block. */ - func pass(_ messageToPass:PSDMessage, delegate:PSDMessageSendDelegate?, completion: @escaping() -> Void) { - let task = PSDMessageSender.pass(messageToPass.text, messageToPass.attachments, rating: messageToPass.rating, clientId: messageToPass.clientId) { + func pass(_ messageToPass: PSDMessage, ticketId: Int = 0, delegate:PSDMessageSendDelegate?, completion: @escaping() -> Void) { + let task = PSDMessageSender.pass(messageToPass.text, messageToPass.attachments, rating: messageToPass.rating, clientId: messageToPass.clientId, ticketId: ticketId) { commentId, attachments in if let commentId = commentId, commentId.count > 0 { //put attachments id @@ -79,7 +79,7 @@ class PSDMessageSender: NSObject { - completion: Completion of passing message. - commentId: Return id of new message as String. If Request end with error return nil or "0" if received bad data from server. */ - private static func pass(_ message: String, _ attachments: [PSDAttachment]?, rating: Int?, clientId: String, completion: @escaping (_ commentId: String?, _ attachments: NSArray?) -> Void) -> URLSessionDataTask { + private static func pass(_ message: String, _ attachments: [PSDAttachment]?, rating: Int?, clientId: String, ticketId: Int, completion: @escaping (_ commentId: String?, _ attachments: NSArray?) -> Void) -> URLSessionDataTask { //Generate additional parameters for request body var parameters = [String: Any]() parameters[commentParameter] = message @@ -94,7 +94,10 @@ class PSDMessageSender: NSObject { if let fieldsData = PyrusServiceDesk.fieldsData { parameters[EXTRA_FIELDS_KEY] = fieldsData } - let request = URLRequest.createRequest(type:.updateFeed, parameters: parameters) + if ticketId != 0 { + parameters["ticket_id"] = ticketId + } + let request = URLRequest.createRequest(type: .updateFeed, parameters: parameters) let task = PyrusServiceDesk.mainSession.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { // check for fundamental networking error diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/URLCreator.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/URLCreator.swift index 4a71aa38..e5cafa30 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/URLCreator.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/Requests/URLCreator.swift @@ -16,6 +16,8 @@ enum urlType : String{ case avatar = "avatar" ///Add SetPushToken to baseURLString. Use PSDURL(type:urlType). case token = "SetPushToken" + + case createChat = "CreateTicket" } struct PyrusServiceDeskAPI { @@ -25,7 +27,7 @@ struct PyrusServiceDeskAPI { } ///Create URL for urlType in [.chats, .createNew, .upload, .chatFeed, .updateFeed, .token] static func PSDURL(type: urlType) -> URL { - let validTypes : [urlType] = [.chats, .upload, .chatFeed, .updateFeed, .token] + let validTypes : [urlType] = [.chats, .upload, .chatFeed, .updateFeed, .token, .createChat] if !(validTypes.contains(type)){ fatalError("Bad urlType for this function, type = \(urlType.RawValue())") } diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsTableView.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsTableView.swift index 1d1b211c..f5556c8e 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsTableView.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsTableView.swift @@ -1,29 +1,32 @@ import UIKit -protocol PSDChatsTableViewDelegate: class { - func openChat(_ id : String, animated: Bool) +protocol PSDChatsTableViewDelegate: AnyObject { + func openChat(_ id : Int, subject: String?, animated: Bool) func removeOneNewMessage() + func updateLoading(loading: Bool) } -class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource,PSDGetDelegate,PSDNoConnectionViewDelegate { +class PSDChatsTableView: PSDTableView, UITableViewDelegate, UITableViewDataSource, PSDGetDelegate, PSDNoConnectionViewDelegate { weak var chatsDelegate: PSDChatsTableViewDelegate? let chatCellId = "ChatCell" - var progressView : PSDProgressView? - private lazy var customRefresh: PSDRefreshControl = { - let refreshControl = PSDRefreshControl.init(frame: self.bounds) - refreshControl.position = .top + + private lazy var customRefresh: UIRefreshControl = { + let refreshControl = UIRefreshControl() + refreshControl.transform = CGAffineTransformMakeScale(0.8, 0.8) refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged) return refreshControl }() + var chats : [PSDChat] = []{ didSet{ self.reloadData() } } + func setupTableView() { - self.delegate=self - self.dataSource=self + self.delegate = self + self.dataSource = self self.backgroundColor = .psdBackground self.estimatedRowHeight = UITableView.automaticDimension @@ -33,6 +36,10 @@ class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource, self.separatorColor = .psdGray self.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) self.keyboardDismissMode = .onDrag + + if #available(iOS 10.0, *) { + self.refreshControl = customRefresh + } } func setupAutoLayout(view:UIView) { @@ -50,13 +57,13 @@ class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource, self.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true } } - @objc func refresh(sender:AnyObject) { - reloadChats(needProgress:false) + + @objc func refresh(sender: AnyObject) { + reloadChats(needProgress: true) } + override init(frame: CGRect, style: UITableView.Style) { super.init(frame: frame, style: style) - self.contentInset = UIEdgeInsets(top: self.contentInset.top, left: self.contentInset.left, bottom: newConversation.frame.size.height, right: self.contentInset.right) - } required init?(coder aDecoder: NSCoder) { @@ -64,12 +71,6 @@ class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource, } override func didMoveToSuperview() { super.didMoveToSuperview() - if self.superview != nil { - self.superview?.addSubview(newConversation) - } - else{ - newConversation.removeFromSuperview() - } if self.superview != nil{ self.setupAutoLayout(view: self.superview!) } @@ -82,75 +83,70 @@ class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource, if(selectedItems != nil){ self.deselectRow(at: selectedItems!, animated: false) } - } - func reloadChats(needProgress:Bool) - { - customRefresh.insetHeight = 0.0 + + func reloadChats(needProgress: Bool) { + chatsDelegate?.updateLoading(loading: needProgress) self.chats = PyrusServiceDesk.chats self.reloadData() PyrusServiceDesk.restartTimer() - if needProgress{ - self.progressView?.startAnimate() - } - DispatchQueue.global().async { - [weak self] in - PSDGetChats.get(delegate:self, needShowError: !PyrusServiceDesk.hasInfo){ - (chats:[PSDChat]?) in + + DispatchQueue.global().async { [weak self] in + PSDGetChats.get() { [weak self] chats in DispatchQueue.main.async { - if chats != nil && (chats?.count ?? 0)>0{ + if chats != nil && (chats?.count ?? 0) > 0 { self?.chats = chats! self?.reloadData() - if(self != nil){ - self!.insertSubview(self!.customRefresh, at: 0) - } - - } - if needProgress{ - self?.progressView?.progress = 1.0 - } - else{ - self?.customRefresh.endRefreshing() } + self?.chatsDelegate?.updateLoading(loading: false) + self?.customRefresh.endRefreshing() } } } } + deinit { PSDGetChats.remove() self.customRefresh.endRefreshing() self.customRefresh.removeFromSuperview() } + private lazy var noConnectionView : PSDNoConnectionView = { let view = PSDNoConnectionView.init(frame: self.frame) view.delegate = self return view }() + //PSDGetDelegate method func showNoConnectionView(){ - if !(self.superview?.subviews.contains(noConnectionView) ?? false){ + if !(self.superview?.subviews.contains(noConnectionView) ?? false) { self.superview?.addSubview(noConnectionView) } } + //PSDNoConnectionViewDelegate method func retryPressed(){ reloadChats(needProgress: true) } + //MARK: for table func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return chats.count; } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: chatCellId, for: indexPath) as! PSDChatInfoTableViewCell cell.time = chats[indexPath.row].date!.timeIntervalString() cell.notifacationNumber = !(chats[indexPath.row].isRead) as NSNumber cell.firstMessageText = chats[indexPath.row].messages[0].text - if chats[indexPath.row].messages.count>1{ + cell.selectionStyle = .none + if chats[indexPath.row].messages.count > 1 { cell.lastMessageText = chats[indexPath.row].messages[1].text } else{ @@ -159,76 +155,34 @@ class PSDChatsTableView: PSDTableView,UITableViewDelegate,UITableViewDataSource, return cell } + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let chatId :String = chats[indexPath.row].chatId ?? "" - if !(chats[indexPath.row].isRead){ + let chatId = chats[indexPath.row].chatId ?? 0 + if !(chats[indexPath.row].isRead) { self.chatsDelegate?.removeOneNewMessage() } - self.chatsDelegate?.openChat(chatId,animated: true) + + self.chatsDelegate?.openChat(chatId, subject: chats[indexPath.row].subject, animated: true) + } + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { return UIView() } + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { return 1.0 } - private let footerHeight: CGFloat = 50 - ///New conversation view with tapGestureRecognizer. - lazy var newConversation: UIView = { - let footer :UIView = UIView () - var addditionalHeight : CGFloat = 0.0 - if #available(iOS 11.0, *) { - let window = UIApplication.shared.keyWindow - addditionalHeight = window?.safeAreaInsets.bottom ?? 0.0 - } - let label = UILabel() - label.textColor = .darkAppColor - label.text = "New_Conversation".localizedPSD() - label.font = .newConversation - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - label.preferredMaxLayoutWidth = self.frame.size.width - label.textAlignment = .center - label .sizeToFit() - label.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: label.frame.size.height) - - footer.frame = CGRect(x: 0, y: self.frame.size.height-(footerHeight+addditionalHeight), width: self.frame.size.width, height: footerHeight+addditionalHeight) - - label.center = CGPoint(x: footer.frame.size.width/2, y: footerHeight/2) - footer.autoresizingMask = [.flexibleWidth,.flexibleTopMargin] - label.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] - footer .addSubview(createFooterLine(atY: 0)) - footer .addSubview(label) - footer.backgroundColor = UIColor.psdBackground - - let gesture = UITapGestureRecognizer(target: self, action: #selector(footerTapped)) - footer.addGestureRecognizer(gesture) - - return footer - }() - - ///Pass empty id to chatsDelegate - @objc func footerTapped(sender: UITapGestureRecognizer) { - self.chatsDelegate?.openChat("",animated: true) - } - - ///Creates thin line - ///- parameter y: y - float y position for line's frame - func createFooterLine (atY y:CGFloat)->UIView{ - let line : UIView = UIView () - line.frame = CGRect(x: 0, y: y, width: self.frame.size.width, height: 0.5) - line.backgroundColor = .psdGray - line.autoresizingMask = [.flexibleWidth,.flexibleBottomMargin] - return line - } - } + private extension UIFont { static let newConversation = CustomizationHelper.systemFont(ofSize: 17.0) } diff --git a/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsViewController.swift b/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsViewController.swift index 131d6262..890b59a9 100644 --- a/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsViewController.swift +++ b/PyrusServiceDeskIOS/PyrusServiceDesk/chats/PSDChatsViewController.swift @@ -1,84 +1,108 @@ import UIKit -class PSDChatsViewController: UIViewController,PSDChatsTableViewDelegate,CloseButtonItemDelegate,PSDUpdateInfo { - ///Chat id that need to be open when viewcontroller appear. - ///If nil will be opened last chat or new chat. - var customFirstChatId :String? +class PSDChatsViewController: UIViewController, PSDUpdateInfo { + lazy var tableView: PSDChatsTableView = { + let table = PSDChatsTableView(frame: self.view.bounds) + table.chatsDelegate = self + table.setupTableView() + return table + }() + private var timer: Timer? override func viewDidLoad() { super.viewDidLoad() design() designNavigation() - if customFirstChatId != nil{ - self.openChat(customFirstChatId!,animated:false) - } - else{ - openLastChat() - } + PyrusServiceDesk.mainController?.customization?.setCustomLeftBarButtonItem(backBarButtonItem()) if #available(iOS 11.0, *) { self.tableView.contentInsetAdjustmentBehavior = .automatic } } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.tableView.deselectRow() startGettingInfo() } - func startGettingInfo(){ + + func startGettingInfo() { tableView.reloadChats(needProgress:true) } + func refreshChat(showFakeMessage: Int?) { } - lazy var progressView: PSDProgressView = { - let view = PSDProgressView() - return view - }() + /**Setting design To PSDChatsViewController view, add subviews*/ func design() { self.view.backgroundColor = UIColor.psdBackground self.view.addSubview(tableView) - self.setCloseButton() - - progressView.draw(at: self.view) - tableView.progressView = progressView - } - func setCloseButton() - { - let rightButtonItem : UIBarButtonItem - rightButtonItem = CloseButtonItem.init(self) - self.navigationItem.rightBarButtonItem = rightButtonItem - self.navigationItem.rightBarButtonItem?.tintColor = .darkAppColor - } - @objc func closeButtonAction(){ + + @objc func closeButtonAction() { PyrusServiceDesk.mainController?.remove() } - @objc func openNewButtonAction(){ + + @objc func openNewButtonAction() { tableView.deselectRow() - self.openChat("",animated: true) + self.openChat(0, subject: "Новое обращение", animated: true) } - func openLastChat(){ + + //*Setting design to navigation bar, title and buttons*/ + func designNavigation() { + title = "All_Conversations".localizedPSD() + if #available(iOS 13.0, *) { + let rightBarButtonItem = UIBarButtonItem( + image: UIImage(systemName: "plus"), + style: .plain, + target: self, + action: #selector(openNewButtonAction) + ) + navigationItem.rightBarButtonItem = rightBarButtonItem + } + navigationItem.rightBarButtonItem?.tintColor = .darkAppColor + navigationItem.leftBarButtonItem = PyrusServiceDesk.mainController?.customization?.chatsLeftBarButtonItem + } + + func backBarButtonItem() -> UIBarButtonItem { + let mainColor = PyrusServiceDesk.mainController?.customization?.barButtonTintColor ?? UIColor.darkAppColor + let button = UIButton() + button.titleLabel?.font = CustomizationHelper.systemFont(ofSize: 18) + button.setTitle(" " + "Back".localizedPSD(), for: .normal) + button.setTitleColor(mainColor, for: .normal) + button.setTitleColor(mainColor.withAlphaComponent(0.2), for: .highlighted) + if #available(iOS 13.0, *) { + let backImage = UIImage(systemName: "chevron.left", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .semibold, scale: .large)) + button.setImage(backImage?.imageWith(color: mainColor), for: .normal) + button.setImage(backImage?.imageWith(color: mainColor.withAlphaComponent(0.2)), for: .highlighted) + } + button.addTarget(self, action: #selector(goBack), for: .touchUpInside) + button.sizeToFit() + return UIBarButtonItem(customView: button) + } + + @objc func goBack() { + navigationController?.popViewController(animated: true) } - //PSDChatsTableViewDelegate - func openChat(_ id : String, animated: Bool) - { +} + +extension PSDChatsViewController: PSDChatsTableViewDelegate { + func openChat(_ id: Int, subject: String?, animated: Bool) { + let config = PyrusServiceDesk.mainController?.customization + config?.setChatTitile(subject) + let pyrusChat = PSDChatViewController() + pyrusChat.ticketId = id + navigationController?.pushViewController(pyrusChat, animated: false) + } + + func updateLoading(loading: Bool) { + title = loading ? "Uploading".localizedPSD() : "All_Conversations".localizedPSD() } + ///Remove from new messages counter 1 func removeOneNewMessage(){ - PSDGetChats.refreshNewMessagesCount(PyrusServiceDesk.newMessagesCount-1) - } - //*Setting design to navigation bar, title and buttons*/ - func designNavigation() - { - self.title = "All_Conversations".localizedPSD() + //PSDGetChats.refreshNewMessagesCount(PyrusServiceDesk.newMessagesCount-1) } - lazy var tableView: PSDChatsTableView = { - let table = PSDChatsTableView(frame: self.view.bounds) - table.chatsDelegate = self - table.setupTableView() - return table - }() }