mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 14:17:19 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
4.2 KiB
Swift
78 lines
4.2 KiB
Swift
import Foundation
|
|
import Postbox
|
|
|
|
/// An InstantPage button in the composer currency. Unlike `RichTextEditorCore.ButtonRef`, this layer
|
|
/// can name `ReplyMarkupButtonAction` directly, so no opaque blob appears here — the blob exists only
|
|
/// on the editor side, and `ButtonActionCodec` (RichTextEditorMessageConversion) bridges the two.
|
|
///
|
|
/// The label lives INSIDE the button; the carrying run's text is a bare `U+FFFC`, mirroring the
|
|
/// custom-emoji and formula invariants.
|
|
public struct ChatInputButton: Equatable, Codable {
|
|
public var label: [ChatInputRun]
|
|
public var action: ReplyMarkupButtonAction
|
|
public var color: ReplyMarkupButton.Style.Color?
|
|
/// `richButtonStyle`'s `link` bit, kept independent of `color` so `link + danger` round-trips.
|
|
public var isLink: Bool
|
|
|
|
public init(label: [ChatInputRun], action: ReplyMarkupButtonAction = .disabled, color: ReplyMarkupButton.Style.Color? = nil, isLink: Bool = false) {
|
|
self.label = label
|
|
self.action = action
|
|
self.color = color
|
|
self.isLink = isLink
|
|
}
|
|
|
|
private enum CodingKeys: String, CodingKey { case label, action, color, isLink }
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
self.label = try container.decodeIfPresent([ChatInputRun].self, forKey: .label) ?? []
|
|
// `ReplyMarkupButtonAction` is PostboxCoding, not Codable. Carried as a Postbox object blob via
|
|
// the same `RawObjectData` idiom `ChatInputMediaItem` uses for its `Media` — a plain `Data` field
|
|
// would not survive the `AdaptedPostbox*coder` path that drafts actually persist through.
|
|
let raw = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .action)
|
|
self.action = ReplyMarkupButtonAction(decoder: PostboxDecoder(buffer: MemoryBuffer(data: raw.data)))
|
|
// Decoded as a raw `Int32` (NOT `Color.self`): the Postbox coder does not support the
|
|
// `singleValueContainer` a `RawRepresentable` enum's synthesized Codable uses. -1 encodes nil.
|
|
let rawColor = try container.decodeIfPresent(Int32.self, forKey: .color) ?? -1
|
|
self.color = rawColor == -1 ? nil : ReplyMarkupButton.Style.Color(rawValue: rawColor)
|
|
self.isLink = try container.decodeIfPresent(Bool.self, forKey: .isLink) ?? false
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encode(self.label, forKey: .label)
|
|
try container.encode(PostboxEncoder().encodeObjectToRawData(self.action), forKey: .action)
|
|
try container.encode(self.color?.rawValue ?? -1, forKey: .color)
|
|
try container.encode(self.isLink, forKey: .isLink)
|
|
}
|
|
}
|
|
|
|
/// A block-level row of buttons — `InstantPageBlock.buttonRow`. The row owns the alignment; a pill
|
|
/// does not, so a per-pill alignment that could disagree across the row is not representable.
|
|
public struct ChatInputButtonRow: Equatable, Codable {
|
|
public var buttons: [ChatInputButton]
|
|
public var alignment: InstantPageButtonRowAlignment
|
|
|
|
public init(buttons: [ChatInputButton], alignment: InstantPageButtonRowAlignment = .justify) {
|
|
self.buttons = buttons
|
|
self.alignment = alignment
|
|
}
|
|
|
|
private enum CodingKeys: String, CodingKey { case buttons, alignment }
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
self.buttons = try container.decodeIfPresent([ChatInputButton].self, forKey: .buttons) ?? []
|
|
// Raw `Int32` for the same reason as `color` above. `justify` is rawValue 0, so a row written
|
|
// before this field existed (there are none, but the decode is lenient anyway) reads as justify.
|
|
let raw = try container.decodeIfPresent(Int32.self, forKey: .alignment) ?? 0
|
|
self.alignment = InstantPageButtonRowAlignment(rawValue: raw) ?? .justify
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encode(self.buttons, forKey: .buttons)
|
|
try container.encode(self.alignment.rawValue, forKey: .alignment)
|
|
}
|
|
}
|