mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
462 lines
17 KiB
Swift
462 lines
17 KiB
Swift
import Foundation
|
|
|
|
public enum WidgetCodingError: Error {
|
|
case generic
|
|
}
|
|
|
|
public struct WidgetDataPeer: Codable, Equatable {
|
|
public struct Badge: Codable, Equatable {
|
|
public var count: Int
|
|
public var isMuted: Bool
|
|
|
|
public init(count: Int, isMuted: Bool) {
|
|
self.count = count
|
|
self.isMuted = isMuted
|
|
}
|
|
}
|
|
|
|
public struct Message: Codable, Equatable {
|
|
public struct Author: Codable, Equatable {
|
|
public var isMe: Bool
|
|
public var title: String
|
|
|
|
public init(isMe: Bool, title: String) {
|
|
self.isMe = isMe
|
|
self.title = title
|
|
}
|
|
}
|
|
|
|
public enum Content: Codable, Equatable {
|
|
public enum DecodingError: Error {
|
|
case generic
|
|
}
|
|
|
|
public struct Image: Codable, Equatable {
|
|
public init() {
|
|
}
|
|
}
|
|
|
|
public struct Video: Codable, Equatable {
|
|
public init() {
|
|
}
|
|
}
|
|
|
|
public struct File: Codable, Equatable {
|
|
public var name: String
|
|
|
|
public init(name: String) {
|
|
self.name = name
|
|
}
|
|
}
|
|
|
|
public struct Gif: Codable, Equatable {
|
|
public init() {
|
|
}
|
|
}
|
|
|
|
public struct Music: Codable, Equatable {
|
|
public var artist: String
|
|
public var title: String
|
|
public var duration: Int32
|
|
|
|
public init(artist: String, title: String, duration: Int32) {
|
|
self.artist = artist
|
|
self.title = title
|
|
self.duration = duration
|
|
}
|
|
}
|
|
|
|
public struct VoiceMessage: Codable, Equatable {
|
|
public var duration: Int32
|
|
|
|
public init(duration: Int32) {
|
|
self.duration = duration
|
|
}
|
|
}
|
|
|
|
public struct VideoMessage: Codable, Equatable {
|
|
public var duration: Int32
|
|
|
|
public init(duration: Int32) {
|
|
self.duration = duration
|
|
}
|
|
}
|
|
|
|
public struct Sticker: Codable, Equatable {
|
|
public var altText: String
|
|
|
|
public init(altText: String) {
|
|
self.altText = altText
|
|
}
|
|
}
|
|
|
|
public struct Call: Codable, Equatable {
|
|
public var isVideo: Bool
|
|
|
|
public init(isVideo: Bool) {
|
|
self.isVideo = isVideo
|
|
}
|
|
}
|
|
|
|
public struct MapLocation: Codable, Equatable {
|
|
public init() {
|
|
}
|
|
}
|
|
|
|
public struct Game: Codable, Equatable {
|
|
public var title: String
|
|
|
|
public init(title: String) {
|
|
self.title = title
|
|
}
|
|
}
|
|
|
|
public struct Poll: Codable, Equatable {
|
|
public var title: String
|
|
|
|
public init(title: String) {
|
|
self.title = title
|
|
}
|
|
}
|
|
|
|
public struct AutodeleteTimer: Codable, Equatable {
|
|
public var value: Int32?
|
|
|
|
public init(value: Int32?) {
|
|
self.value = value
|
|
}
|
|
}
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case text
|
|
case image
|
|
case video
|
|
case file
|
|
case gif
|
|
case music
|
|
case voiceMessage
|
|
case videoMessage
|
|
case sticker
|
|
case call
|
|
case mapLocation
|
|
case game
|
|
case poll
|
|
case autodeleteTimer
|
|
}
|
|
|
|
case text
|
|
case image(Image)
|
|
case video(Video)
|
|
case file(File)
|
|
case gif(Gif)
|
|
case music(Music)
|
|
case voiceMessage(VoiceMessage)
|
|
case videoMessage(VideoMessage)
|
|
case sticker(Sticker)
|
|
case call(Call)
|
|
case mapLocation(MapLocation)
|
|
case game(Game)
|
|
case poll(Poll)
|
|
case autodeleteTimer(AutodeleteTimer)
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
if let _ = try? container.decode(String.self, forKey: .text) {
|
|
self = .text
|
|
} else if let image = try? container.decode(Image.self, forKey: .image) {
|
|
self = .image(image)
|
|
} else if let video = try? container.decode(Video.self, forKey: .video) {
|
|
self = .video(video)
|
|
} else if let gif = try? container.decode(Gif.self, forKey: .gif) {
|
|
self = .gif(gif)
|
|
} else if let file = try? container.decode(File.self, forKey: .file) {
|
|
self = .file(file)
|
|
} else if let music = try? container.decode(Music.self, forKey: .voiceMessage) {
|
|
self = .music(music)
|
|
} else if let voiceMessage = try? container.decode(VoiceMessage.self, forKey: .voiceMessage) {
|
|
self = .voiceMessage(voiceMessage)
|
|
} else if let videoMessage = try? container.decode(VideoMessage.self, forKey: .videoMessage) {
|
|
self = .videoMessage(videoMessage)
|
|
} else if let sticker = try? container.decode(Sticker.self, forKey: .sticker) {
|
|
self = .sticker(sticker)
|
|
} else if let call = try? container.decode(Call.self, forKey: .call) {
|
|
self = .call(call)
|
|
} else if let mapLocation = try? container.decode(MapLocation.self, forKey: .mapLocation) {
|
|
self = .mapLocation(mapLocation)
|
|
} else if let game = try? container.decode(Game.self, forKey: .game) {
|
|
self = .game(game)
|
|
} else if let poll = try? container.decode(Poll.self, forKey: .poll) {
|
|
self = .poll(poll)
|
|
} else if let autodeleteTimer = try? container.decode(AutodeleteTimer.self, forKey: .autodeleteTimer) {
|
|
self = .autodeleteTimer(autodeleteTimer)
|
|
} else {
|
|
throw DecodingError.generic
|
|
}
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
switch self {
|
|
case .text:
|
|
try container.encode("", forKey: .text)
|
|
case let .image(image):
|
|
try container.encode(image, forKey: .image)
|
|
case let .video(video):
|
|
try container.encode(video, forKey: .video)
|
|
case let .file(file):
|
|
try container.encode(file, forKey: .file)
|
|
case let .gif(gif):
|
|
try container.encode(gif, forKey: .gif)
|
|
case let .music(music):
|
|
try container.encode(music, forKey: .music)
|
|
case let .voiceMessage(voiceMessage):
|
|
try container.encode(voiceMessage, forKey: .voiceMessage)
|
|
case let .videoMessage(videoMessage):
|
|
try container.encode(videoMessage, forKey: .videoMessage)
|
|
case let .sticker(sticker):
|
|
try container.encode(sticker, forKey: .sticker)
|
|
case let .call(call):
|
|
try container.encode(call, forKey: .call)
|
|
case let .mapLocation(mapLocation):
|
|
try container.encode(mapLocation, forKey: .mapLocation)
|
|
case let .game(game):
|
|
try container.encode(game, forKey: .game)
|
|
case let .poll(poll):
|
|
try container.encode(poll, forKey: .poll)
|
|
case let .autodeleteTimer(autodeleteTimer):
|
|
try container.encode(autodeleteTimer, forKey: .autodeleteTimer)
|
|
}
|
|
}
|
|
}
|
|
|
|
public var author: Author?
|
|
public var text: String
|
|
public var content: Content
|
|
public var timestamp: Int32
|
|
|
|
public init(author: Author?, text: String, content: Content, timestamp: Int32) {
|
|
self.author = author
|
|
self.text = text
|
|
self.content = content
|
|
self.timestamp = timestamp
|
|
}
|
|
}
|
|
|
|
public var id: Int64
|
|
public var name: String
|
|
public var lastName: String?
|
|
public var letters: [String]
|
|
public var avatarPath: String?
|
|
public var badge: Badge?
|
|
public var message: Message?
|
|
public var isForum: Bool
|
|
|
|
public init(id: Int64, name: String, lastName: String?, letters: [String], avatarPath: String?, badge: Badge?, message: Message?, isForum: Bool) {
|
|
self.id = id
|
|
self.name = name
|
|
self.lastName = lastName
|
|
self.letters = letters
|
|
self.avatarPath = avatarPath
|
|
self.badge = badge
|
|
self.message = message
|
|
self.isForum = isForum
|
|
}
|
|
}
|
|
|
|
public struct WidgetDataPeers: Codable, Equatable {
|
|
public var accountPeerId: Int64
|
|
public var peers: [WidgetDataPeer]
|
|
public var updateTimestamp: Int32
|
|
|
|
public init(accountPeerId: Int64, peers: [WidgetDataPeer], updateTimestamp: Int32) {
|
|
self.accountPeerId = accountPeerId
|
|
self.peers = peers
|
|
self.updateTimestamp = updateTimestamp
|
|
}
|
|
}
|
|
|
|
public struct WidgetPresentationData: Codable, Equatable {
|
|
public var widgetChatsGalleryTitle: String
|
|
public var widgetChatsGalleryDescription: String
|
|
public var widgetShortcutsGalleryTitle: String
|
|
public var widgetShortcutsGalleryDescription: String
|
|
|
|
public var widgetLongTapToEdit: String
|
|
public var widgetUpdatedTodayAt: String
|
|
public var widgetUpdatedAt: String
|
|
|
|
public var messageAuthorYou: String
|
|
public var messagePhoto: String
|
|
public var messageVideo: String
|
|
public var messageAnimation: String
|
|
public var messageVoice: String
|
|
public var messageVideoMessage: String
|
|
public var messageSticker: String
|
|
public var messageVoiceCall: String
|
|
public var messageVideoCall: String
|
|
public var messageLocation: String
|
|
|
|
public var autodeleteTimerUpdated: String
|
|
public var autodeleteTimerRemoved: String
|
|
|
|
public var generalLockedTitle: String
|
|
public var generalLockedText: String
|
|
|
|
public var chatSavedMessages: String
|
|
|
|
public init(
|
|
widgetChatsGalleryTitle: String,
|
|
widgetChatsGalleryDescription: String,
|
|
widgetShortcutsGalleryTitle: String,
|
|
widgetShortcutsGalleryDescription: String,
|
|
widgetLongTapToEdit: String,
|
|
widgetUpdatedTodayAt: String,
|
|
widgetUpdatedAt: String,
|
|
messageAuthorYou: String,
|
|
messagePhoto: String,
|
|
messageVideo: String,
|
|
messageAnimation: String,
|
|
messageVoice: String,
|
|
messageVideoMessage: String,
|
|
messageSticker: String,
|
|
messageVoiceCall: String,
|
|
messageVideoCall: String,
|
|
messageLocation: String,
|
|
autodeleteTimerUpdated: String,
|
|
autodeleteTimerRemoved: String,
|
|
generalLockedTitle: String,
|
|
generalLockedText: String,
|
|
chatSavedMessages: String
|
|
) {
|
|
self.widgetChatsGalleryTitle = widgetChatsGalleryTitle
|
|
self.widgetChatsGalleryDescription = widgetChatsGalleryDescription
|
|
self.widgetShortcutsGalleryTitle = widgetShortcutsGalleryTitle
|
|
self.widgetShortcutsGalleryDescription = widgetShortcutsGalleryDescription
|
|
self.widgetLongTapToEdit = widgetLongTapToEdit
|
|
self.widgetUpdatedTodayAt = widgetUpdatedTodayAt
|
|
self.widgetUpdatedAt = widgetUpdatedAt
|
|
self.messageAuthorYou = messageAuthorYou
|
|
self.messagePhoto = messagePhoto
|
|
self.messageVideo = messageVideo
|
|
self.messageAnimation = messageAnimation
|
|
self.messageVoice = messageVoice
|
|
self.messageVideoMessage = messageVideoMessage
|
|
self.messageSticker = messageSticker
|
|
self.messageVoiceCall = messageVoiceCall
|
|
self.messageVideoCall = messageVideoCall
|
|
self.messageLocation = messageLocation
|
|
self.autodeleteTimerUpdated = autodeleteTimerUpdated
|
|
self.autodeleteTimerRemoved = autodeleteTimerRemoved
|
|
self.generalLockedTitle = generalLockedTitle
|
|
self.generalLockedText = generalLockedText
|
|
self.chatSavedMessages = chatSavedMessages
|
|
}
|
|
|
|
public static func getForExtension() -> WidgetPresentationData {
|
|
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
|
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
|
return WidgetPresentationData.default
|
|
}
|
|
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
|
|
|
let appGroupName = "group.\(baseAppBundleId)"
|
|
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
|
|
|
guard let appGroupUrl = maybeAppGroupUrl else {
|
|
return WidgetPresentationData.default
|
|
}
|
|
|
|
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
|
|
|
if let data = try? Data(contentsOf: URL(fileURLWithPath: widgetPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(WidgetPresentationData.self, from: data) {
|
|
return value
|
|
} else {
|
|
return WidgetPresentationData.default
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension WidgetPresentationData {
|
|
static var `default` = WidgetPresentationData(
|
|
widgetChatsGalleryTitle: "Chats",
|
|
widgetChatsGalleryDescription: "Display the latest message from the most important chats.",
|
|
widgetShortcutsGalleryTitle: "Shortcuts",
|
|
widgetShortcutsGalleryDescription: "Display shortcuts of your most important chats to always have quick access to them.",
|
|
widgetLongTapToEdit: "Tap or hold to edit widget.",
|
|
widgetUpdatedTodayAt: "Updated at {}",
|
|
widgetUpdatedAt: "Updated {}",
|
|
messageAuthorYou: "You",
|
|
messagePhoto: "Photo",
|
|
messageVideo: "Video",
|
|
messageAnimation: "GIF",
|
|
messageVoice: "Voice Message",
|
|
messageVideoMessage: "Video Message",
|
|
messageSticker: "Sticker",
|
|
messageVoiceCall: "Call",
|
|
messageVideoCall: "Video Call",
|
|
messageLocation: "Map",
|
|
autodeleteTimerUpdated: "Auto-delete timer updated",
|
|
autodeleteTimerRemoved: "Auto-delete timer disabled",
|
|
generalLockedTitle: "Locked",
|
|
generalLockedText: "Open Telegram and enter passcode to edit widget.",
|
|
chatSavedMessages: "Saved Messages"
|
|
)
|
|
}
|
|
|
|
private func rootPathForBasePath(_ appGroupPath: String) -> String {
|
|
return appGroupPath + "/telegram-data"
|
|
}
|
|
|
|
public func widgetPresentationDataPath(rootPath: String) -> String {
|
|
return rootPath + "/widgetPresentationData.json"
|
|
}
|
|
|
|
public struct WidgetData: Codable, Equatable {
|
|
public enum Content: Codable, Equatable {
|
|
private enum CodingKeys: CodingKey {
|
|
case discriminator
|
|
case peers
|
|
}
|
|
|
|
private enum Cases: Int32, Codable {
|
|
case empty
|
|
case peers
|
|
}
|
|
|
|
case empty
|
|
case peers(WidgetDataPeers)
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
let discriminator = try container.decode(Cases.self, forKey: .discriminator)
|
|
switch discriminator {
|
|
case .empty:
|
|
self = .empty
|
|
case .peers:
|
|
self = .peers(try container.decode(WidgetDataPeers.self, forKey: .peers))
|
|
}
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
switch self {
|
|
case .empty:
|
|
try container.encode(Cases.empty, forKey: .discriminator)
|
|
case let .peers(peers):
|
|
try container.encode(Cases.peers, forKey: .discriminator)
|
|
try container.encode(peers, forKey: .peers)
|
|
}
|
|
}
|
|
}
|
|
|
|
public var accountId: Int64
|
|
public var content: Content
|
|
public var unlockedForLockId: String?
|
|
|
|
public init(accountId: Int64, content: Content, unlockedForLockId: String?) {
|
|
self.accountId = accountId
|
|
self.content = content
|
|
self.unlockedForLockId = unlockedForLockId
|
|
}
|
|
}
|