diff --git a/apps/ios/Shared/Model/AppAPITypes.swift b/apps/ios/Shared/Model/AppAPITypes.swift index 85b0b9a1dc..0aa653ab2e 100644 --- a/apps/ios/Shared/Model/AppAPITypes.swift +++ b/apps/ios/Shared/Model/AppAPITypes.swift @@ -158,7 +158,6 @@ enum ChatCommand: ChatCmdProtocol { case apiGetCallInvitations case apiCallStatus(contact: Contact, callStatus: WebRTCCallStatus) // WebRTC calls / - case apiGetNetworkStatuses case apiChatRead(type: ChatType, id: Int64, scope: GroupChatScope?) case apiChatItemsRead(type: ChatType, id: Int64, scope: GroupChatScope?, itemIds: [Int64]) case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool) @@ -359,7 +358,6 @@ enum ChatCommand: ChatCmdProtocol { case let .apiEndCall(contact): return "/_call end @\(contact.apiId)" case .apiGetCallInvitations: return "/_call get" case let .apiCallStatus(contact, callStatus): return "/_call status @\(contact.apiId) \(callStatus.rawValue)" - case .apiGetNetworkStatuses: return "/_network_statuses" case let .apiChatRead(type, id, scope): return "/_read chat \(ref(type, id, scope: scope))" case let .apiChatItemsRead(type, id, scope, itemIds): return "/_read chat items \(ref(type, id, scope: scope)) \(joinedIds(itemIds))" case let .apiChatUnread(type, id, unreadChat): return "/_unread chat \(ref(type, id, scope: nil)) \(onOff(unreadChat))" @@ -534,7 +532,6 @@ enum ChatCommand: ChatCmdProtocol { case .apiEndCall: return "apiEndCall" case .apiGetCallInvitations: return "apiGetCallInvitations" case .apiCallStatus: return "apiCallStatus" - case .apiGetNetworkStatuses: return "apiGetNetworkStatuses" case .apiChatRead: return "apiChatRead" case .apiChatItemsRead: return "apiChatItemsRead" case .apiChatUnread: return "apiChatUnread" @@ -793,7 +790,6 @@ enum ChatResponse1: Decodable, ChatAPIResult { case userContactLinkDeleted(user: User) case acceptingContactRequest(user: UserRef, contact: Contact) case contactRequestRejected(user: UserRef, contactRequest: UserContactRequest, contact_: Contact?) - case networkStatuses(user_: UserRef?, networkStatuses: [ConnNetworkStatus]) case newChatItems(user: UserRef, chatItems: [AChatItem]) case groupChatItemsDeleted(user: UserRef, groupInfo: GroupInfo, chatItemIDs: Set, byUser: Bool, member_: GroupMember?) case forwardPlan(user: UserRef, chatItemIds: [Int64], forwardConfirmation: ForwardConfirmation?) @@ -837,7 +833,6 @@ enum ChatResponse1: Decodable, ChatAPIResult { case .userContactLinkDeleted: "userContactLinkDeleted" case .acceptingContactRequest: "acceptingContactRequest" case .contactRequestRejected: "contactRequestRejected" - case .networkStatuses: "networkStatuses" case .newChatItems: "newChatItems" case .groupChatItemsDeleted: "groupChatItemsDeleted" case .forwardPlan: "forwardPlan" @@ -870,7 +865,6 @@ enum ChatResponse1: Decodable, ChatAPIResult { case .userContactLinkDeleted: return noDetails case let .acceptingContactRequest(u, contact): return withUser(u, String(describing: contact)) case let .contactRequestRejected(u, contactRequest, contact_): return withUser(u, "contactRequest: \(String(describing: contactRequest))\ncontact_: \(String(describing: contact_))") - case let .networkStatuses(u, statuses): return withUser(u, String(describing: statuses)) case let .newChatItems(u, chatItems): let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n") return withUser(u, itemsString) @@ -1060,7 +1054,6 @@ enum ChatEvent: Decodable, ChatAPIResult { case contactUpdated(user: UserRef, toContact: Contact) case groupMemberUpdated(user: UserRef, groupInfo: GroupInfo, fromMember: GroupMember, toMember: GroupMember) case networkStatus(networkStatus: NetworkStatus, connections: [String]) - case networkStatuses(user_: UserRef?, networkStatuses: [ConnNetworkStatus]) case chatInfoUpdated(user: UserRef, chatInfo: ChatInfo) case newChatItems(user: UserRef, chatItems: [AChatItem]) case chatItemsStatusesUpdated(user: UserRef, chatItems: [AChatItem]) @@ -1138,7 +1131,6 @@ enum ChatEvent: Decodable, ChatAPIResult { case .contactUpdated: "contactUpdated" case .groupMemberUpdated: "groupMemberUpdated" case .networkStatus: "networkStatus" - case .networkStatuses: "networkStatuses" case .chatInfoUpdated: "chatInfoUpdated" case .newChatItems: "newChatItems" case .chatItemsStatusesUpdated: "chatItemsStatusesUpdated" @@ -1211,7 +1203,6 @@ enum ChatEvent: Decodable, ChatAPIResult { case let .contactUpdated(u, toContact): return withUser(u, String(describing: toContact)) case let .groupMemberUpdated(u, groupInfo, fromMember, toMember): return withUser(u, "groupInfo: \(groupInfo)\nfromMember: \(fromMember)\ntoMember: \(toMember)") case let .networkStatus(status, conns): return "networkStatus: \(String(describing: status))\nconnections: \(String(describing: conns))" - case let .networkStatuses(u, statuses): return withUser(u, String(describing: statuses)) case let .chatInfoUpdated(u, chatInfo): return withUser(u, String(describing: chatInfo)) case let .newChatItems(u, chatItems): let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n") @@ -1410,11 +1401,6 @@ enum ForwardConfirmation: Decodable, Hashable { case filesFailed(filesCount: Int) } -struct ConnNetworkStatus: Decodable { - var agentConnId: String - var networkStatus: NetworkStatus -} - struct UserMsgReceiptSettings: Codable { var enable: Bool var clearOverrides: Bool diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index e5fd6362a3..032e8e67d6 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -283,29 +283,6 @@ class ChatTagsModel: ObservableObject { } } -class NetworkModel: ObservableObject { - // map of connections network statuses, key is agent connection id - @Published var networkStatuses: Dictionary = [:] - - static let shared = NetworkModel() - - private init() { } - - func setContactNetworkStatus(_ contact: Contact, _ status: NetworkStatus) { - if let conn = contact.activeConn { - networkStatuses[conn.agentConnId] = status - } - } - - func contactNetworkStatus(_ contact: Contact) -> NetworkStatus { - if let conn = contact.activeConn { - networkStatuses[conn.agentConnId] ?? .unknown - } else { - .unknown - } - } -} - /// ChatItemWithMenu can depend on previous or next item for it's appearance /// This dummy model is used to force an update of all chat items, /// when they might have changed appearance. diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index c7e382f3ed..84b952915d 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -15,8 +15,6 @@ import SwiftUI private var chatController: chat_ctrl? -private let networkStatusesLock = DispatchQueue(label: "chat.simplex.app.network-statuses.lock") - enum TerminalItem: Identifiable { case cmd(Date, ChatCommand) case res(Date, ChatAPIResult) @@ -1640,7 +1638,8 @@ func acceptContactRequest(incognito: Bool, contactRequestId: Int64, inProgress: } else { ChatModel.shared.replaceChat(contactRequestChatId(contactRequestId), chat) } - NetworkModel.shared.setContactNetworkStatus(contact, .connected) + // TODO [sub status] review + // NetworkModel.shared.setContactNetworkStatus(contact, .connected) inProgress?.wrappedValue = false } if contact.sndReady { @@ -1728,12 +1727,6 @@ func apiCallStatus(_ contact: Contact, _ status: String) async throws { } } -func apiGetNetworkStatuses() throws -> [ConnNetworkStatus] { - let r: ChatResponse1 = try chatSendCmdSync(.apiGetNetworkStatuses) - if case let .networkStatuses(_, statuses) = r { return statuses } - throw r.unexpected -} - func markChatRead(_ im: ItemsModel, _ chat: Chat) async { do { if chat.chatStats.unreadCount > 0 { @@ -1955,7 +1948,8 @@ func acceptMemberContact(contactId: Int64, inProgress: Binding? = nil) asy if let contact = await apiAcceptMemberContact(contactId: contactId) { await MainActor.run { ChatModel.shared.updateContact(contact) - NetworkModel.shared.setContactNetworkStatus(contact, .connected) + // TODO [sub status] review + // NetworkModel.shared.setContactNetworkStatus(contact, .connected) inProgress?.wrappedValue = false } if contact.sndReady { @@ -2241,7 +2235,6 @@ class ChatReceiver { func processReceivedMsg(_ res: ChatEvent) async { let m = ChatModel.shared - let n = NetworkModel.shared logger.debug("processReceivedMsg: \(res.responseType)") switch res { case let .contactDeletedByContact(user, contact): @@ -2263,9 +2256,10 @@ func processReceivedMsg(_ res: ChatEvent) async { if contact.directOrUsed { NtfManager.shared.notifyContactConnected(user, contact) } - await MainActor.run { - n.setContactNetworkStatus(contact, .connected) - } + // TODO [sub status] review + // await MainActor.run { + // n.setContactNetworkStatus(contact, .connected) + // } case let .contactConnecting(user, contact): if active(user) && contact.directOrUsed { await MainActor.run { @@ -2286,9 +2280,10 @@ func processReceivedMsg(_ res: ChatEvent) async { } } } - await MainActor.run { - n.setContactNetworkStatus(contact, .connected) - } + // TODO [sub status] review + // await MainActor.run { + // n.setContactNetworkStatus(contact, .connected) + // } case let .receivedContactRequest(user, contactRequest, chat_): if active(user) { await MainActor.run { @@ -2328,31 +2323,8 @@ func processReceivedMsg(_ res: ChatEvent) async { } } case let .networkStatus(status, connections): - // dispatch queue to synchronize access - networkStatusesLock.sync { - var ns = n.networkStatuses - // slow loop is on the background thread - for cId in connections { - ns[cId] = status - } - // fast model update is on the main thread - DispatchQueue.main.sync { - n.networkStatuses = ns - } - } - case let .networkStatuses(_, statuses): () - // dispatch queue to synchronize access - networkStatusesLock.sync { - var ns = n.networkStatuses - // slow loop is on the background thread - for s in statuses { - ns[s.agentConnId] = s.networkStatus - } - // fast model update is on the main thread - DispatchQueue.main.sync { - n.networkStatuses = ns - } - } + // TODO [sub status] update status for current chat in model if id matches + return case let .chatInfoUpdated(user, chatInfo): if active(user) { await MainActor.run { @@ -2554,11 +2526,12 @@ func processReceivedMsg(_ res: ChatEvent) async { _ = m.upsertGroupMember(groupInfo, member) } } - if let contact = memberContact { - await MainActor.run { - n.setContactNetworkStatus(contact, .connected) - } - } + // TODO [sub status] review + // if let contact = memberContact { + // await MainActor.run { + // n.setContactNetworkStatus(contact, .connected) + // } + // } case let .groupUpdated(user, toGroup): if active(user) { await MainActor.run { @@ -2784,13 +2757,10 @@ func processReceivedMsg(_ res: ChatEvent) async { func switchToLocalSession() { let m = ChatModel.shared - let n = NetworkModel.shared m.remoteCtrlSession = nil do { m.users = try listUsers() try getUserChatData() - let statuses = (try apiGetNetworkStatuses()).map { s in (s.agentConnId, s.networkStatus) } - n.networkStatuses = Dictionary(uniqueKeysWithValues: statuses) } catch let error { logger.debug("error updating chat data: \(responseError(error))") } diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift index 77c1db341a..37255e652a 100644 --- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift @@ -92,7 +92,6 @@ struct ChatInfoView: View { @EnvironmentObject var chatModel: ChatModel @EnvironmentObject var theme: AppTheme @Environment(\.dismiss) var dismiss: DismissAction - @ObservedObject var networkModel = NetworkModel.shared @ObservedObject var chat: Chat @State var contact: Contact @State var localAlias: String @@ -553,14 +552,17 @@ struct ChatInfoView: View { .foregroundColor(theme.colors.primary) .font(.system(size: 14)) Spacer() - Text(networkModel.contactNetworkStatus(contact).statusString) + // TODO [sub status] use status from model + // Text(networkModel.contactNetworkStatus(contact).statusString) + Text(NetworkStatus.connected.statusString) .foregroundColor(theme.colors.secondary) serverImage() } } private func serverImage() -> some View { - let status = networkModel.contactNetworkStatus(contact) + // TODO [sub status] use status from model + let status = NetworkStatus.connected // networkModel.contactNetworkStatus(contact) return Image(systemName: status.imageName) .foregroundColor(status == .connected ? .green : theme.colors.secondary) .font(.system(size: 12)) @@ -608,7 +610,8 @@ struct ChatInfoView: View { private func networkStatusAlert() -> Alert { Alert( title: Text("Network status"), - message: Text(networkModel.contactNetworkStatus(contact).statusExplanation) + // TODO [sub status] use status from model + message: Text("") // Text(networkModel.contactNetworkStatus(contact).statusExplanation) ) } diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 683dea0f56..0919932ee9 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -788,7 +788,8 @@ struct ComposeView: View { await MainActor.run { self.chatModel.updateContact(contact) clearState() - NetworkModel.shared.setContactNetworkStatus(contact, .connected) + // TODO [sub status] review + // NetworkModel.shared.setContactNetworkStatus(contact, .connected) } } else { AlertManager.shared.showAlertMsg(title: "Empty message!") @@ -827,7 +828,8 @@ struct ComposeView: View { if let contact = await apiConnectPreparedContact(contactId: chat.chatInfo.apiId, incognito: incognito, msg: mc) { await MainActor.run { self.chatModel.updateContact(contact) - NetworkModel.shared.setContactNetworkStatus(contact, .connected) + // TODO [sub status] review + // NetworkModel.shared.setContactNetworkStatus(contact, .connected) clearState() } } else { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift index 2298af614e..f48bf5a446 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift @@ -396,7 +396,8 @@ struct GroupMemberInfoView: View { ItemsModel.shared.loadOpenChat(memberContact.id) { dismissAllSheets(animated: true) } - NetworkModel.shared.setContactNetworkStatus(memberContact, .connected) + // TODO [sub status] review + // NetworkModel.shared.setContactNetworkStatus(memberContact, .connected) } } catch let error { logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))") diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index c56d947a5a..be2c456802 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -460,12 +460,6 @@ struct ChatPreviewView: View { @ViewBuilder private func chatStatusImage() -> some View { let size = dynamicSize(userFont).incognitoSize switch chat.chatInfo { - case let .direct(contact): - if contact.active, let status = contact.activeConn?.connStatus, status == .ready || status == .sndReady { - NetworkStatusView(contact: contact, size: size) - } else { - incognitoIcon(chat.chatInfo.incognito, theme.colors.secondary, size: size) - } case .group: if progressByTimeout { ProgressView() @@ -482,30 +476,6 @@ struct ChatPreviewView: View { incognitoIcon(chat.chatInfo.incognito, theme.colors.secondary, size: size) } } - - struct NetworkStatusView: View { - @Environment(\.dynamicTypeSize) private var userFont: DynamicTypeSize - @EnvironmentObject var theme: AppTheme - @ObservedObject var networkModel = NetworkModel.shared - - let contact: Contact - let size: CGFloat - - var body: some View { - let dynamicChatInfoSize = dynamicSize(userFont).chatInfoSize - switch (networkModel.contactNetworkStatus(contact)) { - case .connected: incognitoIcon(contact.contactConnIncognito, theme.colors.secondary, size: size) - case .error: - Image(systemName: "exclamationmark.circle") - .resizable() - .scaledToFit() - .frame(width: dynamicChatInfoSize, height: dynamicChatInfoSize) - .foregroundColor(theme.colors.secondary) - default: - ProgressView() - } - } - } } @ViewBuilder func incognitoIcon(_ incognito: Bool, _ secondaryColor: Color, size: CGFloat) -> some View { diff --git a/tests/JSONFixtures.hs b/tests/JSONFixtures.hs index 0110c21fae..f02d04491e 100644 --- a/tests/JSONFixtures.hs +++ b/tests/JSONFixtures.hs @@ -28,12 +28,6 @@ chatStartedSwift = "{\"result\":{\"_owsf\":true,\"chatStarted\":{}}}" chatStartedTagged :: LB.ByteString chatStartedTagged = "{\"result\":{\"type\":\"chatStarted\"}}" -networkStatusesSwift :: LB.ByteString -networkStatusesSwift = "{\"result\":{\"_owsf\":true,\"networkStatuses\":{\"user_\":" <> userJSON <> ",\"networkStatuses\":[]}}}" - -networkStatusesTagged :: LB.ByteString -networkStatusesTagged = "{\"result\":{\"type\":\"networkStatuses\",\"user_\":" <> userJSON <> ",\"networkStatuses\":[]}}" - userJSON :: LB.ByteString userJSON = "{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"\",\"shortDescr\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"files\":{\"allow\":\"always\"},\"calls\":{\"allow\":\"yes\"},\"sessions\":{\"allow\":\"no\"},\"commands\":[]},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true,\"autoAcceptMemberContacts\":false}" diff --git a/tests/JSONTests.hs b/tests/JSONTests.hs index 33b601f6db..ed4d591547 100644 --- a/tests/JSONTests.hs +++ b/tests/JSONTests.hs @@ -25,7 +25,6 @@ owsf2TaggedJSONTest = do activeUserExistsSwift `to` activeUserExistsTagged activeUserSwift `to` activeUserTagged chatStartedSwift `to` chatStartedTagged - networkStatusesSwift `to` networkStatusesTagged parsedMarkdownSwift `to` parsedMarkdownTagged where to :: LB.ByteString -> LB.ByteString -> IO ()