Skip to content

Commit

Permalink
add new webxdc APIs (#2412)
Browse files Browse the repository at this point in the history
* use new selfAddr api

* add new webxdc-notify api

* open the webxdc on tapping its info

* add deeplink api

* do not make assumptions about href

* simplify href handling further

* add sendUpdateInterval and sendUpdateMaxSize api

* Update deltachat-ios/Controller/WebxdcViewController.swift

Co-authored-by: Casper Zandbergen <[email protected]>

* fix syntax

---------

Co-authored-by: Casper Zandbergen <[email protected]>
  • Loading branch information
r10s and Amzd authored Nov 26, 2024
1 parent f691947 commit 1d1a60e
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 18 deletions.
10 changes: 10 additions & 0 deletions DcCore/DcCore/DC/events.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions DcNotificationService/NotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions deltachat-ios/Chat/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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, href: message.getWebxdcHref())
}
case (_, DC_INFO_PROTECTION_ENABLED):
showProtectionEnabledDialog()
Expand Down Expand Up @@ -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)
}

Expand Down
26 changes: 20 additions & 6 deletions deltachat-ios/Controller/WebxdcViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ class WebxdcViewController: WebViewViewController {
let INTERNALSCHEMA = "webxdc"

var messageId: Int
var href: String?
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?
Expand Down Expand Up @@ -57,7 +61,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)
Expand Down Expand Up @@ -127,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("");
Expand Down Expand Up @@ -267,8 +275,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)

Expand All @@ -279,6 +288,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) {
Expand All @@ -293,7 +303,6 @@ class WebxdcViewController: WebViewViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = moreButton
refreshWebxdcInfo()
}

override func willMove(toParent parent: UIViewController?) {
Expand All @@ -308,6 +317,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

Expand Down Expand Up @@ -412,8 +424,10 @@ 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 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 urlRequest = URLRequest(url: url ?? URL(string: base + "index.html")!)
DispatchQueue.main.async {
self.webView.load(urlRequest)
}
Expand Down
9 changes: 0 additions & 9 deletions deltachat-ios/DC/DcMsg+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
27 changes: 27 additions & 0 deletions deltachat-ios/DC/DcMsg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,33 @@ 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 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))
}
Expand Down
29 changes: 29 additions & 0 deletions deltachat-ios/Helper/NotificationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
}
}
}

0 comments on commit 1d1a60e

Please sign in to comment.