2024-06-07 15:44:12 +04:00

219 lines
7.8 KiB
Swift

import Foundation
import TelegramCore
public func decodeCodableDrawingEntities(data: Data) -> [CodableDrawingEntity] {
if let codableEntities = try? JSONDecoder().decode([CodableDrawingEntity].self, from: data) {
return codableEntities
}
return []
}
public func decodeDrawingEntities(data: Data) -> [DrawingEntity] {
return decodeCodableDrawingEntities(data: data).map { $0.entity }
}
public enum CodableDrawingEntity: Equatable {
public static func == (lhs: CodableDrawingEntity, rhs: CodableDrawingEntity) -> Bool {
return lhs.entity.isEqual(to: rhs.entity)
}
case sticker(DrawingStickerEntity)
case text(DrawingTextEntity)
case simpleShape(DrawingSimpleShapeEntity)
case bubble(DrawingBubbleEntity)
case vector(DrawingVectorEntity)
case location(DrawingLocationEntity)
public init?(entity: DrawingEntity) {
if let entity = entity as? DrawingStickerEntity {
self = .sticker(entity)
} else if let entity = entity as? DrawingTextEntity {
self = .text(entity)
} else if let entity = entity as? DrawingSimpleShapeEntity {
self = .simpleShape(entity)
} else if let entity = entity as? DrawingBubbleEntity {
self = .bubble(entity)
} else if let entity = entity as? DrawingVectorEntity {
self = .vector(entity)
} else if let entity = entity as? DrawingLocationEntity {
self = .location(entity)
} else {
return nil
}
}
public var entity: DrawingEntity {
switch self {
case let .sticker(entity):
return entity
case let .text(entity):
return entity
case let .simpleShape(entity):
return entity
case let .bubble(entity):
return entity
case let .vector(entity):
return entity
case let .location(entity):
return entity
}
}
private var coordinates: MediaArea.Coordinates? {
var position: CGPoint?
var size: CGSize?
var rotation: CGFloat?
var scale: CGFloat?
switch self {
case let .location(entity):
position = entity.position
size = entity.renderImage?.size
rotation = entity.rotation
scale = entity.scale
case let .sticker(entity):
var entityPosition = entity.position
var entitySize = entity.baseSize
let entityRotation = entity.rotation
let entityScale = entity.scale
if case .message = entity.content {
let offset: CGFloat = 16.18 * entityScale //54.0 * entityScale / 3.337
entitySize = CGSize(width: entitySize.width - 38.0, height: entitySize.height - 4.0)
entityPosition = CGPoint(x: entityPosition.x + offset * cos(entityRotation), y: entityPosition.y + offset * sin(entityRotation))
}
position = entityPosition
size = entitySize
rotation = entityRotation
scale = entityScale
default:
return nil
}
guard let position, let size, let scale, let rotation else {
return nil
}
return MediaArea.Coordinates(
x: position.x / 1080.0 * 100.0,
y: position.y / 1920.0 * 100.0,
width: size.width * scale / 1080.0 * 100.0,
height: size.height * scale / 1920.0 * 100.0,
rotation: rotation / .pi * 180.0
)
}
public var mediaArea: MediaArea? {
guard let coordinates = self.coordinates else {
return nil
}
switch self {
case let .location(entity):
return .venue(
coordinates: coordinates,
venue: MediaArea.Venue(
latitude: entity.location.latitude,
longitude: entity.location.longitude,
venue: entity.location.venue,
address: entity.location.address,
queryId: entity.queryId,
resultId: entity.resultId
)
)
case let .sticker(entity):
if case let .link(url, _, _, _, _, _, _) = entity.content {
var url = url
if !url.hasPrefix("http://") && !url.hasPrefix("https://") {
url = "https://\(url)"
}
return .link(
coordinates: coordinates,
url: url
)
} else if case let .file(_, type) = entity.content, case let .reaction(reaction, style) = type {
var flags: MediaArea.ReactionFlags = []
if case .black = style {
flags.insert(.isDark)
}
if entity.mirrored {
flags.insert(.isFlipped)
}
return .reaction(
coordinates: coordinates,
reaction: reaction,
flags: flags
)
} else if case let .message(messageIds, _, _, _, _) = entity.content, let messageId = messageIds.first {
return .channelMessage(
coordinates: coordinates,
messageId: messageId
)
} else {
return nil
}
default:
return nil
}
}
}
extension CodableDrawingEntity: Codable {
private enum CodingKeys: String, CodingKey {
case type
case entity
}
private enum EntityType: Int, Codable {
case sticker
case text
case simpleShape
case bubble
case vector
case location
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(EntityType.self, forKey: .type)
switch type {
case .sticker:
self = .sticker(try container.decode(DrawingStickerEntity.self, forKey: .entity))
case .text:
self = .text(try container.decode(DrawingTextEntity.self, forKey: .entity))
case .simpleShape:
self = .simpleShape(try container.decode(DrawingSimpleShapeEntity.self, forKey: .entity))
case .bubble:
self = .bubble(try container.decode(DrawingBubbleEntity.self, forKey: .entity))
case .vector:
self = .vector(try container.decode(DrawingVectorEntity.self, forKey: .entity))
case .location:
self = .location(try container.decode(DrawingLocationEntity.self, forKey: .entity))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case let .sticker(payload):
try container.encode(EntityType.sticker, forKey: .type)
try container.encode(payload, forKey: .entity)
case let .text(payload):
try container.encode(EntityType.text, forKey: .type)
try container.encode(payload, forKey: .entity)
case let .simpleShape(payload):
try container.encode(EntityType.simpleShape, forKey: .type)
try container.encode(payload, forKey: .entity)
case let .bubble(payload):
try container.encode(EntityType.bubble, forKey: .type)
try container.encode(payload, forKey: .entity)
case let .vector(payload):
try container.encode(EntityType.vector, forKey: .type)
try container.encode(payload, forKey: .entity)
case let .location(payload):
try container.encode(EntityType.location, forKey: .type)
try container.encode(payload, forKey: .entity)
}
}
}