From 815981487bfdd0e3f95e7397da7f3fe26316c230 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 1 Jul 2022 09:49:30 +0100 Subject: [PATCH] ios: register notification token/mode on app start (#761) * ios: register notification token/mode on app start * refactor * register token on start * update model on main thread --- apps/ios/Shared/AppDelegate.swift | 17 ++---- apps/ios/Shared/Model/ChatModel.swift | 5 +- apps/ios/Shared/Model/SimpleXAPI.swift | 31 +++++++++- apps/ios/Shared/SimpleXApp.swift | 4 +- .../UserSettings/NotificationsView.swift | 19 +++--- .../Views/UserSettings/SettingsView.swift | 5 +- apps/ios/SimpleX.xcodeproj/project.pbxproj | 60 +++++++------------ apps/ios/SimpleXChat/APITypes.swift | 35 +++++++---- 8 files changed, 93 insertions(+), 83 deletions(-) diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index 66184591c8..bbec769a79 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -21,17 +21,10 @@ class AppDelegate: NSObject, UIApplicationDelegate { let token = deviceToken.map { String(format: "%02hhx", $0) }.joined() logger.debug("AppDelegate: didRegisterForRemoteNotificationsWithDeviceToken \(token)") let m = ChatModel.shared - let deviceToken = DeviceToken(env: pushEnvironment, token: token) + let deviceToken = DeviceToken(pushProvider: PushProvider(env: pushEnvironment), token: token) m.deviceToken = deviceToken - let useNotifications = UserDefaults.standard.bool(forKey: "useNotifications") - if useNotifications { - Task { - do { - m.tokenStatus = try await apiRegisterToken(token: deviceToken, notificationMode: .instant) - } catch { - logger.error("apiRegisterToken error: \(responseError(error))") - } - } + if m.savedToken != nil { + registerToken(token: deviceToken) } } @@ -44,14 +37,14 @@ class AppDelegate: NSObject, UIApplicationDelegate { fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { logger.debug("AppDelegate: didReceiveRemoteNotification") print("*** userInfo", userInfo) + let m = ChatModel.shared if let ntfData = userInfo["notificationData"] as? [AnyHashable : Any], - UserDefaults.standard.bool(forKey: "useNotifications") { + m.notificationMode != .off { if let verification = ntfData["verification"] as? String, let nonce = ntfData["nonce"] as? String { if let token = ChatModel.shared.deviceToken { logger.debug("AppDelegate: didReceiveRemoteNotification: verification, confirming \(verification)") Task { - let m = ChatModel.shared do { if case .active = m.tokenStatus {} else { m.tokenStatus = .confirmed } try await apiVerifyToken(token: token, nonce: nonce, code: verification) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index be3e1fe446..41ba73c613 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -29,8 +29,9 @@ final class ChatModel: ObservableObject { @Published var userSMPServers: [String]? @Published var appOpenUrl: URL? @Published var deviceToken: DeviceToken? - @Published var tokenStatus = NtfTknStatus.new - @Published var notificationMode = NotificationMode.off + @Published var savedToken: DeviceToken? + @Published var tokenStatus: NtfTknStatus? + @Published var notificationMode = NotificationsMode.off @Published var notificationPreview: NotificationPreviewMode? = .message // current WebRTC call @Published var callInvitations: Dictionary = [:] diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index a9795453eb..5d2b9ade8a 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -226,12 +226,37 @@ func apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteM throw r } -func apiRegisterToken(token: DeviceToken, notificationMode: NotificationMode) async throws -> NtfTknStatus { +func apiGetNtfToken() throws -> (DeviceToken?, NtfTknStatus?, NotificationsMode) { + let r = chatSendCmdSync(.apiGetNtfToken) + switch r { + case let .ntfToken(token, status, ntfMode): return (token, status, ntfMode) + case .chatCmdError(.errorAgent(.CMD(.PROHIBITED))): return (nil, nil, .off) + default: throw r + } +} + +func apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) async throws -> NtfTknStatus { let r = await chatSendCmd(.apiRegisterToken(token: token, notificationMode: notificationMode)) if case let .ntfTokenStatus(status) = r { return status } throw r } +func registerToken(token: DeviceToken) { + let m = ChatModel.shared + let mode = m.notificationMode + if mode != .off { + logger.debug("registerToken \(mode.rawValue)") + Task { + do { + let status = try await apiRegisterToken(token: token, notificationMode: mode) + await MainActor.run { m.tokenStatus = status } + } catch let error { + logger.error("registerToken apiRegisterToken error: \(responseError(error))") + } + } + } +} + func apiVerifyToken(token: DeviceToken, nonce: String, code: String) async throws { try await sendCommandOkResp(.apiVerifyToken(token: token, nonce: nonce, code: code)) } @@ -501,6 +526,10 @@ func startChat() throws { m.userAddress = try apiGetUserAddress() m.userSMPServers = try getUserSMPServers() m.chats = try apiGetChats() + (m.savedToken, m.tokenStatus, m.notificationMode) = try apiGetNtfToken() + if let token = m.deviceToken { + registerToken(token: token) + } withAnimation { m.onboardingStage = m.chats.isEmpty ? .step3_MakeConnection diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 5d983832a7..feb6721476 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -73,8 +73,8 @@ struct SimpleXApp: App { private func setDbContainer() { // Uncomment and run once to open DB in app documents folder: - // dbContainerGroupDefault.set(.documents) - // v3DBMigrationDefault.set(.offer) +// dbContainerGroupDefault.set(.documents) +// v3DBMigrationDefault.set(.offer) // to create database in app documents folder also uncomment: // let legacyDatabase = true let legacyDatabase = hasLegacyDatabase() diff --git a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift index 3cf7d39198..46c1da8a55 100644 --- a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift +++ b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift @@ -11,9 +11,8 @@ import SimpleXChat struct NotificationsView: View { @EnvironmentObject var m: ChatModel - @State private var notificationMode: NotificationMode? + @State private var notificationMode: NotificationsMode? @State private var showAlert: NotificationAlert? - @AppStorage(DEFAULT_USE_NOTIFICATIONS) private var useNotifications = false var body: some View { List { @@ -21,7 +20,7 @@ struct NotificationsView: View { NavigationLink { List { Section { - SelectionListView(list: NotificationMode.values, selection: $notificationMode) { mode in + SelectionListView(list: NotificationsMode.values, selection: $notificationMode) { mode in showAlert = .setMode(mode: mode) } } footer: { @@ -93,7 +92,7 @@ struct NotificationsView: View { } } - private func ntfModeAlertTitle(_ mode: NotificationMode) -> LocalizedStringKey { + private func ntfModeAlertTitle(_ mode: NotificationsMode) -> LocalizedStringKey { switch mode { case .off: return "Turn off notifications?" case .periodic: return "Enable periodic notifications?" @@ -101,18 +100,16 @@ struct NotificationsView: View { } } - private func setNotificationsMode(_ mode: NotificationMode, _ token: DeviceToken) { + private func setNotificationsMode(_ mode: NotificationsMode, _ token: DeviceToken) { Task { switch mode { case .off: do { try await apiDeleteToken(token: token) - useNotifications = false m.tokenStatus = .new notificationMode = .off m.notificationMode = .off - } - catch let error { + } catch let error { DispatchQueue.main.async { let err = responseError(error) logger.error("apiDeleteToken error: \(err)") @@ -123,12 +120,10 @@ struct NotificationsView: View { do { do { m.tokenStatus = try await apiRegisterToken(token: token, notificationMode: mode) - useNotifications = true notificationMode = mode m.notificationMode = mode } catch let error { DispatchQueue.main.async { - useNotifications = notificationMode != .off let err = responseError(error) logger.error("apiRegisterToken error: \(err)") showAlert = .error(title: "Error enabling notifications", error: err) @@ -140,7 +135,7 @@ struct NotificationsView: View { } } -func ntfModeDescription(_ mode: NotificationMode) -> LocalizedStringKey { +func ntfModeDescription(_ mode: NotificationsMode) -> LocalizedStringKey { switch mode { case .off: return "**Maximum privacy**: push notifications are off.\nNo meta-data is shared with SimpleX Chat notification server." case .periodic: return "**High privacy**: new messages are checked every 20 minutes.\nYour device token is shared with SimpleX Chat notification server, but it cannot see how many connections you have or how many messages you receive." @@ -187,7 +182,7 @@ struct SelectionListView: View { } enum NotificationAlert: Identifiable { - case setMode(mode: NotificationMode) + case setMode(mode: NotificationsMode) case error(title: LocalizedStringKey, error: String) var id: String { diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index 97e0ba5c0f..d99f31b350 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -18,7 +18,6 @@ let appBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? let DEFAULT_SHOW_LA_NOTICE = "showLocalAuthenticationNotice" let DEFAULT_LA_NOTICE_SHOWN = "localAuthenticationNoticeShown" let DEFAULT_PERFORM_LA = "performLocalAuthentication" -let DEFAULT_USE_NOTIFICATIONS = "useNotifications" let DEFAULT_PENDING_CONNECTIONS = "pendingConnections" let DEFAULT_WEBRTC_POLICY_RELAY = "webrtcPolicyRelay" let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages" @@ -32,7 +31,6 @@ let appDefaults: [String: Any] = [ DEFAULT_SHOW_LA_NOTICE: false, DEFAULT_LA_NOTICE_SHOWN: false, DEFAULT_PERFORM_LA: false, - DEFAULT_USE_NOTIFICATIONS: false, DEFAULT_PENDING_CONNECTIONS: true, DEFAULT_WEBRTC_POLICY_RELAY: true, DEFAULT_PRIVACY_ACCEPT_IMAGES: true, @@ -218,6 +216,9 @@ struct SettingsView: View { case .expired: icon = "bolt.slash.fill" color = .primary + case .none: + icon = "bolt" + color = .primary } return Image(systemName: icon) .padding(.trailing, 9) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 4edc81a91b..7d8778b3db 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -18,6 +18,11 @@ 5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; }; 5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; 5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; }; + 5C14247E286DAC1D0004E3EE /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C142479286DAC1D0004E3EE /* libffi.a */; }; + 5C14247F286DAC1D0004E3EE /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C14247A286DAC1D0004E3EE /* libgmpxx.a */; }; + 5C142480286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C14247B286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a */; }; + 5C142481286DAC1D0004E3EE /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C14247C286DAC1D0004E3EE /* libgmp.a */; }; + 5C142482286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C14247D286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a */; }; 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; @@ -102,11 +107,6 @@ 5CEACCE327DE9246000BD591 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCE227DE9246000BD591 /* ComposeView.swift */; }; 5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; }; 5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; }; - 5CFA59CA2864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CFA59C52864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a */; }; - 5CFA59CB2864464A00863A68 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CFA59C62864464A00863A68 /* libffi.a */; }; - 5CFA59CC2864464A00863A68 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CFA59C72864464A00863A68 /* libgmpxx.a */; }; - 5CFA59CD2864464A00863A68 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CFA59C82864464A00863A68 /* libgmp.a */; }; - 5CFA59CE2864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CFA59C92864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a */; }; 5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59CF286477B400863A68 /* ChatArchiveView.swift */; }; 5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; }; 5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; }; @@ -190,6 +190,11 @@ 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = ""; }; 5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = ""; }; 5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 5C142479286DAC1D0004E3EE /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + 5C14247A286DAC1D0004E3EE /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C14247B286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a"; sourceTree = ""; }; + 5C14247C286DAC1D0004E3EE /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C14247D286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a"; sourceTree = ""; }; 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.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 = ""; }; @@ -275,11 +280,6 @@ 5CEACCE227DE9246000BD591 /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = ""; }; 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = ""; }; 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = ""; }; - 5CFA59C52864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a"; sourceTree = ""; }; - 5CFA59C62864464A00863A68 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 5CFA59C72864464A00863A68 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 5CFA59C82864464A00863A68 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5CFA59C92864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a"; sourceTree = ""; }; 5CFA59CF286477B400863A68 /* ChatArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatArchiveView.swift; sourceTree = ""; }; 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; }; 640F50E227CF991C001E05C2 /* SMPServers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMPServers.swift; sourceTree = ""; }; @@ -325,13 +325,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5CFA59CE2864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a in Frameworks */, - 5CFA59CA2864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a in Frameworks */, - 5CFA59CC2864464A00863A68 /* libgmpxx.a in Frameworks */, + 5C14247F286DAC1D0004E3EE /* libgmpxx.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, + 5C142480286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a in Frameworks */, + 5C14247E286DAC1D0004E3EE /* libffi.a in Frameworks */, + 5C142482286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a in Frameworks */, + 5C142481286DAC1D0004E3EE /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 5CFA59CD2864464A00863A68 /* libgmp.a in Frameworks */, - 5CFA59CB2864464A00863A68 /* libffi.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -385,11 +385,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5CFA59C62864464A00863A68 /* libffi.a */, - 5CFA59C82864464A00863A68 /* libgmp.a */, - 5CFA59C72864464A00863A68 /* libgmpxx.a */, - 5CFA59C52864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl-ghc8.10.7.a */, - 5CFA59C92864464A00863A68 /* libHSsimplex-chat-2.2.0-40J3CUJkXRXAsiR552cpHl.a */, + 5C142479286DAC1D0004E3EE /* libffi.a */, + 5C14247C286DAC1D0004E3EE /* libgmp.a */, + 5C14247A286DAC1D0004E3EE /* libgmpxx.a */, + 5C14247B286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj-ghc8.10.7.a */, + 5C14247D286DAC1D0004E3EE /* libHSsimplex-chat-2.2.0-B9XlcSXdcwBJ5TIVTDfRQj.a */, ); path = Libraries; sourceTree = ""; @@ -1122,8 +1122,6 @@ "$(inherited)", "@executable_path/Frameworks", ); - "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios"; - "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim"; MARKETING_VERSION = 2.2.1; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; @@ -1164,8 +1162,6 @@ "$(inherited)", "@executable_path/Frameworks", ); - "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios"; - "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim"; MARKETING_VERSION = 2.2.1; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; @@ -1237,14 +1233,6 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries/ios", - ); - "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries/sim", - ); MARKETING_VERSION = 2.2.1; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1275,14 +1263,6 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries/ios", - ); - "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries/sim", - ); MARKETING_VERSION = 2.2.1; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 8d9b06447a..5b92fd3e87 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -28,7 +28,8 @@ public enum ChatCommand { case apiSendMessage(type: ChatType, id: Int64, file: String?, quotedItemId: Int64?, msg: MsgContent) case apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, msg: MsgContent) case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode) - case apiRegisterToken(token: DeviceToken, notificationMode: NotificationMode) + case apiGetNtfToken + case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) case apiVerifyToken(token: DeviceToken, nonce: String, code: String) case apiDeleteToken(token: DeviceToken) case apiGetNtfMessage(nonce: String, encNtfInfo: String) @@ -76,6 +77,7 @@ public enum ChatCommand { return "/_send \(ref(type, id)) json \(msg)" case let .apiUpdateChatItem(type, id, itemId, mc): return "/_update item \(ref(type, id)) \(itemId) \(mc.cmdString)" case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)" + case .apiGetNtfToken: return "/_ntf get " case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)" case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)" case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)" @@ -124,6 +126,7 @@ public enum ChatCommand { case .apiSendMessage: return "apiSendMessage" case .apiUpdateChatItem: return "apiUpdateChatItem" case .apiDeleteChatItem: return "apiDeleteChatItem" + case .apiGetNtfToken: return "apiGetNtfToken" case .apiRegisterToken: return "apiRegisterToken" case .apiVerifyToken: return "apiVerifyToken" case .apiDeleteToken: return "apiDeleteToken" @@ -222,6 +225,7 @@ public enum ChatResponse: Decodable, Error { case callExtraInfo(contact: Contact, extraInfo: WebRTCExtraInfo) case callEnded(contact: Contact) case ntfTokenStatus(status: NtfTknStatus) + case ntfToken(token: DeviceToken, status: NtfTknStatus, ntfMode: NotificationsMode) case ntfMessages(connEntity: ConnectionEntity?, msgTs: Date?, ntfMessages: [NtfMsgInfo]) case newContactConnection(connection: PendingContactConnection) case contactConnectionDeleted(connection: PendingContactConnection) @@ -284,6 +288,7 @@ public enum ChatResponse: Decodable, Error { case .callExtraInfo: return "callExtraInfo" case .callEnded: return "callEnded" case .ntfTokenStatus: return "ntfTokenStatus" + case .ntfToken: return "ntfToken" case .ntfMessages: return "ntfMessages" case .newContactConnection: return "newContactConnection" case .contactConnectionDeleted: return "contactConnectionDeleted" @@ -349,6 +354,7 @@ public enum ChatResponse: Decodable, Error { case let .callExtraInfo(contact, extraInfo): return "contact: \(contact.id)\nextraInfo: \(String(describing: extraInfo))" case let .callEnded(contact): return "contact: \(contact.id)" case let .ntfTokenStatus(status): return String(describing: status) + case let .ntfToken(token, status, ntfMode): return "token: \(token)\nstatus: \(status.rawValue)\nntfMode: \(ntfMode.rawValue)" case let .ntfMessages(connEntity, msgTs, ntfMessages): return "connEntity: \(String(describing: connEntity))\nmsgTs: \(String(describing: msgTs))\nntfMessages: \(String(describing: ntfMessages))" case let .newContactConnection(connection): return String(describing: connection) case let .contactConnectionDeleted(connection): return String(describing: connection) @@ -383,33 +389,38 @@ public protocol SelectableItem: Hashable, Identifiable { static var values: [Self] { get } } -public struct DeviceToken { - var env: PushEnvironment +public struct DeviceToken: Decodable { + var pushProvider: PushProvider var token: String - public init(env: PushEnvironment, token: String) { - self.env = env + public init(pushProvider: PushProvider, token: String) { + self.pushProvider = pushProvider self.token = token } public var cmdString: String { - "\(env.pushProvider) \(token)" + "\(pushProvider) \(token)" } } public enum PushEnvironment: String { case development case production +} - public var pushProvider: String { - switch self { - case .development: return "apns_dev" - case .production: return "apns_prod" +public enum PushProvider: String, Decodable { + case apns_dev + case apns_prod + + public init(env: PushEnvironment) { + switch env { + case .development: self = .apns_dev + case .production: self = .apns_prod } } } -public enum NotificationMode: String, SelectableItem { +public enum NotificationsMode: String, Decodable, SelectableItem { case off = "OFF" case periodic = "PERIODIC" case instant = "INSTANT" @@ -424,7 +435,7 @@ public enum NotificationMode: String, SelectableItem { public var id: String { self.rawValue } - public static var values: [NotificationMode] = [.instant, .periodic, .off] + public static var values: [NotificationsMode] = [.instant, .periodic, .off] } public enum NotificationPreviewMode: String, SelectableItem {