diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 65b69a75c8..279dcebe16 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -554,6 +554,12 @@ func apiVerifyToken(token: DeviceToken, nonce: String, code: String) async throw try await sendCommandOkResp(.apiVerifyToken(token: token, nonce: nonce, code: code)) } +func apiCheckToken(token: DeviceToken) async throws -> NtfTknStatus { + let r = await chatSendCmd(.apiCheckToken(token: token)) + if case let .ntfTokenStatus(status) = r { return status } + throw r +} + func apiDeleteToken(token: DeviceToken) async throws { try await sendCommandOkResp(.apiDeleteToken(token: token)) } diff --git a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift index 4e7f826f4f..d9473bad4a 100644 --- a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift +++ b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift @@ -13,7 +13,7 @@ struct NotificationsView: View { @EnvironmentObject var m: ChatModel @EnvironmentObject var theme: AppTheme @State private var notificationMode: NotificationsMode = ChatModel.shared.notificationMode - @State private var showAlert: NotificationAlert? + @State private var ntfAlert: NotificationAlert? @State private var legacyDatabase = dbContainerGroupDefault.get() == .documents @State private var testing = false @State private var testedSuccess: Bool? = nil @@ -25,7 +25,7 @@ struct NotificationsView: View { ProgressView().scaleEffect(2) } } - .alert(item: $showAlert) { alert in + .alert(item: $ntfAlert) { alert in if let token = m.deviceToken { return notificationAlert(alert, token) } else { @@ -41,7 +41,7 @@ struct NotificationsView: View { List { Section { SelectionListView(list: NotificationsMode.values, selection: $notificationMode) { mode in - showAlert = .setMode(mode: mode) + ntfAlert = .setMode(mode: mode) } } footer: { VStack(alignment: .leading) { @@ -163,7 +163,7 @@ struct NotificationsView: View { await MainActor.run { let err = responseError(error) logger.error("apiDeleteToken error: \(err)") - showAlert = .error(title: "Error deleting token", error: err) + ntfAlert = .error(title: "Error deleting token", error: err) } } default: @@ -181,7 +181,7 @@ struct NotificationsView: View { await MainActor.run { let err = responseError(error) logger.error("apiRegisterToken error: \(err)") - showAlert = .error(title: "Error enabling notifications", error: err) + ntfAlert = .error(title: "Error enabling notifications", error: err) } } } @@ -193,7 +193,7 @@ struct NotificationsView: View { Button("Test server") { testing = true Task { - await testServer(server) + await testServerAndToken(server) await MainActor.run { testing = false } } } @@ -215,17 +215,39 @@ struct NotificationsView: View { } } - private func testServer(_ server: String) async { + private func testServerAndToken(_ server: String) async { do { let r = try await testProtoServer(server: server) switch r { case .success: - await MainActor.run { - testedSuccess = true + if let token = m.deviceToken { + do { + let status = try await apiCheckToken(token: token) + await MainActor.run { + m.tokenStatus = status + if [.invalid, .expired].contains(status) { + testedSuccess = false + } else { + testedSuccess = true + } + showAlert( + NSLocalizedString("Token status", comment: "alert title"), + message: status.rawValue + ) + } + } catch let error { + logger.error("apiCheckToken \(responseError(error))") + } + } else { + await MainActor.run { + showAlert( + NSLocalizedString("No token!", comment: "alert title") + ) + } } case let .failure(f): await MainActor.run { - showAlert = .testFailure(testFailure: f) + ntfAlert = .testFailure(testFailure: f) testedSuccess = false } } diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 3a5f9ec995..4c26b0cf00 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -62,6 +62,7 @@ public enum ChatCommand { case apiGetNtfToken case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) case apiVerifyToken(token: DeviceToken, nonce: String, code: String) + case apiCheckToken(token: DeviceToken) case apiDeleteToken(token: DeviceToken) case apiGetNtfConns(nonce: String, encNtfInfo: String) case apiGetConnNtfMessages(connIds: [String]) @@ -238,6 +239,7 @@ public enum ChatCommand { 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 .apiCheckToken(token): return "/_ntf check \(token.cmdString)" case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)" case let .apiGetNtfConns(nonce, encNtfInfo): return "/_ntf conns \(nonce) \(encNtfInfo)" case let .apiGetConnNtfMessages(connIds): return "/_ntf conn messages \(connIds.joined(separator: ","))" @@ -409,6 +411,7 @@ public enum ChatCommand { case .apiGetNtfToken: return "apiGetNtfToken" case .apiRegisterToken: return "apiRegisterToken" case .apiVerifyToken: return "apiVerifyToken" + case .apiCheckToken: return "apiCheckToken" case .apiDeleteToken: return "apiDeleteToken" case .apiGetNtfConns: return "apiGetNtfConns" case .apiGetConnNtfMessages: return "apiGetConnNtfMessages"