2022-02-05 20:10:47 +00:00
|
|
|
//
|
|
|
|
// ChatInfoView.swift
|
|
|
|
// SimpleX
|
|
|
|
//
|
|
|
|
// Created by Evgeny Poberezkin on 05/02/2022.
|
|
|
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import SwiftUI
|
2022-05-31 07:55:13 +01:00
|
|
|
import SimpleXChat
|
2022-02-05 20:10:47 +00:00
|
|
|
|
2022-07-27 13:40:26 +04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 20:10:47 +00:00
|
|
|
struct ChatInfoView: View {
|
2022-02-07 10:36:11 +00:00
|
|
|
@EnvironmentObject var chatModel: ChatModel
|
2022-02-05 20:10:47 +00:00
|
|
|
@ObservedObject var chat: Chat
|
2022-07-26 12:33:10 +04:00
|
|
|
@Binding var showSheet: Bool
|
2022-07-27 13:40:26 +04:00
|
|
|
@State private var alert: ChatInfoViewAlert? = nil
|
|
|
|
@State private var connectionStats: ConnectionStats?
|
2022-02-05 20:10:47 +00:00
|
|
|
|
2022-05-19 16:56:34 +04:00
|
|
|
enum ChatInfoViewAlert: Identifiable {
|
|
|
|
case deleteContactAlert
|
|
|
|
case clearChatAlert
|
2022-07-27 13:40:26 +04:00
|
|
|
case networkStatusAlert
|
2022-05-19 16:56:34 +04:00
|
|
|
|
|
|
|
var id: ChatInfoViewAlert { get { self } }
|
|
|
|
}
|
|
|
|
|
2022-02-05 20:10:47 +00:00
|
|
|
var body: some View {
|
2022-07-27 13:40:26 +04:00
|
|
|
NavigationView {
|
|
|
|
List {
|
|
|
|
contactInfoHeader()
|
|
|
|
.listRowBackground(Color.clear)
|
2022-02-05 20:10:47 +00:00
|
|
|
|
2022-07-27 13:40:26 +04:00
|
|
|
if let connStats = connectionStats {
|
|
|
|
Section("Servers") {
|
|
|
|
networkStatusRow()
|
|
|
|
.onTapGesture {
|
|
|
|
alert = .networkStatusAlert
|
|
|
|
}
|
|
|
|
smpServers("Receiving via", connStats.rcvServers)
|
|
|
|
smpServers("Sending via", connStats.sndServers)
|
|
|
|
}
|
|
|
|
}
|
2022-02-07 10:36:11 +00:00
|
|
|
|
2022-07-27 13:40:26 +04:00
|
|
|
Section {
|
|
|
|
clearChatButton()
|
|
|
|
deleteContactButton()
|
|
|
|
}
|
|
|
|
|
|
|
|
Section(header: Text("For console")) {
|
|
|
|
infoRow("Local name", chat.chatInfo.localDisplayName)
|
|
|
|
infoRow("Database ID", "\(chat.chatInfo.apiId)")
|
|
|
|
}
|
2022-07-14 16:40:32 +04:00
|
|
|
}
|
2022-07-27 13:40:26 +04:00
|
|
|
.navigationBarHidden(true)
|
2022-07-14 16:40:32 +04:00
|
|
|
}
|
2022-07-27 13:40:26 +04:00
|
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
2022-07-14 16:40:32 +04:00
|
|
|
.alert(item: $alert) { alertItem in
|
|
|
|
switch(alertItem) {
|
2022-07-26 12:33:10 +04:00
|
|
|
case .deleteContactAlert: return deleteContactAlert()
|
2022-07-14 16:40:32 +04:00
|
|
|
case .clearChatAlert: return clearChatAlert()
|
2022-07-27 13:40:26 +04:00
|
|
|
case .networkStatusAlert: return networkStatusAlert()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.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))")
|
2022-05-19 16:56:34 +04:00
|
|
|
}
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
2022-07-27 13:40:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func serverImage() -> some View {
|
|
|
|
let status = chat.serverInfo.networkStatus
|
|
|
|
return Image(systemName: status.imageName)
|
|
|
|
.foregroundColor(status == .connected ? .green : .secondary)
|
2022-07-27 13:40:26 +04:00
|
|
|
.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)
|
|
|
|
}
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
2022-02-07 10:36:11 +00:00
|
|
|
|
2022-07-26 12:33:10 +04:00
|
|
|
private func deleteContactAlert() -> Alert {
|
2022-02-07 10:36:11 +00:00
|
|
|
Alert(
|
|
|
|
title: Text("Delete contact?"),
|
2022-04-16 09:37:01 +01:00
|
|
|
message: Text("Contact and all messages will be deleted - this cannot be undone!"),
|
2022-02-07 10:36:11 +00:00
|
|
|
primaryButton: .destructive(Text("Delete")) {
|
2022-02-24 17:16:41 +00:00
|
|
|
Task {
|
|
|
|
do {
|
2022-07-26 12:33:10 +04:00
|
|
|
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId)
|
|
|
|
await MainActor.run {
|
|
|
|
chatModel.removeChat(chat.chatInfo.id)
|
|
|
|
showSheet = false
|
2022-02-24 17:16:41 +00:00
|
|
|
}
|
|
|
|
} catch let error {
|
2022-07-26 12:33:10 +04:00
|
|
|
logger.error("deleteContactAlert apiDeleteChat error: \(error.localizedDescription)")
|
2022-02-24 17:16:41 +00:00
|
|
|
}
|
2022-02-07 10:36:11 +00:00
|
|
|
}
|
2022-02-12 15:59:43 +00:00
|
|
|
},
|
|
|
|
secondaryButton: .cancel()
|
2022-02-07 10:36:11 +00:00
|
|
|
)
|
|
|
|
}
|
2022-05-19 16:56:34 +04:00
|
|
|
|
|
|
|
private func clearChatAlert() -> Alert {
|
|
|
|
Alert(
|
|
|
|
title: Text("Clear conversation?"),
|
|
|
|
message: Text("All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you."),
|
|
|
|
primaryButton: .destructive(Text("Clear")) {
|
|
|
|
Task {
|
|
|
|
await clearChat(chat)
|
2022-07-26 12:33:10 +04:00
|
|
|
await MainActor.run {
|
|
|
|
showSheet = false
|
2022-05-19 16:56:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
secondaryButton: .cancel()
|
|
|
|
)
|
|
|
|
}
|
2022-07-27 13:40:26 +04:00
|
|
|
|
|
|
|
private func networkStatusAlert() -> Alert {
|
|
|
|
Alert(
|
|
|
|
title: Text("Network status"),
|
|
|
|
message: Text(chat.serverInfo.networkStatus.statusExplanation)
|
|
|
|
)
|
|
|
|
}
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ChatInfoView_Previews: PreviewProvider {
|
|
|
|
static var previews: some View {
|
2022-07-26 12:33:10 +04:00
|
|
|
@State var showSheet = true
|
|
|
|
return ChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []), showSheet: $showSheet)
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
|
|
|
}
|