From 88c57c82d4691ac89f428c43ada827609a476fc2 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 10 Jun 2022 22:49:48 +0100 Subject: [PATCH] file provider works --- apps/ios/Shared/AppDelegate.swift | 3 +- apps/ios/Shared/FPService.swift | 77 --- apps/ios/Shared/Model/BGManager.swift | 4 +- apps/ios/Shared/Model/ChatModel.swift | 2 +- apps/ios/Shared/Model/NtfManager.swift | 3 +- apps/ios/Shared/Model/SimpleXAPI.swift | 119 +++-- apps/ios/Shared/SimpleXApp.swift | 51 +- .../Shared/Views/Call/ActiveCallView.swift | 2 +- .../Shared/Views/Call/CallController.swift | 2 +- apps/ios/Shared/Views/Call/CallManager.swift | 2 +- .../Shared/Views/Call/IncomingCallView.swift | 2 +- apps/ios/Shared/Views/Call/WebRTC.swift | 2 +- apps/ios/Shared/Views/Call/WebRTCView.swift | 2 +- .../Shared/Views/Chat/ChatInfoToolbar.swift | 2 +- apps/ios/Shared/Views/Chat/ChatInfoView.swift | 2 +- .../Views/Chat/ChatItem/CICallItemView.swift | 2 +- .../Views/Chat/ChatItem/CIFileView.swift | 3 +- .../Views/Chat/ChatItem/CIImageView.swift | 3 +- .../Views/Chat/ChatItem/CILinkView.swift | 3 +- .../Views/Chat/ChatItem/CIMetaView.swift | 2 +- .../Views/Chat/ChatItem/DeletedItemView.swift | 2 +- .../Views/Chat/ChatItem/EmojiItemView.swift | 2 +- .../Views/Chat/ChatItem/FramedItemView.swift | 3 +- .../ChatItem/IntegrityErrorItemView.swift | 2 +- .../Views/Chat/ChatItem/MsgContentView.swift | 2 +- apps/ios/Shared/Views/Chat/ChatItemView.swift | 2 +- apps/ios/Shared/Views/Chat/ChatView.swift | 3 +- .../ComposeMessage/ComposeImageView.swift | 2 +- .../Chat/ComposeMessage/ComposeLinkView.swift | 3 +- .../Chat/ComposeMessage/ComposeView.swift | 25 +- .../Chat/ComposeMessage/ContextItemView.swift | 2 +- .../Chat/ComposeMessage/SendMessageView.swift | 2 +- .../Views/ChatList/ChatListNavLink.swift | 20 +- .../Shared/Views/ChatList/ChatListView.swift | 2 +- .../Views/ChatList/ChatPreviewView.swift | 2 +- .../ChatList/ContactConnectionView.swift | 2 +- .../Views/ChatList/ContactRequestView.swift | 2 +- .../Shared/Views/Helpers/ChatInfoImage.swift | 2 +- .../Shared/Views/Helpers/ProfileImage.swift | 2 +- .../Shared/Views/NewChat/NewChatButton.swift | 8 +- .../Views/Onboarding/CreateProfile.swift | 18 +- .../Views/Onboarding/MakeConnection.swift | 8 +- apps/ios/Shared/Views/TerminalView.swift | 2 +- .../Views/UserSettings/SMPServers.swift | 2 +- .../Views/UserSettings/SettingsView.swift | 2 +- .../Views/UserSettings/UserProfile.swift | 3 +- .../ios/SimpleX NSE/NotificationService.swift | 128 ++--- .../FileProviderExtension.swift | 2 +- .../SimpleX Service/FileProviderItem.swift | 2 +- ...ervice.swift => FileProviderService.swift} | 25 +- apps/ios/SimpleX.xcodeproj/project.pbxproj | 442 +++++++++++++----- .../AppGroup.swift | 0 .../FileUtils.swift | 3 +- .../Notifications.swift | 1 + apps/ios/SimpleXAppShared/ServiceAPI.swift | 62 +++ .../SimpleXAppShared.docc/SimpleXAppShared.md | 13 + apps/ios/SimpleXAppShared/SimpleXAppShared.h | 19 + apps/ios/SimpleXChat/API.swift | 100 ++-- apps/ios/SimpleXChatAPI/SimpleXChatAPI.h | 19 - .../APITypes.swift | 34 ++ .../CallTypes.swift | 0 .../ChatTypes.swift | 2 +- .../JSON.swift | 7 + .../SimpleXChatSDK.docc/SimpleXChatSDK.md} | 2 +- apps/ios/SimpleXChatSDK/SimpleXChatSDK.h | 19 + .../ServiceProtocol.swift | 15 +- 66 files changed, 762 insertions(+), 546 deletions(-) delete mode 100644 apps/ios/Shared/FPService.swift rename apps/ios/SimpleX Service/{SimpleXFPService.swift => FileProviderService.swift} (66%) rename apps/ios/{SimpleXChat => SimpleXAppShared}/AppGroup.swift (100%) rename apps/ios/{SimpleXChat => SimpleXAppShared}/FileUtils.swift (98%) rename apps/ios/{SimpleXChat => SimpleXAppShared}/Notifications.swift (99%) create mode 100644 apps/ios/SimpleXAppShared/ServiceAPI.swift create mode 100755 apps/ios/SimpleXAppShared/SimpleXAppShared.docc/SimpleXAppShared.md create mode 100644 apps/ios/SimpleXAppShared/SimpleXAppShared.h delete mode 100644 apps/ios/SimpleXChatAPI/SimpleXChatAPI.h rename apps/ios/{SimpleXChat => SimpleXChatSDK}/APITypes.swift (95%) rename apps/ios/{SimpleXChat => SimpleXChatSDK}/CallTypes.swift (100%) rename apps/ios/{SimpleXChat => SimpleXChatSDK}/ChatTypes.swift (99%) rename apps/ios/{SimpleXChat => SimpleXChatSDK}/JSON.swift (84%) rename apps/ios/{SimpleXChatAPI/SimpleXChatAPI.docc/SimpleXChatAPI.md => SimpleXChatSDK/SimpleXChatSDK.docc/SimpleXChatSDK.md} (70%) create mode 100644 apps/ios/SimpleXChatSDK/SimpleXChatSDK.h diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index ee981ffbb..753bbd9a4 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -8,7 +8,8 @@ import Foundation import UIKit -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { diff --git a/apps/ios/Shared/FPService.swift b/apps/ios/Shared/FPService.swift deleted file mode 100644 index de2dd4e69..000000000 --- a/apps/ios/Shared/FPService.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// FPService.swift -// SimpleX Service -// -// Created by Evgeny on 01/06/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import Foundation -import FileProvider -import SimpleXChat -import SimpleXServiceProtocol - -func testFPService() { - logger.debug("testFPService get services") - let manager = NSFileProviderManager.default - // TODO try access file - logger.debug("testFPService NSFileProviderManager.documentStorageURL \(manager.documentStorageURL, privacy: .public)") - -// let res = machMessenger.sendMessageWithReply(FPS_MACH_PORT, msg: "machMessenger before getFileProviderServicesForItem") -// print("reply 1", res) - - FileManager.default.getFileProviderServicesForItem(at: URL(string: "\(manager.documentStorageURL)123")!) { (services, error) in -// let res = machMessenger.sendMessageWithReply(FPS_MACH_PORT, msg: "machMessenger after getFileProviderServicesForItem") -// print("reply 2", res) - - // Check to see if an error occurred. - guard error == nil else { - logger.debug("testFPService error getting service") - print(error!) // <-- this prints the error I posted - // Handle the error here... - return - } - - if let desiredService = services?[SIMPLEX_SERVICE_NAME] { - logger.debug("testFPService has desiredService") - - // The named service is available for the item at the provided URL. - // To use the service, get the connection object. - desiredService.getFileProviderConnection(completionHandler: { (connectionOrNil, connectionError) in - - guard connectionError == nil else { - // Handle the error here... - return - } - - guard let connection = connectionOrNil else { - // No connection object found. - return - } - - // Set the remote interface. - connection.remoteObjectInterface = simpleXServiceInterface - - // Start the connection. - connection.resume() - - // Get the proxy object. - let rawProxy = connection.remoteObjectProxyWithErrorHandler({ (errorAccessingRemoteObject) in - // Handle the error here... - }) - - // Cast the proxy object to the interface's protocol. - guard let proxy = rawProxy as? SimpleXFPServiceProtocol else { - // If the interface is set up properly, this should never fail. - fatalError("*** Unable to cast \(rawProxy) to a DesiredProtocol instance ***") - } - - logger.debug("testFPService calling service") - proxy.upperCaseString("hello to service", withReply: { reply in - logger.debug("testFPService reply from service \(reply)") - }) - }) - } - } - -} diff --git a/apps/ios/Shared/Model/BGManager.swift b/apps/ios/Shared/Model/BGManager.swift index b76097bc7..4f8d77ab9 100644 --- a/apps/ios/Shared/Model/BGManager.swift +++ b/apps/ios/Shared/Model/BGManager.swift @@ -70,8 +70,8 @@ class BGManager { return } self.completed = false - DispatchQueue.main.async { - initializeChat() + Task { + await initializeChat() if ChatModel.shared.currentUser == nil { completeReceiving("no current user") return diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 0696b0b6e..671e2026a 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -10,7 +10,7 @@ import Foundation import Combine import SwiftUI import WebKit -import SimpleXChat +import SimpleXChatSDK final class ChatModel: ObservableObject { @Published var onboardingStage: OnboardingStage? diff --git a/apps/ios/Shared/Model/NtfManager.swift b/apps/ios/Shared/Model/NtfManager.swift index 8a189ef72..532c47f71 100644 --- a/apps/ios/Shared/Model/NtfManager.swift +++ b/apps/ios/Shared/Model/NtfManager.swift @@ -9,7 +9,8 @@ import Foundation import UserNotifications import UIKit -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared let ntfActionAcceptContact = "NTF_ACT_ACCEPT_CONTACT" let ntfActionAcceptCall = "NTF_ACT_ACCEPT_CALL" diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index e29a92a46..dce467e1a 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -11,9 +11,8 @@ import UIKit import Dispatch import BackgroundTasks import SwiftUI -import SimpleXChat - -private var chatController: chat_ctrl? +import SimpleXChatSDK +import SimpleXAppShared enum TerminalItem: Identifiable { case cmd(Date, ChatCommand) @@ -47,7 +46,7 @@ enum TerminalItem: Identifiable { } } -private func beginBGTask(_ handler: (() -> Void)? = nil) -> (() -> Void) { +private func beginBGTask(_ handler: (() -> Void)? = nil) -> (@Sendable () -> Void) { var id: UIBackgroundTaskIdentifier! var running = true let endTask = { @@ -72,10 +71,10 @@ private func beginBGTask(_ handler: (() -> Void)? = nil) -> (() -> Void) { let msgDelay: Double = 7.5 let maxTaskDuration: Double = 15 -private func withBGTask(bgDelay: Double? = nil, f: @escaping () -> ChatResponse) -> ChatResponse { +private func withBGTask(bgDelay: Double? = nil, f: @escaping () async -> ChatResponse) async -> ChatResponse { let endTask = beginBGTask() DispatchQueue.global().asyncAfter(deadline: .now() + maxTaskDuration, execute: endTask) - let r = f() + let r = await f() if let d = bgDelay { DispatchQueue.global().asyncAfter(deadline: .now() + d, execute: endTask) } else { @@ -84,10 +83,10 @@ private func withBGTask(bgDelay: Double? = nil, f: @escaping () -> ChatResponse) return r } -func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil) -> ChatResponse { +func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil) async -> ChatResponse { logger.debug("chatSendCmd \(cmd.cmdType)") - let resp = bgTask - ? withBGTask(bgDelay: bgDelay) { sendSimpleXCmd(cmd) } + let resp = await bgTask + ? withBGTask(bgDelay: bgDelay) { await sendSimpleXCmd(cmd) } : sendSimpleXCmd(cmd) logger.debug("chatSendCmd \(cmd.cmdType): \(resp.responseType)") if case let .response(_, json) = resp { @@ -102,25 +101,14 @@ func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = return resp } -func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil) async -> ChatResponse { - await withCheckedContinuation { cont in - cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay)) - } -} - func chatRecvMsg() async -> ChatResponse { - await withCheckedContinuation { cont in - _ = withBGTask(bgDelay: msgDelay) { - let resp = chatResponse(chat_recv_msg(getChatCtrl())!) - cont.resume(returning: resp) - return resp - } + await withBGTask(bgDelay: msgDelay) { + await recvSimpleXMsg() } } -func apiGetActiveUser() throws -> User? { - let _ = getChatCtrl() - let r = chatSendCmdSync(.showActiveUser) +func apiGetActiveUser() async throws -> User? { + let r = await chatSendCmd(.showActiveUser) switch r { case let .activeUser(user): return user case .chatCmdError(.error(.noActiveUser)): return nil @@ -128,14 +116,14 @@ func apiGetActiveUser() throws -> User? { } } -func apiCreateActiveUser(_ p: Profile) throws -> User { - let r = chatSendCmdSync(.createActiveUser(profile: p)) +func apiCreateActiveUser(_ p: Profile) async throws -> User { + let r = await chatSendCmd(.createActiveUser(profile: p)) if case let .activeUser(user) = r { return user } throw r } -func apiStartChat() throws -> Bool { - let r = chatSendCmdSync(.startChat) +func apiStartChat() async throws -> Bool { + let r = await chatSendCmd(.startChat) switch r { case .chatStarted: return true case .chatRunning: return false @@ -143,20 +131,20 @@ func apiStartChat() throws -> Bool { } } -func apiSetFilesFolder(filesFolder: String) throws { - let r = chatSendCmdSync(.setFilesFolder(filesFolder: filesFolder)) +func apiSetFilesFolder(filesFolder: String) async throws { + let r = await chatSendCmd(.setFilesFolder(filesFolder: filesFolder)) if case .cmdOk = r { return } throw r } -func apiGetChats() throws -> [Chat] { - let r = chatSendCmdSync(.apiGetChats) +func apiGetChats() async throws -> [Chat] { + let r = await chatSendCmd(.apiGetChats) if case let .apiChats(chats) = r { return chats.map { Chat.init($0) } } throw r } -func apiGetChat(type: ChatType, id: Int64) throws -> Chat { - let r = chatSendCmdSync(.apiGetChat(type: type, id: id)) +func apiGetChat(type: ChatType, id: Int64) async throws -> Chat { + let r = await chatSendCmd(.apiGetChat(type: type, id: id)) if case let .apiChat(chat) = r { return Chat.init(chat) } throw r } @@ -214,8 +202,8 @@ func apiDeleteToken(token: String) async throws { try await sendCommandOkResp(.apiDeleteToken(token: token)) } -func getUserSMPServers() throws -> [String] { - let r = chatSendCmdSync(.getUserSMPServers) +func getUserSMPServers() async throws -> [String] { + let r = await chatSendCmd(.getUserSMPServers) if case let .userSMPServers(smpServers) = r { return smpServers } throw r } @@ -224,8 +212,8 @@ func setUserSMPServers(smpServers: [String]) async throws { try await sendCommandOkResp(.setUserSMPServers(smpServers: smpServers)) } -func apiAddContact() throws -> String { - let r = chatSendCmdSync(.addContact, bgTask: false) +func apiAddContact() async throws -> String { + let r = await chatSendCmd(.addContact, bgTask: false) if case let .invitation(connReqInvitation) = r { return connReqInvitation } throw r } @@ -312,8 +300,8 @@ func apiUpdateProfile(profile: Profile) async throws -> Profile? { } } -func apiParseMarkdown(text: String) throws -> [FormattedText]? { - let r = chatSendCmdSync(.apiParseMarkdown(text: text)) +func apiParseMarkdown(text: String) async throws -> [FormattedText]? { + let r = await sendSimpleXCmd(.apiParseMarkdown(text: text)) if case let .apiParsedMarkdown(formattedText) = r { return formattedText } throw r } @@ -330,8 +318,8 @@ func apiDeleteUserAddress() async throws { throw r } -func apiGetUserAddress() throws -> String? { - let r = chatSendCmdSync(.showMyAddress) +func apiGetUserAddress() async throws -> String? { + let r = await sendSimpleXCmd(.showMyAddress) switch r { case let .userContactLink(connReq): return connReq @@ -454,36 +442,45 @@ private func sendCommandOkResp(_ cmd: ChatCommand) async throws { throw r } -func initializeChat() { +func initializeChat() async { logger.debug("initializeChat") do { let m = ChatModel.shared - m.currentUser = try apiGetActiveUser() - if m.currentUser == nil { - m.onboardingStage = .step1_SimpleXInfo - } else { - startChat() + let user = try await apiGetActiveUser() + await MainActor.run { + m.currentUser = user + if user == nil { + m.onboardingStage = .step1_SimpleXInfo + } + } + if user != nil { + await startChat() } } catch { fatalError("Failed to initialize chat controller or database: \(error)") } } -func startChat() { +func startChat() async { logger.debug("startChat") do { - let m = ChatModel.shared // TODO set file folder once, before chat is started - let justStarted = try apiStartChat() + let justStarted = try await apiStartChat() if justStarted { - try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) - m.userAddress = try apiGetUserAddress() - m.userSMPServers = try getUserSMPServers() - m.chats = try apiGetChats() - withAnimation { - m.onboardingStage = m.chats.isEmpty - ? .step3_MakeConnection - : .onboardingComplete + try await apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) + let userAddress = try await apiGetUserAddress() + let userSMPServers = try await getUserSMPServers() + let chats = try await apiGetChats() + DispatchQueue.main.async { + let m = ChatModel.shared + m.userAddress = userAddress + m.userSMPServers = userSMPServers + m.chats = chats + withAnimation { + m.onboardingStage = m.chats.isEmpty + ? .step3_MakeConnection + : .onboardingComplete + } } } ChatReceiver.shared.start() @@ -512,7 +509,7 @@ class ChatReceiver { func receiveMsgLoop() async { let msg = await chatRecvMsg() self._lastMsgTime = .now - processReceivedMsg(msg) + await processReceivedMsg(msg) if self.receiveMessages { do { try await Task.sleep(nanoseconds: 7_500_000) } catch { logger.error("receiveMsgLoop: Task.sleep error: \(error.localizedDescription)") } @@ -528,7 +525,7 @@ class ChatReceiver { } } -func processReceivedMsg(_ res: ChatResponse) { +func processReceivedMsg(_ res: ChatResponse) async { let m = ChatModel.shared DispatchQueue.main.async { m.terminalItems.append(.resp(.now, res)) diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 80bdc437c..b32de22f8 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -7,47 +7,10 @@ import SwiftUI import OSLog -import SimpleXChat +import SimpleXAppShared let logger = Logger() -//let machMessenger = MachMessenger(APP_MACH_PORT, callback: receivedMachMessage) -// -//func receivedMachMessage(msgId: Int32, msg: String) -> String? { -// logger.debug("MachMessenger: receivedMachMessage from FPS") -//// return "reply from App to: \(msg)" -// -// if let data = msg.data(using: .utf8) { -// logger.debug("receivedMachMessage has data") -// let endpoint = try! NSKeyedUnarchiver.unarchivedObject(ofClass: NSXPCListenerEndpoint.self, from: data)! -// logger.debug("receivedMachMessage has endpoint") -// let connection = NSXPCConnection(listenerEndpoint: endpoint) -// logger.debug("receivedMachMessage has connection") -// connection.remoteObjectInterface = NSXPCInterface(with: SimpleXFPServiceProtocol.self) -// -// // Start the connection. -// connection.resume() -// -// // Get the proxy object. -// let rawProxy = connection.remoteObjectProxyWithErrorHandler({ (errorAccessingRemoteObject) in -// // Handle the error here... -// }) -// -// // Cast the proxy object to the interface's protocol. -// guard let proxy = rawProxy as? SimpleXFPServiceProtocol else { -// // If the interface is set up properly, this should never fail. -// fatalError("*** Unable to cast \(rawProxy) to a DesiredProtocol instance ***") -// } -// -// logger.debug("receivedMachMessage calling service") -// proxy.upperCaseString("hello to service", withReply: { reply in -// logger.debug("receivedMachMessage reply from service \(reply)") -// }) -// -// } -// return nil -//} - @main struct SimpleXApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @@ -60,16 +23,10 @@ struct SimpleXApp: App { @State private var enteredBackground: Double? = nil init() { - hs_init(0, nil) +// hs_init(0, nil) UserDefaults.standard.register(defaults: appDefaults) BGManager.shared.register() NtfManager.shared.registerCategories() -// machMessenger.start() - - // test service comms - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { - testFPService() - } } var body: some Scene { @@ -80,8 +37,8 @@ struct SimpleXApp: App { logger.debug("ContentView.onOpenURL: \(url)") chatModel.appOpenUrl = url } - .onAppear() { - initializeChat() + .onAppear { + Task { await initializeChat() } } .onChange(of: scenePhase) { phase in logger.debug("scenePhase \(String(describing: scenePhase))") diff --git a/apps/ios/Shared/Views/Call/ActiveCallView.swift b/apps/ios/Shared/Views/Call/ActiveCallView.swift index 7e914a866..98e74349f 100644 --- a/apps/ios/Shared/Views/Call/ActiveCallView.swift +++ b/apps/ios/Shared/Views/Call/ActiveCallView.swift @@ -8,7 +8,7 @@ import SwiftUI import WebKit -import SimpleXChat +import SimpleXChatSDK struct ActiveCallView: View { @EnvironmentObject var m: ChatModel diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index df103c02e..34574e00c 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -9,7 +9,7 @@ import Foundation //import CallKit import AVFoundation -import SimpleXChat +import SimpleXChatSDK //class CallController: NSObject, CXProviderDelegate, ObservableObject { class CallController: NSObject, ObservableObject { diff --git a/apps/ios/Shared/Views/Call/CallManager.swift b/apps/ios/Shared/Views/Call/CallManager.swift index 493a3a1d6..440ad02e6 100644 --- a/apps/ios/Shared/Views/Call/CallManager.swift +++ b/apps/ios/Shared/Views/Call/CallManager.swift @@ -7,7 +7,7 @@ // import Foundation -import SimpleXChat +import SimpleXChatSDK class CallManager { func newOutgoingCall(_ contact: Contact, _ media: CallMediaType) -> UUID { diff --git a/apps/ios/Shared/Views/Call/IncomingCallView.swift b/apps/ios/Shared/Views/Call/IncomingCallView.swift index 45651b89b..0495705b8 100644 --- a/apps/ios/Shared/Views/Call/IncomingCallView.swift +++ b/apps/ios/Shared/Views/Call/IncomingCallView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct IncomingCallView: View { @EnvironmentObject var m: ChatModel diff --git a/apps/ios/Shared/Views/Call/WebRTC.swift b/apps/ios/Shared/Views/Call/WebRTC.swift index 7e63f4f49..c7c13e264 100644 --- a/apps/ios/Shared/Views/Call/WebRTC.swift +++ b/apps/ios/Shared/Views/Call/WebRTC.swift @@ -8,7 +8,7 @@ import Foundation import SwiftUI -import SimpleXChat +import SimpleXChatSDK class Call: ObservableObject, Equatable { static func == (lhs: Call, rhs: Call) -> Bool { diff --git a/apps/ios/Shared/Views/Call/WebRTCView.swift b/apps/ios/Shared/Views/Call/WebRTCView.swift index ab48d93a3..b333f55ae 100644 --- a/apps/ios/Shared/Views/Call/WebRTCView.swift +++ b/apps/ios/Shared/Views/Call/WebRTCView.swift @@ -8,7 +8,7 @@ import SwiftUI import WebKit -import SimpleXChat +import SimpleXChatSDK class WebRTCCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate { var rtcWebView: Binding diff --git a/apps/ios/Shared/Views/Chat/ChatInfoToolbar.swift b/apps/ios/Shared/Views/Chat/ChatInfoToolbar.swift index 6e3fcfd96..d429e5006 100644 --- a/apps/ios/Shared/Views/Chat/ChatInfoToolbar.swift +++ b/apps/ios/Shared/Views/Chat/ChatInfoToolbar.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK private let chatImageColorLight = Color(red: 0.9, green: 0.9, blue: 0.9) private let chatImageColorDark = Color(red: 0.2, green: 0.2, blue: 0.2 ) diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift index fc82d543b..20e2dceaf 100644 --- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatInfoView: View { @EnvironmentObject var chatModel: ChatModel diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift index a2204cb9b..ad7bbe021 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct CICallItemView: View { @EnvironmentObject var m: ChatModel diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift index 31b90e2ee..938a81e3f 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared struct CIFileView: View { @Environment(\.colorScheme) var colorScheme diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift index 9c131cc1c..63559295f 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared struct CIImageView: View { @Environment(\.colorScheme) var colorScheme diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift index 4c12c7312..4a65c2c27 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared struct CILinkView: View { @Environment(\.colorScheme) var colorScheme diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift index b6de98d81..65be61770 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct CIMetaView: View { var chatItem: ChatItem diff --git a/apps/ios/Shared/Views/Chat/ChatItem/DeletedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/DeletedItemView.swift index 4ac47188c..4f2f8f60a 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/DeletedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/DeletedItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct DeletedItemView: View { var chatItem: ChatItem diff --git a/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift index e45b5bd18..2b8e22d14 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/EmojiItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct EmojiItemView: View { var chatItem: ChatItem diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index ddaf6d1d2..a2a06280f 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared let sentColorLight = Color(.sRGB, red: 0.27, green: 0.72, blue: 1, opacity: 0.12) let sentColorDark = Color(.sRGB, red: 0.27, green: 0.72, blue: 1, opacity: 0.17) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift index 7a4fa4682..b3839ad0e 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct IntegrityErrorItemView: View { var chatItem: ChatItem diff --git a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift index 6707f8bde..cd15ce015 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK private let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1) private let linkColor = Color(uiColor: uiLinkColor) diff --git a/apps/ios/Shared/Views/Chat/ChatItemView.swift b/apps/ios/Shared/Views/Chat/ChatItemView.swift index 62edc343a..8e9b7c9fd 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatItemView: View { var chatInfo: ChatInfo diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 79b30ebf2..db50b2221 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared private let memberImageSize: CGFloat = 34 diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift index 3e65600ce..36a49774c 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXAppShared struct ComposeImageView: View { @Environment(\.colorScheme) var colorScheme diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift index 335755c00..3ff161a1a 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift @@ -8,7 +8,8 @@ import SwiftUI import LinkPresentation -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared func getLinkPreview(url: URL, cb: @escaping (LinkPreview?) -> Void) { logger.debug("getLinkMetadata: fetching URL preview") diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 87f6c44e3..6fae42ba5 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared enum ComposePreview { case noPreview @@ -164,7 +165,7 @@ struct ComposeView: View { .onChange(of: composeState.message) { _ in if composeState.linkPreviewAllowed() { if composeState.message.count > 0 { - showLinkPreview(composeState.message) + Task { await showLinkPreview(composeState.message) } } else { resetLinkPreview() } @@ -306,7 +307,7 @@ struct ComposeView: View { case .noPreview: mc = .text(composeState.message) case .linkPreview: - mc = checkLinkPreview() + mc = await checkLinkPreview() case let .imagePreview(imagePreview: image): if let uiImage = chosenImage, let savedFile = saveImage(uiImage) { @@ -357,12 +358,12 @@ struct ComposeView: View { chosenFile = nil } - private func updateMsgContent(_ msgContent: MsgContent) -> MsgContent { + private func updateMsgContent(_ msgContent: MsgContent) async -> MsgContent { switch msgContent { case .text: - return checkLinkPreview() + return await checkLinkPreview() case .link: - return checkLinkPreview() + return await checkLinkPreview() case .image(_, let image): return .image(text: composeState.message, image: image) case .file: @@ -372,9 +373,9 @@ struct ComposeView: View { } } - private func showLinkPreview(_ s: String) { + private func showLinkPreview(_ s: String) async { prevLinkUrl = linkUrl - linkUrl = parseMessage(s) + linkUrl = await parseMessage(s) if let url = linkUrl { if url != composeState.linkPreview()?.uri && url != pendingLinkUrl { pendingLinkUrl = url @@ -391,9 +392,9 @@ struct ComposeView: View { } } - private func parseMessage(_ msg: String) -> URL? { + private func parseMessage(_ msg: String) async -> URL? { do { - let parsedMsg = try apiParseMarkdown(text: msg) + let parsedMsg = try await apiParseMarkdown(text: msg) let uri = parsedMsg?.first(where: { ft in ft.format == .uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text) }) @@ -437,10 +438,10 @@ struct ComposeView: View { cancelledLinks = [] } - private func checkLinkPreview() -> MsgContent { + private func checkLinkPreview() async -> MsgContent { switch (composeState.preview) { case let .linkPreview(linkPreview: linkPreview): - if let url = parseMessage(composeState.message), + if let url = await parseMessage(composeState.message), let linkPreview = linkPreview, url == linkPreview.uri { return .link(text: composeState.message, preview: linkPreview) diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift index b9fec6500..d1989fe84 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ContextItemView: View { @Environment(\.colorScheme) var colorScheme diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift index c5269c380..49a97d9a1 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct SendMessageView: View { @Binding var composeState: ComposeState diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index bce1f0a66..746465687 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatListNavLink: View { @EnvironmentObject var chatModel: ChatModel @@ -31,13 +31,17 @@ struct ChatListNavLink: View { private func chatView() -> some View { ChatView(chat: chat, showChatInfo: $showChatInfo) .onAppear { - do { - let cInfo = chat.chatInfo - let chat = try apiGetChat(type: cInfo.chatType, id: cInfo.apiId) - chatModel.updateChatInfo(chat.chatInfo) - chatModel.chatItems = chat.chatItems - } catch { - logger.error("ChatListNavLink.chatView apiGetChatItems error: \(error.localizedDescription)") + Task { + do { + let cInfo = chat.chatInfo + let chat = try await apiGetChat(type: cInfo.chatType, id: cInfo.apiId) + DispatchQueue.main.async { + chatModel.updateChatInfo(chat.chatInfo) + chatModel.chatItems = chat.chatItems + } + } catch { + logger.error("ChatListNavLink.chatView apiGetChatItems error: \(String(describing: error))") + } } } } diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 721365c2f..120aae854 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatListView: View { @EnvironmentObject var chatModel: ChatModel diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index d1490eaf0..3e25644e9 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatPreviewView: View { @ObservedObject var chat: Chat diff --git a/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift b/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift index 7f9388fc5..e6bc06439 100644 --- a/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift +++ b/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ContactConnectionView: View { var contactConnection: PendingContactConnection diff --git a/apps/ios/Shared/Views/ChatList/ContactRequestView.swift b/apps/ios/Shared/Views/ChatList/ContactRequestView.swift index 2edb1ad0e..db948a4ce 100644 --- a/apps/ios/Shared/Views/ChatList/ContactRequestView.swift +++ b/apps/ios/Shared/Views/ChatList/ContactRequestView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ContactRequestView: View { var contactRequest: UserContactRequest diff --git a/apps/ios/Shared/Views/Helpers/ChatInfoImage.swift b/apps/ios/Shared/Views/Helpers/ChatInfoImage.swift index 1b344148c..cfef56ed0 100644 --- a/apps/ios/Shared/Views/Helpers/ChatInfoImage.swift +++ b/apps/ios/Shared/Views/Helpers/ChatInfoImage.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct ChatInfoImage: View { @ObservedObject var chat: Chat diff --git a/apps/ios/Shared/Views/Helpers/ProfileImage.swift b/apps/ios/Shared/Views/Helpers/ProfileImage.swift index cc4f09ae3..a8f901986 100644 --- a/apps/ios/Shared/Views/Helpers/ProfileImage.swift +++ b/apps/ios/Shared/Views/Helpers/ProfileImage.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXAppShared struct ProfileImage: View { var imageStr: String? = nil diff --git a/apps/ios/Shared/Views/NewChat/NewChatButton.swift b/apps/ios/Shared/Views/NewChat/NewChatButton.swift index 3adf3d4c2..64ed1e51c 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatButton.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatButton.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK enum NewChatAction: Identifiable { case createLink @@ -27,7 +27,7 @@ struct NewChatButton: View { Image(systemName: "person.crop.circle.badge.plus") } .confirmationDialog("Add contact to start a new chat", isPresented: $showAddChat, titleVisibility: .visible) { - Button("Create link / QR code") { addContactAction() } + Button("Create link / QR code") { Task { await addContactAction() } } Button("Paste received link") { actionSheet = .pasteLink } Button("Scan QR code") { actionSheet = .scanQRCode } } @@ -40,9 +40,9 @@ struct NewChatButton: View { } } - func addContactAction() { + func addContactAction() async { do { - connReq = try apiAddContact() + connReq = try await apiAddContact() actionSheet = .createLink } catch { DispatchQueue.global().async { diff --git a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift index 578cd85d6..b1c59bf5d 100644 --- a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift +++ b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct CreateProfile: View { @EnvironmentObject var m: ChatModel @@ -43,7 +43,7 @@ struct CreateProfile: View { .focused($focusFullName) .submitLabel(.go) .onSubmit { - if canCreateProfile() { createProfile() } + if canCreateProfile() { Task { await createProfile() } } else { focusFullName = true } } @@ -64,7 +64,7 @@ struct CreateProfile: View { HStack { Button { - createProfile() + Task { await createProfile() } } label: { Text("Create") Image(systemName: "greaterthan") @@ -87,17 +87,19 @@ struct CreateProfile: View { .padding(.bottom) } - func createProfile() { + func createProfile() async { hideKeyboard() let profile = Profile( displayName: displayName, fullName: fullName ) do { - m.currentUser = try apiCreateActiveUser(profile) - startChat() - withAnimation { m.onboardingStage = .step3_MakeConnection } - + let user = try await apiCreateActiveUser(profile) + await MainActor.run { m.currentUser = user } + await startChat() + DispatchQueue.main.async { + withAnimation { m.onboardingStage = .step3_MakeConnection } + } } catch { fatalError("Failed to create user: \(error)") } diff --git a/apps/ios/Shared/Views/Onboarding/MakeConnection.swift b/apps/ios/Shared/Views/Onboarding/MakeConnection.swift index 88676535b..5792c2e7b 100644 --- a/apps/ios/Shared/Views/Onboarding/MakeConnection.swift +++ b/apps/ios/Shared/Views/Onboarding/MakeConnection.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK struct MakeConnection: View { @EnvironmentObject var m: ChatModel @@ -38,7 +38,7 @@ struct MakeConnection: View { icon: "link.badge.plus", title: "Create 1-time link / QR code", text: "It's secure to share - only one contact can use it." - ) { addContactAction() } + ) { Task { await addContactAction() } } actionRow( icon: "doc.plaintext", @@ -102,9 +102,9 @@ struct MakeConnection: View { } } - private func addContactAction() { + private func addContactAction() async { do { - connReq = try apiAddContact() + connReq = try await apiAddContact() actionSheet = .createLink } catch { DispatchQueue.global().async { diff --git a/apps/ios/Shared/Views/TerminalView.swift b/apps/ios/Shared/Views/TerminalView.swift index 6aa9e8804..d652c7e34 100644 --- a/apps/ios/Shared/Views/TerminalView.swift +++ b/apps/ios/Shared/Views/TerminalView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK private let terminalFont = Font.custom("Menlo", size: 16) diff --git a/apps/ios/Shared/Views/UserSettings/SMPServers.swift b/apps/ios/Shared/Views/UserSettings/SMPServers.swift index 07913c59a..2b10eb068 100644 --- a/apps/ios/Shared/Views/UserSettings/SMPServers.swift +++ b/apps/ios/Shared/Views/UserSettings/SMPServers.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK private let serversFont = Font.custom("Menlo", size: 14) diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index 017360e30..a59c13ee8 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK let simplexTeamURL = URL(string: "simplex:/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D")! diff --git a/apps/ios/Shared/Views/UserSettings/UserProfile.swift b/apps/ios/Shared/Views/UserSettings/UserProfile.swift index 52137f476..04d0b5d30 100644 --- a/apps/ios/Shared/Views/UserSettings/UserProfile.swift +++ b/apps/ios/Shared/Views/UserSettings/UserProfile.swift @@ -7,7 +7,8 @@ // import SwiftUI -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared struct UserProfile: View { @EnvironmentObject var chatModel: ChatModel diff --git a/apps/ios/SimpleX NSE/NotificationService.swift b/apps/ios/SimpleX NSE/NotificationService.swift index 03d881dea..3cd0c8446 100644 --- a/apps/ios/SimpleX NSE/NotificationService.swift +++ b/apps/ios/SimpleX NSE/NotificationService.swift @@ -9,7 +9,8 @@ import UserNotifications import OSLog import FileProvider -import SimpleXChat +import SimpleXChatSDK +import SimpleXAppShared import SimpleXServiceProtocol import Foundation @@ -23,8 +24,6 @@ class NotificationService: UNNotificationServiceExtension { var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { - testFPService() - logger.debug("NotificationService.didReceive") machMessenger.start() let res = machMessenger.sendMessageWithReply(APP_MACH_PORT, msg: "starting NSE didReceive") @@ -37,20 +36,22 @@ class NotificationService: UNNotificationServiceExtension { logger.debug("NotificationService: app is in the background") self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - if let _ = startChat() { - let content = receiveMessages() - contentHandler (content) - machMessenger.stop() - return - } + Task { + if let _ = await startChat() { + let content = await receiveMessages() + contentHandler (content) + machMessenger.stop() + return + } - if let bestAttemptContent = bestAttemptContent { - // Modify the notification content here... - bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" - - contentHandler(bestAttemptContent) + if let bestAttemptContent = bestAttemptContent { + // Modify the notification content here... + bestAttemptContent.title = "\(bestAttemptContent.title) [modified]" + + contentHandler(bestAttemptContent) + } + machMessenger.stop() } - machMessenger.stop() } override func serviceExtensionTimeWillExpire() { @@ -68,13 +69,13 @@ func receivedAppMachMessage(msgId: Int32, msg: String) -> String? { return "reply from NSE to: \(msg)" } -func startChat() -> User? { - hs_init(0, nil) - if let user = apiGetActiveUser() { +func startChat() async -> User? { +// hs_init(0, nil) + if let user = await apiGetActiveUser() { logger.debug("active user \(String(describing: user))") do { - try apiStartChat() - try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) + try await apiStartChat() + try await apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) return user } catch { logger.error("NotificationService startChat error: \(responseError(error), privacy: .public)") @@ -85,10 +86,11 @@ func startChat() -> User? { return nil } -func receiveMessages() -> UNNotificationContent { +func receiveMessages() async -> UNNotificationContent { logger.debug("NotificationService receiveMessages started") while true { - let res = chatResponse(chat_recv_msg(getChatCtrl())!) +// let res = chatResponse(chat_recv_msg(getChatCtrl())!) + let res = await recvSimpleXMsg() logger.debug("NotificationService receiveMessages: \(res.responseType)") switch res { // case let .newContactConnection(connection): @@ -123,9 +125,9 @@ func receiveMessages() -> UNNotificationContent { } } -func apiGetActiveUser() -> User? { - let _ = getChatCtrl() - let r = sendSimpleXCmd(.showActiveUser) +func apiGetActiveUser() async -> User? { +// let _ = getChatCtrl() + let r = await sendSimpleXCmd(.showActiveUser) logger.debug("apiGetActiveUser sendSimpleXCmd responce: \(String(describing: r))") switch r { case let .activeUser(user): return user @@ -136,8 +138,8 @@ func apiGetActiveUser() -> User? { } } -func apiStartChat() throws { - let r = sendSimpleXCmd(.startChat) +func apiStartChat() async throws { + let r = await sendSimpleXCmd(.startChat) switch r { case .chatStarted: return case .chatRunning: return @@ -145,76 +147,8 @@ func apiStartChat() throws { } } -func apiSetFilesFolder(filesFolder: String) throws { - let r = sendSimpleXCmd(.setFilesFolder(filesFolder: filesFolder)) +func apiSetFilesFolder(filesFolder: String) async throws { + let r = await sendSimpleXCmd(.setFilesFolder(filesFolder: filesFolder)) if case .cmdOk = r { return } throw r } - - - - - -func testFPService() { - logger.debug("testFPService get services") - let manager = NSFileProviderManager.default - // TODO try access file - logger.debug("testFPService NSFileProviderManager.documentStorageURL \(manager.documentStorageURL, privacy: .public)") - -// let res = machMessenger.sendMessageWithReply(FPS_MACH_PORT, msg: "machMessenger before getFileProviderServicesForItem") -// print("reply 1", res) - - FileManager.default.getFileProviderServicesForItem(at: URL(string: "\(manager.documentStorageURL)123")!) { (services, error) in -// let res = machMessenger.sendMessageWithReply(FPS_MACH_PORT, msg: "machMessenger after getFileProviderServicesForItem") -// print("reply 2", res) - - // Check to see if an error occurred. - guard error == nil else { - logger.debug("testFPService error getting service") - print(error!) // <-- this prints the error I posted - // Handle the error here... - return - } - - if let desiredService = services?[SIMPLEX_SERVICE_NAME] { - logger.debug("testFPService has desiredService") - - // The named service is available for the item at the provided URL. - // To use the service, get the connection object. - desiredService.getFileProviderConnection(completionHandler: { (connectionOrNil, connectionError) in - - guard connectionError == nil else { - // Handle the error here... - return - } - - guard let connection = connectionOrNil else { - // No connection object found. - return - } - - // Set the remote interface. - connection.remoteObjectInterface = simpleXServiceInterface - - // Start the connection. - connection.resume() - - // Get the proxy object. - let rawProxy = connection.remoteObjectProxyWithErrorHandler({ (errorAccessingRemoteObject) in - // Handle the error here... - }) - - // Cast the proxy object to the interface's protocol. - guard let proxy = rawProxy as? SimpleXFPServiceProtocol else { - // If the interface is set up properly, this should never fail. - fatalError("*** Unable to cast \(rawProxy) to a DesiredProtocol instance ***") - } - - logger.debug("testFPService calling service") - proxy.upperCaseString("hello to service", withReply: { reply in - logger.debug("testFPService reply from service \(reply, privacy: .public)") - }) - }) - } - } -} diff --git a/apps/ios/SimpleX Service/FileProviderExtension.swift b/apps/ios/SimpleX Service/FileProviderExtension.swift index cb5f03bfb..052d458ab 100644 --- a/apps/ios/SimpleX Service/FileProviderExtension.swift +++ b/apps/ios/SimpleX Service/FileProviderExtension.swift @@ -52,7 +52,7 @@ class FileProviderExtension: NSFileProviderExtension { // FileManager.default.createFile(atPath: "\(manager.documentStorageURL)123", contents: "hello".data(using: .utf8)) - self.providePlaceholder(at: URL(string: "\(manager.documentStorageURL)123")!) { err in + self.providePlaceholder(at: SERVICE_PROXY_ITEM_URL) { err in if let err = err { logger.debug("FileProviderExtension.providePlaceholder error \(String(describing: err), privacy: .public)") } else { diff --git a/apps/ios/SimpleX Service/FileProviderItem.swift b/apps/ios/SimpleX Service/FileProviderItem.swift index c87f3d56e..e756f68f1 100644 --- a/apps/ios/SimpleX Service/FileProviderItem.swift +++ b/apps/ios/SimpleX Service/FileProviderItem.swift @@ -23,7 +23,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { [.allowsReading, .allowsWriting, .allowsRenaming, .allowsReparenting, .allowsTrashing, .allowsDeleting] } - var filename: String { "123" } + var filename: String { SERVICE_PROXY_ITEM_NAME } var contentType: UTType { itemIdentifier == NSFileProviderItemIdentifier.rootContainer ? .folder : .plainText diff --git a/apps/ios/SimpleX Service/SimpleXFPService.swift b/apps/ios/SimpleX Service/FileProviderService.swift similarity index 66% rename from apps/ios/SimpleX Service/SimpleXFPService.swift rename to apps/ios/SimpleX Service/FileProviderService.swift index f0430f997..edc8b93e8 100644 --- a/apps/ios/SimpleX Service/SimpleXFPService.swift +++ b/apps/ios/SimpleX Service/FileProviderService.swift @@ -8,14 +8,15 @@ import Foundation import FileProvider +import SimpleXChat import SimpleXServiceProtocol extension FileProviderExtension { - class SimpleXFPService: NSObject, NSFileProviderServiceSource, SimpleXFPServiceProtocol, NSXPCListenerDelegate { + class FileProviderService: NSObject, NSFileProviderServiceSource, SimpleXServiceProtocol, NSXPCListenerDelegate { var serviceName: NSFileProviderServiceName { SIMPLEX_SERVICE_NAME } func makeListenerEndpoint() throws -> NSXPCListenerEndpoint { - logger.debug("SimpleXFPService.makeListenerEndpoint") + logger.debug("FileProviderService.makeListenerEndpoint") let listener = NSXPCListener.anonymous() listener.delegate = self synchronized(self) { @@ -26,7 +27,7 @@ extension FileProviderExtension { } func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { - logger.debug("SimpleXFPService.listener") + logger.debug("FileProviderService.listener") newConnection.exportedInterface = simpleXServiceInterface newConnection.exportedObject = self @@ -43,22 +44,28 @@ extension FileProviderExtension { init(_ ext: FileProviderExtension) { self.ext = ext + hs_init(0, nil) } - func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void) { - logger.debug("FileProviderExtension SimpleXFPService.upperCaseString") - let response = string.uppercased() - reply(response) + func chatSendCmd(_ cmd: String) async -> String { + logger.debug("chatSendCmd cmd: \(cmd, privacy: .public)") + let r = SimpleXChat.chatSendCmd(cmd) + logger.debug("chatSendCmd resp: \(r, privacy: .public)") + return r + } + + func chatRecvMsg() async -> String { + SimpleXChat.chatRecvMsg() } } override func supportedServiceSources(for itemIdentifier: NSFileProviderItemIdentifier) throws -> [NSFileProviderServiceSource] { logger.debug("FileProviderExtension.supportedServiceSources") - return [SimpleXFPService(self)] + return [FileProviderService(self)] } } -public func synchronized(_ lock: AnyObject, _ closure: () throws -> T) rethrows -> T { +private func synchronized(_ lock: AnyObject, _ closure: () throws -> T) rethrows -> T { objc_sync_enter(lock) defer { objc_sync_exit(lock) } return try closure() diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 1ce1beb3e..36ce01222 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -23,12 +23,10 @@ 5C1CAA1A2847C5C8009E5C72 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA192847C5C8009E5C72 /* FileProviderExtension.swift */; }; 5C1CAA1C2847C5C8009E5C72 /* FileProviderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA1B2847C5C8009E5C72 /* FileProviderItem.swift */; }; 5C1CAA1E2847C5C8009E5C72 /* FileProviderEnumerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */; }; - 5C1CAA282847D7C0009E5C72 /* SimpleXFPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA272847D7C0009E5C72 /* SimpleXFPService.swift */; }; + 5C1CAA282847D7C0009E5C72 /* FileProviderService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA272847D7C0009E5C72 /* FileProviderService.swift */; }; 5C1CAA322847DDA0009E5C72 /* SimpleXServiceProtocol.docc in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA312847DDA0009E5C72 /* SimpleXServiceProtocol.docc */; }; 5C1CAA332847DDA0009E5C72 /* SimpleXServiceProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C1CAA302847DDA0009E5C72 /* SimpleXServiceProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5C1CAA662847F5BD009E5C72 /* FPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1CAA3B2847DE88009E5C72 /* FPService.swift */; }; 5C1CAA672848168A009E5C72 /* SimpleX Service.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 5C1CAA6A2849119A009E5C72 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; platformFilter = ios; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; 5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; }; @@ -55,14 +53,18 @@ 5C69D5B42852379F009B27A4 /* libHSsimplex-chat-2.2.0-3TOca6xkke4IR3YLgDepFy-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C6F2A3A28522C9A00103588 /* libHSsimplex-chat-2.2.0-3TOca6xkke4IR3YLgDepFy-ghc8.10.7.a */; }; 5C69D5B52852379F009B27A4 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C6F2A3828522C9A00103588 /* libffi.a */; }; 5C69D5B62852379F009B27A4 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C6F2A3928522C9A00103588 /* libgmpxx.a */; }; - 5C69D5C028524D67009B27A4 /* SimpleXChatAPI.docc in Sources */ = {isa = PBXBuildFile; fileRef = 5C69D5BF28524D67009B27A4 /* SimpleXChatAPI.docc */; }; - 5C69D5C128524D67009B27A4 /* SimpleXChatAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C69D5BE28524D67009B27A4 /* SimpleXChatAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5C69D5C428524D67009B27A4 /* SimpleXChatAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5BC28524D67009B27A4 /* SimpleXChatAPI.framework */; }; - 5C69D5C528524D67009B27A4 /* SimpleXChatAPI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5BC28524D67009B27A4 /* SimpleXChatAPI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5C69D5CA28525085009B27A4 /* ServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C69D5C928525085009B27A4 /* ServiceProtocol.swift */; }; 5C69D5CB285250FB009B27A4 /* SimpleXServiceProtocol.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; platformFilter = ios; }; 5C69D5CC285250FB009B27A4 /* SimpleXServiceProtocol.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5C69D5CF28525108009B27A4 /* SimpleXServiceProtocol.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; platformFilter = ios; }; + 5C69D5FB2852A01F009B27A4 /* SimpleXAppShared.docc in Sources */ = {isa = PBXBuildFile; fileRef = 5C69D5FA2852A01F009B27A4 /* SimpleXAppShared.docc */; }; + 5C69D5FC2852A01F009B27A4 /* SimpleXAppShared.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C69D5F92852A01F009B27A4 /* SimpleXAppShared.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5C69D5FF2852A01F009B27A4 /* SimpleXAppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */; }; + 5C69D6002852A01F009B27A4 /* SimpleXAppShared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5C69D6042852A03F009B27A4 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD80281A7E2700503DA2 /* Notifications.swift */; }; + 5C69D6052852A058009B27A4 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DAE1502809D9F5000DA960 /* FileUtils.swift */; }; + 5C69D6062852A14A009B27A4 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD5228186F9500503DA2 /* AppGroup.swift */; }; + 5C69D6082852A1C7009B27A4 /* ServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C69D6072852A1C7009B27A4 /* ServiceAPI.swift */; }; 5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; }; 5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; }; 5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */; }; @@ -97,25 +99,29 @@ 5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; }; 5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; }; 5CCD403A27A5F9BE00368C90 /* CreateGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403927A5F9BE00368C90 /* CreateGroupView.swift */; }; + 5CCE914528532015005E7E0B /* SimpleXChatSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */; platformFilter = ios; }; + 5CCE914A28532029005E7E0B /* CallTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5E5D3C282447AB00B0488A /* CallTypes.swift */; }; + 5CCE914B28532029005E7E0B /* ChatTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */; }; + 5CCE914C28532029005E7E0B /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96A27A56D4D0075386C /* JSON.swift */; }; + 5CCE914D28532029005E7E0B /* APITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7428188D2900503DA2 /* APITypes.swift */; }; + 5CCE91522853202E005E7E0B /* SimpleXChatSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C69D5F128529FAD009B27A4 /* SimpleXChatSDK.h */; }; + 5CCE9153285320ED005E7E0B /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; platformFilter = ios; }; + 5CCE9154285320ED005E7E0B /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; platformFilter = ios; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5CCE915628532107005E7E0B /* SimpleXServiceProtocol.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; platformFilter = ios; }; + 5CCE915A28532144005E7E0B /* SimpleXChatSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */; platformFilter = ios; }; + 5CCE915B28532144005E7E0B /* SimpleXChatSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5CCE915E28532150005E7E0B /* SimpleXAppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */; platformFilter = ios; }; + 5CCE916328532155005E7E0B /* SimpleXChatSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */; platformFilter = ios; }; + 5CCE91672853215A005E7E0B /* SimpleXServiceProtocol.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; platformFilter = ios; }; 5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; }; - 5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; - 5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5CE2BA77284530BF00EC33A6 /* SimpleXChat.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */; }; 5CE2BA79284530CC00EC33A6 /* SimpleXChat.docc in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2BA78284530CC00EC33A6 /* SimpleXChat.docc */; }; - 5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */; }; - 5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD5228186F9500503DA2 /* AppGroup.swift */; }; - 5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5E5D3C282447AB00B0488A /* CallTypes.swift */; }; 5CE2BA8E284533A300EC33A6 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7D2818941F00503DA2 /* API.swift */; }; - 5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7428188D2900503DA2 /* APITypes.swift */; }; - 5CE2BA90284533A300EC33A6 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96A27A56D4D0075386C /* JSON.swift */; }; - 5CE2BA91284533A300EC33A6 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD80281A7E2700503DA2 /* Notifications.swift */; }; - 5CE2BA922845340900EC33A6 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DAE1502809D9F5000DA960 /* FileUtils.swift */; }; 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDCAD5E28187D4A00503DA2 /* libiconv.tbd */; }; 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDCAD6028187D7900503DA2 /* libz.tbd */; }; 5CE2BA952845354B00EC33A6 /* SimpleX.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2BA8A2845332200EC33A6 /* SimpleX.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5CE2BA97284537A800EC33A6 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2BA96284537A800EC33A6 /* dummy.m */; }; 5CE2BA9D284555F500EC33A6 /* SimpleX NSE.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5CDCAD452818589900503DA2 /* SimpleX NSE.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 5CE2BAA62845617C00EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; platformFilter = ios; }; 5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407127ADB1D0007B033A /* Emoji.swift */; }; 5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407827ADB701007B033A /* EmojiItemView.swift */; }; 5CEACCE327DE9246000BD591 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCE227DE9246000BD591 /* ComposeView.swift */; }; @@ -148,13 +154,6 @@ remoteGlobalIDString = 5CE2BA672845308900EC33A6; remoteInfo = SimpleXChat; }; - 5C69D5C228524D67009B27A4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 5C69D5BB28524D67009B27A4; - remoteInfo = SimpleXChatAPI; - }; 5C69D5CD285250FB009B27A4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; @@ -169,6 +168,13 @@ remoteGlobalIDString = 5C1CAA2D2847DDA0009E5C72; remoteInfo = SimpleXServiceProtocol; }; + 5C69D5FD2852A01F009B27A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C69D5F62852A01F009B27A4; + remoteInfo = SimpleXAppShared; + }; 5CA059D8279559F40002BEB4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; @@ -176,12 +182,47 @@ remoteGlobalIDString = 5CA059C9279559F40002BEB4; remoteInfo = "SimpleX (iOS)"; }; - 5CE2BA6E2845308900EC33A6 /* PBXContainerItemProxy */ = { + 5CCE914728532015005E7E0B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; proxyType = 1; - remoteGlobalIDString = 5CE2BA672845308900EC33A6; - remoteInfo = SimpleXChat; + remoteGlobalIDString = 5C69D5E128529F66009B27A4; + remoteInfo = SimpleXChatSDK; + }; + 5CCE915828532107005E7E0B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C1CAA2D2847DDA0009E5C72; + remoteInfo = SimpleXServiceProtocol; + }; + 5CCE915C28532144005E7E0B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C69D5E128529F66009B27A4; + remoteInfo = SimpleXChatSDK; + }; + 5CCE916028532150005E7E0B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C69D5F62852A01F009B27A4; + remoteInfo = SimpleXAppShared; + }; + 5CCE916528532155005E7E0B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C69D5E128529F66009B27A4; + remoteInfo = SimpleXChatSDK; + }; + 5CCE91692853215A005E7E0B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C1CAA2D2847DDA0009E5C72; + remoteInfo = SimpleXServiceProtocol; }; 5CE2BA9E284555F500EC33A6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -190,24 +231,28 @@ remoteGlobalIDString = 5CDCAD442818589900503DA2; remoteInfo = "SimpleX NSE"; }; - 5CE2BAA82845617C00EC33A6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5CA059BE279559F40002BEB4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 5CE2BA672845308900EC33A6; - remoteInfo = SimpleXChat; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 5CCE9155285320ED005E7E0B /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 5CCE9154285320ED005E7E0B /* SimpleXChat.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; 5CE2BA722845308900EC33A6 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - 5C69D5C528524D67009B27A4 /* SimpleXChatAPI.framework in Embed Frameworks */, - 5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */, + 5CCE915B28532144005E7E0B /* SimpleXChatSDK.framework in Embed Frameworks */, + 5C69D6002852A01F009B27A4 /* SimpleXAppShared.framework in Embed Frameworks */, 5C69D5CC285250FB009B27A4 /* SimpleXServiceProtocol.framework in Embed Frameworks */, ); name = "Embed Frameworks"; @@ -248,11 +293,10 @@ 5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderEnumerator.swift; sourceTree = ""; }; 5C1CAA1F2847C5C8009E5C72 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5C1CAA202847C5C8009E5C72 /* SimpleX_Service.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SimpleX_Service.entitlements; sourceTree = ""; }; - 5C1CAA272847D7C0009E5C72 /* SimpleXFPService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXFPService.swift; sourceTree = ""; }; + 5C1CAA272847D7C0009E5C72 /* FileProviderService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderService.swift; sourceTree = ""; }; 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXServiceProtocol.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5C1CAA302847DDA0009E5C72 /* SimpleXServiceProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleXServiceProtocol.h; sourceTree = ""; }; 5C1CAA312847DDA0009E5C72 /* SimpleXServiceProtocol.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXServiceProtocol.docc; sourceTree = ""; }; - 5C1CAA3B2847DE88009E5C72 /* FPService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPService.swift; sourceTree = ""; }; 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = ""; }; 5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = ""; }; 5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; @@ -276,10 +320,14 @@ 5C5E5D3C282447AB00B0488A /* CallTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallTypes.swift; sourceTree = ""; }; 5C5F2B6C27EBC3FE006A9D5F /* ImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = ""; }; 5C5F2B6F27EBC704006A9D5F /* ProfileImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileImage.swift; sourceTree = ""; }; - 5C69D5BC28524D67009B27A4 /* SimpleXChatAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXChatAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5C69D5BE28524D67009B27A4 /* SimpleXChatAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleXChatAPI.h; sourceTree = ""; }; - 5C69D5BF28524D67009B27A4 /* SimpleXChatAPI.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXChatAPI.docc; sourceTree = ""; }; 5C69D5C928525085009B27A4 /* ServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceProtocol.swift; sourceTree = ""; }; + 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXChatSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C69D5F028529FAD009B27A4 /* SimpleXChatSDK.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXChatSDK.docc; sourceTree = ""; }; + 5C69D5F128529FAD009B27A4 /* SimpleXChatSDK.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleXChatSDK.h; sourceTree = ""; }; + 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXAppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C69D5F92852A01F009B27A4 /* SimpleXAppShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleXAppShared.h; sourceTree = ""; }; + 5C69D5FA2852A01F009B27A4 /* SimpleXAppShared.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXAppShared.docc; sourceTree = ""; }; + 5C69D6072852A1C7009B27A4 /* ServiceAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceAPI.swift; sourceTree = ""; }; 5C6AD81227A834E300348BD7 /* NewChatButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatButton.swift; sourceTree = ""; }; 5C6F2A3728522C9A00103588 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; 5C6F2A3828522C9A00103588 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; @@ -361,7 +409,7 @@ buildActionMask = 2147483647; files = ( 5C1CAA172847C5C8009E5C72 /* UniformTypeIdentifiers.framework in Frameworks */, - 5C1CAA6A2849119A009E5C72 /* SimpleXChat.framework in Frameworks */, + 5CCE9153285320ED005E7E0B /* SimpleXChat.framework in Frameworks */, 5C69D5CF28525108009B27A4 /* SimpleXServiceProtocol.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -373,22 +421,31 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5C69D5B928524D67009B27A4 /* Frameworks */ = { + 5C69D5DF28529F66009B27A4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; + 5C69D5F42852A01F009B27A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CCE915628532107005E7E0B /* SimpleXServiceProtocol.framework in Frameworks */, + 5CCE914528532015005E7E0B /* SimpleXChatSDK.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5CA059C7279559F40002BEB4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C69D5C428524D67009B27A4 /* SimpleXChatAPI.framework in Frameworks */, 5C69D5CB285250FB009B27A4 /* SimpleXServiceProtocol.framework in Frameworks */, - 5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */, 646BB38C283BEEB9001CE359 /* LocalAuthentication.framework in Frameworks */, + 5CCE915A28532144005E7E0B /* SimpleXChatSDK.framework in Frameworks */, 5C8F01CD27A6F0D8007D2C8D /* CodeScanner in Frameworks */, + 5C69D5FF2852A01F009B27A4 /* SimpleXAppShared.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -403,7 +460,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5CE2BAA62845617C00EC33A6 /* SimpleXChat.framework in Frameworks */, + 5CCE916328532155005E7E0B /* SimpleXChatSDK.framework in Frameworks */, + 5CCE915E28532150005E7E0B /* SimpleXAppShared.framework in Frameworks */, + 5CCE91672853215A005E7E0B /* SimpleXServiceProtocol.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -444,7 +503,7 @@ 5C1CAA192847C5C8009E5C72 /* FileProviderExtension.swift */, 5C1CAA1B2847C5C8009E5C72 /* FileProviderItem.swift */, 5C1CAA1D2847C5C8009E5C72 /* FileProviderEnumerator.swift */, - 5C1CAA272847D7C0009E5C72 /* SimpleXFPService.swift */, + 5C1CAA272847D7C0009E5C72 /* FileProviderService.swift */, 5C1CAA1F2847C5C8009E5C72 /* Info.plist */, 5C1CAA202847C5C8009E5C72 /* SimpleX_Service.entitlements */, ); @@ -490,13 +549,30 @@ path = Chat; sourceTree = ""; }; - 5C69D5BD28524D67009B27A4 /* SimpleXChatAPI */ = { + 5C69D5EF28529FAD009B27A4 /* SimpleXChatSDK */ = { isa = PBXGroup; children = ( - 5C69D5BE28524D67009B27A4 /* SimpleXChatAPI.h */, - 5C69D5BF28524D67009B27A4 /* SimpleXChatAPI.docc */, + 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */, + 5CDCAD7428188D2900503DA2 /* APITypes.swift */, + 5C5E5D3C282447AB00B0488A /* CallTypes.swift */, + 5C9FD96A27A56D4D0075386C /* JSON.swift */, + 5C69D5F128529FAD009B27A4 /* SimpleXChatSDK.h */, + 5C69D5F028529FAD009B27A4 /* SimpleXChatSDK.docc */, ); - path = SimpleXChatAPI; + path = SimpleXChatSDK; + sourceTree = ""; + }; + 5C69D5F82852A01F009B27A4 /* SimpleXAppShared */ = { + isa = PBXGroup; + children = ( + 5CDCAD5228186F9500503DA2 /* AppGroup.swift */, + 64DAE1502809D9F5000DA960 /* FileUtils.swift */, + 5CDCAD80281A7E2700503DA2 /* Notifications.swift */, + 5C69D6072852A1C7009B27A4 /* ServiceAPI.swift */, + 5C69D5F92852A01F009B27A4 /* SimpleXAppShared.h */, + 5C69D5FA2852A01F009B27A4 /* SimpleXAppShared.docc */, + ); + path = SimpleXAppShared; sourceTree = ""; }; 5C764E5C279C70B7000C6508 /* Libraries */ = { @@ -561,7 +637,8 @@ 5CDCAD462818589900503DA2 /* SimpleX NSE */, 5C1CAA182847C5C8009E5C72 /* SimpleX Service */, 5C1CAA2F2847DDA0009E5C72 /* SimpleXServiceProtocol */, - 5C69D5BD28524D67009B27A4 /* SimpleXChatAPI */, + 5C69D5F82852A01F009B27A4 /* SimpleXAppShared */, + 5C69D5EF28529FAD009B27A4 /* SimpleXChatSDK */, 5CE2BA692845308900EC33A6 /* SimpleXChat */, 5CA059DA279559F40002BEB4 /* Tests iOS */, 5CA059CB279559F40002BEB4 /* Products */, @@ -575,7 +652,6 @@ 5CA059C3279559F40002BEB4 /* SimpleXApp.swift */, 5C36027227F47AD5009F19D9 /* AppDelegate.swift */, 5CA059C4279559F40002BEB4 /* ContentView.swift */, - 5C1CAA3B2847DE88009E5C72 /* FPService.swift */, 5C764E87279CBC8E000C6508 /* Model */, 5C2E260D27A30E2400F70299 /* Views */, 5CA059C5279559F40002BEB4 /* Assets.xcassets */, @@ -593,7 +669,8 @@ 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */, 5C1CAA152847C5C8009E5C72 /* SimpleX Service.appex */, 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */, - 5C69D5BC28524D67009B27A4 /* SimpleXChatAPI.framework */, + 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */, + 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */, ); name = Products; sourceTree = ""; @@ -676,14 +753,7 @@ 5CE2BA692845308900EC33A6 /* SimpleXChat */ = { isa = PBXGroup; children = ( - 5CDCAD5228186F9500503DA2 /* AppGroup.swift */, - 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */, - 5CDCAD7428188D2900503DA2 /* APITypes.swift */, - 5C5E5D3C282447AB00B0488A /* CallTypes.swift */, - 5C9FD96A27A56D4D0075386C /* JSON.swift */, 5CDCAD7D2818941F00503DA2 /* API.swift */, - 5CDCAD80281A7E2700503DA2 /* Notifications.swift */, - 64DAE1502809D9F5000DA960 /* FileUtils.swift */, 5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */, 5CE2BA8A2845332200EC33A6 /* SimpleX.h */, 5CE2BA78284530CC00EC33A6 /* SimpleXChat.docc */, @@ -733,11 +803,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5C69D5B728524D67009B27A4 /* Headers */ = { + 5C69D5DD28529F66009B27A4 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 5C69D5C128524D67009B27A4 /* SimpleXChatAPI.h in Headers */, + 5CCE91522853202E005E7E0B /* SimpleXChatSDK.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5C69D5F22852A01F009B27A4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5C69D5FC2852A01F009B27A4 /* SimpleXAppShared.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -760,6 +838,7 @@ 5C1CAA112847C5C8009E5C72 /* Sources */, 5C1CAA122847C5C8009E5C72 /* Frameworks */, 5C1CAA132847C5C8009E5C72 /* Resources */, + 5CCE9155285320ED005E7E0B /* Embed Frameworks */, ); buildRules = ( ); @@ -790,22 +869,42 @@ productReference = 5C1CAA2E2847DDA0009E5C72 /* SimpleXServiceProtocol.framework */; productType = "com.apple.product-type.framework"; }; - 5C69D5BB28524D67009B27A4 /* SimpleXChatAPI */ = { + 5C69D5E128529F66009B27A4 /* SimpleXChatSDK */ = { isa = PBXNativeTarget; - buildConfigurationList = 5C69D5C628524D67009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXChatAPI" */; + buildConfigurationList = 5C69D5EC28529F66009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXChatSDK" */; buildPhases = ( - 5C69D5B728524D67009B27A4 /* Headers */, - 5C69D5B828524D67009B27A4 /* Sources */, - 5C69D5B928524D67009B27A4 /* Frameworks */, - 5C69D5BA28524D67009B27A4 /* Resources */, + 5C69D5DD28529F66009B27A4 /* Headers */, + 5C69D5DE28529F66009B27A4 /* Sources */, + 5C69D5DF28529F66009B27A4 /* Frameworks */, + 5C69D5E028529F66009B27A4 /* Resources */, ); buildRules = ( ); dependencies = ( ); - name = SimpleXChatAPI; - productName = SimpleXChatAPI; - productReference = 5C69D5BC28524D67009B27A4 /* SimpleXChatAPI.framework */; + name = SimpleXChatSDK; + productName = SimpleXChatSDK; + productReference = 5C69D5E228529F66009B27A4 /* SimpleXChatSDK.framework */; + productType = "com.apple.product-type.framework"; + }; + 5C69D5F62852A01F009B27A4 /* SimpleXAppShared */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5C69D6012852A01F009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXAppShared" */; + buildPhases = ( + 5C69D5F22852A01F009B27A4 /* Headers */, + 5C69D5F32852A01F009B27A4 /* Sources */, + 5C69D5F42852A01F009B27A4 /* Frameworks */, + 5C69D5F52852A01F009B27A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5CCE914828532015005E7E0B /* PBXTargetDependency */, + 5CCE915928532107005E7E0B /* PBXTargetDependency */, + ); + name = SimpleXAppShared; + productName = SimpleXAppShared; + productReference = 5C69D5F72852A01F009B27A4 /* SimpleXAppShared.framework */; productType = "com.apple.product-type.framework"; }; 5CA059C9279559F40002BEB4 /* SimpleX (iOS) */ = { @@ -821,11 +920,11 @@ buildRules = ( ); dependencies = ( - 5CE2BA6F2845308900EC33A6 /* PBXTargetDependency */, 5CE2BA9F284555F500EC33A6 /* PBXTargetDependency */, 5C1CAA692848168A009E5C72 /* PBXTargetDependency */, - 5C69D5C328524D67009B27A4 /* PBXTargetDependency */, 5C69D5CE285250FB009B27A4 /* PBXTargetDependency */, + 5C69D5FE2852A01F009B27A4 /* PBXTargetDependency */, + 5CCE915D28532144005E7E0B /* PBXTargetDependency */, ); name = "SimpleX (iOS)"; packageProductDependencies = ( @@ -864,7 +963,9 @@ buildRules = ( ); dependencies = ( - 5CE2BAA92845617C00EC33A6 /* PBXTargetDependency */, + 5CCE916128532150005E7E0B /* PBXTargetDependency */, + 5CCE916628532155005E7E0B /* PBXTargetDependency */, + 5CCE916A2853215A005E7E0B /* PBXTargetDependency */, ); name = "SimpleX NSE"; productName = "SimpleX NSE"; @@ -906,7 +1007,10 @@ 5C1CAA2D2847DDA0009E5C72 = { CreatedOnToolsVersion = 13.3; }; - 5C69D5BB28524D67009B27A4 = { + 5C69D5E128529F66009B27A4 = { + CreatedOnToolsVersion = 13.3; + }; + 5C69D5F62852A01F009B27A4 = { CreatedOnToolsVersion = 13.3; }; 5CA059C9279559F40002BEB4 = { @@ -948,7 +1052,8 @@ 5CDCAD442818589900503DA2 /* SimpleX NSE */, 5C1CAA142847C5C8009E5C72 /* SimpleX Service */, 5C1CAA2D2847DDA0009E5C72 /* SimpleXServiceProtocol */, - 5C69D5BB28524D67009B27A4 /* SimpleXChatAPI */, + 5C69D5F62852A01F009B27A4 /* SimpleXAppShared */, + 5C69D5E128529F66009B27A4 /* SimpleXChatSDK */, 5CE2BA672845308900EC33A6 /* SimpleXChat */, ); }; @@ -969,7 +1074,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5C69D5BA28524D67009B27A4 /* Resources */ = { + 5C69D5E028529F66009B27A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5C69D5F52852A01F009B27A4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1018,7 +1130,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5C1CAA282847D7C0009E5C72 /* SimpleXFPService.swift in Sources */, + 5C1CAA282847D7C0009E5C72 /* FileProviderService.swift in Sources */, 5C1CAA1A2847C5C8009E5C72 /* FileProviderExtension.swift in Sources */, 5C1CAA1C2847C5C8009E5C72 /* FileProviderItem.swift in Sources */, 5C1CAA1E2847C5C8009E5C72 /* FileProviderEnumerator.swift in Sources */, @@ -1034,11 +1146,26 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5C69D5B828524D67009B27A4 /* Sources */ = { + 5C69D5DE28529F66009B27A4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5C69D5C028524D67009B27A4 /* SimpleXChatAPI.docc in Sources */, + 5CCE914D28532029005E7E0B /* APITypes.swift in Sources */, + 5CCE914C28532029005E7E0B /* JSON.swift in Sources */, + 5CCE914A28532029005E7E0B /* CallTypes.swift in Sources */, + 5CCE914B28532029005E7E0B /* ChatTypes.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5C69D5F32852A01F009B27A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5C69D6082852A1C7009B27A4 /* ServiceAPI.swift in Sources */, + 5C69D6052852A058009B27A4 /* FileUtils.swift in Sources */, + 5C69D6042852A03F009B27A4 /* Notifications.swift in Sources */, + 5C69D5FB2852A01F009B27A4 /* SimpleXAppShared.docc in Sources */, + 5C69D6062852A14A009B27A4 /* AppGroup.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1103,7 +1230,6 @@ 5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */, 5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */, 5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */, - 5C1CAA662847F5BD009E5C72 /* FPService.swift in Sources */, 5CC1C99527A6CF7F000D9FF6 /* ShareSheet.swift in Sources */, 5C5E5D3B2824468B00B0488A /* ActiveCallView.swift in Sources */, 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */, @@ -1143,14 +1269,7 @@ buildActionMask = 2147483647; files = ( 5CE2BA97284537A800EC33A6 /* dummy.m in Sources */, - 5CE2BA922845340900EC33A6 /* FileUtils.swift in Sources */, - 5CE2BA91284533A300EC33A6 /* Notifications.swift in Sources */, 5CE2BA79284530CC00EC33A6 /* SimpleXChat.docc in Sources */, - 5CE2BA90284533A300EC33A6 /* JSON.swift in Sources */, - 5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */, - 5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */, - 5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */, - 5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */, 5CE2BA8E284533A300EC33A6 /* API.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1169,11 +1288,6 @@ target = 5CE2BA672845308900EC33A6 /* SimpleXChat */; targetProxy = 5C1CAA6C2849119A009E5C72 /* PBXContainerItemProxy */; }; - 5C69D5C328524D67009B27A4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 5C69D5BB28524D67009B27A4 /* SimpleXChatAPI */; - targetProxy = 5C69D5C228524D67009B27A4 /* PBXContainerItemProxy */; - }; 5C69D5CE285250FB009B27A4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; platformFilter = ios; @@ -1186,27 +1300,57 @@ target = 5C1CAA2D2847DDA0009E5C72 /* SimpleXServiceProtocol */; targetProxy = 5C69D5D128525108009B27A4 /* PBXContainerItemProxy */; }; + 5C69D5FE2852A01F009B27A4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5C69D5F62852A01F009B27A4 /* SimpleXAppShared */; + targetProxy = 5C69D5FD2852A01F009B27A4 /* PBXContainerItemProxy */; + }; 5CA059D9279559F40002BEB4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5CA059C9279559F40002BEB4 /* SimpleX (iOS) */; targetProxy = 5CA059D8279559F40002BEB4 /* PBXContainerItemProxy */; }; - 5CE2BA6F2845308900EC33A6 /* PBXTargetDependency */ = { + 5CCE914828532015005E7E0B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 5CE2BA672845308900EC33A6 /* SimpleXChat */; - targetProxy = 5CE2BA6E2845308900EC33A6 /* PBXContainerItemProxy */; + platformFilter = ios; + target = 5C69D5E128529F66009B27A4 /* SimpleXChatSDK */; + targetProxy = 5CCE914728532015005E7E0B /* PBXContainerItemProxy */; + }; + 5CCE915928532107005E7E0B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = 5C1CAA2D2847DDA0009E5C72 /* SimpleXServiceProtocol */; + targetProxy = 5CCE915828532107005E7E0B /* PBXContainerItemProxy */; + }; + 5CCE915D28532144005E7E0B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = 5C69D5E128529F66009B27A4 /* SimpleXChatSDK */; + targetProxy = 5CCE915C28532144005E7E0B /* PBXContainerItemProxy */; + }; + 5CCE916128532150005E7E0B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = 5C69D5F62852A01F009B27A4 /* SimpleXAppShared */; + targetProxy = 5CCE916028532150005E7E0B /* PBXContainerItemProxy */; + }; + 5CCE916628532155005E7E0B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = 5C69D5E128529F66009B27A4 /* SimpleXChatSDK */; + targetProxy = 5CCE916528532155005E7E0B /* PBXContainerItemProxy */; + }; + 5CCE916A2853215A005E7E0B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + platformFilter = ios; + target = 5C1CAA2D2847DDA0009E5C72 /* SimpleXServiceProtocol */; + targetProxy = 5CCE91692853215A005E7E0B /* PBXContainerItemProxy */; }; 5CE2BA9F284555F500EC33A6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5CDCAD442818589900503DA2 /* SimpleX NSE */; targetProxy = 5CE2BA9E284555F500EC33A6 /* PBXContainerItemProxy */; }; - 5CE2BAA92845617C00EC33A6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - platformFilter = ios; - target = 5CE2BA672845308900EC33A6 /* SimpleXChat */; - targetProxy = 5CE2BAA82845617C00EC33A6 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1374,7 +1518,7 @@ }; name = Release; }; - 5C69D5C728524D67009B27A4 /* Debug */ = { + 5C69D5ED28529F66009B27A4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1395,7 +1539,7 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChatAPI; + PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChatSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -1408,7 +1552,7 @@ }; name = Debug; }; - 5C69D5C828524D67009B27A4 /* Release */ = { + 5C69D5EE28529F66009B27A4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1429,7 +1573,76 @@ "@loader_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChatAPI; + PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChatSDK; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 5C69D6022852A01F009B27A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 5NN7GUYB6T; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXAppShared; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 5C69D6032852A01F009B27A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 5NN7GUYB6T; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXAppShared; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -1884,11 +2097,20 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 5C69D5C628524D67009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXChatAPI" */ = { + 5C69D5EC28529F66009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXChatSDK" */ = { isa = XCConfigurationList; buildConfigurations = ( - 5C69D5C728524D67009B27A4 /* Debug */, - 5C69D5C828524D67009B27A4 /* Release */, + 5C69D5ED28529F66009B27A4 /* Debug */, + 5C69D5EE28529F66009B27A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5C69D6012852A01F009B27A4 /* Build configuration list for PBXNativeTarget "SimpleXAppShared" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5C69D6022852A01F009B27A4 /* Debug */, + 5C69D6032852A01F009B27A4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/apps/ios/SimpleXChat/AppGroup.swift b/apps/ios/SimpleXAppShared/AppGroup.swift similarity index 100% rename from apps/ios/SimpleXChat/AppGroup.swift rename to apps/ios/SimpleXAppShared/AppGroup.swift diff --git a/apps/ios/SimpleXChat/FileUtils.swift b/apps/ios/SimpleXAppShared/FileUtils.swift similarity index 98% rename from apps/ios/SimpleXChat/FileUtils.swift rename to apps/ios/SimpleXAppShared/FileUtils.swift index 039303931..16b6b60f5 100644 --- a/apps/ios/SimpleXChat/FileUtils.swift +++ b/apps/ios/SimpleXAppShared/FileUtils.swift @@ -9,6 +9,7 @@ import Foundation import SwiftUI import OSLog +import SimpleXChatSDK let logger = Logger() @@ -17,7 +18,7 @@ public let maxImageSize: Int64 = 236700 public let maxFileSize: Int64 = 8000000 -func getDocumentsDirectory() -> URL { +public func getDocumentsDirectory() -> URL { // FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: APP_GROUP_NAME)! } diff --git a/apps/ios/SimpleXChat/Notifications.swift b/apps/ios/SimpleXAppShared/Notifications.swift similarity index 99% rename from apps/ios/SimpleXChat/Notifications.swift rename to apps/ios/SimpleXAppShared/Notifications.swift index 9413e6381..28a68d583 100644 --- a/apps/ios/SimpleXChat/Notifications.swift +++ b/apps/ios/SimpleXAppShared/Notifications.swift @@ -9,6 +9,7 @@ import Foundation import UserNotifications import SwiftUI +import SimpleXChatSDK public let ntfCategoryContactRequest = "NTF_CAT_CONTACT_REQUEST" public let ntfCategoryContactConnected = "NTF_CAT_CONTACT_CONNECTED" diff --git a/apps/ios/SimpleXAppShared/ServiceAPI.swift b/apps/ios/SimpleXAppShared/ServiceAPI.swift new file mode 100644 index 000000000..e08d2cd88 --- /dev/null +++ b/apps/ios/SimpleXAppShared/ServiceAPI.swift @@ -0,0 +1,62 @@ +// +// ServiceAPI.swift +// SimpleXAppShared +// +// Created by Evgeny on 09/06/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +import Foundation +import SimpleXServiceProtocol +import SimpleXChatSDK + +private var serviceProxy: SimpleXServiceProtocol? + +public func sendSimpleXCmd(_ cmd: ChatCommand) async -> ChatResponse { + let proxy = await getServiceProxy() + let resp = await proxy.chatSendCmd(cmd.cmdString) + return chatResponse(resp) +} + +public func recvSimpleXMsg() async -> ChatResponse { + let proxy = await getServiceProxy() + let msg = await proxy.chatRecvMsg() + return chatResponse(msg) +} + +public func getServiceProxy() async -> SimpleXServiceProtocol { + if let proxy = serviceProxy { return proxy } + var err: Error? + for i in 1...20 { + do { + let proxy = try await _getServiceProxy() + serviceProxy = proxy + logger.debug("getServiceProxy \(i): success") + return proxy + } catch let error { + err = error + logger.debug("getServiceProxy \(i): \(String(describing: error), privacy: .public)") + try! await Task.sleep(nanoseconds: 250_000) + } + } + fatalError("getServiceProxy: error \(String(describing: err))") +} + +private func _getServiceProxy() async throws -> SimpleXServiceProtocol { + let services = try await FileManager.default.fileProviderServicesForItem(at: SERVICE_PROXY_ITEM_URL) + guard let service = services[SIMPLEX_SERVICE_NAME] else { throw ServiceError.noService } + let connection = try await service.fileProviderConnection() + connection.remoteObjectInterface = simpleXServiceInterface + connection.resume() + var err: ServiceError? + let rawProxy = connection.remoteObjectProxyWithErrorHandler { error in err = .noProxy(error) } + if let err = err { throw ServiceError.noProxy(err) } + guard let proxy = rawProxy as? SimpleXServiceProtocol else { throw ServiceError.badProxy } + return proxy +} + +enum ServiceError: Error { + case noService + case noProxy(Error) + case badProxy +} diff --git a/apps/ios/SimpleXAppShared/SimpleXAppShared.docc/SimpleXAppShared.md b/apps/ios/SimpleXAppShared/SimpleXAppShared.docc/SimpleXAppShared.md new file mode 100755 index 000000000..de0ae7050 --- /dev/null +++ b/apps/ios/SimpleXAppShared/SimpleXAppShared.docc/SimpleXAppShared.md @@ -0,0 +1,13 @@ +# ``SimpleXAppShared`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` \ No newline at end of file diff --git a/apps/ios/SimpleXAppShared/SimpleXAppShared.h b/apps/ios/SimpleXAppShared/SimpleXAppShared.h new file mode 100644 index 000000000..ed52d6791 --- /dev/null +++ b/apps/ios/SimpleXAppShared/SimpleXAppShared.h @@ -0,0 +1,19 @@ +// +// SimpleXAppShared.h +// SimpleXAppShared +// +// Created by Evgeny on 09/06/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +#import + +//! Project version number for SimpleXAppShared. +FOUNDATION_EXPORT double SimpleXAppSharedVersionNumber; + +//! Project version string for SimpleXAppShared. +FOUNDATION_EXPORT const unsigned char SimpleXAppSharedVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/apps/ios/SimpleXChat/API.swift b/apps/ios/SimpleXChat/API.swift index 091a5a719..1ed56804f 100644 --- a/apps/ios/SimpleXChat/API.swift +++ b/apps/ios/SimpleXChat/API.swift @@ -7,60 +7,76 @@ // import Foundation +import OSLog + +let logger = Logger() private var chatController: chat_ctrl? -public func getChatCtrl() -> chat_ctrl { +private func getChatCtrl() -> chat_ctrl { if let controller = chatController { return controller } - let dataDir = getDocumentsDirectory().path + "/mobile_v1" - logger.debug("documents directory \(dataDir)") - var cstr = dataDir.cString(using: .utf8)! + let dbFilePrefix = getDocumentsDirectory().path + "/mobile_v1" + logger.debug("getChatCtrl: dbFilePrefix \(dbFilePrefix)") + var cstr = dbFilePrefix.cString(using: .utf8)! chatController = chat_init(&cstr) logger.debug("getChatCtrl: chat_init") return chatController! } -public func sendSimpleXCmd(_ cmd: ChatCommand) -> ChatResponse { - var c = cmd.cmdString.cString(using: .utf8)! - return chatResponse(chat_send_cmd(getChatCtrl(), &c)) +func getDocumentsDirectory() -> URL { + FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! +// FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: APP_GROUP_NAME)! } -public func chatResponse(_ cjson: UnsafeMutablePointer) -> ChatResponse { +//public func sendSimpleXCmd(_ cmd: ChatCommand) -> ChatResponse { +// var c = cmd.cmdString.cString(using: .utf8)! +// return chatResponse(chat_send_cmd(getChatCtrl(), &c)) +//} + +public func chatSendCmd(_ cmd: String) -> String { + var c = cmd.cString(using: .utf8)! + return rawChatResponse(chat_send_cmd(getChatCtrl(), &c)) +} + +public func chatRecvMsg() -> String { + rawChatResponse(chat_recv_msg(getChatCtrl())) +} + +public func rawChatResponse(_ cjson: UnsafeMutablePointer) -> String { let s = String.init(cString: cjson) - let d = s.data(using: .utf8)! -// TODO is there a way to do it without copying the data? e.g: -// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson)) -// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free) - do { - let r = try jsonDecoder.decode(APIResponse.self, from: d) - return r.resp - } catch { - logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)") - } - - var type: String? - var json: String? - if let j = try? JSONSerialization.jsonObject(with: d) as? NSDictionary { - if let j1 = j["resp"] as? NSDictionary, j1.count == 1 { - type = j1.allKeys[0] as? String - } - json = prettyJSON(j) - } free(cjson) - return ChatResponse.response(type: type ?? "invalid", json: json ?? s) + return s } -func prettyJSON(_ obj: NSDictionary) -> String? { - if let d = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) { - return String(decoding: d, as: UTF8.self) - } - return nil -} - -public func responseError(_ err: Error) -> String { - if let r = err as? ChatResponse { - return String(describing: r) - } else { - return err.localizedDescription - } -} +//public func chatResponse(_ cjson: UnsafeMutablePointer) -> ChatResponse { +// let s = String.init(cString: cjson) +// let d = s.data(using: .utf8)! +//// TODO is there a way to do it without copying the data? e.g: +//// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson)) +//// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free) +// do { +// let r = try jsonDecoder.decode(APIResponse.self, from: d) +// return r.resp +// } catch { +// logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)") +// } +// +// var type: String? +// var json: String? +// if let j = try? JSONSerialization.jsonObject(with: d) as? NSDictionary { +// if let j1 = j["resp"] as? NSDictionary, j1.count == 1 { +// type = j1.allKeys[0] as? String +// } +// json = prettyJSON(j) +// } +// free(cjson) +// return ChatResponse.response(type: type ?? "invalid", json: json ?? s) +//} +// +//public func responseError(_ err: Error) -> String { +// if let r = err as? ChatResponse { +// return String(describing: r) +// } else { +// return err.localizedDescription +// } +//} diff --git a/apps/ios/SimpleXChatAPI/SimpleXChatAPI.h b/apps/ios/SimpleXChatAPI/SimpleXChatAPI.h deleted file mode 100644 index 48e9d0988..000000000 --- a/apps/ios/SimpleXChatAPI/SimpleXChatAPI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// SimpleXChatAPI.h -// SimpleXChatAPI -// -// Created by Evgeny on 09/06/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -#import - -//! Project version number for SimpleXChatAPI. -FOUNDATION_EXPORT double SimpleXChatAPIVersionNumber; - -//! Project version string for SimpleXChatAPI. -FOUNDATION_EXPORT const unsigned char SimpleXChatAPIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChatSDK/APITypes.swift similarity index 95% rename from apps/ios/SimpleXChat/APITypes.swift rename to apps/ios/SimpleXChatSDK/APITypes.swift index d45ceef19..b15217f3f 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChatSDK/APITypes.swift @@ -7,6 +7,9 @@ // import Foundation +import OSLog + +let logger = Logger() let jsonDecoder = getJSONDecoder() let jsonEncoder = getJSONEncoder() @@ -520,3 +523,34 @@ public enum SMPAgentError: Decodable { case A_VERSION case A_ENCRYPTION } + +public func chatResponse(_ s: String) -> ChatResponse { + let d = s.data(using: .utf8)! +// TODO is there a way to do it without copying the data? e.g: +// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson)) +// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free) + do { + let r = try jsonDecoder.decode(APIResponse.self, from: d) + return r.resp + } catch { + logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)") + } + + var type: String? + var json: String? + if let j = try? JSONSerialization.jsonObject(with: d) as? NSDictionary { + if let j1 = j["resp"] as? NSDictionary, j1.count == 1 { + type = j1.allKeys[0] as? String + } + json = prettyJSON(j) + } + return ChatResponse.response(type: type ?? "invalid", json: json ?? s) +} + +public func responseError(_ err: Error) -> String { + if let r = err as? ChatResponse { + return String(describing: r) + } else { + return err.localizedDescription + } +} diff --git a/apps/ios/SimpleXChat/CallTypes.swift b/apps/ios/SimpleXChatSDK/CallTypes.swift similarity index 100% rename from apps/ios/SimpleXChat/CallTypes.swift rename to apps/ios/SimpleXChatSDK/CallTypes.swift diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChatSDK/ChatTypes.swift similarity index 99% rename from apps/ios/SimpleXChat/ChatTypes.swift rename to apps/ios/SimpleXChatSDK/ChatTypes.swift index fd631a0cc..73f33fa22 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChatSDK/ChatTypes.swift @@ -700,7 +700,7 @@ public struct CIFile: Decodable { CIFile(fileId: fileId, fileName: fileName, fileSize: fileSize, filePath: filePath, fileStatus: fileStatus) } - var loaded: Bool { + public var loaded: Bool { get { switch self.fileStatus { case .sndStored: return true diff --git a/apps/ios/SimpleXChat/JSON.swift b/apps/ios/SimpleXChatSDK/JSON.swift similarity index 84% rename from apps/ios/SimpleXChat/JSON.swift rename to apps/ios/SimpleXChatSDK/JSON.swift index e9dfdef44..1e7525cc8 100644 --- a/apps/ios/SimpleXChat/JSON.swift +++ b/apps/ios/SimpleXChatSDK/JSON.swift @@ -36,3 +36,10 @@ private func getDateFormatter(_ format: String) -> DateFormatter { df.timeZone = TimeZone(secondsFromGMT: 0) return df } + +func prettyJSON(_ obj: NSDictionary) -> String? { + if let d = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) { + return String(decoding: d, as: UTF8.self) + } + return nil +} diff --git a/apps/ios/SimpleXChatAPI/SimpleXChatAPI.docc/SimpleXChatAPI.md b/apps/ios/SimpleXChatSDK/SimpleXChatSDK.docc/SimpleXChatSDK.md similarity index 70% rename from apps/ios/SimpleXChatAPI/SimpleXChatAPI.docc/SimpleXChatAPI.md rename to apps/ios/SimpleXChatSDK/SimpleXChatSDK.docc/SimpleXChatSDK.md index e94a5f23b..64a39ae31 100755 --- a/apps/ios/SimpleXChatAPI/SimpleXChatAPI.docc/SimpleXChatAPI.md +++ b/apps/ios/SimpleXChatSDK/SimpleXChatSDK.docc/SimpleXChatSDK.md @@ -1,4 +1,4 @@ -# ``SimpleXChatAPI`` +# ``SimpleXChatSDK`` Summary diff --git a/apps/ios/SimpleXChatSDK/SimpleXChatSDK.h b/apps/ios/SimpleXChatSDK/SimpleXChatSDK.h new file mode 100644 index 000000000..1d268b845 --- /dev/null +++ b/apps/ios/SimpleXChatSDK/SimpleXChatSDK.h @@ -0,0 +1,19 @@ +// +// SimpleXChatSDK.h +// SimpleXChatSDK +// +// Created by Evgeny on 09/06/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +#import + +//! Project version number for SimpleXChatSDK. +FOUNDATION_EXPORT double SimpleXChatSDKVersionNumber; + +//! Project version string for SimpleXChatSDK. +FOUNDATION_EXPORT const unsigned char SimpleXChatSDKVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/apps/ios/SimpleXServiceProtocol/ServiceProtocol.swift b/apps/ios/SimpleXServiceProtocol/ServiceProtocol.swift index 268da04e3..1358aff6b 100644 --- a/apps/ios/SimpleXServiceProtocol/ServiceProtocol.swift +++ b/apps/ios/SimpleXServiceProtocol/ServiceProtocol.swift @@ -8,13 +8,20 @@ import Foundation import FileProvider +import OSLog + +let logger = Logger() public let SIMPLEX_SERVICE_NAME = NSFileProviderServiceName("group.chat.simplex.app.service") -public let SERVICE_PROXY_ITEM_ID = NSFileProviderItemIdentifier("123") +public let SERVICE_PROXY_ITEM_NAME = "123" +public let SERVICE_PROXY_ITEM_ID = NSFileProviderItemIdentifier(SERVICE_PROXY_ITEM_NAME) +public let SERVICE_PROXY_ITEM_URL = URL(string: "\(NSFileProviderManager.default.documentStorageURL)\(SERVICE_PROXY_ITEM_NAME)")! public let simpleXServiceInterface: NSXPCInterface = { - NSXPCInterface(with: SimpleXFPServiceProtocol.self) + NSXPCInterface(with: SimpleXServiceProtocol.self) }() -@objc public protocol SimpleXFPServiceProtocol { - func upperCaseString(_ string: String, withReply reply: @escaping (String) -> Void) +@objc public protocol SimpleXServiceProtocol { + func chatSendCmd(_ cmd: String) async -> String + func chatRecvMsg() async -> String } +