From 9864533dae3bafa36c90ec3b8c23fd1e622324e7 Mon Sep 17 00:00:00 2001 From: JRoberts <8711996+jr-simplex@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:40:26 +0400 Subject: [PATCH] ios: update chat info view (#844) --- apps/ios/Shared/Model/ChatModel.swift | 6 +- apps/ios/Shared/Views/Chat/ChatInfoView.swift | 163 ++++++++++++++---- .../Chat/Group/GroupMemberInfoView.swift | 19 +- .../Shared/Views/Chat/GroupChatInfoView.swift | 19 -- 4 files changed, 134 insertions(+), 73 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 61acc502db..5cbc708bbc 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -310,9 +310,9 @@ final class Chat: ObservableObject, Identifiable { var statusString: LocalizedStringKey { get { switch self { - case .connected: return "Server connected" - case let .error(err): return "Connecting server… (error: \(err))" - default: return "Connecting server…" + case .connected: return "connected" + case .error: return "error" + default: return "connecting" } } } diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift index 50fc5acabc..49050b1d74 100644 --- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift @@ -9,69 +9,157 @@ import SwiftUI import SimpleXChat +func infoRow(_ title: LocalizedStringKey, _ value: String) -> some View { + HStack { + Text(title) + Spacer() + Text(value) + .foregroundStyle(.secondary) + } +} + +func localizedInfoRow(_ title: LocalizedStringKey, _ value: LocalizedStringKey) -> some View { + HStack { + Text(title) + Spacer() + Text(value) + .foregroundStyle(.secondary) + } +} + +@ViewBuilder func smpServers(_ title: LocalizedStringKey, _ servers: [String]?) -> some View { + if let servers = servers, + servers.count > 0 { + infoRow(title, serverHost(servers[0])) + } +} + +private func serverHost(_ s: String) -> String { + if let i = s.range(of: "@")?.lowerBound { + return String(s[i...].dropFirst()) + } else { + return s + } +} + struct ChatInfoView: View { @EnvironmentObject var chatModel: ChatModel - @ObservedObject var alertManager = AlertManager.shared @ObservedObject var chat: Chat @Binding var showSheet: Bool - @State var alert: ChatInfoViewAlert? = nil + @State private var alert: ChatInfoViewAlert? = nil + @State private var connectionStats: ConnectionStats? enum ChatInfoViewAlert: Identifiable { case deleteContactAlert case clearChatAlert + case networkStatusAlert var id: ChatInfoViewAlert { get { self } } } var body: some View { - VStack { - ChatInfoImage(chat: chat) - .frame(width: 192, height: 192) - .padding(.top, 48) - .padding() - Text(chat.chatInfo.localDisplayName).font(.largeTitle) - .padding(.bottom, 2) - Text(chat.chatInfo.fullName).font(.title) - .padding(.bottom) + NavigationView { + List { + contactInfoHeader() + .listRowBackground(Color.clear) - HStack { - serverImage() - Text(chat.serverInfo.networkStatus.statusString) - .foregroundColor(.primary) - } - Text(chat.serverInfo.networkStatus.statusExplanation) - .font(.subheadline) - .multilineTextAlignment(.center) - .padding(.horizontal, 64) - .padding(.vertical, 8) + if let connStats = connectionStats { + Section("Servers") { + networkStatusRow() + .onTapGesture { + alert = .networkStatusAlert + } + smpServers("Receiving via", connStats.rcvServers) + smpServers("Sending via", connStats.sndServers) + } + } - Spacer() - Button() { - alert = .clearChatAlert - } label: { - Label("Clear conversation", systemImage: "gobackward") + Section { + clearChatButton() + deleteContactButton() + } + + Section(header: Text("For console")) { + infoRow("Local name", chat.chatInfo.localDisplayName) + infoRow("Database ID", "\(chat.chatInfo.apiId)") + } } - .tint(Color.orange) - Button(role: .destructive) { - alert = .deleteContactAlert - } label: { - Label("Delete contact", systemImage: "trash") - } - .padding() + .navigationBarHidden(true) } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) .alert(item: $alert) { alertItem in switch(alertItem) { case .deleteContactAlert: return deleteContactAlert() case .clearChatAlert: return clearChatAlert() + case .networkStatusAlert: return networkStatusAlert() } } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) + .task { + do { + let stats = try await apiContactInfo(contactId: chat.chatInfo.apiId) + await MainActor.run { connectionStats = stats } + } catch let error { + logger.error("apiContactInfo error: \(responseError(error))") + } + } + } + + func contactInfoHeader() -> some View { + VStack { + let cInfo = chat.chatInfo + ChatInfoImage(chat: chat, color: Color(uiColor: .tertiarySystemFill)) + .frame(width: 192, height: 192) + .padding(.top, 12) + .padding() + Text(cInfo.displayName) + .font(.largeTitle) + .lineLimit(1) + .padding(.bottom, 2) + if cInfo.fullName != "" && cInfo.fullName != cInfo.displayName { + Text(cInfo.fullName) + .font(.title2) + .lineLimit(2) + } + } + .frame(maxWidth: .infinity, alignment: .center) + } + + func networkStatusRow() -> some View { + HStack { + Text("Network status") + Image(systemName: "info.circle") + .foregroundColor(.accentColor) + .font(.system(size: 14)) + Spacer() + Text(chat.serverInfo.networkStatus.statusString) + .foregroundColor(.secondary) + serverImage() + } } func serverImage() -> some View { let status = chat.serverInfo.networkStatus return Image(systemName: status.imageName) .foregroundColor(status == .connected ? .green : .secondary) + .font(.system(size: 12)) + } + + func deleteContactButton() -> some View { + Button(role: .destructive) { + alert = .deleteContactAlert + } label: { + Label("Delete contact", systemImage: "trash") + .foregroundColor(Color.red) + } + } + + func clearChatButton() -> some View { + Button() { + alert = .clearChatAlert + } label: { + Label("Clear conversation", systemImage: "gobackward") + .foregroundColor(Color.orange) + } } private func deleteContactAlert() -> Alert { @@ -110,6 +198,13 @@ struct ChatInfoView: View { secondaryButton: .cancel() ) } + + private func networkStatusAlert() -> Alert { + Alert( + title: Text("Network status"), + message: Text(chat.serverInfo.networkStatus.statusExplanation) + ) + } } struct ChatInfoView_Previews: PreviewProvider { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift index 75f1f5794e..62c9bd67f1 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift @@ -43,8 +43,8 @@ struct GroupMemberInfoView: View { if let connStats = connectionStats { Section("Servers") { // TODO network connection status - smpServers("receiving via", connStats.rcvServers) - smpServers("sending via", connStats.sndServers) + smpServers("Receiving via", connStats.rcvServers) + smpServers("Sending via", connStats.sndServers) } } @@ -96,21 +96,6 @@ struct GroupMemberInfoView: View { .frame(maxWidth: .infinity, alignment: .center) } - @ViewBuilder private func smpServers(_ title: LocalizedStringKey, _ servers: [String]?) -> some View { - if let servers = servers, - servers.count > 0 { - infoRow(title, serverHost(servers[0])) - } - } - - private func serverHost(_ s: String) -> String { - if let i = s.range(of: "@")?.lowerBound { - return String(s[i...].dropFirst()) - } else { - return s - } - } - func removeMemberButton() -> some View { Button(role: .destructive) { alert = .removeMemberAlert diff --git a/apps/ios/Shared/Views/Chat/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/GroupChatInfoView.swift index f11d2506db..0c6ee9c4f4 100644 --- a/apps/ios/Shared/Views/Chat/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/GroupChatInfoView.swift @@ -9,24 +9,6 @@ import SwiftUI import SimpleXChat -func infoRow(_ title: LocalizedStringKey, _ value: String) -> some View { - HStack { - Text(title) - Spacer() - Text(value) - .foregroundStyle(.secondary) - } -} - -func localizedInfoRow(_ title: LocalizedStringKey, _ value: LocalizedStringKey) -> some View { - HStack { - Text(title) - Spacer() - Text(value) - .foregroundStyle(.secondary) - } -} - struct GroupChatInfoView: View { @EnvironmentObject var chatModel: ChatModel @ObservedObject var alertManager = AlertManager.shared @@ -174,7 +156,6 @@ struct GroupChatInfoView: View { Label("Clear conversation", systemImage: "gobackward") .foregroundColor(Color.orange) } - .tint(Color.orange) } func leaveGroupButton() -> some View {