279 lines
9.2 KiB
Swift
279 lines
9.2 KiB
Swift
import Foundation
|
||
|
||
struct PrivateChatListData: Decodable {
|
||
let items: [PrivateChatListItem]
|
||
let hasMore: Bool
|
||
}
|
||
|
||
struct PrivateChatHistoryData: Decodable {
|
||
let items: [MessageItem]
|
||
let hasMore: Bool
|
||
}
|
||
|
||
struct PrivateMessageSendData: Decodable {
|
||
let messageId: String
|
||
let chatId: String
|
||
let createdAt: Date?
|
||
|
||
private enum CodingKeys: String, CodingKey {
|
||
case messageId
|
||
case chatId
|
||
case createdAt
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.messageId = try container.decodeFlexibleString(forKey: .messageId)
|
||
self.chatId = try container.decodeFlexibleString(forKey: .chatId)
|
||
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
|
||
}
|
||
}
|
||
|
||
struct PrivateChatListItem: Decodable, Identifiable {
|
||
enum ChatType: String, Decodable {
|
||
case `self`
|
||
case privateChat = "private"
|
||
case unknown
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.singleValueContainer()
|
||
let rawValue = try container.decode(String.self)
|
||
self = ChatType(rawValue: rawValue) ?? .unknown
|
||
}
|
||
}
|
||
|
||
let chatId: String
|
||
let chatType: ChatType
|
||
let chatData: ChatProfile?
|
||
let lastMessage: MessageItem?
|
||
let createdAt: Date?
|
||
let unreadCount: Int
|
||
|
||
var id: String { chatId }
|
||
}
|
||
|
||
struct MessageItem: Decodable, Identifiable {
|
||
let messageId: String
|
||
let messageType: String
|
||
let chatId: String
|
||
let senderId: String
|
||
let senderData: ChatProfile?
|
||
let content: String?
|
||
let mediaLink: String?
|
||
let isViewed: Bool?
|
||
let createdAt: Date?
|
||
let updatedAt: Date?
|
||
let forwardMetadata: ForwardMetadata?
|
||
|
||
var id: String { messageId }
|
||
|
||
private enum CodingKeys: String, CodingKey {
|
||
case messageId
|
||
case messageType
|
||
case chatId
|
||
case senderId
|
||
case senderData
|
||
case content
|
||
case mediaLink
|
||
case isViewed
|
||
case createdAt
|
||
case updatedAt
|
||
case forwardMetadata
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.messageId = try container.decodeFlexibleString(forKey: .messageId)
|
||
self.messageType = try container.decodeFlexibleStringOrArray(forKey: .messageType)
|
||
self.chatId = try container.decodeFlexibleString(forKey: .chatId)
|
||
self.senderId = try container.decodeFlexibleString(forKey: .senderId)
|
||
self.senderData = try container.decodeIfPresent(ChatProfile.self, forKey: .senderData)
|
||
self.content = try container.decodeIfPresent(String.self, forKey: .content)
|
||
self.mediaLink = try container.decodeIfPresent(String.self, forKey: .mediaLink)
|
||
self.isViewed = try container.decodeIfPresent(Bool.self, forKey: .isViewed)
|
||
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
|
||
self.updatedAt = try container.decodeIfPresent(Date.self, forKey: .updatedAt)
|
||
self.forwardMetadata = try container.decodeIfPresent(ForwardMetadata.self, forKey: .forwardMetadata)
|
||
}
|
||
|
||
init(
|
||
messageId: String,
|
||
messageType: String,
|
||
chatId: String,
|
||
senderId: String,
|
||
senderData: ChatProfile?,
|
||
content: String?,
|
||
mediaLink: String?,
|
||
isViewed: Bool?,
|
||
createdAt: Date?,
|
||
updatedAt: Date?,
|
||
forwardMetadata: ForwardMetadata?
|
||
) {
|
||
self.messageId = messageId
|
||
self.messageType = messageType
|
||
self.chatId = chatId
|
||
self.senderId = senderId
|
||
self.senderData = senderData
|
||
self.content = content
|
||
self.mediaLink = mediaLink
|
||
self.isViewed = isViewed
|
||
self.createdAt = createdAt
|
||
self.updatedAt = updatedAt
|
||
self.forwardMetadata = forwardMetadata
|
||
}
|
||
}
|
||
|
||
struct ForwardMetadata: Decodable {
|
||
let forwardType: String?
|
||
let forwardSenderId: String?
|
||
let forwardMessageId: String?
|
||
let forwardChatData: ChatProfile?
|
||
|
||
private enum CodingKeys: String, CodingKey {
|
||
case forwardType
|
||
case forwardSenderId
|
||
case forwardMessageId
|
||
case forwardChatData
|
||
}
|
||
}
|
||
|
||
struct ChatProfile: Decodable {
|
||
let userId: String
|
||
let login: String?
|
||
let fullName: String?
|
||
let customName: String?
|
||
let bio: String?
|
||
let lastSeen: Int?
|
||
let createdAt: Date?
|
||
let stories: [JSONValue]
|
||
let permissions: ChatPermissions?
|
||
let profilePermissions: ChatProfilePermissions?
|
||
let relationship: RelationshipStatus?
|
||
|
||
private enum CodingKeys: String, CodingKey {
|
||
case userId
|
||
case login
|
||
case fullName
|
||
case customName
|
||
case bio
|
||
case lastSeen
|
||
case createdAt
|
||
case stories
|
||
case permissions
|
||
case profilePermissions
|
||
case relationship
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.userId = try container.decodeFlexibleString(forKey: .userId)
|
||
self.login = try container.decodeIfPresent(String.self, forKey: .login)
|
||
self.fullName = try container.decodeIfPresent(String.self, forKey: .fullName)
|
||
self.customName = try container.decodeIfPresent(String.self, forKey: .customName)
|
||
self.bio = try container.decodeIfPresent(String.self, forKey: .bio)
|
||
self.lastSeen = try container.decodeIfPresent(Int.self, forKey: .lastSeen)
|
||
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
|
||
self.stories = try container.decodeIfPresent([JSONValue].self, forKey: .stories) ?? []
|
||
self.permissions = try container.decodeIfPresent(ChatPermissions.self, forKey: .permissions)
|
||
self.profilePermissions = try container.decodeIfPresent(ChatProfilePermissions.self, forKey: .profilePermissions)
|
||
self.relationship = try container.decodeIfPresent(RelationshipStatus.self, forKey: .relationship)
|
||
}
|
||
}
|
||
|
||
struct ChatPermissions: Decodable {
|
||
let youCanSendMessage: Bool
|
||
let youCanPublicInvitePermission: Bool
|
||
let youCanGroupInvitePermission: Bool
|
||
let youCanCallPermission: Bool
|
||
}
|
||
|
||
struct ChatProfilePermissions: Decodable {
|
||
let isSearchable: Bool?
|
||
let allowMessageForwarding: Bool
|
||
let allowMessagesFromNonContacts: Bool
|
||
let allowServerChats: Bool
|
||
let forceAutoDeleteMessagesInPrivate: Bool
|
||
let maxMessageAutoDeleteSeconds: Int?
|
||
}
|
||
|
||
struct RelationshipStatus: Decodable {
|
||
let isCurrentUserInContactsOfTarget: Bool
|
||
let isTargetUserBlockedByCurrentUser: Bool
|
||
let isCurrentUserInBlacklistOfTarget: Bool
|
||
}
|
||
|
||
enum JSONValue: Decodable {
|
||
case string(String)
|
||
case int(Int)
|
||
case double(Double)
|
||
case bool(Bool)
|
||
case array([JSONValue])
|
||
case object([String: JSONValue])
|
||
case null
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.singleValueContainer()
|
||
if container.decodeNil() {
|
||
self = .null
|
||
return
|
||
}
|
||
if let value = try? container.decode(Bool.self) {
|
||
self = .bool(value)
|
||
return
|
||
}
|
||
if let value = try? container.decode(Int.self) {
|
||
self = .int(value)
|
||
return
|
||
}
|
||
if let value = try? container.decode(Double.self) {
|
||
self = .double(value)
|
||
return
|
||
}
|
||
if let value = try? container.decode(String.self) {
|
||
self = .string(value)
|
||
return
|
||
}
|
||
if let value = try? container.decode([JSONValue].self) {
|
||
self = .array(value)
|
||
return
|
||
}
|
||
if let value = try? container.decode([String: JSONValue].self) {
|
||
self = .object(value)
|
||
return
|
||
}
|
||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Не удалось декодировать значение JSONValue")
|
||
}
|
||
}
|
||
|
||
private extension KeyedDecodingContainer {
|
||
func decodeFlexibleString(forKey key: Key) throws -> String {
|
||
if let string = try? decode(String.self, forKey: key) {
|
||
return string
|
||
}
|
||
if let int = try? decode(Int.self, forKey: key) {
|
||
return String(int)
|
||
}
|
||
if let double = try? decode(Double.self, forKey: key) {
|
||
return String(double)
|
||
}
|
||
throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: codingPath + [key], debugDescription: "Expected to decode String or number for key \(key.stringValue)"))
|
||
}
|
||
|
||
func decodeFlexibleStringOrArray(forKey key: Key) throws -> String {
|
||
if let string = try? decode(String.self, forKey: key) {
|
||
return string
|
||
}
|
||
if let stringArray = try? decode([String].self, forKey: key), let first = stringArray.first {
|
||
return first
|
||
}
|
||
if let intArray = try? decode([Int].self, forKey: key), let first = intArray.first {
|
||
return String(first)
|
||
}
|
||
if let doubleArray = try? decode([Double].self, forKey: key), let first = doubleArray.first {
|
||
return String(first)
|
||
}
|
||
|
||
throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: codingPath + [key], debugDescription: "Expected to decode String or array for key \(key.stringValue)"))
|
||
}
|
||
}
|