2022-01-24 16:07:17 +00:00
|
|
|
//
|
|
|
|
// ChatModel.swift
|
|
|
|
// SimpleX
|
|
|
|
//
|
|
|
|
// Created by Evgeny Poberezkin on 22/01/2022.
|
|
|
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import Combine
|
2022-01-31 21:28:07 +00:00
|
|
|
import SwiftUI
|
2022-01-24 16:07:17 +00:00
|
|
|
|
|
|
|
final class ChatModel: ObservableObject {
|
|
|
|
@Published var currentUser: User?
|
2022-02-02 12:51:39 +00:00
|
|
|
// list of chat "previews"
|
|
|
|
@Published var chats: [Chat] = []
|
|
|
|
// current chat
|
|
|
|
@Published var chatId: String?
|
2022-01-29 11:10:04 +00:00
|
|
|
@Published var chatItems: [ChatItem] = []
|
2022-02-02 12:51:39 +00:00
|
|
|
// items in the terminal view
|
2022-01-29 23:37:02 +00:00
|
|
|
@Published var terminalItems: [TerminalItem] = []
|
2022-02-01 17:34:06 +00:00
|
|
|
@Published var userAddress: String?
|
2022-02-01 20:30:33 +00:00
|
|
|
@Published var appOpenUrl: URL?
|
|
|
|
@Published var connectViaUrl = false
|
2022-02-09 22:53:06 +00:00
|
|
|
static let shared = ChatModel()
|
2022-02-02 12:51:39 +00:00
|
|
|
|
|
|
|
func hasChat(_ id: String) -> Bool {
|
|
|
|
chats.first(where: { $0.id == id }) != nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getChat(_ id: String) -> Chat? {
|
|
|
|
chats.first(where: { $0.id == id })
|
|
|
|
}
|
|
|
|
|
2022-02-05 20:10:47 +00:00
|
|
|
private func getChatIndex(_ id: String) -> Int? {
|
|
|
|
chats.firstIndex(where: { $0.id == id })
|
|
|
|
}
|
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
func addChat(_ chat: Chat) {
|
2022-02-02 16:46:05 +00:00
|
|
|
withAnimation {
|
|
|
|
chats.insert(chat, at: 0)
|
|
|
|
}
|
2022-02-02 12:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateChatInfo(_ cInfo: ChatInfo) {
|
2022-02-05 20:10:47 +00:00
|
|
|
if let ix = getChatIndex(cInfo.id) {
|
2022-02-02 12:51:39 +00:00
|
|
|
chats[ix].chatInfo = cInfo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 20:10:47 +00:00
|
|
|
func updateContact(_ contact: Contact) {
|
|
|
|
let cInfo = ChatInfo.direct(contact: contact)
|
|
|
|
if hasChat(contact.id) {
|
|
|
|
updateChatInfo(cInfo)
|
|
|
|
} else {
|
|
|
|
addChat(Chat(chatInfo: cInfo, chatItems: []))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateNetworkStatus(_ contact: Contact, _ status: Chat.NetworkStatus) {
|
|
|
|
if let ix = getChatIndex(contact.id) {
|
|
|
|
chats[ix].serverInfo.networkStatus = status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
func replaceChat(_ id: String, _ chat: Chat) {
|
|
|
|
if let ix = chats.firstIndex(where: { $0.id == id }) {
|
|
|
|
chats[ix] = chat
|
|
|
|
} else {
|
|
|
|
// invalid state, correcting
|
|
|
|
chats.insert(chat, at: 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func addChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
|
|
|
|
if let ix = chats.firstIndex(where: { $0.id == cInfo.id }) {
|
|
|
|
chats[ix].chatItems = [cItem]
|
2022-02-05 14:24:23 +00:00
|
|
|
if ix > 0 {
|
|
|
|
if chatId == nil {
|
|
|
|
withAnimation { popChat(ix) }
|
|
|
|
} else {
|
|
|
|
DispatchQueue.main.async { self.popChat(ix) }
|
|
|
|
}
|
2022-02-02 12:51:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if chatId == cInfo.id {
|
2022-02-03 07:16:29 +00:00
|
|
|
withAnimation { chatItems.append(cItem) }
|
2022-02-02 12:51:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 14:24:23 +00:00
|
|
|
private func popChat(_ ix: Int) {
|
|
|
|
let chat = chats.remove(at: ix)
|
|
|
|
chats.insert(chat, at: 0)
|
|
|
|
}
|
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
func removeChat(_ id: String) {
|
2022-02-02 16:46:05 +00:00
|
|
|
withAnimation {
|
|
|
|
chats.removeAll(where: { $0.id == id })
|
|
|
|
}
|
2022-02-02 12:51:39 +00:00
|
|
|
}
|
2022-01-24 16:07:17 +00:00
|
|
|
}
|
|
|
|
|
2022-02-11 07:42:00 +00:00
|
|
|
struct User: Decodable, NamedChat {
|
2022-01-24 16:07:17 +00:00
|
|
|
var userId: Int64
|
|
|
|
var userContactId: Int64
|
|
|
|
var localDisplayName: ContactName
|
|
|
|
var profile: Profile
|
|
|
|
var activeUser: Bool
|
2022-01-31 21:28:07 +00:00
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
// internal init(userId: Int64, userContactId: Int64, localDisplayName: ContactName, profile: Profile, activeUser: Bool) {
|
|
|
|
// self.userId = userId
|
|
|
|
// self.userContactId = userContactId
|
|
|
|
// self.localDisplayName = localDisplayName
|
|
|
|
// self.profile = profile
|
|
|
|
// self.activeUser = activeUser
|
|
|
|
// }
|
2022-01-24 16:07:17 +00:00
|
|
|
|
2022-02-11 07:42:00 +00:00
|
|
|
var displayName: String { get { profile.displayName } }
|
|
|
|
|
|
|
|
var fullName: String { get { profile.fullName } }
|
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = User(
|
|
|
|
userId: 1,
|
|
|
|
userContactId: 1,
|
|
|
|
localDisplayName: "alice",
|
|
|
|
profile: Profile.sampleData,
|
|
|
|
activeUser: true
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-01-24 16:07:17 +00:00
|
|
|
typealias ContactName = String
|
|
|
|
|
|
|
|
typealias GroupName = String
|
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
struct Profile: Codable, NamedChat {
|
2022-01-24 16:07:17 +00:00
|
|
|
var displayName: String
|
|
|
|
var fullName: String
|
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = Profile(
|
|
|
|
displayName: "alice",
|
|
|
|
fullName: "Alice"
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
|
|
|
enum ChatType: String {
|
2022-01-30 18:27:20 +00:00
|
|
|
case direct = "@"
|
|
|
|
case group = "#"
|
2022-02-01 17:34:06 +00:00
|
|
|
case contactRequest = "<@"
|
2022-01-29 23:37:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
protocol NamedChat {
|
|
|
|
var displayName: String { get }
|
|
|
|
var fullName: String { get }
|
|
|
|
}
|
|
|
|
|
|
|
|
extension NamedChat {
|
|
|
|
var chatViewName: String {
|
|
|
|
get { displayName + (fullName == "" || fullName == displayName ? "" : " / \(fullName)") }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typealias ChatId = String
|
|
|
|
|
|
|
|
enum ChatInfo: Identifiable, Decodable, NamedChat {
|
2022-01-29 11:10:04 +00:00
|
|
|
case direct(contact: Contact)
|
2022-01-30 00:35:20 +04:00
|
|
|
case group(groupInfo: GroupInfo)
|
2022-02-01 17:34:06 +00:00
|
|
|
case contactRequest(contactRequest: UserContactRequest)
|
2022-01-29 11:10:04 +00:00
|
|
|
|
2022-01-30 18:27:20 +00:00
|
|
|
var localDisplayName: String {
|
2022-01-29 11:10:04 +00:00
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-04 22:13:52 +00:00
|
|
|
case let .direct(contact): return contact.localDisplayName
|
|
|
|
case let .group(groupInfo): return groupInfo.localDisplayName
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.localDisplayName
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-04 22:13:52 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
var displayName: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-09 22:53:06 +00:00
|
|
|
case let .direct(contact): return contact.displayName
|
|
|
|
case let .group(groupInfo): return groupInfo.displayName
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.displayName
|
2022-02-08 09:19:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 22:13:52 +00:00
|
|
|
var fullName: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-09 22:53:06 +00:00
|
|
|
case let .direct(contact): return contact.fullName
|
|
|
|
case let .group(groupInfo): return groupInfo.fullName
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.fullName
|
2022-02-04 22:13:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId {
|
2022-01-29 11:10:04 +00:00
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-01 17:34:06 +00:00
|
|
|
case let .direct(contact): return contact.id
|
|
|
|
case let .group(groupInfo): return groupInfo.id
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.id
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
var chatType: ChatType {
|
2022-01-29 11:10:04 +00:00
|
|
|
get {
|
|
|
|
switch self {
|
2022-01-29 23:37:02 +00:00
|
|
|
case .direct: return .direct
|
|
|
|
case .group: return .group
|
2022-02-01 17:34:06 +00:00
|
|
|
case .contactRequest: return .contactRequest
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var apiId: Int64 {
|
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-02 12:51:39 +00:00
|
|
|
case let .direct(contact): return contact.apiId
|
|
|
|
case let .group(groupInfo): return groupInfo.apiId
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.apiId
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-04 22:13:52 +00:00
|
|
|
|
|
|
|
var createdAt: Date {
|
|
|
|
switch self {
|
|
|
|
case let .direct(contact): return contact.createdAt
|
|
|
|
case let .group(groupInfo): return groupInfo.createdAt
|
|
|
|
case let .contactRequest(contactRequest): return contactRequest.createdAt
|
|
|
|
}
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
struct SampleData {
|
|
|
|
var direct: ChatInfo
|
|
|
|
var group: ChatInfo
|
|
|
|
var contactRequest: ChatInfo
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static var sampleData: ChatInfo.SampleData = SampleData(
|
|
|
|
direct: ChatInfo.direct(contact: Contact.sampleData),
|
|
|
|
group: ChatInfo.group(groupInfo: GroupInfo.sampleData),
|
|
|
|
contactRequest: ChatInfo.contactRequest(contactRequest: UserContactRequest.sampleData)
|
|
|
|
)
|
|
|
|
}
|
2022-02-01 17:34:06 +00:00
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
final class Chat: ObservableObject, Identifiable {
|
|
|
|
@Published var chatInfo: ChatInfo
|
|
|
|
@Published var chatItems: [ChatItem]
|
2022-02-05 20:10:47 +00:00
|
|
|
@Published var serverInfo = ServerInfo(networkStatus: .unknown)
|
|
|
|
|
|
|
|
struct ServerInfo: Decodable {
|
|
|
|
var networkStatus: NetworkStatus
|
|
|
|
}
|
|
|
|
|
|
|
|
enum NetworkStatus: Decodable, Equatable {
|
|
|
|
case unknown
|
|
|
|
case connected
|
|
|
|
case disconnected
|
|
|
|
case error(String)
|
|
|
|
|
|
|
|
var statusString: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-07 10:36:11 +00:00
|
|
|
case .connected: return "Server connected"
|
|
|
|
case let .error(err): return "Connecting server… (error: \(err))"
|
|
|
|
default: return "Connecting server…"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var statusExplanation: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
|
|
|
case .connected: return "You are connected to the server you use to receve messages from this contact."
|
|
|
|
case let .error(err): return "Trying to connect to the server you use to receve messages from this contact (error: \(err))."
|
|
|
|
default: return "Trying to connect to the server you use to receve messages from this contact."
|
2022-02-05 20:10:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var imageName: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
|
|
|
case .unknown: return "circle.dotted"
|
|
|
|
case .connected: return "circle.fill"
|
|
|
|
case .disconnected: return "ellipsis.circle.fill"
|
|
|
|
case .error: return "exclamationmark.circle.fill"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-02 12:51:39 +00:00
|
|
|
|
|
|
|
init(_ cData: ChatData) {
|
|
|
|
self.chatInfo = cData.chatInfo
|
|
|
|
self.chatItems = cData.chatItems
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
init(chatInfo: ChatInfo, chatItems: [ChatItem] = []) {
|
2022-01-29 23:37:02 +00:00
|
|
|
self.chatInfo = chatInfo
|
|
|
|
self.chatItems = chatItems
|
|
|
|
}
|
2022-01-31 21:28:07 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId { get { chatInfo.id } }
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-02-02 12:51:39 +00:00
|
|
|
struct ChatData: Decodable, Identifiable {
|
|
|
|
var chatInfo: ChatInfo
|
|
|
|
var chatItems: [ChatItem]
|
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId { get { chatInfo.id } }
|
2022-02-02 12:51:39 +00:00
|
|
|
}
|
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
struct Contact: Identifiable, Decodable, NamedChat {
|
2022-01-24 16:07:17 +00:00
|
|
|
var contactId: Int64
|
|
|
|
var localDisplayName: ContactName
|
|
|
|
var profile: Profile
|
2022-02-01 17:34:06 +00:00
|
|
|
var activeConn: Connection
|
2022-01-24 16:07:17 +00:00
|
|
|
var viaGroup: Int64?
|
2022-02-04 22:13:52 +00:00
|
|
|
var createdAt: Date
|
2022-02-05 20:10:47 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId { get { "@\(contactId)" } }
|
2022-02-02 12:51:39 +00:00
|
|
|
var apiId: Int64 { get { contactId } }
|
2022-02-05 20:10:47 +00:00
|
|
|
var ready: Bool { get { activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready" } }
|
2022-02-09 22:53:06 +00:00
|
|
|
var displayName: String { get { profile.displayName } }
|
|
|
|
var fullName: String { get { profile.fullName } }
|
2022-01-24 16:07:17 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = Contact(
|
|
|
|
contactId: 1,
|
|
|
|
localDisplayName: "alice",
|
|
|
|
profile: Profile.sampleData,
|
|
|
|
activeConn: Connection.sampleData,
|
|
|
|
createdAt: .now
|
|
|
|
)
|
|
|
|
}
|
2022-02-01 17:34:06 +00:00
|
|
|
|
|
|
|
struct Connection: Decodable {
|
|
|
|
var connStatus: String
|
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = Connection(connStatus: "ready")
|
|
|
|
}
|
2022-02-01 17:34:06 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
struct UserContactRequest: Decodable, NamedChat {
|
2022-02-01 17:34:06 +00:00
|
|
|
var contactRequestId: Int64
|
|
|
|
var localDisplayName: ContactName
|
|
|
|
var profile: Profile
|
2022-02-04 22:13:52 +00:00
|
|
|
var createdAt: Date
|
2022-02-01 17:34:06 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId { get { "<@\(contactRequestId)" } }
|
2022-02-02 12:51:39 +00:00
|
|
|
var apiId: Int64 { get { contactRequestId } }
|
2022-02-09 22:53:06 +00:00
|
|
|
var displayName: String { get { profile.displayName } }
|
|
|
|
var fullName: String { get { profile.fullName } }
|
2022-02-01 17:34:06 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = UserContactRequest(
|
|
|
|
contactRequestId: 1,
|
|
|
|
localDisplayName: "alice",
|
|
|
|
profile: Profile.sampleData,
|
|
|
|
createdAt: .now
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
struct GroupInfo: Identifiable, Decodable, NamedChat {
|
2022-01-24 16:07:17 +00:00
|
|
|
var groupId: Int64
|
|
|
|
var localDisplayName: GroupName
|
|
|
|
var groupProfile: GroupProfile
|
2022-02-04 22:13:52 +00:00
|
|
|
var createdAt: Date
|
2022-01-29 11:10:04 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
var id: ChatId { get { "#\(groupId)" } }
|
2022-02-02 12:51:39 +00:00
|
|
|
var apiId: Int64 { get { groupId } }
|
2022-02-09 22:53:06 +00:00
|
|
|
var displayName: String { get { groupProfile.displayName } }
|
|
|
|
var fullName: String { get { groupProfile.fullName } }
|
2022-01-24 16:07:17 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = GroupInfo(
|
|
|
|
groupId: 1,
|
|
|
|
localDisplayName: "team",
|
|
|
|
groupProfile: GroupProfile.sampleData,
|
|
|
|
createdAt: .now
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-09 22:53:06 +00:00
|
|
|
struct GroupProfile: Codable, NamedChat {
|
2022-01-24 16:07:17 +00:00
|
|
|
var displayName: String
|
|
|
|
var fullName: String
|
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static let sampleData = GroupProfile(
|
|
|
|
displayName: "team",
|
|
|
|
fullName: "My Team"
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-02-01 17:34:06 +00:00
|
|
|
struct GroupMember: Decodable {
|
2022-02-08 09:19:25 +00:00
|
|
|
var groupMemberId: Int64
|
|
|
|
var memberId: String
|
|
|
|
// var memberRole: GroupMemberRole
|
|
|
|
// var memberCategory: GroupMemberCategory
|
|
|
|
// var memberStatus: GroupMemberStatus
|
|
|
|
// var invitedBy: InvitedBy
|
|
|
|
var localDisplayName: ContactName
|
|
|
|
var memberProfile: Profile
|
|
|
|
var memberContactId: Int64?
|
|
|
|
// var activeConn: Connection?
|
|
|
|
|
|
|
|
static let sampleData = GroupMember(
|
|
|
|
groupMemberId: 1,
|
|
|
|
memberId: "abcd",
|
|
|
|
localDisplayName: "alice",
|
|
|
|
memberProfile: Profile.sampleData,
|
|
|
|
memberContactId: 1
|
|
|
|
)
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
struct AChatItem: Decodable {
|
|
|
|
var chatInfo: ChatInfo
|
|
|
|
var chatItem: ChatItem
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ChatItem: Identifiable, Decodable {
|
2022-01-29 11:10:04 +00:00
|
|
|
var chatDir: CIDirection
|
|
|
|
var meta: CIMeta
|
|
|
|
var content: CIContent
|
|
|
|
|
|
|
|
var id: Int64 { get { meta.itemId } }
|
2022-01-24 16:07:17 +00:00
|
|
|
|
2022-02-08 09:19:25 +00:00
|
|
|
static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String) -> ChatItem {
|
|
|
|
ChatItem(
|
|
|
|
chatDir: dir,
|
|
|
|
meta: CIMeta.getSample(id, ts, text),
|
|
|
|
content: .sndMsgContent(msgContent: .text(text))
|
|
|
|
)
|
|
|
|
}
|
2022-01-31 21:28:07 +00:00
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
enum CIDirection: Decodable {
|
2022-01-29 11:10:04 +00:00
|
|
|
case directSnd
|
|
|
|
case directRcv
|
|
|
|
case groupSnd
|
2022-02-08 09:19:25 +00:00
|
|
|
case groupRcv(groupMember: GroupMember)
|
2022-01-31 21:28:07 +00:00
|
|
|
|
|
|
|
var sent: Bool {
|
|
|
|
get {
|
|
|
|
switch self {
|
|
|
|
case .directSnd: return true
|
|
|
|
case .directRcv: return false
|
|
|
|
case .groupSnd: return true
|
|
|
|
case .groupRcv: return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
struct CIMeta: Decodable {
|
2022-01-29 11:10:04 +00:00
|
|
|
var itemId: Int64
|
|
|
|
var itemTs: Date
|
|
|
|
var itemText: String
|
|
|
|
var createdAt: Date
|
2022-02-08 09:19:25 +00:00
|
|
|
|
|
|
|
static func getSample(_ id: Int64, _ ts: Date, _ text: String) -> CIMeta {
|
|
|
|
CIMeta(
|
|
|
|
itemId: id,
|
|
|
|
itemTs: ts,
|
|
|
|
itemText: text,
|
|
|
|
createdAt: ts
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
|
2022-02-08 11:20:41 +04:00
|
|
|
enum CIStatus: Decodable {
|
|
|
|
case sndNew
|
|
|
|
case sndSent
|
|
|
|
case sndErrorAuth
|
|
|
|
case sndError(agentErrorType: AgentErrorType)
|
|
|
|
case rcvNew
|
|
|
|
case rcvRead
|
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
enum CIContent: Decodable {
|
2022-01-29 11:10:04 +00:00
|
|
|
case sndMsgContent(msgContent: MsgContent)
|
|
|
|
case rcvMsgContent(msgContent: MsgContent)
|
|
|
|
// files etc.
|
|
|
|
|
|
|
|
var text: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
2022-02-03 07:16:29 +00:00
|
|
|
case let .sndMsgContent(mc): return mc.text
|
|
|
|
case let .rcvMsgContent(mc): return mc.text
|
2022-01-29 11:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
enum MsgContent {
|
2022-01-24 16:07:17 +00:00
|
|
|
case text(String)
|
2022-01-29 23:37:02 +00:00
|
|
|
case unknown(type: String, text: String)
|
|
|
|
case invalid(error: String)
|
2022-01-29 11:10:04 +00:00
|
|
|
|
2022-02-03 07:16:29 +00:00
|
|
|
var text: String {
|
2022-01-29 11:10:04 +00:00
|
|
|
get {
|
|
|
|
switch self {
|
2022-01-29 23:37:02 +00:00
|
|
|
case let .text(text): return text
|
|
|
|
case let .unknown(_, text): return text
|
2022-01-29 11:10:04 +00:00
|
|
|
case .invalid: return "invalid"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-29 23:37:02 +00:00
|
|
|
|
2022-01-30 18:27:20 +00:00
|
|
|
var cmdString: String {
|
|
|
|
get {
|
|
|
|
switch self {
|
|
|
|
case let .text(text): return "text \(text)"
|
|
|
|
default: return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-29 23:37:02 +00:00
|
|
|
enum CodingKeys: String, CodingKey {
|
|
|
|
case type
|
|
|
|
case text
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension MsgContent: Decodable {
|
|
|
|
init(from decoder: Decoder) throws {
|
|
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
|
|
do {
|
|
|
|
let type = try container.decode(String.self, forKey: CodingKeys.type)
|
|
|
|
switch type {
|
|
|
|
case "text":
|
|
|
|
let text = try container.decode(String.self, forKey: CodingKeys.text)
|
|
|
|
self = .text(text)
|
|
|
|
default:
|
|
|
|
let text = try? container.decode(String.self, forKey: CodingKeys.text)
|
|
|
|
self = .unknown(type: type, text: text ?? "unknown message format")
|
|
|
|
}
|
|
|
|
} catch {
|
|
|
|
self = .invalid(error: String(describing: error))
|
|
|
|
}
|
|
|
|
}
|
2022-01-24 16:07:17 +00:00
|
|
|
}
|