2019-11-20 01:13:59 +07:00
|
|
|
|
//
|
|
|
|
|
|
// ChatController.swift
|
|
|
|
|
|
// OnlineChatSdk
|
|
|
|
|
|
//
|
|
|
|
|
|
// Created by Andrew Blinov on 22/03/2019.
|
|
|
|
|
|
// Copyright © 2019 Andrew Blinov. All rights reserved.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
import UIKit
|
2024-11-21 17:36:28 +07:00
|
|
|
|
@preconcurrency import WebKit
|
2019-11-20 01:13:59 +07:00
|
|
|
|
import AVFoundation
|
|
|
|
|
|
|
2024-11-21 17:15:50 +07:00
|
|
|
|
@available(iOS 13.0, *)
|
2020-06-01 12:58:55 +07:00
|
|
|
|
open class ChatController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
|
2021-12-15 16:53:43 +07:00
|
|
|
|
|
|
|
|
|
|
public static let event_operatorSendMessage = "operatorSendMessage"
|
|
|
|
|
|
public static let event_clientSendMessage = "clientSendMessage"
|
|
|
|
|
|
public static let event_clientMakeSubscribe = "clientMakeSubscribe"
|
|
|
|
|
|
public static let event_contactsUpdated = "contactsUpdated"
|
|
|
|
|
|
public static let event_sendRate = "sendRate"
|
|
|
|
|
|
public static let event_clientId = "clientId"
|
|
|
|
|
|
public static let event_closeSupport = "closeSupport"
|
2019-11-20 01:13:59 +07:00
|
|
|
|
|
2021-12-15 16:53:43 +07:00
|
|
|
|
public static let method_setClientInfo = "setClientInfo"
|
|
|
|
|
|
public static let method_setTarget = "setTarget"
|
|
|
|
|
|
public static let method_openReviewsTab = "openReviewsTab"
|
|
|
|
|
|
public static let method_openTab = "openTab"
|
|
|
|
|
|
public static let method_sendMessage = "sendMessage"
|
|
|
|
|
|
public static let method_receiveMessage = "receiveMessage"
|
|
|
|
|
|
public static let method_setOperator = "setOperator"
|
|
|
|
|
|
public static let method_getContacts = "getContacts"
|
|
|
|
|
|
private static let method_destroy = "destroy"
|
2023-07-08 00:10:42 +07:00
|
|
|
|
private static let method_pageLoaded = "pageLoaded"
|
2024-12-03 19:49:44 +07:00
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
public var chatView: WKWebView!
|
|
|
|
|
|
private var callJs: Array<String>!
|
|
|
|
|
|
private var didFinish: Bool = false
|
2020-06-01 12:58:55 +07:00
|
|
|
|
private var widgetUrl: String = ""
|
2023-07-08 00:35:44 +07:00
|
|
|
|
private var widgetOrg: String = ""
|
2023-07-08 00:10:42 +07:00
|
|
|
|
private var css: String = ""
|
2024-12-03 19:47:04 +07:00
|
|
|
|
private var alertLoading: UIAlertController?
|
2020-08-17 16:07:57 +07:00
|
|
|
|
|
2020-08-18 17:37:46 +07:00
|
|
|
|
private static func getUnreadedMessagesCallback(_ result: NSDictionary) -> NSDictionary {
|
|
|
|
|
|
let resultWrapper = ChatApiMessagesWrapper(result)
|
|
|
|
|
|
if resultWrapper.getMessages().count == 0 {
|
|
|
|
|
|
return resultWrapper.getResult()
|
|
|
|
|
|
}
|
|
|
|
|
|
var unreadedMessages: Array<NSDictionary> = []
|
|
|
|
|
|
for message: NSDictionary in resultWrapper.getMessages() as! Array<NSDictionary> {
|
|
|
|
|
|
if message.value(forKey: "isVisibleForClient") != nil {
|
|
|
|
|
|
if (message.value(forKey: "isVisibleForClient") as! Int) == 1 {
|
|
|
|
|
|
unreadedMessages.append(message)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if unreadedMessages.count == 0 {
|
|
|
|
|
|
return resultWrapper.getResult()
|
|
|
|
|
|
}
|
|
|
|
|
|
resultWrapper.setMessages(unreadedMessages as NSArray)
|
|
|
|
|
|
return resultWrapper.getResult()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-27 19:06:34 +07:00
|
|
|
|
private static func getUnreadedMessages(_ startDate: String, _ clientId: String, _ token: String, callback: @escaping (NSDictionary?) -> Void) {
|
2020-08-17 18:48:47 +07:00
|
|
|
|
if token == "" {
|
|
|
|
|
|
callback([
|
|
|
|
|
|
"success": false,
|
|
|
|
|
|
"error": [
|
|
|
|
|
|
"code": 0,
|
|
|
|
|
|
"descr": "Не задан token"
|
|
|
|
|
|
]
|
|
|
|
|
|
])
|
|
|
|
|
|
}
|
|
|
|
|
|
if clientId == "" {
|
|
|
|
|
|
callback([
|
|
|
|
|
|
"success": false,
|
|
|
|
|
|
"error": [
|
|
|
|
|
|
"code": 0,
|
|
|
|
|
|
"descr": "Не задан clientId"
|
|
|
|
|
|
]
|
|
|
|
|
|
])
|
|
|
|
|
|
}
|
|
|
|
|
|
ChatApi().messages(token, params: [
|
|
|
|
|
|
"client": [
|
|
|
|
|
|
"clientId": clientId
|
|
|
|
|
|
],
|
|
|
|
|
|
"sender": "operator",
|
|
|
|
|
|
"status": "unreaded",
|
|
|
|
|
|
"dateRange": [
|
|
|
|
|
|
"start": startDate,
|
2020-08-18 17:37:46 +07:00
|
|
|
|
"stop": ChatDateFormatter().getCurrent()
|
2020-08-17 18:48:47 +07:00
|
|
|
|
]
|
|
|
|
|
|
] as [String: Any], callback: {(result) in
|
2020-08-18 17:37:46 +07:00
|
|
|
|
callback( ChatController.getUnreadedMessagesCallback(result!) )
|
2020-08-17 18:48:47 +07:00
|
|
|
|
})
|
2020-08-17 16:07:57 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-27 19:06:34 +07:00
|
|
|
|
public static func getUnreadedMessages(clientId: String, token: String, callback: @escaping (NSDictionary?) -> Void) {
|
|
|
|
|
|
let startDate = ChatDateFormatter().string(from: Date(timeIntervalSince1970: TimeInterval(Int(NSDate().timeIntervalSince1970) - 86400 * 14)))
|
|
|
|
|
|
ChatController.getUnreadedMessages(startDate, clientId, token, callback: callback)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-17 18:48:47 +07:00
|
|
|
|
public static func getUnreadedMessages(callback: @escaping (NSDictionary?) -> Void) {
|
2020-08-18 17:37:46 +07:00
|
|
|
|
let startDate = ChatDateFormatter().string(from: Date(timeIntervalSince1970: TimeInterval(Int(NSDate().timeIntervalSince1970) - 86400 * 14)))
|
2020-08-27 19:06:34 +07:00
|
|
|
|
ChatController.getUnreadedMessages(startDate, ChatConfig.getClientId(), ChatConfig.getApiToken(), callback: callback)
|
2020-08-18 17:37:46 +07:00
|
|
|
|
}
|
2020-08-17 16:07:57 +07:00
|
|
|
|
|
2020-08-18 17:37:46 +07:00
|
|
|
|
private static func getNewMessagesCallback(_ result: NSDictionary) -> NSDictionary {
|
|
|
|
|
|
let resultWrapper = ChatApiMessagesWrapper(result)
|
|
|
|
|
|
if resultWrapper.getMessages().count == 0 {
|
|
|
|
|
|
return resultWrapper.getResult()
|
|
|
|
|
|
}
|
|
|
|
|
|
let lastMessage = resultWrapper.getMessages()[resultWrapper.getMessages().count - 1] as! NSDictionary
|
|
|
|
|
|
let lastDate = ChatDateFormatter().date(from: lastMessage["dateTime"] as! String)
|
|
|
|
|
|
let nextDate = Date(timeIntervalSince1970: TimeInterval( Int(lastDate!.timeIntervalSince1970) + 1 ))
|
|
|
|
|
|
ChatConfig.setLastDateTimeNewMessage( ChatDateFormatter().string(from: nextDate) )
|
|
|
|
|
|
return resultWrapper.getResult()
|
2020-08-17 16:07:57 +07:00
|
|
|
|
}
|
2020-08-17 18:48:47 +07:00
|
|
|
|
|
2020-08-27 19:06:34 +07:00
|
|
|
|
public static func getNewMessages(clientId: String, token: String, callback: @escaping (NSDictionary?) -> Void) {
|
2020-08-18 17:37:46 +07:00
|
|
|
|
let startDate = ChatConfig.getLastDateTimeNewMessage()
|
|
|
|
|
|
if startDate == "" {
|
2020-08-27 19:06:34 +07:00
|
|
|
|
self.getUnreadedMessages(clientId: clientId, token: token, callback: {(result) in
|
2020-08-18 17:37:46 +07:00
|
|
|
|
callback( ChatController.getNewMessagesCallback(result!) )
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
2020-08-27 19:06:34 +07:00
|
|
|
|
self.getUnreadedMessages(startDate, clientId, token, callback: {(result) in
|
2020-08-18 17:37:46 +07:00
|
|
|
|
callback( ChatController.getNewMessagesCallback(result!) )
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2020-08-17 18:48:47 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-27 19:06:34 +07:00
|
|
|
|
public static func getNewMessages(callback: @escaping (NSDictionary?) -> Void) {
|
|
|
|
|
|
self.getNewMessages(clientId: ChatConfig.getClientId(), token: ChatConfig.getApiToken(), callback: {(result) in
|
|
|
|
|
|
callback( ChatController.getNewMessagesCallback(result!) )
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-02-06 12:24:38 +07:00
|
|
|
|
|
|
|
|
|
|
public static func setInfoCustomDataValue(key: String, value: String, callback: @escaping (NSDictionary?) -> Void) {
|
|
|
|
|
|
DispatchQueue.global().async {
|
|
|
|
|
|
ChatApi.setInfo(
|
|
|
|
|
|
ChatConfig.getApiToken(),
|
|
|
|
|
|
[
|
|
|
|
|
|
"client": [
|
|
|
|
|
|
"id": ChatConfig.getClientId(),
|
|
|
|
|
|
"customData": [
|
|
|
|
|
|
key: value
|
|
|
|
|
|
]
|
|
|
|
|
|
],
|
|
|
|
|
|
] as [String : Any],
|
|
|
|
|
|
callback: callback
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-08-27 19:06:34 +07:00
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
override public func loadView() {
|
|
|
|
|
|
let contentController = WKUserContentController()
|
|
|
|
|
|
contentController.add(self, name: "chatInterface")
|
|
|
|
|
|
|
|
|
|
|
|
let preferences = WKPreferences()
|
|
|
|
|
|
preferences.javaScriptEnabled = true
|
|
|
|
|
|
preferences.javaScriptCanOpenWindowsAutomatically = true
|
|
|
|
|
|
|
|
|
|
|
|
let config = WKWebViewConfiguration()
|
|
|
|
|
|
config.userContentController = contentController
|
|
|
|
|
|
config.preferences = preferences
|
2019-11-20 13:50:21 +07:00
|
|
|
|
|
2020-03-17 18:27:35 +07:00
|
|
|
|
var frame = UIScreen.main.bounds
|
2021-12-09 23:07:47 +07:00
|
|
|
|
if parent != nil && parent?.view != nil && parent?.view.bounds != nil {
|
|
|
|
|
|
frame = (parent?.view.bounds)!
|
2020-03-17 18:27:35 +07:00
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
chatView = WKWebView(frame: frame, configuration: config)
|
|
|
|
|
|
chatView.navigationDelegate = self
|
2024-11-21 17:15:50 +07:00
|
|
|
|
|
2024-12-03 19:47:04 +07:00
|
|
|
|
view = chatView
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func getAlertLoadingActionCloseTitle() -> String {
|
|
|
|
|
|
let currentLanguage = Locale.current.languageCode
|
|
|
|
|
|
if currentLanguage == "ru" {
|
|
|
|
|
|
return "Закрыть"
|
|
|
|
|
|
}
|
|
|
|
|
|
return "Close"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func showLoadingDialog() {
|
|
|
|
|
|
if alertLoading != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
alertLoading = UIAlertController(
|
|
|
|
|
|
title: nil,
|
|
|
|
|
|
message: " ",
|
|
|
|
|
|
preferredStyle: .alert
|
|
|
|
|
|
)
|
|
|
|
|
|
alertLoading?.addAction(UIAlertAction(title: getAlertLoadingActionCloseTitle(), style: .destructive, handler: cancelLoading))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let loadingIndicator = UIActivityIndicatorView(style: .medium)
|
|
|
|
|
|
loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
|
loadingIndicator.startAnimating()
|
2024-11-21 17:15:50 +07:00
|
|
|
|
|
2024-12-03 19:47:04 +07:00
|
|
|
|
alertLoading?.view.addSubview(loadingIndicator)
|
|
|
|
|
|
|
2024-11-21 17:15:50 +07:00
|
|
|
|
NSLayoutConstraint.activate([
|
2024-12-03 19:47:04 +07:00
|
|
|
|
loadingIndicator.centerXAnchor.constraint(equalTo: alertLoading!.view.centerXAnchor),
|
|
|
|
|
|
loadingIndicator.bottomAnchor.constraint(equalTo: alertLoading!.view.bottomAnchor, constant: -60)
|
2024-11-21 17:15:50 +07:00
|
|
|
|
])
|
2024-12-03 19:47:04 +07:00
|
|
|
|
present(alertLoading!, animated: true)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func cancelLoading(action: UIAlertAction) {
|
|
|
|
|
|
onCloseSupport()
|
|
|
|
|
|
}
|
2024-11-21 17:15:50 +07:00
|
|
|
|
|
2024-12-03 19:47:04 +07:00
|
|
|
|
private func hideLoadingDialog() {
|
|
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
|
|
|
|
|
if self.alertLoading == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
self.alertLoading?.dismiss(animated: true, completion: nil)
|
|
|
|
|
|
self.alertLoading = nil
|
|
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-03 19:47:04 +07:00
|
|
|
|
|
2024-11-21 17:15:50 +07:00
|
|
|
|
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
2024-12-03 19:47:04 +07:00
|
|
|
|
showLoadingDialog()
|
2024-11-21 17:15:50 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
2024-12-03 19:47:04 +07:00
|
|
|
|
hideLoadingDialog()
|
2024-11-21 17:15:50 +07:00
|
|
|
|
showMessage(error.localizedDescription)
|
2024-12-03 19:47:04 +07:00
|
|
|
|
}
|
2024-11-21 17:15:50 +07:00
|
|
|
|
|
|
|
|
|
|
public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: any Error) {
|
2024-12-03 19:47:04 +07:00
|
|
|
|
hideLoadingDialog()
|
2024-11-21 17:15:50 +07:00
|
|
|
|
showMessage(error.localizedDescription)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func showMessage(_ message: String) {
|
|
|
|
|
|
let alert = UIAlertController(
|
|
|
|
|
|
title: nil,
|
|
|
|
|
|
message: message,
|
|
|
|
|
|
preferredStyle: .alert
|
|
|
|
|
|
)
|
|
|
|
|
|
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
|
|
|
|
|
|
self.onCloseSupport()
|
|
|
|
|
|
})
|
|
|
|
|
|
present(alert, animated: true, completion: nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
2021-12-09 23:07:47 +07:00
|
|
|
|
didFinish = true
|
|
|
|
|
|
if callJs != nil && !callJs.isEmpty {
|
|
|
|
|
|
for script in callJs {
|
2019-11-20 01:13:59 +07:00
|
|
|
|
callJs(script)
|
|
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
callJs = nil
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
2024-12-03 19:47:04 +07:00
|
|
|
|
// hideLoadingDialog()
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
2020-06-01 12:58:55 +07:00
|
|
|
|
|
|
|
|
|
|
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> ()) {
|
2020-06-01 14:44:50 +07:00
|
|
|
|
if let _ = navigationAction.request.url?.host {
|
2023-07-08 00:35:44 +07:00
|
|
|
|
if (navigationAction.request.url?.absoluteString.contains(self.widgetOrg))! {
|
|
|
|
|
|
decisionHandler(.allow)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2020-09-09 18:13:02 +07:00
|
|
|
|
if (navigationAction.request.url?.absoluteString.contains(self.widgetUrl))! {
|
2020-06-01 12:58:55 +07:00
|
|
|
|
decisionHandler(.allow)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-07-08 00:35:44 +07:00
|
|
|
|
if (
|
|
|
|
|
|
(navigationAction.request.url?.absoluteString.contains( "https://www.google.com/recaptcha/api2/anchor?" ))! ||
|
|
|
|
|
|
(navigationAction.request.url?.absoluteString.contains( "https://www.google.com/recaptcha/api/fallback?" ))! ||
|
|
|
|
|
|
(navigationAction.request.url?.absoluteString.contains( "https://www.google.com/recaptcha/api2/bframe?" ))!
|
|
|
|
|
|
) {
|
|
|
|
|
|
decisionHandler(.allow)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2020-06-01 12:58:55 +07:00
|
|
|
|
}
|
|
|
|
|
|
decisionHandler(.cancel)
|
2021-12-09 23:07:47 +07:00
|
|
|
|
onLinkPressed(url: navigationAction.request.url!)
|
2020-06-01 12:58:55 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
private func getCallJsMethod(_ name: String, params: Array<Any>) -> String {
|
|
|
|
|
|
var res: String = "window.MeTalk('"
|
|
|
|
|
|
res.append(name)
|
|
|
|
|
|
res.append("'")
|
|
|
|
|
|
if params.count > 0 {
|
|
|
|
|
|
for p in params {
|
|
|
|
|
|
res.append(",")
|
|
|
|
|
|
if p is Int {
|
|
|
|
|
|
res.append(String(describing: p))
|
|
|
|
|
|
} else if p is Command {
|
|
|
|
|
|
res.append((p as! Command).command)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
res.append("'")
|
|
|
|
|
|
res.append(String(describing: p))
|
|
|
|
|
|
res.append("'")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
res.append(")")
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func callJs(_ script: String) {
|
2025-02-06 12:24:38 +07:00
|
|
|
|
print("callJs : \(script)")
|
2021-12-09 23:07:47 +07:00
|
|
|
|
chatView.evaluateJavaScript(script)
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func toJson(_ jsonObj: AnyObject) -> String {
|
|
|
|
|
|
var data:Data? = nil
|
|
|
|
|
|
do {
|
|
|
|
|
|
data = try JSONSerialization.data(withJSONObject: jsonObj, options: JSONSerialization.WritingOptions());
|
|
|
|
|
|
} catch {}
|
|
|
|
|
|
if data != nil {
|
|
|
|
|
|
return NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! as String
|
|
|
|
|
|
}
|
|
|
|
|
|
return "{}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-08 00:35:44 +07:00
|
|
|
|
// public func load(_ id: String, _ domain: String, _ language: String = "", _ clientId: String = "", _ apiToken: String = "", _ showCloseButton: Bool = true, css: String = "") {
|
|
|
|
|
|
// if apiToken != "" {
|
|
|
|
|
|
// ChatConfig.setApiToken(apiToken)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// var setup: Dictionary<String, Any> = [:]
|
|
|
|
|
|
// if !language.isEmpty {
|
|
|
|
|
|
// setup["language"] = language
|
|
|
|
|
|
// }
|
|
|
|
|
|
// if !clientId.isEmpty {
|
|
|
|
|
|
// setup["clientId"] = clientId
|
|
|
|
|
|
// }
|
|
|
|
|
|
// widgetUrl = "https://admin.verbox.ru/support/chat/\(id)/\(domain)"
|
|
|
|
|
|
// self.css = css
|
|
|
|
|
|
// var url = URL(string: widgetUrl)
|
|
|
|
|
|
// if url == nil {
|
|
|
|
|
|
// var encodeDomain = String(describing: domain.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
|
|
|
|
|
|
// encodeDomain = encodeDomain.replacingOccurrences(of: "Optional(\"", with: "")
|
|
|
|
|
|
// encodeDomain = encodeDomain.replacingOccurrences(of: "\")", with: "")
|
|
|
|
|
|
// widgetUrl = "https://admin.verbox.ru/support/chat/\(id)/\(encodeDomain)"
|
|
|
|
|
|
// url = URL(string: widgetUrl)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// var urlComponents = URLComponents(url: url!, resolvingAgainstBaseURL: false)
|
|
|
|
|
|
// if !setup.isEmpty {
|
|
|
|
|
|
// if (showCloseButton) {
|
|
|
|
|
|
// urlComponents?.queryItems = [
|
|
|
|
|
|
// URLQueryItem(name: "setup", value: toJson(setup as AnyObject)),
|
|
|
|
|
|
// URLQueryItem(name: "sdk-show-close-button", value: "1")
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// urlComponents?.queryItems = [
|
|
|
|
|
|
// URLQueryItem(name: "setup", value: toJson(setup as AnyObject))
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// }
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// if (showCloseButton) {
|
|
|
|
|
|
// urlComponents?.queryItems = [
|
|
|
|
|
|
// URLQueryItem(name: "sdk-show-close-button", value: "1")
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// url = urlComponents!.url!
|
|
|
|
|
|
// if url == nil {
|
|
|
|
|
|
// url = URL(string: widgetUrl)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// chatView.load(URLRequest(url: url!))
|
|
|
|
|
|
// chatView.allowsBackForwardNavigationGestures = true
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-07-08 00:10:42 +07:00
|
|
|
|
public func load(_ id: String, _ domain: String, _ language: String = "", _ clientId: String = "", _ apiToken: String = "", _ showCloseButton: Bool = true, css: String = "") {
|
2020-08-17 18:48:47 +07:00
|
|
|
|
if apiToken != "" {
|
|
|
|
|
|
ChatConfig.setApiToken(apiToken)
|
|
|
|
|
|
}
|
2019-11-20 01:13:59 +07:00
|
|
|
|
var setup: Dictionary<String, Any> = [:]
|
|
|
|
|
|
if !language.isEmpty {
|
|
|
|
|
|
setup["language"] = language
|
|
|
|
|
|
}
|
|
|
|
|
|
if !clientId.isEmpty {
|
|
|
|
|
|
setup["clientId"] = clientId
|
|
|
|
|
|
}
|
2023-07-08 00:10:42 +07:00
|
|
|
|
self.css = css
|
2023-07-08 00:35:44 +07:00
|
|
|
|
var encodeDomain: String = String(describing: domain.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
|
|
|
|
|
|
if (encodeDomain.contains("Optional(\"")) {
|
2022-05-12 12:44:52 +07:00
|
|
|
|
encodeDomain = encodeDomain.replacingOccurrences(of: "Optional(\"", with: "")
|
|
|
|
|
|
encodeDomain = encodeDomain.replacingOccurrences(of: "\")", with: "")
|
|
|
|
|
|
}
|
2023-07-08 00:35:44 +07:00
|
|
|
|
widgetUrl = "https://admin.verbox.ru/support/chat/\(id)/\(encodeDomain)"
|
|
|
|
|
|
widgetOrg = "https://admin.verbox.ru/support/chat/\(id)/"
|
|
|
|
|
|
var url = URL(string: widgetUrl)
|
2021-12-09 23:07:47 +07:00
|
|
|
|
var urlComponents = URLComponents(url: url!, resolvingAgainstBaseURL: false)
|
2019-11-20 01:13:59 +07:00
|
|
|
|
if !setup.isEmpty {
|
2021-12-15 16:53:43 +07:00
|
|
|
|
if (showCloseButton) {
|
|
|
|
|
|
urlComponents?.queryItems = [
|
|
|
|
|
|
URLQueryItem(name: "setup", value: toJson(setup as AnyObject)),
|
|
|
|
|
|
URLQueryItem(name: "sdk-show-close-button", value: "1")
|
|
|
|
|
|
]
|
|
|
|
|
|
} else {
|
|
|
|
|
|
urlComponents?.queryItems = [
|
|
|
|
|
|
URLQueryItem(name: "setup", value: toJson(setup as AnyObject))
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
} else {
|
2021-12-15 16:53:43 +07:00
|
|
|
|
if (showCloseButton) {
|
|
|
|
|
|
urlComponents?.queryItems = [
|
|
|
|
|
|
URLQueryItem(name: "sdk-show-close-button", value: "1")
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
url = urlComponents!.url!
|
2019-11-20 01:13:59 +07:00
|
|
|
|
if url == nil {
|
2021-12-09 23:07:47 +07:00
|
|
|
|
url = URL(string: widgetUrl)
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
chatView.load(URLRequest(url: url!))
|
|
|
|
|
|
chatView.allowsBackForwardNavigationGestures = true
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-08 00:10:42 +07:00
|
|
|
|
public func injectCss(style: String) {
|
|
|
|
|
|
if (style.isEmpty) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let injectCssTemplate = "(function() {" +
|
|
|
|
|
|
"var parent = document.getElementsByTagName('head').item(0);" +
|
|
|
|
|
|
"var style = document.createElement('style');" +
|
|
|
|
|
|
"style.type = 'text/css';" +
|
|
|
|
|
|
"style.innerHTML = '\(style)';" +
|
2023-07-08 00:35:44 +07:00
|
|
|
|
"parent.appendChild(style) ;" +
|
2023-07-08 00:10:42 +07:00
|
|
|
|
"})()";
|
|
|
|
|
|
|
|
|
|
|
|
callJs(injectCssTemplate);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
public func callJsMethod(_ name: String, params: Array<Any>) {
|
2021-12-09 23:07:47 +07:00
|
|
|
|
if didFinish {
|
2019-11-20 01:13:59 +07:00
|
|
|
|
callJs(getCallJsMethod(name, params: params))
|
|
|
|
|
|
} else {
|
2021-12-09 23:07:47 +07:00
|
|
|
|
if callJs == nil {
|
|
|
|
|
|
callJs = []
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
callJs.append(getCallJsMethod(name, params: params))
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsSetClientInfo(_ jsonInfo: String) {
|
2020-06-01 12:58:55 +07:00
|
|
|
|
callJsMethod(ChatController.method_setClientInfo, params: [Command(jsonInfo)])
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsSetTarget(_ reason: String) {
|
|
|
|
|
|
callJsMethod(ChatController.method_setTarget, params: [reason])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsOpenReviewsTab() {
|
|
|
|
|
|
callJsMethod(ChatController.method_openReviewsTab, params: [])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsOpenTab(_ index: Int) {
|
|
|
|
|
|
callJsMethod(ChatController.method_openTab, params: [index])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsSendMessage(_ text: String) {
|
|
|
|
|
|
callJsMethod(ChatController.method_sendMessage, params: [text])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsReceiveMessage(_ text: String, _ oper: String, _ simulateTyping: Int) {
|
|
|
|
|
|
callJsMethod(ChatController.method_receiveMessage, params: [text, oper, simulateTyping])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsSetOperator(_ login: String) {
|
|
|
|
|
|
callJsMethod(ChatController.method_setOperator, params: [login])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func callJsGetContacts() {
|
|
|
|
|
|
callJsMethod(ChatController.method_getContacts, params: [Command("window.getContactsCallback")])
|
|
|
|
|
|
}
|
2021-12-15 16:53:43 +07:00
|
|
|
|
|
|
|
|
|
|
private func callJsDestroy() {
|
|
|
|
|
|
callJsMethod(ChatController.method_destroy, params: [])
|
|
|
|
|
|
}
|
2019-11-20 01:13:59 +07:00
|
|
|
|
|
|
|
|
|
|
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
2024-12-03 19:47:04 +07:00
|
|
|
|
hideLoadingDialog()
|
2019-11-20 01:13:59 +07:00
|
|
|
|
if message.name != "chatInterface" {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let jsonBody = (message.body as! String).data(using: .utf8)!
|
|
|
|
|
|
let body = try? (JSONSerialization.jsonObject(with: jsonBody, options: .mutableLeaves) as! NSDictionary)
|
|
|
|
|
|
if body == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if body!["name"] == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2021-12-15 16:53:43 +07:00
|
|
|
|
if chatView == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2019-11-20 01:13:59 +07:00
|
|
|
|
var data: NSDictionary?
|
|
|
|
|
|
if body!["data"] != nil {
|
|
|
|
|
|
data = (body!["data"] as! NSDictionary)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
data = [:]
|
|
|
|
|
|
}
|
|
|
|
|
|
let name = body!["name"] as! String
|
|
|
|
|
|
switch name {
|
2023-07-08 00:10:42 +07:00
|
|
|
|
case ChatController.method_pageLoaded:
|
|
|
|
|
|
injectCss(style: self.css)
|
2025-02-06 12:24:38 +07:00
|
|
|
|
onChatWasOpen()
|
2025-02-06 18:44:43 +07:00
|
|
|
|
listenApplicationState()
|
2023-07-08 00:10:42 +07:00
|
|
|
|
break
|
2021-12-09 23:07:47 +07:00
|
|
|
|
case ChatController.event_closeSupport:
|
|
|
|
|
|
onCloseSupport()
|
|
|
|
|
|
break
|
2019-11-20 01:13:59 +07:00
|
|
|
|
case ChatController.event_clientId:
|
2020-08-17 18:48:47 +07:00
|
|
|
|
let clientId = data!["clientId"] != nil ? data!["clientId"] as! String : ""
|
|
|
|
|
|
ChatConfig.setClientId(clientId)
|
|
|
|
|
|
onClientId(clientId)
|
2019-11-20 01:13:59 +07:00
|
|
|
|
break
|
|
|
|
|
|
case ChatController.event_sendRate:
|
|
|
|
|
|
onSendRate(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
case ChatController.event_contactsUpdated:
|
|
|
|
|
|
onContactsUpdated(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
case ChatController.event_clientSendMessage:
|
|
|
|
|
|
onClientSendMessage(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
case ChatController.event_clientMakeSubscribe:
|
|
|
|
|
|
onClientMakeSubscribe(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
case ChatController.event_operatorSendMessage:
|
|
|
|
|
|
onOperatorSendMessage(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
case ChatController.method_getContacts:
|
|
|
|
|
|
getContactsCallback(data!)
|
|
|
|
|
|
break
|
|
|
|
|
|
default:
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
onEvent(name, data!)
|
|
|
|
|
|
}
|
2021-12-15 16:53:43 +07:00
|
|
|
|
|
2025-02-06 18:44:43 +07:00
|
|
|
|
private func listenApplicationState() {
|
|
|
|
|
|
NotificationCenter.default.addObserver(
|
|
|
|
|
|
self,
|
|
|
|
|
|
selector: #selector(appDidBecomeActive),
|
|
|
|
|
|
name: UIApplication.didBecomeActiveNotification,
|
|
|
|
|
|
object: nil
|
|
|
|
|
|
)
|
|
|
|
|
|
NotificationCenter.default.addObserver(
|
|
|
|
|
|
self,
|
|
|
|
|
|
selector: #selector(appWillResignActive),
|
|
|
|
|
|
name: UIApplication.willResignActiveNotification,
|
|
|
|
|
|
object: nil
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@objc private func appDidBecomeActive() {
|
|
|
|
|
|
onChatWasOpen()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@objc private func appWillResignActive() {
|
|
|
|
|
|
onChatWasClosed()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-02-06 12:24:38 +07:00
|
|
|
|
open func onChatWasOpen() {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onChatWasClosed() {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-09 23:07:47 +07:00
|
|
|
|
open func onCloseSupport() {
|
2021-12-15 16:53:43 +07:00
|
|
|
|
if chatView == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-01-15 18:40:59 +07:00
|
|
|
|
chatView.stopLoading()
|
|
|
|
|
|
callJsDestroy()
|
|
|
|
|
|
chatView = nil
|
|
|
|
|
|
|
2021-12-09 23:07:47 +07:00
|
|
|
|
dismiss(animated: true, completion: nil)
|
2021-12-15 16:53:43 +07:00
|
|
|
|
navigationController?.popViewController(animated: true)
|
2025-02-06 18:44:43 +07:00
|
|
|
|
NotificationCenter.default.removeObserver(self)
|
2025-02-06 12:24:38 +07:00
|
|
|
|
|
|
|
|
|
|
onChatWasClosed()
|
2021-12-15 16:53:43 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open override func viewDidDisappear(_ animated: Bool) {
|
|
|
|
|
|
super.viewDidDisappear(animated)
|
2025-01-15 18:40:59 +07:00
|
|
|
|
onCloseSupport()
|
2021-12-09 23:07:47 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-15 01:39:32 +07:00
|
|
|
|
open func onLinkPressed(url: URL) {
|
2024-11-21 17:36:28 +07:00
|
|
|
|
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
2020-08-15 01:39:32 +07:00
|
|
|
|
}
|
2019-11-20 01:13:59 +07:00
|
|
|
|
|
|
|
|
|
|
open func playSound(_ systemSoundId: SystemSoundID) {
|
|
|
|
|
|
AudioServicesPlaySystemSound(systemSoundId)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onClientId(_ clientId: String) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2020-08-15 02:03:05 +07:00
|
|
|
|
|
2019-11-20 01:13:59 +07:00
|
|
|
|
open func onSendRate(_ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onContactsUpdated(_ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onClientSendMessage(_ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onClientMakeSubscribe(_ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onOperatorSendMessage(_ data: NSDictionary) {
|
2021-12-09 23:07:47 +07:00
|
|
|
|
playSound(1315)
|
2019-11-20 01:13:59 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func onEvent(_ name: String, _ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
open func getContactsCallback(_ data: NSDictionary) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2021-12-09 23:07:47 +07:00
|
|
|
|
}
|