import Foundation public struct Account: Identifiable, Equatable, Sendable { public var id: String public var displayName: String public var databasePath: URL public init(id: String, displayName: String, databasePath: URL) { self.id = id self.displayName = displayName self.databasePath = databasePath } } public enum AuthState: Equatable, Sendable { case waitTdlibParameters case waitPhoneNumber case waitCode case waitPassword case ready case closed case error(String) } public struct Folder: Identifiable, Equatable, Sendable { public var id: Int32 public var name: String public init(id: Int32, name: String) { self.id = id self.name = name } } public struct Draft: Hashable, Sendable { public var chatId: Int64 public var text: String public init(chatId: Int64, text: String) { self.chatId = chatId self.text = text } } public struct ChatSummary: Identifiable, Hashable, Sendable { public var id: Int64 public var title: String public var username: String? public var lastMessage: String public var unreadCount: Int32 public var unreadMentionCount: Int32 public var isPinned: Bool public var folderIds: [Int32] public var isMuted: Bool public var draft: Draft? public init( id: Int64, title: String, username: String? = nil, lastMessage: String, unreadCount: Int32 = 0, unreadMentionCount: Int32 = 0, isPinned: Bool = false, folderIds: [Int32] = [0], isMuted: Bool = false, draft: Draft? = nil ) { self.id = id self.title = title self.username = username self.lastMessage = lastMessage self.unreadCount = unreadCount self.unreadMentionCount = unreadMentionCount self.isPinned = isPinned self.folderIds = folderIds self.isMuted = isMuted self.draft = draft } } public struct Reaction: Equatable, Sendable { public var emoji: String public var count: Int32 public var isChosen: Bool public init(emoji: String, count: Int32, isChosen: Bool) { self.emoji = emoji self.count = count self.isChosen = isChosen } } public enum MediaDownloadState: Equatable, Sendable { case notDownloaded case downloading case downloaded(path: String) case error(String) } public struct PhotoMedia: Equatable, Sendable { public var fileId: Int32 public var width: Int32 public var height: Int32 public var downloadState: MediaDownloadState public init( fileId: Int32, width: Int32, height: Int32, downloadState: MediaDownloadState = .notDownloaded ) { self.fileId = fileId self.width = width self.height = height self.downloadState = downloadState } } public struct VoiceMedia: Equatable, Sendable { public var fileId: Int32 public var duration: Int32 public var mimeType: String? public var waveform: String? public var downloadState: MediaDownloadState public init( fileId: Int32, duration: Int32, mimeType: String? = nil, waveform: String? = nil, downloadState: MediaDownloadState = .notDownloaded ) { self.fileId = fileId self.duration = duration self.mimeType = mimeType self.waveform = waveform self.downloadState = downloadState } } public enum MessageMedia: Equatable, Sendable { case photo(PhotoMedia) case voice(VoiceMedia) } public struct Message: Identifiable, Equatable, Sendable { public var id: Int64 public var chatId: Int64 public var senderName: String public var text: String public var date: Int32 public var mediaAlbumId: Int64? public var media: MessageMedia? public var isOutgoing: Bool public var isRead: Bool public var editDate: Int32? public var replyText: String? public var forwardSenderName: String? public var reactions: [Reaction] public init( id: Int64, chatId: Int64, senderName: String, text: String, date: Int32 = 0, mediaAlbumId: Int64? = nil, media: MessageMedia? = nil, isOutgoing: Bool, isRead: Bool = true, editDate: Int32? = nil, replyText: String? = nil, forwardSenderName: String? = nil, reactions: [Reaction] = [] ) { self.id = id self.chatId = chatId self.senderName = senderName self.text = text self.date = date self.mediaAlbumId = mediaAlbumId self.media = media self.isOutgoing = isOutgoing self.isRead = isRead self.editDate = editDate self.replyText = replyText self.forwardSenderName = forwardSenderName self.reactions = reactions } } public struct Profile: Equatable, Sendable { public var chatId: Int64 public var title: String public var username: String? public var bio: String? public var isGroup: Bool public var memberCount: Int32? public init( chatId: Int64, title: String, username: String? = nil, bio: String? = nil, isGroup: Bool = false, memberCount: Int32? = nil ) { self.chatId = chatId self.title = title self.username = username self.bio = bio self.isGroup = isGroup self.memberCount = memberCount } } public struct DownloadedFile: Equatable, Sendable { public var fileId: Int32 public var path: String public init(fileId: Int32, path: String) { self.fileId = fileId self.path = path } } public enum SessionEvent: Equatable, Sendable { case authChanged(AuthState) case chatListChanged([ChatSummary]) case folderListChanged([Folder]) case messageAdded(Int64, Message) case messageUpdated(Int64, Message) case messageDeleted(Int64, [Int64]) case reactionChanged(Int64, Int64, [Reaction]) case incomingNotificationCandidate(ChatSummary, Message, String) case networkChanged(NetworkState) case typingChanged(TypingState) case draftChanged(Draft) case profileLoaded(Profile) case mediaDownloadProgress(fileId: Int32, downloadedSize: Int64, totalSize: Int64) } public enum NetworkState: Equatable, Sendable { case waitingForNetwork case connectingToProxy case connecting case updating case ready } public enum TypingState: Equatable, Sendable { case idle case typing(chatId: Int64, userId: Int64, text: String) }