From 25475c271332b707bf78e0411a8f763fa883aac0 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 23 Nov 2024 19:46:55 +0100 Subject: [PATCH 1/9] use new selfAddr api --- deltachat-ios/Controller/WebxdcViewController.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index feadbf72c..c2c58672e 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -17,6 +17,7 @@ class WebxdcViewController: WebViewViewController { var messageId: Int var webxdcName: String = "" var sourceCodeUrl: String? + var selfAddr: String = "" private var allowInternet: Bool = false private var shortcutManager: ShortcutManager? @@ -57,7 +58,7 @@ class WebxdcViewController: WebViewViewController { """ lazy var webxdcbridge: String = { - let addr = dcContext.addr? + let addr = selfAddr .addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) let displayname = (dcContext.displayname ?? dcContext.addr)? .addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) @@ -284,6 +285,7 @@ class WebxdcViewController: WebViewViewController { object: nil) NotificationCenter.default.addObserver(self, selector: #selector(WebxdcViewController.handleWebxdcStatusUpdate(_:)), name: Event.webxdcStatusUpdate, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(WebxdcViewController.handleWebxdcRealtimeDataReceived(_:)), name: Event.webxdcRealtimeDataReceived, object: nil) + refreshWebxdcInfo() } required init?(coder: NSCoder) { @@ -298,7 +300,6 @@ class WebxdcViewController: WebViewViewController { override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = moreButton - refreshWebxdcInfo() } override func willMove(toParent parent: UIViewController?) { @@ -321,6 +322,10 @@ class WebxdcViewController: WebViewViewController { !sourceCode.isEmpty { sourceCodeUrl = sourceCode } + + if let addr = dict["self_addr"] as? String { + selfAddr = addr + } } // MARK: - Notifications From cd3e5dc4e90e739de466d029b0beccd929d1d51e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 23 Nov 2024 21:24:41 +0100 Subject: [PATCH 2/9] add new webxdc-notify api --- DcCore/DcCore/DC/events.swift | 10 +++++++ .../NotificationService.swift | 16 ++++++++++ deltachat-ios/DC/DcMsg+Extension.swift | 9 ------ deltachat-ios/DC/DcMsg.swift | 20 +++++++++++++ .../Helper/NotificationManager.swift | 29 +++++++++++++++++++ 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/DcCore/DcCore/DC/events.swift b/DcCore/DcCore/DC/events.swift index 1e413c75d..9294c5828 100644 --- a/DcCore/DcCore/DC/events.swift +++ b/DcCore/DcCore/DC/events.swift @@ -8,6 +8,7 @@ public enum Event { public static let incomingMessage = Notification.Name(rawValue: "incomingMessage") public static let incomingMessageOnAnyAccount = Notification.Name(rawValue: "incomingMessageOnAnyAccount") public static let incomingReaction = Notification.Name(rawValue: "incomingReaction") + public static let incomingWebxdcNotify = Notification.Name(rawValue: "incomingWebxdcNotify") public static let messagesNoticed = Notification.Name(rawValue: "messagesNoticed") // Chats @@ -155,6 +156,15 @@ public class DcEventHandler { "reaction": event.data2String ]) + case DC_EVENT_INCOMING_WEBXDC_NOTIFY: + logger.info("📡[\(accountId)] incoming webxdc notify") + NotificationCenter.default.post(name: Event.incomingWebxdcNotify, object: nil, userInfo: [ + "account_id": Int(accountId), + "contact_id": Int(data1), + "msg_id": Int(data2), + "text": event.data2String + ]) + case DC_EVENT_CONTACTS_CHANGED: if accountId != dcAccounts.getSelected().id { return diff --git a/DcNotificationService/NotificationService.swift b/DcNotificationService/NotificationService.swift index 7c7ab057e..4a0d9fb8d 100644 --- a/DcNotificationService/NotificationService.swift +++ b/DcNotificationService/NotificationService.swift @@ -74,6 +74,22 @@ class NotificationService: UNNotificationServiceExtension { reactionCount += 1 } } + } else if event.id == DC_EVENT_INCOMING_WEBXDC_NOTIFY { + let dcContext = dcAccounts.get(id: event.accountId) + if !dcContext.isMuted() { + let msg = dcContext.getMessage(id: event.data2Int) + let chat = dcContext.getChat(chatId: msg.chatId) + if !chat.isMuted { + bestAttemptContent.title = chat.name + bestAttemptContent.body = msg.getWebxdcAppName() + ": " + event.data2String + bestAttemptContent.userInfo["account_id"] = dcContext.id + bestAttemptContent.userInfo["chat_id"] = chat.id + bestAttemptContent.userInfo["message_id"] = msg.id + + uniqueChats["\(dcContext.id)-\(chat.id)"] = bestAttemptContent.title + messageCount += 1 + } + } } } diff --git a/deltachat-ios/DC/DcMsg+Extension.swift b/deltachat-ios/DC/DcMsg+Extension.swift index 357402cc5..a45916bb8 100644 --- a/deltachat-ios/DC/DcMsg+Extension.swift +++ b/deltachat-ios/DC/DcMsg+Extension.swift @@ -12,15 +12,6 @@ extension DcMsg { return "\(size) \(units[digitGroups])" } - public func getWebxdcInfoDict() -> [String: AnyObject] { - let jsonString = self.getWebxdcInfoJson() - if let data: Data = jsonString.data(using: .utf8), - let infoDict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: AnyObject] { - return infoDict - } - return [:] - } - public func getWebxdcPreviewImage() -> UIImage? { let dict = self.getWebxdcInfoDict() if let iconfilePath = dict["icon"] as? String { diff --git a/deltachat-ios/DC/DcMsg.swift b/deltachat-ios/DC/DcMsg.swift index 190dea60d..d7597c435 100644 --- a/deltachat-ios/DC/DcMsg.swift +++ b/deltachat-ios/DC/DcMsg.swift @@ -168,6 +168,26 @@ public class DcMsg { return swiftString } + public func getWebxdcInfoDict() -> [String: AnyObject] { + let jsonString = self.getWebxdcInfoJson() + if let data: Data = jsonString.data(using: .utf8), + let infoDict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: AnyObject] { + return infoDict + } + return [:] + } + + // returns webxdc app name for an webxdc-info-messages or webxdc-instances + public func getWebxdcAppName() -> String { + let msg = if self.isInfo, let parent = self.parent { + parent + } else { + self + } + let dict = msg.getWebxdcInfoDict() + return dict["name"] as? String ?? "ErrName" + } + public var messageHeight: CGFloat { return CGFloat(dc_msg_get_height(messagePointer)) } diff --git a/deltachat-ios/Helper/NotificationManager.swift b/deltachat-ios/Helper/NotificationManager.swift index 50b6893da..3e0f3bb92 100644 --- a/deltachat-ios/Helper/NotificationManager.swift +++ b/deltachat-ios/Helper/NotificationManager.swift @@ -14,6 +14,7 @@ public class NotificationManager { NotificationCenter.default.addObserver(self, selector: #selector(NotificationManager.handleIncomingMessageOnAnyAccount(_:)), name: Event.incomingMessageOnAnyAccount, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(NotificationManager.handleIncomingReaction(_:)), name: Event.incomingReaction, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(NotificationManager.handleIncomingWebxdcNotify(_:)), name: Event.incomingWebxdcNotify, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(NotificationManager.handleMessagesNoticed(_:)), name: Event.messagesNoticed, object: nil) } @@ -155,4 +156,32 @@ public class NotificationManager { UIApplication.shared.endBackgroundTask(backgroundTask) // this line must be reached to balance call to `beginBackgroundTask` above } } + + @objc private func handleIncomingWebxdcNotify(_ notification: Notification) { + let backgroundTask = UIApplication.shared.beginBackgroundTask { + logger.info("incoming-webxdc-notify-task will end soon") + } + + DispatchQueue.global().async { [weak self] in + guard let self, let ui = notification.userInfo else { return } + let eventContext = dcAccounts.get(id: ui["account_id"] as? Int ?? 0) + if !eventContext.isMuted() { + let msg = eventContext.getMessage(id: ui["msg_id"] as? Int ?? 0) + let chat = eventContext.getChat(chatId: msg.chatId) + if !chat.isMuted { + let content = UNMutableNotificationContent() + content.title = chat.name + content.body = msg.getWebxdcAppName() + ": " + (ui["text"] as? String ?? "") + content.userInfo["account_id"] = eventContext.id + content.userInfo["chat_id"] = chat.id + content.userInfo["message_id"] = msg.id + + let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) + UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) + } + } + + UIApplication.shared.endBackgroundTask(backgroundTask) // this line must be reached to balance call to `beginBackgroundTask` above + } + } } From 52c4685d109192303fc5ddd3cbd4039113488a54 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 23 Nov 2024 22:45:02 +0100 Subject: [PATCH 3/9] open the webxdc on tapping its info --- deltachat-ios/Chat/ChatViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deltachat-ios/Chat/ChatViewController.swift b/deltachat-ios/Chat/ChatViewController.swift index b71953082..905638301 100644 --- a/deltachat-ios/Chat/ChatViewController.swift +++ b/deltachat-ios/Chat/ChatViewController.swift @@ -833,7 +833,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { showWebxdcViewFor(message: message) case (_, DC_INFO_WEBXDC_INFO_MESSAGE): if let parent = message.parent { - scrollToMessage(msgId: parent.id) + showWebxdcViewFor(message: parent) } case (_, DC_INFO_PROTECTION_ENABLED): showProtectionEnabledDialog() From 6e9ef84904680a7fb971f6f81451fcd1569a6262 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 23 Nov 2024 23:55:41 +0100 Subject: [PATCH 4/9] add deeplink api --- deltachat-ios/Chat/ChatViewController.swift | 6 +++--- .../Controller/WebxdcViewController.swift | 17 +++++++++++++++-- deltachat-ios/DC/DcMsg.swift | 7 +++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/deltachat-ios/Chat/ChatViewController.swift b/deltachat-ios/Chat/ChatViewController.swift index 905638301..4e7f95aea 100644 --- a/deltachat-ios/Chat/ChatViewController.swift +++ b/deltachat-ios/Chat/ChatViewController.swift @@ -833,7 +833,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { showWebxdcViewFor(message: message) case (_, DC_INFO_WEBXDC_INFO_MESSAGE): if let parent = message.parent { - showWebxdcViewFor(message: parent) + showWebxdcViewFor(message: parent, href: message.getWebxdcHref()) } case (_, DC_INFO_PROTECTION_ENABLED): showProtectionEnabledDialog() @@ -2106,8 +2106,8 @@ extension ChatViewController: MCEmojiPickerDelegate { extension ChatViewController { - func showWebxdcViewFor(message: DcMsg) { - let webxdcViewController = WebxdcViewController(dcContext: dcContext, messageId: message.id) + func showWebxdcViewFor(message: DcMsg, href: String? = nil) { + let webxdcViewController = WebxdcViewController(dcContext: dcContext, messageId: message.id, href: href) navigationController?.pushViewController(webxdcViewController, animated: true) } diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index c2c58672e..fcfa30c30 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -15,6 +15,7 @@ class WebxdcViewController: WebViewViewController { let INTERNALSCHEMA = "webxdc" var messageId: Int + var href: String? var webxdcName: String = "" var sourceCodeUrl: String? var selfAddr: String = "" @@ -273,8 +274,9 @@ class WebxdcViewController: WebViewViewController { } - init(dcContext: DcContext, messageId: Int) { + init(dcContext: DcContext, messageId: Int, href: String? = nil) { self.messageId = messageId + self.href = href self.shortcutManager = ShortcutManager(dcContext: dcContext, messageId: messageId) super.init(dcContext: dcContext) @@ -422,7 +424,18 @@ class WebxdcViewController: WebViewViewController { private func loadHtml() { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self else { return } - let url = URL(string: "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/index.html") + + let file = if let href { + if href.starts(with: "#") { + "index.html" + href + } else { + href + } + } else { + "index.html" + } + + let url = URL(string: "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + file) let urlRequest = URLRequest(url: url!) DispatchQueue.main.async { self.webView.load(urlRequest) diff --git a/deltachat-ios/DC/DcMsg.swift b/deltachat-ios/DC/DcMsg.swift index d7597c435..11846ae48 100644 --- a/deltachat-ios/DC/DcMsg.swift +++ b/deltachat-ios/DC/DcMsg.swift @@ -188,6 +188,13 @@ public class DcMsg { return dict["name"] as? String ?? "ErrName" } + public func getWebxdcHref() -> String? { + guard let cString = dc_msg_get_webxdc_href(messagePointer) else { return nil } + let swiftString = String(cString: cString) + dc_str_unref(cString) + return swiftString + } + public var messageHeight: CGFloat { return CGFloat(dc_msg_get_height(messagePointer)) } From b0eb5dec73d6876cfaa8d22fb197b141f8b688d8 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 25 Nov 2024 22:09:23 +0100 Subject: [PATCH 5/9] do not make assumptions about href --- deltachat-ios/Controller/WebxdcViewController.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index fcfa30c30..638fa1364 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -426,11 +426,7 @@ class WebxdcViewController: WebViewViewController { guard let self else { return } let file = if let href { - if href.starts(with: "#") { - "index.html" + href - } else { - href - } + href } else { "index.html" } From 8a4072df8a0b57028950605e976e643aafb91f37 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 26 Nov 2024 12:08:15 +0100 Subject: [PATCH 6/9] simplify href handling further --- deltachat-ios/Controller/WebxdcViewController.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index 638fa1364..28de7dcef 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -425,13 +425,7 @@ class WebxdcViewController: WebViewViewController { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self else { return } - let file = if let href { - href - } else { - "index.html" - } - - let url = URL(string: "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + file) + let url = URL(string: "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + (href ?? "index.html")) let urlRequest = URLRequest(url: url!) DispatchQueue.main.async { self.webView.load(urlRequest) From 7eb1352f9b72e608547503a02db4bd2b0de5e0d3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 26 Nov 2024 13:30:32 +0100 Subject: [PATCH 7/9] add sendUpdateInterval and sendUpdateMaxSize api --- .../Controller/WebxdcViewController.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index 28de7dcef..15850445a 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -19,6 +19,8 @@ class WebxdcViewController: WebViewViewController { var webxdcName: String = "" var sourceCodeUrl: String? var selfAddr: String = "" + var sendUpdateInterval: Int = 0 + var sendUpdateMaxSize: Int = 0 private var allowInternet: Bool = false private var shortcutManager: ShortcutManager? @@ -129,7 +131,11 @@ class WebxdcViewController: WebViewViewController { selfAddr: decodeURI("\((addr ?? "unknown"))"), selfName: decodeURI("\((displayname ?? "unknown"))"), - + + sendUpdateInterval: \(sendUpdateInterval), + + sendUpdateMaxSize: \(sendUpdateMaxSize), + joinRealtimeChannel: () => { realtimeChannel = createRealtimeChannel(); webkit.messageHandlers.sendRealtimeAdvertisement.postMessage(""); @@ -316,6 +322,9 @@ class WebxdcViewController: WebViewViewController { let document = dict["document"] as? String ?? "" webxdcName = dict["name"] as? String ?? "ErrName" // name should not be empty + selfAddr = dict["self_addr"] as? String ?? "ErrAddr" + sendUpdateInterval = dict["send_update_interval"] as? Int ?? 0 + sendUpdateMaxSize = dict["send_update_max_size"] as? Int ?? 0 let chatName = dcContext.getChat(chatId: msg.chatId).name self.allowInternet = dict["internet_access"] as? Bool ?? false @@ -324,10 +333,6 @@ class WebxdcViewController: WebViewViewController { !sourceCode.isEmpty { sourceCodeUrl = sourceCode } - - if let addr = dict["self_addr"] as? String { - selfAddr = addr - } } // MARK: - Notifications From ce0a86755352806d9abeafd356cd52f89c60b915 Mon Sep 17 00:00:00 2001 From: bjoern Date: Tue, 26 Nov 2024 14:22:24 +0100 Subject: [PATCH 8/9] Update deltachat-ios/Controller/WebxdcViewController.swift Co-authored-by: Casper Zandbergen --- deltachat-ios/Controller/WebxdcViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index 15850445a..de96c952d 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -430,8 +430,10 @@ class WebxdcViewController: WebViewViewController { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self else { return } - let url = URL(string: "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + (href ?? "index.html")) - let urlRequest = URLRequest(url: url!) + let base ="\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + let url = URL(string: base + href ?? "index.html") + let fallbackUrl = URL(string: base + "index.html")! + let urlRequest = URLRequest(url: url ?? fallbackUrl) DispatchQueue.main.async { self.webView.load(urlRequest) } From 33a73cafca762f14bd922d2796bdc69ce3804a05 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 26 Nov 2024 14:28:20 +0100 Subject: [PATCH 9/9] fix syntax --- deltachat-ios/Controller/WebxdcViewController.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index de96c952d..7cda14be4 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -430,10 +430,9 @@ class WebxdcViewController: WebViewViewController { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self else { return } - let base ="\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" - let url = URL(string: base + href ?? "index.html") - let fallbackUrl = URL(string: base + "index.html")! - let urlRequest = URLRequest(url: url ?? fallbackUrl) + let base = "\(self.INTERNALSCHEMA)://acc\(self.dcContext.id)-msg\(self.messageId).localhost/" + let url = URL(string: base + (href ?? "index.html")) + let urlRequest = URLRequest(url: url ?? URL(string: base + "index.html")!) DispatchQueue.main.async { self.webView.load(urlRequest) }