Skip to content

Commit

Permalink
manage webxdc-integration via core, this also hides the message and d…
Browse files Browse the repository at this point in the history
…oes not clutter UI
  • Loading branch information
r10s committed Apr 21, 2024
1 parent 0a44fa4 commit d983304
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 185 deletions.
10 changes: 0 additions & 10 deletions DcCore/DcCore/DC/events.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public let eventEphemeralTimerModified = Notification.Name(rawValue: "eventEphe
public let eventMsgsNoticed = Notification.Name(rawValue: "eventMsgsNoticed")
public let eventConnectivityChanged = Notification.Name(rawValue: "eventConnectivityChanged")
public let eventWebxdcStatusUpdate = Notification.Name(rawValue: "eventWebxdcStatusUpdate")
public let eventLocationChanged = Notification.Name(rawValue: "eventLocationChanged")

public class DcEventHandler {
let dcAccounts: DcAccounts
Expand Down Expand Up @@ -175,15 +174,6 @@ public class DcEventHandler {
])
}

case DC_EVENT_LOCATION_CHANGED:
if accountId != dcAccounts.getSelected().id {
return
}
logger.info("📡[\(accountId)] location changed for contact \(data1)")
DispatchQueue.main.async {
NotificationCenter.default.post(name: eventLocationChanged, object: nil)
}

default:
break
}
Expand Down
12 changes: 0 additions & 12 deletions DcCore/DcCore/Extensions/UIColor+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
77 changes: 9 additions & 68 deletions deltachat-ios/Controller/MapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,18 @@ 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) {
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))
isGlobalMap = chatId == 0
var webxdcInstanceId = dcContext.initWebxdcIntegration(for: chatId)
if webxdcInstanceId == 0 {
if let mapsXdc = Bundle.main.url(forResource: "maps", withExtension: "xdc", subdirectory: "Assets") {
dcContext.setWebxdcIntegration(filepath: mapsXdc.path)
webxdcInstanceId = dcContext.initWebxdcIntegration(for: chatId)
}
}
super.init(dcContext: dcContext, messageId: msgId)
super.init(dcContext: dcContext, messageId: webxdcInstanceId)
}

required init?(coder: NSCoder) {
Expand All @@ -38,55 +26,8 @@ class MapViewController: WebxdcViewController {
navigationItem.rightBarButtonItem = nil
}

override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
if parent == nil {
removeObservers()
} else {
addObservers()
}
}

override func refreshWebxdcInfo() {
super.refreshWebxdcInfo()
title = String.localized(chatId == 0 ? "menu_show_global_map" : "locations")
}

// MARK: - setup

private func addObservers() {
locationChangedObserver = NotificationCenter.default.addObserver(forName: eventLocationChanged, object: nil, queue: nil) { [weak self]_ in
self?.updateWebxdc()
}
}

private func removeObservers() {
if let locationChangedObserver = self.locationChangedObserver {
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
title = String.localized(isGlobalMap ? "menu_show_global_map" : "locations")
}
}
15 changes: 4 additions & 11 deletions deltachat-ios/Controller/WebxdcViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ class WebxdcViewController: WebViewViewController {
}
}

func updateWebxdc() {
private func updateWebxdc() {
webView.evaluateJavaScript("window.__webxdcUpdate()", completionHandler: nil)
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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] {
Expand Down Expand Up @@ -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 {
Expand Down
90 changes: 10 additions & 80 deletions deltachat-ios/DC/DcContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -90,6 +78,14 @@ public class DcContext {
return swiftString
}

public func setWebxdcIntegration(filepath: String?) {
dc_set_webxdc_integration(contextPointer, filepath)
}

public func initWebxdcIntegration(for chatId: Int) -> Int {
return Int(dc_init_webxdc_integration(contextPointer, UInt32(chatId)))
}

public func sendVideoChatInvitation(chatId: Int) -> Int {
return Int(dc_send_videochat_invitation(contextPointer, UInt32(chatId)))
}
Expand Down Expand Up @@ -544,72 +540,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 {
Expand Down
4 changes: 0 additions & 4 deletions deltachat-ios/DC/DcMsg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,6 @@ public class DcMsg {
dc_msg_set_dimension(messagePointer, Int32(width), Int32(height))
}

public func setLocation(lat: Double, lng: Double) {
dc_msg_set_location(messagePointer, lat, lng)
}

public var filesize: Int {
return Int(dc_msg_get_filebytes(messagePointer))
}
Expand Down

0 comments on commit d983304

Please sign in to comment.