ios: connect with contact via address (for preset simplex contact) (#3323)
* ios: connect with contact via address (for preset simplex contact) * remove diff * remove floating button * refactor active * open chat * remove disabled * fix incognito --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
parent
96d94d3438
commit
f49ded5ae5
@ -194,7 +194,7 @@ final class ChatModel: ObservableObject {
|
|||||||
|
|
||||||
func updateContactConnectionStats(_ contact: Contact, _ connectionStats: ConnectionStats) {
|
func updateContactConnectionStats(_ contact: Contact, _ connectionStats: ConnectionStats) {
|
||||||
var updatedConn = contact.activeConn
|
var updatedConn = contact.activeConn
|
||||||
updatedConn.connectionStats = connectionStats
|
updatedConn?.connectionStats = connectionStats
|
||||||
var updatedContact = contact
|
var updatedContact = contact
|
||||||
updatedContact.activeConn = updatedConn
|
updatedContact.activeConn = updatedConn
|
||||||
updateContact(updatedContact)
|
updateContact(updatedContact)
|
||||||
@ -671,11 +671,17 @@ final class ChatModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setContactNetworkStatus(_ contact: Contact, _ status: NetworkStatus) {
|
func setContactNetworkStatus(_ contact: Contact, _ status: NetworkStatus) {
|
||||||
networkStatuses[contact.activeConn.agentConnId] = status
|
if let conn = contact.activeConn {
|
||||||
|
networkStatuses[conn.agentConnId] = status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func contactNetworkStatus(_ contact: Contact) -> NetworkStatus {
|
func contactNetworkStatus(_ contact: Contact) -> NetworkStatus {
|
||||||
networkStatuses[contact.activeConn.agentConnId] ?? .unknown
|
if let conn = contact.activeConn {
|
||||||
|
networkStatuses[conn.agentConnId] ?? .unknown
|
||||||
|
} else {
|
||||||
|
.unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,6 +675,18 @@ private func connectionErrorAlert(_ r: ChatResponse) -> Alert {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiConnectContactViaAddress(incognito: Bool, contactId: Int64) async -> (Contact?, Alert?) {
|
||||||
|
guard let userId = ChatModel.shared.currentUser?.userId else {
|
||||||
|
logger.error("apiConnectContactViaAddress: no current user")
|
||||||
|
return (nil, nil)
|
||||||
|
}
|
||||||
|
let r = await chatSendCmd(.apiConnectContactViaAddress(userId: userId, incognito: incognito, contactId: contactId))
|
||||||
|
if case let .sentInvitationToContact(_, contact, _) = r { return (contact, nil) }
|
||||||
|
logger.error("apiConnectContactViaAddress error: \(responseError(r))")
|
||||||
|
let alert = connectionErrorAlert(r)
|
||||||
|
return (nil, alert)
|
||||||
|
}
|
||||||
|
|
||||||
func apiDeleteChat(type: ChatType, id: Int64, notify: Bool? = nil) async throws {
|
func apiDeleteChat(type: ChatType, id: Int64, notify: Bool? = nil) async throws {
|
||||||
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, notify: notify), bgTask: false)
|
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, notify: notify), bgTask: false)
|
||||||
if case .direct = type, case .contactDeleted = r { return }
|
if case .direct = type, case .contactDeleted = r { return }
|
||||||
@ -1326,8 +1338,10 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
|||||||
if active(user) && contact.directOrUsed {
|
if active(user) && contact.directOrUsed {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
m.updateContact(contact)
|
m.updateContact(contact)
|
||||||
m.dismissConnReqView(contact.activeConn.id)
|
if let conn = contact.activeConn {
|
||||||
m.removeChat(contact.activeConn.id)
|
m.dismissConnReqView(conn.id)
|
||||||
|
m.removeChat(conn.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if contact.directOrUsed {
|
if contact.directOrUsed {
|
||||||
@ -1340,8 +1354,10 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
|||||||
if active(user) && contact.directOrUsed {
|
if active(user) && contact.directOrUsed {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
m.updateContact(contact)
|
m.updateContact(contact)
|
||||||
m.dismissConnReqView(contact.activeConn.id)
|
if let conn = contact.activeConn {
|
||||||
m.removeChat(contact.activeConn.id)
|
m.dismissConnReqView(conn.id)
|
||||||
|
m.removeChat(conn.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .receivedContactRequest(user, contactRequest):
|
case let .receivedContactRequest(user, contactRequest):
|
||||||
@ -1480,9 +1496,9 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
|||||||
|
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
m.updateGroup(groupInfo)
|
m.updateGroup(groupInfo)
|
||||||
if let hostContact = hostContact {
|
if let conn = hostContact?.activeConn {
|
||||||
m.dismissConnReqView(hostContact.activeConn.id)
|
m.dismissConnReqView(conn.id)
|
||||||
m.removeChat(hostContact.activeConn.id)
|
m.removeChat(conn.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .groupLinkConnecting(user, groupInfo, hostMember):
|
case let .groupLinkConnecting(user, groupInfo, hostMember):
|
||||||
|
@ -338,7 +338,7 @@ struct ChatInfoView: View {
|
|||||||
verify: { code in
|
verify: { code in
|
||||||
if let r = apiVerifyContact(chat.chatInfo.apiId, connectionCode: code) {
|
if let r = apiVerifyContact(chat.chatInfo.apiId, connectionCode: code) {
|
||||||
let (verified, existingCode) = r
|
let (verified, existingCode) = r
|
||||||
contact.activeConn.connectionCode = verified ? SecurityCode(securityCode: existingCode, verifiedAt: .now) : nil
|
contact.activeConn?.connectionCode = verified ? SecurityCode(securityCode: existingCode, verifiedAt: .now) : nil
|
||||||
connectionCode = existingCode
|
connectionCode = existingCode
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
chat.chatInfo = .direct(contact: contact)
|
chat.chatInfo = .direct(contact: contact)
|
||||||
|
@ -66,7 +66,7 @@ struct CIRcvDecryptionError: View {
|
|||||||
|
|
||||||
@ViewBuilder private func viewBody() -> some View {
|
@ViewBuilder private func viewBody() -> some View {
|
||||||
if case let .direct(contact) = chat.chatInfo,
|
if case let .direct(contact) = chat.chatInfo,
|
||||||
let contactStats = contact.activeConn.connectionStats {
|
let contactStats = contact.activeConn?.connectionStats {
|
||||||
if contactStats.ratchetSyncAllowed {
|
if contactStats.ratchetSyncAllowed {
|
||||||
decryptionErrorItemFixButton(syncSupported: true) {
|
decryptionErrorItemFixButton(syncSupported: true) {
|
||||||
alert = .syncAllowedAlert { syncContactConnection(contact) }
|
alert = .syncAllowedAlert { syncContactConnection(contact) }
|
||||||
|
@ -114,7 +114,7 @@ struct ChatView: View {
|
|||||||
connectionStats = stats
|
connectionStats = stats
|
||||||
customUserProfile = profile
|
customUserProfile = profile
|
||||||
connectionCode = code
|
connectionCode = code
|
||||||
if contact.activeConn.connectionCode != ct.activeConn.connectionCode {
|
if contact.activeConn?.connectionCode != ct.activeConn?.connectionCode {
|
||||||
chat.chatInfo = .direct(contact: ct)
|
chat.chatInfo = .direct(contact: ct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ struct ChatListNavLink: View {
|
|||||||
@State private var showContactConnectionInfo = false
|
@State private var showContactConnectionInfo = false
|
||||||
@State private var showInvalidJSON = false
|
@State private var showInvalidJSON = false
|
||||||
@State private var showDeleteContactActionSheet = false
|
@State private var showDeleteContactActionSheet = false
|
||||||
|
@State private var showConnectContactViaAddressDialog = false
|
||||||
@State private var inProgress = false
|
@State private var inProgress = false
|
||||||
@State private var progressByTimeout = false
|
@State private var progressByTimeout = false
|
||||||
|
|
||||||
@ -63,6 +64,24 @@ struct ChatListNavLink: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder private func contactNavLink(_ contact: Contact) -> some View {
|
@ViewBuilder private func contactNavLink(_ contact: Contact) -> some View {
|
||||||
|
Group {
|
||||||
|
if contact.activeConn == nil && contact.profile.contactLink != nil {
|
||||||
|
ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false))
|
||||||
|
.frame(height: rowHeights[dynamicTypeSize])
|
||||||
|
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||||
|
Button {
|
||||||
|
showDeleteContactActionSheet = true
|
||||||
|
} label: {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
}
|
||||||
|
.tint(.red)
|
||||||
|
}
|
||||||
|
.onTapGesture { showConnectContactViaAddressDialog = true }
|
||||||
|
.confirmationDialog("Connect with \(contact.chatViewName)", isPresented: $showConnectContactViaAddressDialog, titleVisibility: .visible) {
|
||||||
|
Button("Use current profile") { connectContactViaAddress_(contact, false) }
|
||||||
|
Button("Use new incognito profile") { connectContactViaAddress_(contact, true) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
NavLinkPlain(
|
NavLinkPlain(
|
||||||
tag: chat.chatInfo.id,
|
tag: chat.chatInfo.id,
|
||||||
selection: $chatModel.chatId,
|
selection: $chatModel.chatId,
|
||||||
@ -89,6 +108,8 @@ struct ChatListNavLink: View {
|
|||||||
.tint(.red)
|
.tint(.red)
|
||||||
}
|
}
|
||||||
.frame(height: rowHeights[dynamicTypeSize])
|
.frame(height: rowHeights[dynamicTypeSize])
|
||||||
|
}
|
||||||
|
}
|
||||||
.actionSheet(isPresented: $showDeleteContactActionSheet) {
|
.actionSheet(isPresented: $showDeleteContactActionSheet) {
|
||||||
if contact.ready && contact.active {
|
if contact.ready && contact.active {
|
||||||
return ActionSheet(
|
return ActionSheet(
|
||||||
@ -411,6 +432,17 @@ struct ChatListNavLink: View {
|
|||||||
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
|
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func connectContactViaAddress_(_ contact: Contact, _ incognito: Bool) {
|
||||||
|
Task {
|
||||||
|
let ok = await connectContactViaAddress(contact.contactId, incognito)
|
||||||
|
if ok {
|
||||||
|
await MainActor.run {
|
||||||
|
chatModel.chatId = contact.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection, showError: @escaping (ErrorAlert) -> Void, success: @escaping () -> Void = {}) -> Alert {
|
func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection, showError: @escaping (ErrorAlert) -> Void, success: @escaping () -> Void = {}) -> Alert {
|
||||||
@ -439,6 +471,21 @@ func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func connectContactViaAddress(_ contactId: Int64, _ incognito: Bool) async -> Bool {
|
||||||
|
let (contact, alert) = await apiConnectContactViaAddress(incognito: incognito, contactId: contactId)
|
||||||
|
if let alert = alert {
|
||||||
|
AlertManager.shared.showAlert(alert)
|
||||||
|
return false
|
||||||
|
} else if let contact = contact {
|
||||||
|
await MainActor.run {
|
||||||
|
ChatModel.shared.updateContact(contact)
|
||||||
|
AlertManager.shared.showAlert(connReqSentAlert(.contact))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
|
func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
|
||||||
Task {
|
Task {
|
||||||
logger.debug("joinGroup")
|
logger.debug("joinGroup")
|
||||||
|
@ -177,13 +177,6 @@ struct ChatListView: View {
|
|||||||
showAddChat = true
|
showAddChat = true
|
||||||
}
|
}
|
||||||
|
|
||||||
connectButton("or chat with the developers") {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
UIApplication.shared.open(simplexTeamURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.top, 10)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("You have no chats")
|
Text("You have no chats")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
@ -190,7 +190,10 @@ struct ChatPreviewView: View {
|
|||||||
} else {
|
} else {
|
||||||
switch (chat.chatInfo) {
|
switch (chat.chatInfo) {
|
||||||
case let .direct(contact):
|
case let .direct(contact):
|
||||||
if !contact.ready {
|
if contact.activeConn == nil && contact.profile.contactLink != nil {
|
||||||
|
chatPreviewInfoText("Tap to Connect")
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
} else if !contact.ready && contact.activeConn != nil {
|
||||||
if contact.nextSendGrpInv {
|
if contact.nextSendGrpInv {
|
||||||
chatPreviewInfoText("send direct message")
|
chatPreviewInfoText("send direct message")
|
||||||
} else if contact.active {
|
} else if contact.active {
|
||||||
@ -238,7 +241,7 @@ struct ChatPreviewView: View {
|
|||||||
@ViewBuilder private func chatStatusImage() -> some View {
|
@ViewBuilder private func chatStatusImage() -> some View {
|
||||||
switch chat.chatInfo {
|
switch chat.chatInfo {
|
||||||
case let .direct(contact):
|
case let .direct(contact):
|
||||||
if contact.active {
|
if contact.active && contact.activeConn != nil {
|
||||||
switch (chatModel.contactNetworkStatus(contact)) {
|
switch (chatModel.contactNetworkStatus(contact)) {
|
||||||
case .connected: incognitoIcon(chat.chatInfo.incognito)
|
case .connected: incognitoIcon(chat.chatInfo.incognito)
|
||||||
case .error:
|
case .error:
|
||||||
|
@ -155,12 +155,14 @@ func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool) -> Alert {
|
|||||||
enum PlanAndConnectActionSheet: Identifiable {
|
enum PlanAndConnectActionSheet: Identifiable {
|
||||||
case askCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan?, title: LocalizedStringKey)
|
case askCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan?, title: LocalizedStringKey)
|
||||||
case askCurrentOrIncognitoProfileDestructive(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey)
|
case askCurrentOrIncognitoProfileDestructive(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey)
|
||||||
|
case askCurrentOrIncognitoProfileConnectContactViaAddress(contact: Contact)
|
||||||
case ownGroupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo)
|
case ownGroupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo)
|
||||||
|
|
||||||
var id: String {
|
var id: String {
|
||||||
switch self {
|
switch self {
|
||||||
case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink)"
|
case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink)"
|
||||||
case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink)"
|
case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink)"
|
||||||
|
case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): return "askCurrentOrIncognitoProfileConnectContactViaAddress \(contact.contactId)"
|
||||||
case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink)"
|
case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,6 +188,15 @@ func planAndConnectActionSheet(_ sheet: PlanAndConnectActionSheet, dismiss: Bool
|
|||||||
.cancel()
|
.cancel()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact):
|
||||||
|
return ActionSheet(
|
||||||
|
title: Text("Connect with \(contact.chatViewName)"),
|
||||||
|
buttons: [
|
||||||
|
.default(Text("Use current profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: false) },
|
||||||
|
.default(Text("Use new incognito profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: true) },
|
||||||
|
.cancel()
|
||||||
|
]
|
||||||
|
)
|
||||||
case let .ownGroupLinkConfirmConnect(connectionLink, connectionPlan, incognito, groupInfo):
|
case let .ownGroupLinkConfirmConnect(connectionLink, connectionPlan, incognito, groupInfo):
|
||||||
if let incognito = incognito {
|
if let incognito = incognito {
|
||||||
return ActionSheet(
|
return ActionSheet(
|
||||||
@ -277,6 +288,13 @@ func planAndConnect(
|
|||||||
case let .known(contact):
|
case let .known(contact):
|
||||||
logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")")
|
logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")")
|
||||||
openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) }
|
openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) }
|
||||||
|
case let .contactViaAddress(contact):
|
||||||
|
logger.debug("planAndConnect, .contactAddress, .contactViaAddress, incognito=\(incognito?.description ?? "nil")")
|
||||||
|
if let incognito = incognito {
|
||||||
|
connectContactViaAddress_(contact, dismiss: dismiss, incognito: incognito)
|
||||||
|
} else {
|
||||||
|
showActionSheet(.askCurrentOrIncognitoProfileConnectContactViaAddress(contact: contact))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case let .groupLink(glp):
|
case let .groupLink(glp):
|
||||||
switch glp {
|
switch glp {
|
||||||
@ -315,6 +333,17 @@ func planAndConnect(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func connectContactViaAddress_(_ contact: Contact, dismiss: Bool, incognito: Bool) {
|
||||||
|
Task {
|
||||||
|
if dismiss {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
dismissAllSheets(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = await connectContactViaAddress(contact.contactId, incognito)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func connectViaLink(_ connectionLink: String, connectionPlan: ConnectionPlan?, dismiss: Bool, incognito: Bool) {
|
private func connectViaLink(_ connectionLink: String, connectionPlan: ConnectionPlan?, dismiss: Bool, incognito: Bool) {
|
||||||
Task {
|
Task {
|
||||||
if let connReqType = await apiConnect(incognito: incognito, connReq: connectionLink) {
|
if let connReqType = await apiConnect(incognito: incognito, connReq: connectionLink) {
|
||||||
|
@ -90,6 +90,7 @@ public enum ChatCommand {
|
|||||||
case apiSetConnectionIncognito(connId: Int64, incognito: Bool)
|
case apiSetConnectionIncognito(connId: Int64, incognito: Bool)
|
||||||
case apiConnectPlan(userId: Int64, connReq: String)
|
case apiConnectPlan(userId: Int64, connReq: String)
|
||||||
case apiConnect(userId: Int64, incognito: Bool, connReq: String)
|
case apiConnect(userId: Int64, incognito: Bool, connReq: String)
|
||||||
|
case apiConnectContactViaAddress(userId: Int64, incognito: Bool, contactId: Int64)
|
||||||
case apiDeleteChat(type: ChatType, id: Int64, notify: Bool?)
|
case apiDeleteChat(type: ChatType, id: Int64, notify: Bool?)
|
||||||
case apiClearChat(type: ChatType, id: Int64)
|
case apiClearChat(type: ChatType, id: Int64)
|
||||||
case apiListContacts(userId: Int64)
|
case apiListContacts(userId: Int64)
|
||||||
@ -226,6 +227,7 @@ public enum ChatCommand {
|
|||||||
case let .apiSetConnectionIncognito(connId, incognito): return "/_set incognito :\(connId) \(onOff(incognito))"
|
case let .apiSetConnectionIncognito(connId, incognito): return "/_set incognito :\(connId) \(onOff(incognito))"
|
||||||
case let .apiConnectPlan(userId, connReq): return "/_connect plan \(userId) \(connReq)"
|
case let .apiConnectPlan(userId, connReq): return "/_connect plan \(userId) \(connReq)"
|
||||||
case let .apiConnect(userId, incognito, connReq): return "/_connect \(userId) incognito=\(onOff(incognito)) \(connReq)"
|
case let .apiConnect(userId, incognito, connReq): return "/_connect \(userId) incognito=\(onOff(incognito)) \(connReq)"
|
||||||
|
case let .apiConnectContactViaAddress(userId, incognito, contactId): return "/_connect contact \(userId) incognito=\(onOff(incognito)) \(contactId)"
|
||||||
case let .apiDeleteChat(type, id, notify): if let notify = notify {
|
case let .apiDeleteChat(type, id, notify): if let notify = notify {
|
||||||
return "/_delete \(ref(type, id)) notify=\(onOff(notify))"
|
return "/_delete \(ref(type, id)) notify=\(onOff(notify))"
|
||||||
} else {
|
} else {
|
||||||
@ -297,6 +299,7 @@ public enum ChatCommand {
|
|||||||
case .apiSendMessage: return "apiSendMessage"
|
case .apiSendMessage: return "apiSendMessage"
|
||||||
case .apiUpdateChatItem: return "apiUpdateChatItem"
|
case .apiUpdateChatItem: return "apiUpdateChatItem"
|
||||||
case .apiDeleteChatItem: return "apiDeleteChatItem"
|
case .apiDeleteChatItem: return "apiDeleteChatItem"
|
||||||
|
case .apiConnectContactViaAddress: return "apiConnectContactViaAddress"
|
||||||
case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem"
|
case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem"
|
||||||
case .apiChatItemReaction: return "apiChatItemReaction"
|
case .apiChatItemReaction: return "apiChatItemReaction"
|
||||||
case .apiGetNtfToken: return "apiGetNtfToken"
|
case .apiGetNtfToken: return "apiGetNtfToken"
|
||||||
@ -478,6 +481,7 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case connectionPlan(user: UserRef, connectionPlan: ConnectionPlan)
|
case connectionPlan(user: UserRef, connectionPlan: ConnectionPlan)
|
||||||
case sentConfirmation(user: UserRef)
|
case sentConfirmation(user: UserRef)
|
||||||
case sentInvitation(user: UserRef)
|
case sentInvitation(user: UserRef)
|
||||||
|
case sentInvitationToContact(user: UserRef, contact: Contact, customUserProfile: Profile?)
|
||||||
case contactAlreadyExists(user: UserRef, contact: Contact)
|
case contactAlreadyExists(user: UserRef, contact: Contact)
|
||||||
case contactRequestAlreadyAccepted(user: UserRef, contact: Contact)
|
case contactRequestAlreadyAccepted(user: UserRef, contact: Contact)
|
||||||
case contactDeleted(user: UserRef, contact: Contact)
|
case contactDeleted(user: UserRef, contact: Contact)
|
||||||
@ -622,6 +626,7 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case .connectionPlan: return "connectionPlan"
|
case .connectionPlan: return "connectionPlan"
|
||||||
case .sentConfirmation: return "sentConfirmation"
|
case .sentConfirmation: return "sentConfirmation"
|
||||||
case .sentInvitation: return "sentInvitation"
|
case .sentInvitation: return "sentInvitation"
|
||||||
|
case .sentInvitationToContact: return "sentInvitationToContact"
|
||||||
case .contactAlreadyExists: return "contactAlreadyExists"
|
case .contactAlreadyExists: return "contactAlreadyExists"
|
||||||
case .contactRequestAlreadyAccepted: return "contactRequestAlreadyAccepted"
|
case .contactRequestAlreadyAccepted: return "contactRequestAlreadyAccepted"
|
||||||
case .contactDeleted: return "contactDeleted"
|
case .contactDeleted: return "contactDeleted"
|
||||||
@ -763,6 +768,7 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case let .connectionPlan(u, connectionPlan): return withUser(u, String(describing: connectionPlan))
|
case let .connectionPlan(u, connectionPlan): return withUser(u, String(describing: connectionPlan))
|
||||||
case .sentConfirmation: return noDetails
|
case .sentConfirmation: return noDetails
|
||||||
case .sentInvitation: return noDetails
|
case .sentInvitation: return noDetails
|
||||||
|
case let .sentInvitationToContact(u, contact, _): return withUser(u, String(describing: contact))
|
||||||
case let .contactAlreadyExists(u, contact): return withUser(u, String(describing: contact))
|
case let .contactAlreadyExists(u, contact): return withUser(u, String(describing: contact))
|
||||||
case let .contactRequestAlreadyAccepted(u, contact): return withUser(u, String(describing: contact))
|
case let .contactRequestAlreadyAccepted(u, contact): return withUser(u, String(describing: contact))
|
||||||
case let .contactDeleted(u, contact): return withUser(u, String(describing: contact))
|
case let .contactDeleted(u, contact): return withUser(u, String(describing: contact))
|
||||||
@ -902,6 +908,7 @@ public enum ContactAddressPlan: Decodable {
|
|||||||
case connectingConfirmReconnect
|
case connectingConfirmReconnect
|
||||||
case connectingProhibit(contact: Contact)
|
case connectingProhibit(contact: Contact)
|
||||||
case known(contact: Contact)
|
case known(contact: Contact)
|
||||||
|
case contactViaAddress(contact: Contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GroupLinkPlan: Decodable {
|
public enum GroupLinkPlan: Decodable {
|
||||||
|
@ -1370,7 +1370,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
|||||||
public var contactId: Int64
|
public var contactId: Int64
|
||||||
var localDisplayName: ContactName
|
var localDisplayName: ContactName
|
||||||
public var profile: LocalProfile
|
public var profile: LocalProfile
|
||||||
public var activeConn: Connection
|
public var activeConn: Connection?
|
||||||
public var viaGroup: Int64?
|
public var viaGroup: Int64?
|
||||||
public var contactUsed: Bool
|
public var contactUsed: Bool
|
||||||
public var contactStatus: ContactStatus
|
public var contactStatus: ContactStatus
|
||||||
@ -1384,10 +1384,10 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
|||||||
|
|
||||||
public var id: ChatId { get { "@\(contactId)" } }
|
public var id: ChatId { get { "@\(contactId)" } }
|
||||||
public var apiId: Int64 { get { contactId } }
|
public var apiId: Int64 { get { contactId } }
|
||||||
public var ready: Bool { get { activeConn.connStatus == .ready } }
|
public var ready: Bool { get { activeConn?.connStatus == .ready } }
|
||||||
public var active: Bool { get { contactStatus == .active } }
|
public var active: Bool { get { contactStatus == .active } }
|
||||||
public var sendMsgEnabled: Bool { get {
|
public var sendMsgEnabled: Bool { get {
|
||||||
(ready && active && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?? false))
|
(ready && active && !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?? false))
|
||||||
|| nextSendGrpInv
|
|| nextSendGrpInv
|
||||||
} }
|
} }
|
||||||
public var nextSendGrpInv: Bool { get { contactGroupMemberId != nil && !contactGrpInvSent } }
|
public var nextSendGrpInv: Bool { get { contactGroupMemberId != nil && !contactGrpInvSent } }
|
||||||
@ -1396,14 +1396,18 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
|||||||
public var image: String? { get { profile.image } }
|
public var image: String? { get { profile.image } }
|
||||||
public var contactLink: String? { get { profile.contactLink } }
|
public var contactLink: String? { get { profile.contactLink } }
|
||||||
public var localAlias: String { profile.localAlias }
|
public var localAlias: String { profile.localAlias }
|
||||||
public var verified: Bool { activeConn.connectionCode != nil }
|
public var verified: Bool { activeConn?.connectionCode != nil }
|
||||||
|
|
||||||
public var directOrUsed: Bool {
|
public var directOrUsed: Bool {
|
||||||
|
if let activeConn = activeConn {
|
||||||
(activeConn.connLevel == 0 && !activeConn.viaGroupLink) || contactUsed
|
(activeConn.connLevel == 0 && !activeConn.viaGroupLink) || contactUsed
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var contactConnIncognito: Bool {
|
public var contactConnIncognito: Bool {
|
||||||
activeConn.customUserProfileId != nil
|
activeConn?.customUserProfileId != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func allowsFeature(_ feature: ChatFeature) -> Bool {
|
public func allowsFeature(_ feature: ChatFeature) -> Bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user