From 097eabad080b693d849f256ced99e4f056ff221b Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 9 Apr 2024 16:31:03 +0200 Subject: [PATCH] manage webxdc-integration via core, this also hides the message and does not clutter UI --- .../Extensions/UIColor+Extensions.swift | 12 --- .../Controller/MapViewController.swift | 48 ++--------- .../Controller/WebxdcViewController.swift | 13 +-- deltachat-ios/DC/DcContext.swift | 86 ++----------------- deltachat-ios/DC/DcMsg.swift | 4 + 5 files changed, 21 insertions(+), 142 deletions(-) diff --git a/DcCore/DcCore/Extensions/UIColor+Extensions.swift b/DcCore/DcCore/Extensions/UIColor+Extensions.swift index 2de0a517d4..2cae4ad1b6 100644 --- a/DcCore/DcCore/Extensions/UIColor+Extensions.swift +++ b/DcCore/DcCore/Extensions/UIColor+Extensions.swift @@ -64,16 +64,4 @@ public extension UIColor { return UIColor(red: red / 255, green: green / 255, blue: blue / 255, alpha: 1) } - var hexValue: String { - var color = self - if color.cgColor.numberOfComponents < 4 { - let c = color.cgColor.components! - color = UIColor(red: c[0], green: c[0], blue: c[0], alpha: c[1]) - } - if color.cgColor.colorSpace!.model != .rgb { - return "#FFFFFF" - } - let c = color.cgColor.components! - return String(format: "#%02X%02X%02X", Int(c[0]*255.0), Int(c[1]*255.0), Int(c[2]*255.0)) - } } diff --git a/deltachat-ios/Controller/MapViewController.swift b/deltachat-ios/Controller/MapViewController.swift index 7e3901a8de..32dc5a7d33 100644 --- a/deltachat-ios/Controller/MapViewController.swift +++ b/deltachat-ios/Controller/MapViewController.swift @@ -3,27 +3,19 @@ import WebKit import DcCore class MapViewController: WebxdcViewController { - private let chatId: Int private var locationChangedObserver: NSObjectProtocol? - private var lastLocationId: Int = 0 + private let isGlobalMap: Bool init(dcContext: DcContext, chatId: Int) { - self.chatId = chatId - let msgIdConfigKey = "maps_webxdc_msg_id16." - var msgId = UserDefaults.standard.integer(forKey: msgIdConfigKey + String(dcContext.id)) - if !dcContext.msgExists(id: msgId) { + isGlobalMap = chatId == 0 + var msgId = dcContext.initWebxdcIntegration(DC_INTEGRATION_MAPS, for: chatId) + if msgId == 0 { if let path = Bundle.main.url(forResource: "maps", withExtension: "xdc", subdirectory: "Assets") { - let chatId = dcContext.createChatByContactId(contactId: Int(DC_CONTACT_ID_SELF)) let msg = dcContext.newMessage(viewType: DC_MSG_WEBXDC) msg.setFile(filepath: path.path) - msg.text = "Thanks for trying out the experimental feature 🧪 \"Location streaming\"\n\n" - + "This message is needed temporarily for development and debugging. " - + "To see locations, POIs and tracks on the map, " - + "do not open it here but from \"All Media\" or from chat \"Profiles\".\n\n" - + "If you want to quit the experimental feature, " - + "you can disable it at \"Settings / Advanced\" and delete this message." - msgId = dcContext.sendMessage(chatId: chatId, message: msg) - UserDefaults.standard.setValue(msgId, forKey: msgIdConfigKey + String(dcContext.id)) + msg.setDefaultWebxdcIntegration() + dcContext.sendMessage(chatId: dcContext.createChatByContactId(contactId: Int(DC_CONTACT_ID_SELF)), message: msg) + msgId = dcContext.initWebxdcIntegration(DC_INTEGRATION_MAPS, for: chatId) } } super.init(dcContext: dcContext, messageId: msgId) @@ -49,7 +41,7 @@ class MapViewController: WebxdcViewController { override func refreshWebxdcInfo() { super.refreshWebxdcInfo() - title = String.localized(chatId == 0 ? "menu_show_global_map" : "locations") + title = String.localized(isGlobalMap ? "menu_show_global_map" : "locations") } // MARK: - setup @@ -65,28 +57,4 @@ class MapViewController: WebxdcViewController { NotificationCenter.default.removeObserver(locationChangedObserver) } } - - - // MARK: - handle updates - - override func sendWebxdcStatusUpdate(payload: String, description: String) -> Bool { - guard let data: Data = payload.data(using: .utf8), - let dict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: AnyObject], - let payload = dict["payload"] as? [String: AnyObject] else { - return false - } - - let msg = dcContext.newMessage(viewType: DC_MSG_TEXT) - msg.text = payload["label"] as? String ?? "ErrLabel" - msg.setLocation(lat: payload["lat"] as? Double ?? 0.0, lng: payload["lng"] as? Double ?? 0.0) - return dcContext.sendMessage(chatId: chatId == 0 ? dcContext.createChatByContactId(contactId: Int(DC_CONTACT_ID_SELF)) : chatId, message: msg) != 0 - } - - override func getWebxdcStatusUpdates(lastKnownSerial: Int) -> String { - let end = Int64(Date().timeIntervalSince1970) - let begin = end - 24*60*60 - let (json, maxLocationId) = dcContext.getLocations(chatId: chatId, timestampBegin: begin, timestampEnd: 0, lastLocationId: lastLocationId) - lastLocationId = max(maxLocationId, lastLocationId) - return json - } } diff --git a/deltachat-ios/Controller/WebxdcViewController.swift b/deltachat-ios/Controller/WebxdcViewController.swift index 224acd6e0d..9d584e65b2 100644 --- a/deltachat-ios/Controller/WebxdcViewController.swift +++ b/deltachat-ios/Controller/WebxdcViewController.swift @@ -414,14 +414,6 @@ class WebxdcViewController: WebViewViewController { private func shareWebxdc(_ action: UIAlertAction) { Utils.share(message: dcContext.getMessage(id: messageId), parentViewController: self, sourceItem: moreButton) } - - func sendWebxdcStatusUpdate(payload: String, description: String) -> Bool { - return dcContext.sendWebxdcStatusUpdate(msgId: messageId, payload: payload, description: description) - } - - func getWebxdcStatusUpdates(lastKnownSerial: Int) -> String { - return dcContext.getWebxdcStatusUpdates(msgId: messageId, lastKnownSerial: lastKnownSerial) - } } extension WebxdcViewController: WKScriptMessageHandler { @@ -444,7 +436,7 @@ extension WebxdcViewController: WKScriptMessageHandler { logger.error("Failed to parse status update parameters \(message.body)") return } - _ = sendWebxdcStatusUpdate(payload: payloadString, description: description) + _ = dcContext.sendWebxdcStatusUpdate(msgId: messageId, payload: payloadString, description: description) case .sendToChat: if let dict = message.body as? [String: AnyObject] { @@ -485,7 +477,8 @@ extension WebxdcViewController: WKURLSchemeHandler { let statusCode: Int if url.path == "/webxdc-update.json" || url.path == "webxdc-update.json" { let lastKnownSerial = Int(url.query ?? "0") ?? 0 - data = Data(getWebxdcStatusUpdates(lastKnownSerial: lastKnownSerial).utf8) + data = Data( + dcContext.getWebxdcStatusUpdates(msgId: messageId, lastKnownSerial: lastKnownSerial).utf8) mimeType = "application/json; charset=utf-8" statusCode = 200 } else { diff --git a/deltachat-ios/DC/DcContext.swift b/deltachat-ios/DC/DcContext.swift index 621926fb45..2809e2be10 100644 --- a/deltachat-ios/DC/DcContext.swift +++ b/deltachat-ios/DC/DcContext.swift @@ -54,25 +54,13 @@ public class DcContext { return DcMsg(pointer: messagePointer) } - public func msgExists(id: Int) -> Bool { - if id <= DC_MSG_ID_LAST_SPECIAL { - return false - } else { - let messagePointer = dc_get_msg(contextPointer, UInt32(id)) - let exists = messagePointer != nil && dc_msg_get_chat_id(messagePointer) != DC_CHAT_ID_TRASH - dc_msg_unref(messagePointer) - return exists - } - } - public func getMessage(id: Int) -> DcMsg { let messagePointer = dc_get_msg(contextPointer, UInt32(id)) return DcMsg(pointer: messagePointer) } - @discardableResult - public func sendMessage(chatId: Int, message: DcMsg) -> Int { - return Int(dc_send_msg(contextPointer, UInt32(chatId), message.messagePointer)) + public func sendMessage(chatId: Int, message: DcMsg) { + dc_send_msg(contextPointer, UInt32(chatId), message.messagePointer) } public func downloadFullMessage(id: Int) { @@ -90,6 +78,10 @@ public class DcContext { return swiftString } + public func initWebxdcIntegration(_ integrationType: Int32, for chatId: Int) -> Int { + return Int(dc_init_webxdc_integration(contextPointer, integrationType, UInt32(chatId))) + } + public func sendVideoChatInvitation(chatId: Int) -> Int { return Int(dc_send_videochat_invitation(contextPointer, UInt32(chatId))) } @@ -544,72 +536,6 @@ public class DcContext { dc_set_location(contextPointer, latitude, longitude, accuracy) } - public func getLocations(chatId: Int, timestampBegin: Int64, timestampEnd: Int64, lastLocationId: Int) -> (String, Int) { - var names = [Int: String]() - var colors = [Int: String]() - var maxLocationId = 0 - - let jsonEncoder = JSONEncoder() - var json: String - json = "[" - let array = dc_get_locations(contextPointer, UInt32(chatId), 0, timestampBegin, timestampEnd) - let arrayCnt = dc_array_get_cnt(array) - for i in (0 ..< arrayCnt).reversed() { // most recent position is reported last - let locationId = Int(dc_array_get_id(array, i)) - if locationId > lastLocationId { - maxLocationId = max(maxLocationId, locationId) - if json != "[" { - json += "," // JSON is picky about commas after the last element - } - - let contactId = Int(dc_array_get_contact_id(array, i)) - if names[contactId] == nil { - let contact = getContact(id: contactId) - names[contactId] = contact.displayName - colors[contactId] = contact.color.hexValue - } - - let isIndependet = dc_array_is_independent(array, i) != 0 - var label: String = "" - let name: String = names[contactId] ?? "ErrName" - if isIndependet { - if let cString = dc_array_get_marker(array, i) { - label = String(cString: cString) // get_marker() returns one-char labels only - dc_str_unref(cString) - } else { - let msgId = Int(dc_array_get_msg_id(array, i)) - if msgId != 0 { - label = String((getMessage(id: msgId).text ?? "").prefix(256)) - } - } - } - - let jsonName = (try? String(data: jsonEncoder.encode(name), encoding: .utf8) ?? "\"\"") ?? "\"\"" - let jsonLabel = (try? String(data: jsonEncoder.encode(label), encoding: .utf8) ?? "\"\"") ?? "\"\"" - json += """ - { - "payload": { - "action": "pos", - "contactId": \(contactId), - "lat": \(dc_array_get_latitude(array, i)), - "lng": \(dc_array_get_longitude(array, i)), - "independent": \(isIndependet), - "timestamp": \(dc_array_get_timestamp(array, i)), - "label": \(jsonLabel), - "name": \(jsonName), - "color": "\(colors[contactId] ?? "#ff0000")" - }, - "serial": \(locationId), - "max_serial": \(locationId) - } - """ - } - } - dc_array_unref(array) - json += "]" - return (json, maxLocationId) - } - public func searchMessages(chatId: Int = 0, searchText: String) -> [Int] { let start = CFAbsoluteTimeGetCurrent() guard let arrayPointer = dc_search_msgs(contextPointer, UInt32(chatId), searchText) else { diff --git a/deltachat-ios/DC/DcMsg.swift b/deltachat-ios/DC/DcMsg.swift index da534d0877..0a32244235 100644 --- a/deltachat-ios/DC/DcMsg.swift +++ b/deltachat-ios/DC/DcMsg.swift @@ -222,6 +222,10 @@ public class DcMsg { dc_msg_set_file(messagePointer, filepath, mimeType) } + public func setDefaultWebxdcIntegration() { + dc_msg_set_default_webxdc_integration(messagePointer) + } + public func setDimension(width: CGFloat, height: CGFloat) { dc_msg_set_dimension(messagePointer, Int32(width), Int32(height)) }