API updates, token login support, initial data usage screen implementation

This commit is contained in:
Ali 2023-01-07 00:36:12 +04:00
parent 798b75dabf
commit 58f6657c6e
73 changed files with 6957 additions and 1329 deletions

View File

@ -167,10 +167,20 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
controller.loginWithNumber = { [weak self, weak controller] number, syncContacts in
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, syncContacts: syncContacts) |> deliverOnMainQueue).start(next: { [weak self] account in
strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, syncContacts: syncContacts, forcedPasswordSetupNotice: { value in
guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else {
return nil
}
return (ApplicationSpecificNotice.forcedPasswordSetupKey(), entry)
}) |> deliverOnMainQueue).start(next: { [weak self] result in
if let strongSelf = self {
controller?.inProgress = false
strongSelf.account = account
switch result {
case let .sentCode(account):
controller?.inProgress = false
strongSelf.account = account
case .loggedIn:
break
}
}
}, error: { error in
if let strongSelf = self, let controller = controller {

View File

@ -59,6 +59,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case sendOneLog(PresentationTheme)
case sendShareLogs
case sendGroupCallLogs
case sendStorageStats
case sendNotificationLogs(PresentationTheme)
case sendCriticalLogs(PresentationTheme)
case sendAllLogs
@ -106,7 +107,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
switch self {
case .testStickerImport:
return DebugControllerSection.sticker.rawValue
case .sendLogs, .sendOneLog, .sendShareLogs, .sendGroupCallLogs, .sendNotificationLogs, .sendCriticalLogs, .sendAllLogs:
case .sendLogs, .sendOneLog, .sendShareLogs, .sendGroupCallLogs, .sendStorageStats, .sendNotificationLogs, .sendCriticalLogs, .sendAllLogs:
return DebugControllerSection.logs.rawValue
case .accounts:
return DebugControllerSection.logs.rawValue
@ -143,76 +144,78 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 6
case .sendAllLogs:
return 7
case .accounts:
case .sendStorageStats:
return 8
case .logToFile:
case .accounts:
return 9
case .logToConsole:
case .logToFile:
return 10
case .redactSensitiveData:
case .logToConsole:
return 11
case .enableRaiseToSpeak:
case .redactSensitiveData:
return 12
case .keepChatNavigationStack:
case .enableRaiseToSpeak:
return 13
case .skipReadHistory:
case .keepChatNavigationStack:
return 14
case .crashOnSlowQueries:
case .skipReadHistory:
return 15
case .clearTips:
case .crashOnSlowQueries:
return 16
case .crash:
case .clearTips:
return 17
case .resetData:
case .crash:
return 18
case .resetDatabase:
case .resetData:
return 19
case .resetDatabaseAndCache:
case .resetDatabase:
return 20
case .resetHoles:
case .resetDatabaseAndCache:
return 21
case .reindexUnread:
case .resetHoles:
return 22
case .resetCacheIndex:
case .reindexUnread:
return 23
case .reindexCache:
case .resetCacheIndex:
return 24
case .resetBiometricsData:
case .reindexCache:
return 25
case .resetWebViewCache:
case .resetBiometricsData:
return 26
case .optimizeDatabase:
case .resetWebViewCache:
return 27
case .photoPreview:
case .optimizeDatabase:
return 28
case .knockoutWallpaper:
case .photoPreview:
return 29
case .experimentalCompatibility:
case .knockoutWallpaper:
return 30
case .enableDebugDataDisplay:
case .experimentalCompatibility:
return 31
case .acceleratedStickers:
case .enableDebugDataDisplay:
return 32
case .experimentalBackground:
case .acceleratedStickers:
return 33
case .inlineForums:
case .experimentalBackground:
return 34
case .localTranscription:
case .inlineForums:
return 35
case .enableReactionOverrides:
case .localTranscription:
return 36
case .restorePurchases:
case .enableReactionOverrides:
return 37
case .playerEmbedding:
case .restorePurchases:
return 38
case .playlistPlayback:
case .playerEmbedding:
return 39
case .enableQuickReactionSwitch:
case .playlistPlayback:
return 40
case .voiceConference:
case .enableQuickReactionSwitch:
return 41
case .voiceConference:
return 42
case let .preferredVideoCodec(index, _, _, _):
return 42 + index
return 43 + index
case .disableVideoAspectScaling:
return 100
case .enableVoipTcp:
@ -806,6 +809,61 @@ private enum DebugControllerEntry: ItemListNodeEntry {
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
arguments.presentController(actionSheet, nil)
})
})
case .sendStorageStats:
return ItemListDisclosureItem(presentationData: presentationData, title: "Send Storage Stats", label: "", sectionId: self.section, style: .blocks, action: {
guard let context = arguments.context, context.sharedContext.applicationBindings.isMainApp else {
return
}
let allStats: Signal<Data, NoError> = Signal { subscriber in
DispatchQueue.global().async {
let log = collectRawStorageUsageReport(containerPath: context.sharedContext.applicationBindings.containerPath)
subscriber.putNext(log.data(using: .utf8) ?? Data())
}
return EmptyDisposable
}
let _ = (allStats
|> deliverOnMainQueue).start(next: { allStatsData in
let presentationData = arguments.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationData: presentationData)
var items: [ActionSheetButtonItem] = []
if let context = arguments.context, context.sharedContext.applicationBindings.isMainApp {
items.append(ActionSheetButtonItem(title: "Via Telegram", color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled]))
controller.peerSelected = { [weak controller] peer, _ in
let peerId = peer.id
if let strongController = controller {
strongController.dismiss()
let id = Int64.random(in: Int64.min ... Int64.max)
let fileResource = LocalFileMediaResource(fileId: id, size: Int64(allStatsData.count), isSecretRelated: false)
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: allStatsData)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/zip", size: Int64(allStatsData.count), attributes: [.FileName(fileName: "StorageReport.txt")])
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}
}
arguments.pushController(controller)
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
@ -1251,6 +1309,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
entries.append(.sendNotificationLogs(presentationData.theme))
entries.append(.sendCriticalLogs(presentationData.theme))
entries.append(.sendAllLogs)
entries.append(.sendStorageStats)
if isMainApp {
entries.append(.accounts(presentationData.theme))
}

View File

@ -4395,7 +4395,15 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if let index = strongSelf.itemIndexAtPoint(strongSelf.touchesPosition) {
var canBeSelectedOrLongTapped = false
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && (strongSelf.items[index].selectable && itemNode.canBeSelected) || itemNode.canBeLongTapped {
var canBeSelected = itemNode.canBeSelected
if canBeSelected {
if !itemNode.isLayerBacked {
if !itemNode.visibleForSelection(at: strongSelf.view.convert(strongSelf.touchesPosition, to: itemNode.view)) {
canBeSelected = false
}
}
}
if itemNode.index == index && (strongSelf.items[index].selectable && canBeSelected) || itemNode.canBeLongTapped {
canBeSelectedOrLongTapped = true
}
}
@ -4403,7 +4411,20 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if canBeSelectedOrLongTapped {
strongSelf.highlightedItemIndex = index
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && itemNode.canBeSelected {
let itemNodeFrame = itemNode.frame
let itemNodeBounds = itemNode.bounds
let itemPoint = strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY)
var canBeSelected = itemNode.canBeSelected
if canBeSelected {
if !itemNode.isLayerBacked {
if !itemNode.visibleForSelection(at: itemPoint) {
canBeSelected = false
}
}
}
if itemNode.index == index && canBeSelected {
if true {
if !itemNode.isLayerBacked {
strongSelf.reorderItemNodeToFront(itemNode)
@ -4411,10 +4432,8 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
strongSelf.reorderHeaderNodeToFront(headerNode)
}
}
let itemNodeFrame = itemNode.frame
let itemNodeBounds = itemNode.bounds
if strongSelf.items[index].selectable {
itemNode.setHighlighted(true, at: strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY), animated: false)
itemNode.setHighlighted(true, at: itemPoint, animated: false)
}
if itemNode.canBeLongTapped {

View File

@ -148,6 +148,10 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
return true
}
open func visibleForSelection(at point: CGPoint) -> Bool {
return true
}
open var canBeLongTapped: Bool {
return false
}

View File

@ -0,0 +1,702 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import TelegramPresentationData
import SwitchNode
import AppBundle
import CheckNode
public enum ItemListExpandableSwitchItemNodeType {
case regular
case icon
}
public class ItemListExpandableSwitchItem: ListViewItem, ItemListItem {
public struct SubItem: Equatable {
public var id: AnyHashable
public var title: String
public var isSelected: Bool
public init(
id: AnyHashable,
title: String,
isSelected: Bool
) {
self.id = id
self.title = title
self.isSelected = isSelected
}
}
let presentationData: ItemListPresentationData
let icon: UIImage?
let title: String
let value: Bool
let isExpanded: Bool
let subItems: [SubItem]
let type: ItemListExpandableSwitchItemNodeType
let enableInteractiveChanges: Bool
let enabled: Bool
let displayLocked: Bool
let disableLeadingInset: Bool
let maximumNumberOfLines: Int
let noCorners: Bool
public let sectionId: ItemListSectionId
let style: ItemListStyle
let updated: (Bool) -> Void
let activatedWhileDisabled: () -> Void
let selectAction: () -> Void
let subAction: (SubItem) -> Void
public let tag: ItemListItemTag?
public let selectable: Bool = true
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, value: Bool, isExpanded: Bool, subItems: [SubItem], type: ItemListExpandableSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, displayLocked: Bool = false, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, noCorners: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, selectAction: @escaping () -> Void, subAction: @escaping (SubItem) -> Void, tag: ItemListItemTag? = nil) {
self.presentationData = presentationData
self.icon = icon
self.title = title
self.value = value
self.isExpanded = isExpanded
self.subItems = subItems
self.type = type
self.enableInteractiveChanges = enableInteractiveChanges
self.enabled = enabled
self.displayLocked = displayLocked
self.disableLeadingInset = disableLeadingInset
self.maximumNumberOfLines = maximumNumberOfLines
self.noCorners = noCorners
self.sectionId = sectionId
self.style = style
self.updated = updated
self.activatedWhileDisabled = activatedWhileDisabled
self.selectAction = selectAction
self.subAction = subAction
self.tag = tag
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async {
let node = ItemListExpandableSwitchItemNode(type: self.type)
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
node.contentSize = layout.contentSize
node.insets = layout.insets
Queue.mainQueue().async {
completion(node, {
return (nil, { _ in apply(ListViewItemUpdateAnimation.None) })
})
}
}
}
public func selected(listView: ListView) {
listView.clearHighlightAnimated(true)
self.selectAction()
}
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
if let nodeValue = node() as? ItemListExpandableSwitchItemNode {
let makeLayout = nodeValue.asyncLayout()
async {
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
Queue.mainQueue().async {
completion(layout, { _ in
apply(animation)
})
}
}
}
}
}
}
private final class SubItemNode: HighlightTrackingButtonNode {
private let textNode: ImmediateTextNode
private var checkNode: CheckNode?
private let separatorNode: ASDisplayNode
private var theme: PresentationTheme?
private var item: ItemListExpandableSwitchItem.SubItem?
private var action: ((ItemListExpandableSwitchItem.SubItem) -> Void)?
init() {
self.textNode = ImmediateTextNode()
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
super.init()
self.addSubnode(self.separatorNode)
self.addSubnode(self.textNode)
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
}
@objc private func pressed() {
guard let item = self.item, let action = self.action else {
return
}
action(item)
}
func update(presentationData: ItemListPresentationData, item: ItemListExpandableSwitchItem.SubItem, action: @escaping (ItemListExpandableSwitchItem.SubItem) -> Void, size: CGSize, transition: ContainedViewLayoutTransition) {
let themeUpdated = self.theme !== presentationData.theme
self.item = item
self.action = action
let leftInset: CGFloat = 60.0
if themeUpdated {
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
}
let checkNode: CheckNode
if let current = self.checkNode {
checkNode = current
if themeUpdated {
checkNode.theme = CheckNodeTheme(theme: presentationData.theme, style: .plain)
}
} else {
checkNode = CheckNode(theme: CheckNodeTheme(theme: presentationData.theme, style: .plain))
self.checkNode = checkNode
self.addSubnode(checkNode)
}
let checkSize = CGSize(width: 22.0, height: 22.0)
checkNode.frame = CGRect(origin: CGPoint(x: floor((leftInset - checkSize.width) / 2.0), y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
checkNode.setSelected(item.isSelected, animated: transition.isAnimated)
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset, y: size.height - UIScreenPixel), size: CGSize(width: size.width - leftInset, height: UIScreenPixel)))
self.textNode.attributedText = NSAttributedString(string: item.title, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
let titleSize = self.textNode.updateLayout(CGSize(width: size.width - leftInset, height: 100.0))
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
}
}
public class ItemListExpandableSwitchItemNode: ListViewItemNode, ItemListItemNode {
private let backgroundNode: ASDisplayNode
private let topStripeNode: ASDisplayNode
private let bottomTopStripeNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
private let maskNode: ASImageNode
private let iconNode: ASImageNode
private let titleNode: TextNode
private let titleValueNode: TextNode
private let expandArrowNode: ASImageNode
private var switchNode: ASDisplayNode & ItemListSwitchNodeImpl
private let switchGestureNode: ASDisplayNode
private var disabledOverlayNode: ASDisplayNode?
private var lockedIconNode: ASImageNode?
private let subItemContainer: ASDisplayNode
private var subItemNodes: [AnyHashable: SubItemNode] = [:]
private let activateArea: AccessibilityAreaNode
private var item: ItemListExpandableSwitchItem?
public var tag: ItemListItemTag? {
return self.item?.tag
}
public init(type: ItemListExpandableSwitchItemNodeType) {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.backgroundColor = .white
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true
self.bottomTopStripeNode = ASDisplayNode()
self.bottomTopStripeNode.isLayerBacked = true
self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true
self.iconNode = ASImageNode()
self.iconNode.isLayerBacked = true
self.iconNode.displaysAsynchronously = false
self.titleNode = TextNode()
self.titleNode.isUserInteractionEnabled = false
switch type {
case .regular:
self.switchNode = SwitchNode()
case .icon:
self.switchNode = IconSwitchNode()
}
self.titleValueNode = TextNode()
self.titleValueNode.isUserInteractionEnabled = false
self.expandArrowNode = ASImageNode()
self.expandArrowNode.displaysAsynchronously = false
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
self.switchGestureNode = ASDisplayNode()
self.activateArea = AccessibilityAreaNode()
self.subItemContainer = ASDisplayNode()
self.subItemContainer.clipsToBounds = true
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.titleNode)
self.addSubnode(self.titleValueNode)
self.addSubnode(self.expandArrowNode)
self.addSubnode(self.switchNode)
self.addSubnode(self.switchGestureNode)
self.addSubnode(self.activateArea)
self.addSubnode(self.subItemContainer)
self.activateArea.activate = { [weak self] in
guard let strongSelf = self, let item = strongSelf.item, item.enabled else {
return false
}
let value = !strongSelf.switchNode.isOn
if item.enableInteractiveChanges {
strongSelf.switchNode.setOn(value, animated: true)
}
item.updated(value)
return true
}
}
override public func didLoad() {
super.didLoad()
(self.switchNode.view as? UISwitch)?.addTarget(self, action: #selector(self.switchValueChanged(_:)), for: .valueChanged)
self.switchGestureNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
func asyncLayout() -> (_ item: ItemListExpandableSwitchItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeTitleValueLayout = TextNode.asyncLayout(self.titleValueNode)
let currentItem = self.item
var currentDisabledOverlayNode = self.disabledOverlayNode
return { item, params, neighbors in
var contentSize: CGSize
var insets: UIEdgeInsets
let separatorHeight = UIScreenPixel
let itemBackgroundColor: UIColor
let itemSeparatorColor: UIColor
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
var updatedTheme: PresentationTheme?
if currentItem?.presentationData.theme !== item.presentationData.theme {
updatedTheme = item.presentationData.theme
}
var updateIcon = false
if currentItem?.icon != item.icon {
updateIcon = true
}
switch item.style {
case .plain:
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor
contentSize = CGSize(width: params.width, height: 44.0)
insets = itemListNeighborsPlainInsets(neighbors)
case .blocks:
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
contentSize = CGSize(width: params.width, height: 44.0)
insets = itemListNeighborsGroupedInsets(neighbors, params)
}
var leftInset = 16.0 + params.leftInset
if let _ = item.icon {
leftInset += 43.0
}
if item.disableLeadingInset {
insets.top = 0.0
insets.bottom = 0.0
}
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: item.maximumNumberOfLines, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - params.rightInset - 64.0 - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let titleValue = "\(item.subItems.filter(\.isSelected).count)/\(item.subItems.count)"
let (titleValueLayout, titleValueApply) = makeTitleValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleValue, font: Font.bold(14.0), textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - params.rightInset - 64.0 - titleLayout.size.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
contentSize.height = max(contentSize.height, titleLayout.size.height + 22.0)
let mainContentHeight = contentSize.height
var effectiveSubItemsHeight: CGFloat = 0.0
if item.isExpanded {
effectiveSubItemsHeight = CGFloat(item.subItems.count) * 44.0
}
contentSize.height += effectiveSubItemsHeight
if !item.enabled {
if currentDisabledOverlayNode == nil {
currentDisabledOverlayNode = ASDisplayNode()
}
} else {
currentDisabledOverlayNode = nil
}
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
let layoutSize = layout.size
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] animation in
if let strongSelf = self {
strongSelf.item = item
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: mainContentHeight))
strongSelf.activateArea.accessibilityLabel = item.title
strongSelf.activateArea.accessibilityValue = item.value ? item.presentationData.strings.VoiceOver_Common_On : item.presentationData.strings.VoiceOver_Common_Off
strongSelf.activateArea.accessibilityHint = item.presentationData.strings.VoiceOver_Common_SwitchHint
var accessibilityTraits = UIAccessibilityTraits()
if item.enabled {
} else {
accessibilityTraits.insert(.notEnabled)
}
strongSelf.activateArea.accessibilityTraits = accessibilityTraits
if let icon = item.icon {
if strongSelf.iconNode.supernode == nil {
strongSelf.addSubnode(strongSelf.iconNode)
}
if updateIcon {
strongSelf.iconNode.image = icon
}
let iconY = floor((mainContentHeight - icon.size.height) / 2.0)
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: iconY), size: icon.size)
} else if strongSelf.iconNode.supernode != nil {
strongSelf.iconNode.image = nil
strongSelf.iconNode.removeFromSupernode()
}
let transition: ContainedViewLayoutTransition = animation.transition
if let currentDisabledOverlayNode = currentDisabledOverlayNode {
if currentDisabledOverlayNode != strongSelf.disabledOverlayNode {
strongSelf.disabledOverlayNode = currentDisabledOverlayNode
strongSelf.insertSubnode(currentDisabledOverlayNode, belowSubnode: strongSelf.switchGestureNode)
currentDisabledOverlayNode.alpha = 0.0
transition.updateAlpha(node: currentDisabledOverlayNode, alpha: 1.0)
currentDisabledOverlayNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width, height: mainContentHeight - separatorHeight))
} else {
transition.updateFrame(node: currentDisabledOverlayNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width, height: mainContentHeight - separatorHeight)))
}
currentDisabledOverlayNode.backgroundColor = itemBackgroundColor.withAlphaComponent(0.6)
} else if let disabledOverlayNode = strongSelf.disabledOverlayNode {
transition.updateAlpha(node: disabledOverlayNode, alpha: 0.0, completion: { [weak disabledOverlayNode] _ in
disabledOverlayNode?.removeFromSupernode()
})
strongSelf.disabledOverlayNode = nil
}
if let _ = updatedTheme {
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
strongSelf.bottomTopStripeNode.backgroundColor = itemSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
strongSelf.switchNode.frameColor = item.presentationData.theme.list.itemSwitchColors.frameColor
strongSelf.switchNode.contentColor = item.presentationData.theme.list.itemSwitchColors.contentColor
strongSelf.switchNode.handleColor = item.presentationData.theme.list.itemSwitchColors.handleColor
strongSelf.switchNode.positiveContentColor = item.presentationData.theme.list.itemSwitchColors.positiveColor
strongSelf.switchNode.negativeContentColor = item.presentationData.theme.list.itemSwitchColors.negativeColor
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
}
let _ = titleApply()
switch item.style {
case .plain:
if strongSelf.backgroundNode.supernode != nil {
strongSelf.backgroundNode.removeFromSupernode()
}
if strongSelf.topStripeNode.supernode != nil {
strongSelf.topStripeNode.removeFromSupernode()
}
if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
}
if strongSelf.bottomTopStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomTopStripeNode, at: 1)
}
if strongSelf.maskNode.supernode != nil {
strongSelf.maskNode.removeFromSupernode()
}
strongSelf.bottomTopStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: mainContentHeight - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: layout.contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
case .blocks:
if strongSelf.backgroundNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
}
if strongSelf.topStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
}
if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
}
if strongSelf.bottomTopStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomTopStripeNode, at: 3)
}
if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, aboveSubnode: strongSelf.switchGestureNode)
}
let hasCorners = itemListHasRoundedBlockLayout(params) && !item.noCorners
var hasTopCorners = false
var hasBottomCorners = false
switch neighbors.top {
case .sameSection(false):
strongSelf.topStripeNode.isHidden = true
default:
hasTopCorners = true
strongSelf.topStripeNode.isHidden = hasCorners
}
let bottomStripeInset: CGFloat
switch neighbors.bottom {
case .sameSection(false):
bottomStripeInset = leftInset
strongSelf.bottomStripeNode.isHidden = false
strongSelf.bottomTopStripeNode.isHidden = false
default:
bottomStripeInset = 0.0
hasBottomCorners = true
strongSelf.bottomStripeNode.isHidden = hasCorners
strongSelf.bottomTopStripeNode.isHidden = false
}
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
animation.animator.updateFrame(layer: strongSelf.backgroundNode.layer, frame: backgroundFrame, completion: nil)
animation.animator.updateFrame(layer: strongSelf.maskNode.layer, frame: backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0), completion: nil)
animation.animator.updateFrame(layer: strongSelf.topStripeNode.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)), completion: nil)
animation.animator.updateFrame(layer: strongSelf.bottomTopStripeNode.layer, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: mainContentHeight - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)), completion: nil)
animation.animator.updateFrame(layer: strongSelf.bottomStripeNode.layer, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)), completion: nil)
}
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floorToScreenPixels((mainContentHeight - titleLayout.size.height) / 2.0)), size: titleLayout.size)
let _ = titleValueApply()
strongSelf.titleValueNode.frame = CGRect(origin: CGPoint(x: strongSelf.titleNode.frame.maxX + 9.0, y: strongSelf.titleNode.frame.minY + floor((titleLayout.size.height - titleValueLayout.size.height) / 2.0)), size: titleValueLayout.size)
if let updatedTheme {
strongSelf.expandArrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Item List/DisclosureArrow"), color: updatedTheme.list.itemPrimaryTextColor)
}
if let image = strongSelf.expandArrowNode.image {
strongSelf.expandArrowNode.position = CGPoint(x: strongSelf.titleValueNode.frame.maxX + 9.0, y: strongSelf.titleValueNode.frame.midY)
let scaleFactor: CGFloat = 0.8
strongSelf.expandArrowNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: image.size.width * scaleFactor, height: image.size.height * scaleFactor))
transition.updateTransformRotation(node: strongSelf.expandArrowNode, angle: item.isExpanded ? CGFloat.pi * 0.5 : -CGFloat.pi * 0.5)
}
if let switchView = strongSelf.switchNode.view as? UISwitch {
if strongSelf.switchNode.bounds.size.width.isZero {
switchView.sizeToFit()
}
let switchSize = switchView.bounds.size
strongSelf.switchNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - switchSize.width - 15.0, y: floor((mainContentHeight - switchSize.height) / 2.0)), size: switchSize)
strongSelf.switchGestureNode.frame = strongSelf.switchNode.frame
if switchView.isOn != item.value {
switchView.setOn(item.value, animated: animation.isAnimated)
}
switchView.isUserInteractionEnabled = item.enableInteractiveChanges
}
strongSelf.switchGestureNode.isHidden = item.enableInteractiveChanges && item.enabled
if item.displayLocked {
var updateLockedIconImage = false
if let _ = updatedTheme {
updateLockedIconImage = true
}
let lockedIconNode: ASImageNode
if let current = strongSelf.lockedIconNode {
lockedIconNode = current
} else {
updateLockedIconImage = true
lockedIconNode = ASImageNode()
strongSelf.lockedIconNode = lockedIconNode
strongSelf.insertSubnode(lockedIconNode, aboveSubnode: strongSelf.switchNode)
}
if updateLockedIconImage, let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/TextLockIcon"), color: item.presentationData.theme.list.itemSecondaryTextColor) {
lockedIconNode.image = image
}
let switchFrame = strongSelf.switchNode.frame
if let icon = lockedIconNode.image {
lockedIconNode.frame = CGRect(origin: CGPoint(x: switchFrame.minX + 10.0 + UIScreenPixel, y: switchFrame.minY + 9.0), size: icon.size)
}
} else if let lockedIconNode = strongSelf.lockedIconNode {
strongSelf.lockedIconNode = nil
lockedIconNode.removeFromSupernode()
}
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 44.0 + UIScreenPixel + UIScreenPixel))
animation.animator.updateFrame(layer: strongSelf.subItemContainer.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: mainContentHeight), size: CGSize(width: params.width, height: effectiveSubItemsHeight)), completion: nil)
var validIds: [AnyHashable] = []
let subItemSize = CGSize(width: params.width - params.leftInset - params.rightInset, height: 44.0)
var nextSubItemPosition = CGPoint(x: params.leftInset, y: 0.0)
for subItem in item.subItems {
validIds.append(subItem.id)
let subItemNode: SubItemNode
var subItemNodeTransition = transition
if let current = strongSelf.subItemNodes[subItem.id] {
subItemNode = current
} else {
subItemNodeTransition = .immediate
subItemNode = SubItemNode()
strongSelf.subItemNodes[subItem.id] = subItemNode
strongSelf.subItemContainer.addSubnode(subItemNode)
}
let subItemFrame = CGRect(origin: nextSubItemPosition, size: subItemSize)
subItemNode.update(presentationData: item.presentationData, item: subItem, action: item.subAction, size: subItemSize, transition: subItemNodeTransition)
subItemNodeTransition.updateFrame(node: subItemNode, frame: subItemFrame)
nextSubItemPosition.y += subItemSize.height
}
var removeIds: [AnyHashable] = []
for (id, itemNode) in strongSelf.subItemNodes {
if !validIds.contains(id) {
removeIds.append(id)
itemNode.removeFromSupernode()
}
}
for id in removeIds {
strongSelf.subItemNodes.removeValue(forKey: id)
}
}
})
}
}
override public func accessibilityActivate() -> Bool {
guard let item = self.item else {
return false
}
if !item.enabled {
return false
}
if let switchNode = self.switchNode as? IconSwitchNode {
switchNode.isOn = !switchNode.isOn
item.updated(switchNode.isOn)
} else if let switchNode = self.switchNode as? SwitchNode {
switchNode.isOn = !switchNode.isOn
item.updated(switchNode.isOn)
}
return true
}
override public func visibleForSelection(at point: CGPoint) -> Bool {
if !self.canBeSelected {
return false
}
if point.y > self.subItemContainer.frame.minY {
return false
}
return true
}
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
var highlighted = highlighted
if point.y > self.subItemContainer.frame.minY {
highlighted = false
}
super.setHighlighted(highlighted, at: point, animated: animated)
if highlighted {
self.highlightedBackgroundNode.alpha = 1.0
if self.highlightedBackgroundNode.supernode == nil {
var anchorNode: ASDisplayNode?
if self.bottomStripeNode.supernode != nil {
anchorNode = self.bottomStripeNode
} else if self.topStripeNode.supernode != nil {
anchorNode = self.topStripeNode
} else if self.backgroundNode.supernode != nil {
anchorNode = self.backgroundNode
}
if let anchorNode = anchorNode {
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
} else {
self.addSubnode(self.highlightedBackgroundNode)
}
}
} else {
if self.highlightedBackgroundNode.supernode != nil {
if animated {
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()
}
}
})
self.highlightedBackgroundNode.alpha = 0.0
} else {
self.highlightedBackgroundNode.removeFromSupernode()
}
}
}
}
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.allowsGroupOpacity = true
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4, completion: { [weak self] _ in
self?.layer.allowsGroupOpacity = false
})
}
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.allowsGroupOpacity = true
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
}
@objc private func switchValueChanged(_ switchView: UISwitch) {
if let item = self.item {
let value = switchView.isOn
item.updated(value)
}
}
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if let item = self.item, let switchView = self.switchNode.view as? UISwitch, case .ended = recognizer.state {
if item.enabled {
let value = switchView.isOn
item.updated(!value)
} else {
item.activatedWhileDisabled()
}
}
}
}

View File

@ -87,7 +87,7 @@ public class ItemListSwitchItem: ListViewItem, ItemListItem {
}
}
private protocol ItemListSwitchNodeImpl {
protocol ItemListSwitchNodeImpl {
var frameColor: UIColor { get set }
var contentColor: UIColor { get set }
var handleColor: UIColor { get set }

View File

@ -14,12 +14,12 @@ public func mediaPasteboardScreen(
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
peer: EnginePeer,
subjects: [MediaPickerScreen.Subject.Media],
presentMediaPicker: @escaping (_ subject: MediaPickerScreen.Subject, _ saveEditedPhotos: Bool, _ bannedSendMedia: (Int32, Bool)?, _ present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void) -> Void,
presentMediaPicker: @escaping (_ subject: MediaPickerScreen.Subject, _ saveEditedPhotos: Bool, _ bannedSendPhotos: (Int32, Bool)?, _ bannedSendVideos: (Int32, Bool)?, _ present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void) -> Void,
getSourceRect: (() -> CGRect?)? = nil
) -> ViewController {
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: peer.id), buttons: [.standalone], initialButton: .standalone)
controller.requestController = { _, present in
presentMediaPicker(.media(subjects), false, nil, { mediaPicker, mediaPickerContext in
presentMediaPicker(.media(subjects), false, nil, nil, { mediaPicker, mediaPickerContext in
present(mediaPicker, mediaPickerContext)
})
}

View File

@ -141,7 +141,8 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private let peer: EnginePeer?
private let threadTitle: String?
private let chatLocation: ChatLocation?
private let bannedSendMedia: (Int32, Bool)?
private let bannedSendPhotos: (Int32, Bool)?
private let bannedSendVideos: (Int32, Bool)?
private let subject: Subject
private let saveEditedPhotos: Bool
@ -945,7 +946,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
if cameraAccess == nil {
cameraRect = nil
}
if let (untilDate, personal) = self.controller?.bannedSendMedia {
/*if let (untilDate, personal) = self.controller?.bannedSendMedia {
self.gridNode.isHidden = true
let banDescription: String
@ -972,8 +973,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
placeholderTransition.updateFrame(node: placeholderNode, frame: innerBounds)
self.updateNavigation(transition: .immediate)
} else if case .notDetermined = mediaAccess {
} else */if case .notDetermined = mediaAccess {
} else {
if case .limited = mediaAccess {
let manageNode: MediaPickerManageNode
@ -1099,7 +1099,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
placeholderNode.update(layout: layout, theme: self.presentationData.theme, strings: self.presentationData.strings, hasCamera: cameraAccess == .authorized, transition: placeholderTransition)
placeholderTransition.updateFrame(node: placeholderNode, frame: innerBounds)
} else if let placeholderNode = self.placeholderNode, self.controller?.bannedSendMedia == nil {
} else if let placeholderNode = self.placeholderNode {//, self.controller?.bannedSendMedia == nil {
self.placeholderNode = nil
placeholderNode.removeFromSupernode()
}
@ -1131,7 +1131,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private var isDismissing = false
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, bannedSendMedia: (Int32, Bool)?, subject: Subject, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil, saveEditedPhotos: Bool = false) {
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, subject: Subject, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil, saveEditedPhotos: Bool = false) {
self.context = context
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
@ -1140,7 +1140,8 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.peer = peer
self.threadTitle = threadTitle
self.chatLocation = chatLocation
self.bannedSendMedia = bannedSendMedia
self.bannedSendPhotos = bannedSendPhotos
self.bannedSendVideos = bannedSendVideos
self.subject = subject
self.saveEditedPhotos = saveEditedPhotos
@ -1495,7 +1496,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.requestAttachmentMenuExpansion()
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
if let strongSelf = self {
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendMedia: strongSelf.bannedSendMedia, subject: .assets(collection), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker

View File

@ -33,8 +33,9 @@ private final class ChannelPermissionsControllerArguments {
let presentConversionToBroadcastGroup: () -> Void
let openChannelExample: () -> Void
let updateSlowmode: (Int32) -> Void
let toggleIsOptionExpanded: (TelegramChatBannedRightsFlags) -> Void
init(context: AccountContext, updatePermission: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addPeer: @escaping () -> Void, removePeer: @escaping (PeerId) -> Void, openPeer: @escaping (ChannelParticipant) -> Void, openPeerInfo: @escaping (Peer) -> Void, openKicked: @escaping () -> Void, presentRestrictedPermissionAlert: @escaping (TelegramChatBannedRightsFlags) -> Void, presentConversionToBroadcastGroup: @escaping () -> Void, openChannelExample: @escaping () -> Void, updateSlowmode: @escaping (Int32) -> Void) {
init(context: AccountContext, updatePermission: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addPeer: @escaping () -> Void, removePeer: @escaping (PeerId) -> Void, openPeer: @escaping (ChannelParticipant) -> Void, openPeerInfo: @escaping (Peer) -> Void, openKicked: @escaping () -> Void, presentRestrictedPermissionAlert: @escaping (TelegramChatBannedRightsFlags) -> Void, presentConversionToBroadcastGroup: @escaping () -> Void, openChannelExample: @escaping () -> Void, updateSlowmode: @escaping (Int32) -> Void, toggleIsOptionExpanded: @escaping (TelegramChatBannedRightsFlags) -> Void) {
self.context = context
self.updatePermission = updatePermission
self.addPeer = addPeer
@ -47,6 +48,7 @@ private final class ChannelPermissionsControllerArguments {
self.presentConversionToBroadcastGroup = presentConversionToBroadcastGroup
self.openChannelExample = openChannelExample
self.updateSlowmode = updateSlowmode
self.toggleIsOptionExpanded = toggleIsOptionExpanded
}
}
@ -63,9 +65,15 @@ private enum ChannelPermissionsEntryStableId: Hashable {
case peer(PeerId)
}
private struct SubPermission: Equatable {
var title: String
var flags: TelegramChatBannedRightsFlags
var isSelected: Bool
}
private enum ChannelPermissionsEntry: ItemListNodeEntry {
case permissionsHeader(PresentationTheme, String)
case permission(PresentationTheme, Int, String, Bool, TelegramChatBannedRightsFlags, Bool?)
case permission(PresentationTheme, Int, String, Bool, TelegramChatBannedRightsFlags, Bool?, [SubPermission], Bool)
case slowmodeHeader(PresentationTheme, String)
case slowmode(PresentationTheme, PresentationStrings, Int32)
case slowmodeInfo(PresentationTheme, String)
@ -96,7 +104,7 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry {
switch self {
case .permissionsHeader:
return .index(0)
case let .permission(_, index, _, _, _, _):
case let .permission(_, index, _, _, _, _, _, _):
return .index(1 + index)
case .conversionHeader:
return .index(998)
@ -129,8 +137,8 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry {
} else {
return false
}
case let .permission(theme, index, title, value, rights, enabled):
if case .permission(theme, index, title, value, rights, enabled) = rhs {
case let .permission(theme, index, title, value, rights, enabled, subPermissions, isExpanded):
if case .permission(theme, index, title, value, rights, enabled, subPermissions, isExpanded) = rhs {
return true
} else {
return false
@ -256,16 +264,47 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry {
switch self {
case let .permissionsHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .permission(_, _, title, value, rights, enabled):
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, type: .icon, enableInteractiveChanges: enabled != nil, enabled: enabled ?? true, sectionId: self.section, style: .blocks, updated: { value in
if let _ = enabled {
arguments.updatePermission(rights, value)
} else {
case let .permission(_, _, title, value, rights, enabled, subPermissions, isExpanded):
if !subPermissions.isEmpty {
return ItemListExpandableSwitchItem(presentationData: presentationData, title: title, value: value, isExpanded: isExpanded, subItems: subPermissions.map { item in
return ItemListExpandableSwitchItem.SubItem(
id: AnyHashable(item.flags.rawValue),
title: item.title,
isSelected: item.isSelected
)
}, type: .icon, enableInteractiveChanges: enabled != nil, enabled: enabled ?? true, sectionId: self.section, style: .blocks, updated: { value in
if let _ = enabled {
arguments.updatePermission(rights, value)
} else {
arguments.presentRestrictedPermissionAlert(rights)
}
}, activatedWhileDisabled: {
arguments.presentRestrictedPermissionAlert(rights)
}
}, activatedWhileDisabled: {
arguments.presentRestrictedPermissionAlert(rights)
})
}, selectAction: {
arguments.toggleIsOptionExpanded(rights)
}, subAction: { item in
guard let value = item.id.base as? Int32 else {
return
}
let subRights = TelegramChatBannedRightsFlags(rawValue: value)
if let _ = enabled {
arguments.updatePermission(subRights, !item.isSelected)
} else {
arguments.presentRestrictedPermissionAlert(subRights)
}
})
} else {
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, type: .icon, enableInteractiveChanges: enabled != nil, enabled: enabled ?? true, sectionId: self.section, style: .blocks, updated: { value in
if let _ = enabled {
arguments.updatePermission(rights, value)
} else {
arguments.presentRestrictedPermissionAlert(rights)
}
}, activatedWhileDisabled: {
arguments.presentRestrictedPermissionAlert(rights)
})
}
case let .slowmodeHeader(_, value):
return ItemListSectionHeaderItem(presentationData: presentationData, text: value, sectionId: self.section)
case let .slowmode(theme, strings, value):
@ -334,9 +373,11 @@ private struct ChannelPermissionsControllerState: Equatable {
var searchingMembers: Bool = false
var modifiedRightsFlags: TelegramChatBannedRightsFlags?
var modifiedSlowmodeTimeout: Int32?
var expandedPermissions = Set<TelegramChatBannedRightsFlags>()
}
func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags, isForum: Bool) -> String {
//TODO:localize
if right.contains(.banSendMessages) {
return strings.Channel_BanUser_PermissionSendMessages
} else if right.contains(.banSendMedia) {
@ -355,6 +396,20 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB
return strings.Channel_EditAdmin_PermissionPinMessages
} else if right.contains(.banManageTopics) {
return strings.Channel_EditAdmin_PermissionCreateTopics
} else if right.contains(.banSendPhotos) {
return "Send Photos"
} else if right.contains(.banSendVideos) {
return "Send Videos"
} else if right.contains(.banSendStickers) {
return strings.Channel_BanUser_PermissionSendStickersAndGifs
} else if right.contains(.banSendMusic) {
return "Send Music"
} else if right.contains(.banSendFiles) {
return "Send Files"
} else if right.contains(.banSendVoice) {
return "Send Voice Messages"
} else if right.contains(.banSendInstantVideos) {
return "Send Video Messages"
} else {
return ""
}
@ -387,7 +442,13 @@ func compactStringForGroupPermission(strings: PresentationStrings, right: Telegr
private let internal_allPossibleGroupPermissionList: [(TelegramChatBannedRightsFlags, TelegramChannelPermission)] = [
(.banSendMessages, .banMembers),
(.banSendMedia, .banMembers),
(.banSendPhotos, .banMembers),
(.banSendVideos, .banMembers),
(.banSendGifs, .banMembers),
(.banSendMusic, .banMembers),
(.banSendFiles, .banMembers),
(.banSendVoice, .banMembers),
(.banSendInstantVideos, .banMembers),
(.banEmbedLinks, .banMembers),
(.banSendPolls, .banMembers),
(.banAddMembers, .banMembers),
@ -401,8 +462,6 @@ public func allGroupPermissionList(peer: EnginePeer) -> [(TelegramChatBannedRigh
return [
(.banSendMessages, .banMembers),
(.banSendMedia, .banMembers),
(.banSendGifs, .banMembers),
(.banEmbedLinks, .banMembers),
(.banSendPolls, .banMembers),
(.banAddMembers, .banMembers),
(.banPinMessages, .pinMessages),
@ -413,8 +472,6 @@ public func allGroupPermissionList(peer: EnginePeer) -> [(TelegramChatBannedRigh
return [
(.banSendMessages, .banMembers),
(.banSendMedia, .banMembers),
(.banSendGifs, .banMembers),
(.banEmbedLinks, .banMembers),
(.banSendPolls, .banMembers),
(.banAddMembers, .banMembers),
(.banPinMessages, .pinMessages),
@ -422,6 +479,19 @@ public func allGroupPermissionList(peer: EnginePeer) -> [(TelegramChatBannedRigh
]
}
}
public func banSendMediaSubList() -> [(TelegramChatBannedRightsFlags, TelegramChannelPermission)] {
return [
(.banSendPhotos, .banMembers),
(.banSendVideos, .banMembers),
(.banSendGifs, .banMembers),
(.banSendMusic, .banMembers),
(.banSendFiles, .banMembers),
(.banSendVoice, .banMembers),
(.banSendInstantVideos, .banMembers),
(.banEmbedLinks, .banMembers),
]
}
let publicGroupRestrictedPermissions: TelegramChatBannedRightsFlags = [
.banPinMessages,
@ -429,7 +499,7 @@ let publicGroupRestrictedPermissions: TelegramChatBannedRightsFlags = [
]
func groupPermissionDependencies(_ right: TelegramChatBannedRightsFlags) -> TelegramChatBannedRightsFlags {
if right.contains(.banSendMedia) {
if right.contains(.banSendMedia) || banSendMediaSubList().contains(where: { $0.0 == right }) {
return [.banSendMessages]
} else if right.contains(.banSendGifs) {
return [.banSendMessages]
@ -476,7 +546,18 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
if !channel.hasPermission(correspondingAdminRight) {
enabled = false
}
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: channel.flags.contains(.isForum)), !effectiveRightsFlags.contains(rights), rights, enabled))
var isSelected = !effectiveRightsFlags.contains(rights)
var subItems: [SubPermission] = []
if rights == .banSendMedia {
isSelected = banSendMediaSubList().allSatisfy({ !effectiveRightsFlags.contains($0.0) })
for (subRight, _) in banSendMediaSubList() {
subItems.append(SubPermission(title: stringForGroupPermission(strings: presentationData.strings, right: subRight, isForum: channel.isForum), flags: subRight, isSelected: !effectiveRightsFlags.contains(subRight)))
}
}
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: channel.flags.contains(.isForum)), isSelected, rights, enabled, subItems, state.expandedPermissions.contains(rights)))
rightIndex += 1
}
@ -513,7 +594,14 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
entries.append(.permissionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_SectionTitle))
var rightIndex: Int = 0
for (rights, _) in allGroupPermissionList(peer: .legacyGroup(group)) {
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: false), !effectiveRightsFlags.contains(rights), rights, true))
var subItems: [SubPermission] = []
if rights == .banSendMedia {
for (subRight, _) in banSendMediaSubList() {
subItems.append(SubPermission(title: stringForGroupPermission(strings: presentationData.strings, right: subRight, isForum: false), flags: subRight, isSelected: !effectiveRightsFlags.contains(subRight)))
}
}
entries.append(.permission(presentationData.theme, rightIndex, stringForGroupPermission(strings: presentationData.strings, right: rights, isForum: false), !effectiveRightsFlags.contains(rights), rights, true, subItems, state.expandedPermissions.contains(rights)))
rightIndex += 1
}
@ -611,16 +699,47 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
} else {
effectiveRightsFlags = TelegramChatBannedRightsFlags()
}
if value {
effectiveRightsFlags.remove(rights)
effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights))
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: .channel(channel)) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
if rights == .banSendMedia {
if value {
effectiveRightsFlags.remove(rights)
for item in banSendMediaSubList() {
effectiveRightsFlags.remove(item.0)
}
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: .channel(channel)) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
}
}
for item in banSendMediaSubList() {
effectiveRightsFlags.insert(item.0)
for (right, _) in allGroupPermissionList(peer: .channel(channel)) {
if groupPermissionDependencies(right).contains(item.0) {
effectiveRightsFlags.insert(right)
}
}
}
}
} else {
if value {
effectiveRightsFlags.remove(rights)
effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights))
} else {
effectiveRightsFlags.insert(rights)
for (right, _) in allGroupPermissionList(peer: .channel(channel)) {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
}
}
}
}
if banSendMediaSubList().allSatisfy({ !effectiveRightsFlags.contains($0.0) }) {
effectiveRightsFlags.remove(.banSendMedia)
} else {
effectiveRightsFlags.insert(.banSendMedia)
}
state.modifiedRightsFlags = effectiveRightsFlags
return state
@ -868,6 +987,16 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
}))
}
})
}, toggleIsOptionExpanded: { flags in
updateState { state in
var state = state
if state.expandedPermissions.contains(flags) {
state.expandedPermissions.remove(flags)
} else {
state.expandedPermissions.insert(flags)
}
return state
}
})
let previousParticipants = Atomic<[RenderedChannelParticipant]?>(value: nil)
@ -889,6 +1018,8 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
return .single((view, peers.1))
}
let previousExpandedPermissionsValue = Atomic<Set<TelegramChatBannedRightsFlags>?>(value: nil)
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest(queue: .mainQueue(), presentationData, statePromise.get(), viewAndParticipants)
|> deliverOnMainQueue
@ -912,6 +1043,7 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
}
let previous = previousParticipants.swap(participants)
let previousExpandedPermissions = previousExpandedPermissionsValue.swap(state.expandedPermissions)
var searchItem: ItemListControllerSearch?
if state.searchingMembers {
@ -940,8 +1072,13 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
})
}
var animateChanges = previous != nil && participants != nil && previous!.count >= participants!.count
if let previousExpandedPermissions, previousExpandedPermissions != state.expandedPermissions {
animateChanges = true
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.GroupInfo_Permissions_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelPermissionsControllerEntries(context: context, presentationData: presentationData, view: view, state: state, participants: participants), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, animateChanges: previous != nil && participants != nil && previous!.count >= participants!.count)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelPermissionsControllerEntries(context: context, presentationData: presentationData, view: view, state: state, participants: participants), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, animateChanges: animateChanges)
return (controllerState, (listState, arguments))
}

View File

@ -76,8 +76,8 @@ public enum DataAndStorageEntryTag: ItemListItemTag {
}
private enum DataAndStorageEntry: ItemListNodeEntry {
case storageUsage(PresentationTheme, String)
case networkUsage(PresentationTheme, String)
case storageUsage(PresentationTheme, String, String)
case networkUsage(PresentationTheme, String, String)
case automaticDownloadHeader(PresentationTheme, String)
case automaticDownloadCellular(PresentationTheme, String, String)
case automaticDownloadWifi(PresentationTheme, String, String)
@ -170,14 +170,14 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
static func ==(lhs: DataAndStorageEntry, rhs: DataAndStorageEntry) -> Bool {
switch lhs {
case let .storageUsage(lhsTheme, lhsText):
if case let .storageUsage(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
case let .storageUsage(lhsTheme, lhsText, lhsValue):
if case let .storageUsage(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .networkUsage(lhsTheme, lhsText):
if case let .networkUsage(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
case let .networkUsage(lhsTheme, lhsText, lhsValue):
if case let .networkUsage(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
@ -306,12 +306,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! DataAndStorageControllerArguments
switch self {
case let .storageUsage(_, text):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Storage")?.precomposed(), title: text, label: "", sectionId: self.section, style: .blocks, action: {
case let .storageUsage(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Storage")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openStorageUsage()
})
case let .networkUsage(_, text):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Network")?.precomposed(), title: text, label: "", sectionId: self.section, style: .blocks, action: {
case let .networkUsage(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Network")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openNetworkUsage()
})
case let .automaticDownloadHeader(_, text):
@ -478,11 +478,11 @@ private func stringForAutoDownloadSetting(strings: PresentationStrings, decimalS
}
}
private func dataAndStorageControllerEntries(state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData, defaultWebBrowser: String, contentSettingsConfiguration: ContentSettingsConfiguration?) -> [DataAndStorageEntry] {
private func dataAndStorageControllerEntries(state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData, defaultWebBrowser: String, contentSettingsConfiguration: ContentSettingsConfiguration?, networkUsage: Int64, storageUsage: Int64) -> [DataAndStorageEntry] {
var entries: [DataAndStorageEntry] = []
entries.append(.storageUsage(presentationData.theme, presentationData.strings.ChatSettings_Cache))
entries.append(.networkUsage(presentationData.theme, presentationData.strings.NetworkUsageSettings_Title))
entries.append(.storageUsage(presentationData.theme, presentationData.strings.ChatSettings_Cache, dataSizeString(storageUsage, formatting: DataSizeStringFormatting(presentationData: presentationData))))
entries.append(.networkUsage(presentationData.theme, presentationData.strings.NetworkUsageSettings_Title, dataSizeString(networkUsage, formatting: DataSizeStringFormatting(presentationData: presentationData))))
entries.append(.automaticDownloadHeader(presentationData.theme, presentationData.strings.ChatSettings_AutoDownloadTitle.uppercased()))
entries.append(.automaticDownloadCellular(presentationData.theme, presentationData.strings.ChatSettings_AutoDownloadUsingCellular, stringForAutoDownloadSetting(strings: presentationData.strings, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator, settings: data.automaticMediaDownloadSettings, connectionType: .cellular)))
@ -554,6 +554,67 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
contentSettingsConfiguration.set(.single(nil)
|> then(updatedContentSettingsConfiguration))
struct UsageData: Equatable {
var network: Int64
var storage: Int64
}
let usageSignal: Signal<UsageData, NoError> = combineLatest(
context.account.postbox.mediaBox.storageBox.totalSize(),
context.account.postbox.mediaBox.cacheStorageBox.totalSize(),
accountNetworkUsageStats(account: context.account, reset: [])
)
|> map { disk1, disk2, networkStats -> UsageData in
var network: Int64 = 0
var keys: [KeyPath<NetworkUsageStats, Int64>] = []
keys.append(\.generic.cellular.outgoing)
keys.append(\.generic.cellular.incoming)
keys.append(\.generic.wifi.incoming)
keys.append(\.generic.wifi.outgoing)
keys.append(\.image.cellular.outgoing)
keys.append(\.image.cellular.incoming)
keys.append(\.image.wifi.incoming)
keys.append(\.image.wifi.outgoing)
keys.append(\.video.cellular.outgoing)
keys.append(\.video.cellular.incoming)
keys.append(\.video.wifi.incoming)
keys.append(\.video.wifi.outgoing)
keys.append(\.audio.cellular.outgoing)
keys.append(\.audio.cellular.incoming)
keys.append(\.audio.wifi.incoming)
keys.append(\.audio.wifi.outgoing)
keys.append(\.file.cellular.outgoing)
keys.append(\.file.cellular.incoming)
keys.append(\.file.wifi.incoming)
keys.append(\.file.wifi.outgoing)
keys.append(\.call.cellular.outgoing)
keys.append(\.call.cellular.incoming)
keys.append(\.call.wifi.incoming)
keys.append(\.call.wifi.outgoing)
keys.append(\.sticker.cellular.outgoing)
keys.append(\.sticker.cellular.incoming)
keys.append(\.sticker.wifi.incoming)
keys.append(\.sticker.wifi.outgoing)
keys.append(\.voiceMessage.cellular.outgoing)
keys.append(\.voiceMessage.cellular.incoming)
keys.append(\.voiceMessage.wifi.incoming)
keys.append(\.voiceMessage.wifi.outgoing)
for key in keys {
network += networkStats[keyPath: key]
}
return UsageData(network: network, storage: disk1 + disk2)
}
let dataAndStorageDataPromise = Promise<DataAndStorageData>()
dataAndStorageDataPromise.set(context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings, ApplicationSpecificSharedDataKeys.voiceCallSettings, SharedDataKeys.proxySettings])
|> map { sharedData -> DataAndStorageData in
@ -599,7 +660,13 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
return storageUsageExceptionsScreen(context: context, category: category)
}))
}, openNetworkUsage: {
pushControllerImpl?(networkUsageStatsController(context: context))
//pushControllerImpl?(networkUsageStatsController(context: context))
let _ = (accountNetworkUsageStats(account: context.account, reset: [])
|> take(1)
|> deliverOnMainQueue).start(next: { stats in
pushControllerImpl?(DataUsageScreen(context: context, stats: stats))
})
}, openProxy: {
pushControllerImpl?(proxySettingsController(context: context))
}, openAutomaticDownloadConnectionType: { connectionType in
@ -679,9 +746,10 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
statePromise.get(),
dataAndStorageDataPromise.get(),
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings]),
contentSettingsConfiguration.get()
contentSettingsConfiguration.get(),
usageSignal
)
|> map { presentationData, state, dataAndStorageData, sharedData, contentSettingsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
|> map { presentationData, state, dataAndStorageData, sharedData, contentSettingsConfiguration, usageSignal -> (ItemListControllerState, (ItemListNodeState, Any)) in
let webBrowserSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) ?? WebBrowserSettings.defaultSettings
let options = availableOpenInOptions(context: context, item: .url(url: "https://telegram.org"))
let defaultWebBrowser: String
@ -692,7 +760,7 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChatSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: dataAndStorageControllerEntries(state: state, data: dataAndStorageData, presentationData: presentationData, defaultWebBrowser: defaultWebBrowser, contentSettingsConfiguration: contentSettingsConfiguration), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: dataAndStorageControllerEntries(state: state, data: dataAndStorageData, presentationData: presentationData, defaultWebBrowser: defaultWebBrowser, contentSettingsConfiguration: contentSettingsConfiguration, networkUsage: usageSignal.network, storageUsage: usageSignal.storage), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: false)
return (controllerState, (listState, arguments))
} |> afterDisposed {

View File

@ -123,7 +123,13 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
self.animationNode = animationNode
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 400.0, height: 400.0))
let fitSize: CGSize
if item.file.isCustomEmoji {
fitSize = CGSize(width: 200.0, height: 200.0)
} else {
fitSize = CGSize(width: 400.0, height: 400.0)
}
let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize)
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: isPremiumSticker ? .once : .loop, mode: .direct(cachePathPrefix: nil))
animationNode.visibility = true
@ -197,7 +203,9 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let boundingSize: CGSize
if let _ = self.additionalAnimationNode {
if self.item.file.isCustomEmoji {
boundingSize = CGSize(width: 120.0, height: 120.0)
} else if let _ = self.additionalAnimationNode {
boundingSize = CGSize(width: 240.0, height: 240.0).fitted(size)
} else {
boundingSize = CGSize(width: 180.0, height: 180.0).fitted(size)
@ -239,7 +247,11 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
self.textNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - textSize.width) / 2.0) - centerOffset, y: -textSize.height - textSpacing), size: textSize)
return CGSize(width: size.width, height: imageFrame.height + textSize.height + textSpacing)
if self.item.file.isCustomEmoji {
return CGSize(width: size.width, height: imageFrame.height)
} else {
return CGSize(width: size.width, height: imageFrame.height + textSize.height + textSpacing)
}
} else {
return CGSize(width: size.width, height: 10.0)
}

View File

@ -939,7 +939,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-842824308] = { return Api.account.WallPapers.parse_wallPapers($0) }
dict[471437699] = { return Api.account.WallPapers.parse_wallPapersNotModified($0) }
dict[-313079300] = { return Api.account.WebAuthorizations.parse_webAuthorizations($0) }
dict[872119224] = { return Api.auth.Authorization.parse_authorization($0) }
dict[782418132] = { return Api.auth.Authorization.parse_authorization($0) }
dict[1148485274] = { return Api.auth.Authorization.parse_authorizationSignUpRequired($0) }
dict[1948046307] = { return Api.auth.CodeType.parse_codeTypeCall($0) }
dict[577556219] = { return Api.auth.CodeType.parse_codeTypeFlashCall($0) }
@ -953,6 +953,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[957176926] = { return Api.auth.LoginToken.parse_loginTokenSuccess($0) }
dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) }
dict[1577067778] = { return Api.auth.SentCode.parse_sentCode($0) }
dict[596704836] = { return Api.auth.SentCode.parse_sentCodeSuccess($0) }
dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) }
dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) }
dict[1511364673] = { return Api.auth.SentCodeType.parse_sentCodeTypeEmailCode($0) }

View File

@ -1176,18 +1176,19 @@ public extension Api.account {
}
public extension Api.auth {
enum Authorization: TypeConstructorDescription {
case authorization(flags: Int32, otherwiseReloginDays: Int32?, tmpSessions: Int32?, user: Api.User)
case authorization(flags: Int32, otherwiseReloginDays: Int32?, tmpSessions: Int32?, futureAuthToken: Buffer?, user: Api.User)
case authorizationSignUpRequired(flags: Int32, termsOfService: Api.help.TermsOfService?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .authorization(let flags, let otherwiseReloginDays, let tmpSessions, let user):
case .authorization(let flags, let otherwiseReloginDays, let tmpSessions, let futureAuthToken, let user):
if boxed {
buffer.appendInt32(872119224)
buffer.appendInt32(782418132)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(otherwiseReloginDays!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(tmpSessions!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)}
user.serialize(buffer, true)
break
case .authorizationSignUpRequired(let flags, let termsOfService):
@ -1202,8 +1203,8 @@ public extension Api.auth {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .authorization(let flags, let otherwiseReloginDays, let tmpSessions, let user):
return ("authorization", [("flags", flags as Any), ("otherwiseReloginDays", otherwiseReloginDays as Any), ("tmpSessions", tmpSessions as Any), ("user", user as Any)])
case .authorization(let flags, let otherwiseReloginDays, let tmpSessions, let futureAuthToken, let user):
return ("authorization", [("flags", flags as Any), ("otherwiseReloginDays", otherwiseReloginDays as Any), ("tmpSessions", tmpSessions as Any), ("futureAuthToken", futureAuthToken as Any), ("user", user as Any)])
case .authorizationSignUpRequired(let flags, let termsOfService):
return ("authorizationSignUpRequired", [("flags", flags as Any), ("termsOfService", termsOfService as Any)])
}
@ -1216,16 +1217,19 @@ public extension Api.auth {
if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() }
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Api.User?
var _4: Buffer?
if Int(_1!) & Int(1 << 2) != 0 {_4 = parseBytes(reader) }
var _5: Api.User?
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.User
_5 = Api.parse(reader, signature: signature) as? Api.User
}
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.auth.Authorization.authorization(flags: _1!, otherwiseReloginDays: _2, tmpSessions: _3, user: _4!)
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.auth.Authorization.authorization(flags: _1!, otherwiseReloginDays: _2, tmpSessions: _3, futureAuthToken: _4, user: _5!)
}
else {
return nil

View File

@ -279,6 +279,7 @@ public extension Api.auth {
public extension Api.auth {
enum SentCode: TypeConstructorDescription {
case sentCode(flags: Int32, type: Api.auth.SentCodeType, phoneCodeHash: String, nextType: Api.auth.CodeType?, timeout: Int32?)
case sentCodeSuccess(authorization: Api.auth.Authorization)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -292,6 +293,12 @@ public extension Api.auth {
if Int(flags) & Int(1 << 1) != 0 {nextType!.serialize(buffer, true)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)}
break
case .sentCodeSuccess(let authorization):
if boxed {
buffer.appendInt32(596704836)
}
authorization.serialize(buffer, true)
break
}
}
@ -299,6 +306,8 @@ public extension Api.auth {
switch self {
case .sentCode(let flags, let type, let phoneCodeHash, let nextType, let timeout):
return ("sentCode", [("flags", flags as Any), ("type", type as Any), ("phoneCodeHash", phoneCodeHash as Any), ("nextType", nextType as Any), ("timeout", timeout as Any)])
case .sentCodeSuccess(let authorization):
return ("sentCodeSuccess", [("authorization", authorization as Any)])
}
}
@ -329,6 +338,19 @@ public extension Api.auth {
return nil
}
}
public static func parse_sentCodeSuccess(_ reader: BufferReader) -> SentCode? {
var _1: Api.auth.Authorization?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.auth.Authorization
}
let _c1 = _1 != nil
if _c1 {
return Api.auth.SentCode.sentCodeSuccess(authorization: _1!)
}
else {
return nil
}
}
}
}
@ -1112,61 +1134,3 @@ public extension Api.contacts {
}
}
public extension Api.contacts {
enum ResolvedPeer: TypeConstructorDescription {
case resolvedPeer(peer: Api.Peer, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .resolvedPeer(let peer, let chats, let users):
if boxed {
buffer.appendInt32(2131196633)
}
peer.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .resolvedPeer(let peer, let chats, let users):
return ("resolvedPeer", [("peer", peer as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_resolvedPeer(_ reader: BufferReader) -> ResolvedPeer? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.contacts.ResolvedPeer.resolvedPeer(peer: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,61 @@
public extension Api.contacts {
enum ResolvedPeer: TypeConstructorDescription {
case resolvedPeer(peer: Api.Peer, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .resolvedPeer(let peer, let chats, let users):
if boxed {
buffer.appendInt32(2131196633)
}
peer.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .resolvedPeer(let peer, let chats, let users):
return ("resolvedPeer", [("peer", peer as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_resolvedPeer(_ reader: BufferReader) -> ResolvedPeer? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.contacts.ResolvedPeer.resolvedPeer(peer: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
}
}
public extension Api.contacts {
enum TopPeers: TypeConstructorDescription {
case topPeers(categories: [Api.TopPeerCategoryPeers], chats: [Api.Chat], users: [Api.User])
@ -1248,61 +1306,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum AvailableReactions: TypeConstructorDescription {
case availableReactions(hash: Int32, reactions: [Api.AvailableReaction])
case availableReactionsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .availableReactions(let hash, let reactions):
if boxed {
buffer.appendInt32(1989032621)
}
serializeInt32(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(reactions.count))
for item in reactions {
item.serialize(buffer, true)
}
break
case .availableReactionsNotModified:
if boxed {
buffer.appendInt32(-1626924713)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .availableReactions(let hash, let reactions):
return ("availableReactions", [("hash", hash as Any), ("reactions", reactions as Any)])
case .availableReactionsNotModified:
return ("availableReactionsNotModified", [])
}
}
public static func parse_availableReactions(_ reader: BufferReader) -> AvailableReactions? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.AvailableReaction]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AvailableReaction.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.AvailableReactions.availableReactions(hash: _1!, reactions: _2!)
}
else {
return nil
}
}
public static func parse_availableReactionsNotModified(_ reader: BufferReader) -> AvailableReactions? {
return Api.messages.AvailableReactions.availableReactionsNotModified
}
}
}

View File

@ -1,3 +1,61 @@
public extension Api.messages {
enum AvailableReactions: TypeConstructorDescription {
case availableReactions(hash: Int32, reactions: [Api.AvailableReaction])
case availableReactionsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .availableReactions(let hash, let reactions):
if boxed {
buffer.appendInt32(1989032621)
}
serializeInt32(hash, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(reactions.count))
for item in reactions {
item.serialize(buffer, true)
}
break
case .availableReactionsNotModified:
if boxed {
buffer.appendInt32(-1626924713)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .availableReactions(let hash, let reactions):
return ("availableReactions", [("hash", hash as Any), ("reactions", reactions as Any)])
case .availableReactionsNotModified:
return ("availableReactionsNotModified", [])
}
}
public static func parse_availableReactions(_ reader: BufferReader) -> AvailableReactions? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.AvailableReaction]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AvailableReaction.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.AvailableReactions.availableReactions(hash: _1!, reactions: _2!)
}
else {
return nil
}
}
public static func parse_availableReactionsNotModified(_ reader: BufferReader) -> AvailableReactions? {
return Api.messages.AvailableReactions.availableReactionsNotModified
}
}
}
public extension Api.messages {
enum BotCallbackAnswer: TypeConstructorDescription {
case botCallbackAnswer(flags: Int32, message: String?, url: String?, cacheTime: Int32)
@ -1432,281 +1490,3 @@ public extension Api.messages {
}
}
public extension Api.messages {
enum MessageViews: TypeConstructorDescription {
case messageViews(views: [Api.MessageViews], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageViews(let views, let chats, let users):
if boxed {
buffer.appendInt32(-1228606141)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageViews(let views, let chats, let users):
return ("messageViews", [("views", views as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_messageViews(_ reader: BufferReader) -> MessageViews? {
var _1: [Api.MessageViews]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageViews.self)
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.MessageViews.messageViews(views: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum Messages: TypeConstructorDescription {
case channelMessages(flags: Int32, pts: Int32, count: Int32, offsetIdOffset: Int32?, messages: [Api.Message], topics: [Api.ForumTopic], chats: [Api.Chat], users: [Api.User])
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case messagesNotModified(count: Int32)
case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, offsetIdOffset: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
if boxed {
buffer.appendInt32(-948520370)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(pts, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(topics.count))
for item in topics {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
case .messages(let messages, let chats, let users):
if boxed {
buffer.appendInt32(-1938715001)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
case .messagesNotModified(let count):
if boxed {
buffer.appendInt32(1951620897)
}
serializeInt32(count, buffer: buffer, boxed: false)
break
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
if boxed {
buffer.appendInt32(978610270)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextRate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
return ("channelMessages", [("flags", flags as Any), ("pts", pts as Any), ("count", count as Any), ("offsetIdOffset", offsetIdOffset as Any), ("messages", messages as Any), ("topics", topics as Any), ("chats", chats as Any), ("users", users as Any)])
case .messages(let messages, let chats, let users):
return ("messages", [("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
case .messagesNotModified(let count):
return ("messagesNotModified", [("count", count as Any)])
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
return ("messagesSlice", [("flags", flags as Any), ("count", count as Any), ("nextRate", nextRate as Any), ("offsetIdOffset", offsetIdOffset as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_channelMessages(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: [Api.Message]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.ForumTopic]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
}
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _8: [Api.User]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.messages.Messages.channelMessages(flags: _1!, pts: _2!, count: _3!, offsetIdOffset: _4, messages: _5!, topics: _6!, chats: _7!, users: _8!)
}
else {
return nil
}
}
public static func parse_messages(_ reader: BufferReader) -> Messages? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.Messages.messages(messages: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
public static func parse_messagesNotModified(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.messages.Messages.messagesNotModified(count: _1!)
}
else {
return nil
}
}
public static func parse_messagesSlice(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: [Api.Message]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.Chat]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _7: [Api.User]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.messages.Messages.messagesSlice(flags: _1!, count: _2!, nextRate: _3, offsetIdOffset: _4, messages: _5!, chats: _6!, users: _7!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,281 @@
public extension Api.messages {
enum MessageViews: TypeConstructorDescription {
case messageViews(views: [Api.MessageViews], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageViews(let views, let chats, let users):
if boxed {
buffer.appendInt32(-1228606141)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(views.count))
for item in views {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageViews(let views, let chats, let users):
return ("messageViews", [("views", views as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_messageViews(_ reader: BufferReader) -> MessageViews? {
var _1: [Api.MessageViews]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageViews.self)
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.MessageViews.messageViews(views: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum Messages: TypeConstructorDescription {
case channelMessages(flags: Int32, pts: Int32, count: Int32, offsetIdOffset: Int32?, messages: [Api.Message], topics: [Api.ForumTopic], chats: [Api.Chat], users: [Api.User])
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case messagesNotModified(count: Int32)
case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, offsetIdOffset: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
if boxed {
buffer.appendInt32(-948520370)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(pts, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(topics.count))
for item in topics {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
case .messages(let messages, let chats, let users):
if boxed {
buffer.appendInt32(-1938715001)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
case .messagesNotModified(let count):
if boxed {
buffer.appendInt32(1951620897)
}
serializeInt32(count, buffer: buffer, boxed: false)
break
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
if boxed {
buffer.appendInt32(978610270)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextRate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(messages.count))
for item in messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
return ("channelMessages", [("flags", flags as Any), ("pts", pts as Any), ("count", count as Any), ("offsetIdOffset", offsetIdOffset as Any), ("messages", messages as Any), ("topics", topics as Any), ("chats", chats as Any), ("users", users as Any)])
case .messages(let messages, let chats, let users):
return ("messages", [("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
case .messagesNotModified(let count):
return ("messagesNotModified", [("count", count as Any)])
case .messagesSlice(let flags, let count, let nextRate, let offsetIdOffset, let messages, let chats, let users):
return ("messagesSlice", [("flags", flags as Any), ("count", count as Any), ("nextRate", nextRate as Any), ("offsetIdOffset", offsetIdOffset as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
public static func parse_channelMessages(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: [Api.Message]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.ForumTopic]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
}
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _8: [Api.User]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.messages.Messages.channelMessages(flags: _1!, pts: _2!, count: _3!, offsetIdOffset: _4, messages: _5!, topics: _6!, chats: _7!, users: _8!)
}
else {
return nil
}
}
public static func parse_messages(_ reader: BufferReader) -> Messages? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.Chat]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.Messages.messages(messages: _1!, chats: _2!, users: _3!)
}
else {
return nil
}
}
public static func parse_messagesNotModified(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.messages.Messages.messagesNotModified(count: _1!)
}
else {
return nil
}
}
public static func parse_messagesSlice(_ reader: BufferReader) -> Messages? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() }
var _5: [Api.Message]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.Chat]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _7: [Api.User]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.messages.Messages.messagesSlice(flags: _1!, count: _2!, nextRate: _3, offsetIdOffset: _4, messages: _5!, chats: _6!, users: _7!)
}
else {
return nil
}
}
}
}
public extension Api.messages {
enum PeerDialogs: TypeConstructorDescription {
case peerDialogs(dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], state: Api.updates.State)
@ -1086,327 +1364,3 @@ public extension Api.payments {
}
}
public extension Api.payments {
enum PaymentForm: TypeConstructorDescription {
case paymentForm(flags: Int32, formId: Int64, botId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, providerId: Int64, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, additionalMethods: [Api.PaymentFormMethod]?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: [Api.PaymentSavedCredentials]?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentForm(let flags, let formId, let botId, let title, let description, let photo, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let additionalMethods, let savedInfo, let savedCredentials, let users):
if boxed {
buffer.appendInt32(-1610250415)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(formId, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 5) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
serializeInt64(providerId, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 4) != 0 {serializeString(nativeProvider!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {nativeParams!.serialize(buffer, true)}
if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(additionalMethods!.count))
for item in additionalMethods! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(savedCredentials!.count))
for item in savedCredentials! {
item.serialize(buffer, true)
}}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentForm(let flags, let formId, let botId, let title, let description, let photo, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let additionalMethods, let savedInfo, let savedCredentials, let users):
return ("paymentForm", [("flags", flags as Any), ("formId", formId as Any), ("botId", botId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("providerId", providerId as Any), ("url", url as Any), ("nativeProvider", nativeProvider as Any), ("nativeParams", nativeParams as Any), ("additionalMethods", additionalMethods as Any), ("savedInfo", savedInfo as Any), ("savedCredentials", savedCredentials as Any), ("users", users as Any)])
}
}
public static func parse_paymentForm(_ reader: BufferReader) -> PaymentForm? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int64?
_3 = reader.readInt64()
var _4: String?
_4 = parseString(reader)
var _5: String?
_5 = parseString(reader)
var _6: Api.WebDocument?
if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _7: Api.Invoice?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _8: Int64?
_8 = reader.readInt64()
var _9: String?
_9 = parseString(reader)
var _10: String?
if Int(_1!) & Int(1 << 4) != 0 {_10 = parseString(reader) }
var _11: Api.DataJSON?
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.DataJSON
} }
var _12: [Api.PaymentFormMethod]?
if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() {
_12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PaymentFormMethod.self)
} }
var _13: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_13 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
var _14: [Api.PaymentSavedCredentials]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PaymentSavedCredentials.self)
} }
var _15: [Api.User]?
if let _ = reader.readInt32() {
_15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 5) == 0) || _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
let _c10 = (Int(_1!) & Int(1 << 4) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 4) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 6) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 0) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 1) == 0) || _14 != nil
let _c15 = _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 {
return Api.payments.PaymentForm.paymentForm(flags: _1!, formId: _2!, botId: _3!, title: _4!, description: _5!, photo: _6, invoice: _7!, providerId: _8!, url: _9!, nativeProvider: _10, nativeParams: _11, additionalMethods: _12, savedInfo: _13, savedCredentials: _14, users: _15!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum PaymentReceipt: TypeConstructorDescription {
case paymentReceipt(flags: Int32, date: Int32, botId: Int64, providerId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, info: Api.PaymentRequestedInfo?, shipping: Api.ShippingOption?, tipAmount: Int64?, currency: String, totalAmount: Int64, credentialsTitle: String, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users):
if boxed {
buffer.appendInt32(1891958275)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false)
serializeInt64(providerId, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {info!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {shipping!.serialize(buffer, true)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(tipAmount!, buffer: buffer, boxed: false)}
serializeString(currency, buffer: buffer, boxed: false)
serializeInt64(totalAmount, buffer: buffer, boxed: false)
serializeString(credentialsTitle, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users):
return ("paymentReceipt", [("flags", flags as Any), ("date", date as Any), ("botId", botId as Any), ("providerId", providerId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("info", info as Any), ("shipping", shipping as Any), ("tipAmount", tipAmount as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("credentialsTitle", credentialsTitle as Any), ("users", users as Any)])
}
}
public static func parse_paymentReceipt(_ reader: BufferReader) -> PaymentReceipt? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int64?
_4 = reader.readInt64()
var _5: String?
_5 = parseString(reader)
var _6: String?
_6 = parseString(reader)
var _7: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _8: Api.Invoice?
if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _9: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_9 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
var _10: Api.ShippingOption?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_10 = Api.parse(reader, signature: signature) as? Api.ShippingOption
} }
var _11: Int64?
if Int(_1!) & Int(1 << 3) != 0 {_11 = reader.readInt64() }
var _12: String?
_12 = parseString(reader)
var _13: Int64?
_13 = reader.readInt64()
var _14: String?
_14 = parseString(reader)
var _15: [Api.User]?
if let _ = reader.readInt32() {
_15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 1) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil
let _c12 = _12 != nil
let _c13 = _13 != nil
let _c14 = _14 != nil
let _c15 = _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 {
return Api.payments.PaymentReceipt.paymentReceipt(flags: _1!, date: _2!, botId: _3!, providerId: _4!, title: _5!, description: _6!, photo: _7, invoice: _8!, info: _9, shipping: _10, tipAmount: _11, currency: _12!, totalAmount: _13!, credentialsTitle: _14!, users: _15!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
indirect enum PaymentResult: TypeConstructorDescription {
case paymentResult(updates: Api.Updates)
case paymentVerificationNeeded(url: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentResult(let updates):
if boxed {
buffer.appendInt32(1314881805)
}
updates.serialize(buffer, true)
break
case .paymentVerificationNeeded(let url):
if boxed {
buffer.appendInt32(-666824391)
}
serializeString(url, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentResult(let updates):
return ("paymentResult", [("updates", updates as Any)])
case .paymentVerificationNeeded(let url):
return ("paymentVerificationNeeded", [("url", url as Any)])
}
}
public static func parse_paymentResult(_ reader: BufferReader) -> PaymentResult? {
var _1: Api.Updates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Updates
}
let _c1 = _1 != nil
if _c1 {
return Api.payments.PaymentResult.paymentResult(updates: _1!)
}
else {
return nil
}
}
public static func parse_paymentVerificationNeeded(_ reader: BufferReader) -> PaymentResult? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.payments.PaymentResult.paymentVerificationNeeded(url: _1!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum SavedInfo: TypeConstructorDescription {
case savedInfo(flags: Int32, savedInfo: Api.PaymentRequestedInfo?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedInfo(let flags, let savedInfo):
if boxed {
buffer.appendInt32(-74456004)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedInfo(let flags, let savedInfo):
return ("savedInfo", [("flags", flags as Any), ("savedInfo", savedInfo as Any)])
}
}
public static func parse_savedInfo(_ reader: BufferReader) -> SavedInfo? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
if _c1 && _c2 {
return Api.payments.SavedInfo.savedInfo(flags: _1!, savedInfo: _2)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,327 @@
public extension Api.payments {
enum PaymentForm: TypeConstructorDescription {
case paymentForm(flags: Int32, formId: Int64, botId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, providerId: Int64, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, additionalMethods: [Api.PaymentFormMethod]?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: [Api.PaymentSavedCredentials]?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentForm(let flags, let formId, let botId, let title, let description, let photo, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let additionalMethods, let savedInfo, let savedCredentials, let users):
if boxed {
buffer.appendInt32(-1610250415)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(formId, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 5) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
serializeInt64(providerId, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 4) != 0 {serializeString(nativeProvider!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {nativeParams!.serialize(buffer, true)}
if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(additionalMethods!.count))
for item in additionalMethods! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(savedCredentials!.count))
for item in savedCredentials! {
item.serialize(buffer, true)
}}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentForm(let flags, let formId, let botId, let title, let description, let photo, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let additionalMethods, let savedInfo, let savedCredentials, let users):
return ("paymentForm", [("flags", flags as Any), ("formId", formId as Any), ("botId", botId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("providerId", providerId as Any), ("url", url as Any), ("nativeProvider", nativeProvider as Any), ("nativeParams", nativeParams as Any), ("additionalMethods", additionalMethods as Any), ("savedInfo", savedInfo as Any), ("savedCredentials", savedCredentials as Any), ("users", users as Any)])
}
}
public static func parse_paymentForm(_ reader: BufferReader) -> PaymentForm? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int64?
_3 = reader.readInt64()
var _4: String?
_4 = parseString(reader)
var _5: String?
_5 = parseString(reader)
var _6: Api.WebDocument?
if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _7: Api.Invoice?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _8: Int64?
_8 = reader.readInt64()
var _9: String?
_9 = parseString(reader)
var _10: String?
if Int(_1!) & Int(1 << 4) != 0 {_10 = parseString(reader) }
var _11: Api.DataJSON?
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.DataJSON
} }
var _12: [Api.PaymentFormMethod]?
if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() {
_12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PaymentFormMethod.self)
} }
var _13: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_13 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
var _14: [Api.PaymentSavedCredentials]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PaymentSavedCredentials.self)
} }
var _15: [Api.User]?
if let _ = reader.readInt32() {
_15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 5) == 0) || _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
let _c10 = (Int(_1!) & Int(1 << 4) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 4) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 6) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 0) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 1) == 0) || _14 != nil
let _c15 = _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 {
return Api.payments.PaymentForm.paymentForm(flags: _1!, formId: _2!, botId: _3!, title: _4!, description: _5!, photo: _6, invoice: _7!, providerId: _8!, url: _9!, nativeProvider: _10, nativeParams: _11, additionalMethods: _12, savedInfo: _13, savedCredentials: _14, users: _15!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum PaymentReceipt: TypeConstructorDescription {
case paymentReceipt(flags: Int32, date: Int32, botId: Int64, providerId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, info: Api.PaymentRequestedInfo?, shipping: Api.ShippingOption?, tipAmount: Int64?, currency: String, totalAmount: Int64, credentialsTitle: String, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users):
if boxed {
buffer.appendInt32(1891958275)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false)
serializeInt64(providerId, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {info!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {shipping!.serialize(buffer, true)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(tipAmount!, buffer: buffer, boxed: false)}
serializeString(currency, buffer: buffer, boxed: false)
serializeInt64(totalAmount, buffer: buffer, boxed: false)
serializeString(credentialsTitle, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users):
return ("paymentReceipt", [("flags", flags as Any), ("date", date as Any), ("botId", botId as Any), ("providerId", providerId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("info", info as Any), ("shipping", shipping as Any), ("tipAmount", tipAmount as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("credentialsTitle", credentialsTitle as Any), ("users", users as Any)])
}
}
public static func parse_paymentReceipt(_ reader: BufferReader) -> PaymentReceipt? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int64?
_4 = reader.readInt64()
var _5: String?
_5 = parseString(reader)
var _6: String?
_6 = parseString(reader)
var _7: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _8: Api.Invoice?
if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _9: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_9 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
var _10: Api.ShippingOption?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_10 = Api.parse(reader, signature: signature) as? Api.ShippingOption
} }
var _11: Int64?
if Int(_1!) & Int(1 << 3) != 0 {_11 = reader.readInt64() }
var _12: String?
_12 = parseString(reader)
var _13: Int64?
_13 = reader.readInt64()
var _14: String?
_14 = parseString(reader)
var _15: [Api.User]?
if let _ = reader.readInt32() {
_15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 1) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil
let _c12 = _12 != nil
let _c13 = _13 != nil
let _c14 = _14 != nil
let _c15 = _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 {
return Api.payments.PaymentReceipt.paymentReceipt(flags: _1!, date: _2!, botId: _3!, providerId: _4!, title: _5!, description: _6!, photo: _7, invoice: _8!, info: _9, shipping: _10, tipAmount: _11, currency: _12!, totalAmount: _13!, credentialsTitle: _14!, users: _15!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
indirect enum PaymentResult: TypeConstructorDescription {
case paymentResult(updates: Api.Updates)
case paymentVerificationNeeded(url: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentResult(let updates):
if boxed {
buffer.appendInt32(1314881805)
}
updates.serialize(buffer, true)
break
case .paymentVerificationNeeded(let url):
if boxed {
buffer.appendInt32(-666824391)
}
serializeString(url, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .paymentResult(let updates):
return ("paymentResult", [("updates", updates as Any)])
case .paymentVerificationNeeded(let url):
return ("paymentVerificationNeeded", [("url", url as Any)])
}
}
public static func parse_paymentResult(_ reader: BufferReader) -> PaymentResult? {
var _1: Api.Updates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Updates
}
let _c1 = _1 != nil
if _c1 {
return Api.payments.PaymentResult.paymentResult(updates: _1!)
}
else {
return nil
}
}
public static func parse_paymentVerificationNeeded(_ reader: BufferReader) -> PaymentResult? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.payments.PaymentResult.paymentVerificationNeeded(url: _1!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum SavedInfo: TypeConstructorDescription {
case savedInfo(flags: Int32, savedInfo: Api.PaymentRequestedInfo?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedInfo(let flags, let savedInfo):
if boxed {
buffer.appendInt32(-74456004)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedInfo(let flags, let savedInfo):
return ("savedInfo", [("flags", flags as Any), ("savedInfo", savedInfo as Any)])
}
}
public static func parse_savedInfo(_ reader: BufferReader) -> SavedInfo? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.PaymentRequestedInfo?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
if _c1 && _c2 {
return Api.payments.SavedInfo.savedInfo(flags: _1!, savedInfo: _2)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum ValidatedRequestedInfo: TypeConstructorDescription {
case validatedRequestedInfo(flags: Int32, id: String?, shippingOptions: [Api.ShippingOption]?)
@ -1220,207 +1544,3 @@ public extension Api.updates {
}
}
public extension Api.updates {
enum Difference: TypeConstructorDescription {
case difference(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], state: Api.updates.State)
case differenceEmpty(date: Int32, seq: Int32)
case differenceSlice(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], intermediateState: Api.updates.State)
case differenceTooLong(pts: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state):
if boxed {
buffer.appendInt32(16030880)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newMessages.count))
for item in newMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newEncryptedMessages.count))
for item in newEncryptedMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(otherUpdates.count))
for item in otherUpdates {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
state.serialize(buffer, true)
break
case .differenceEmpty(let date, let seq):
if boxed {
buffer.appendInt32(1567990072)
}
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(seq, buffer: buffer, boxed: false)
break
case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState):
if boxed {
buffer.appendInt32(-1459938943)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newMessages.count))
for item in newMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newEncryptedMessages.count))
for item in newEncryptedMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(otherUpdates.count))
for item in otherUpdates {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
intermediateState.serialize(buffer, true)
break
case .differenceTooLong(let pts):
if boxed {
buffer.appendInt32(1258196845)
}
serializeInt32(pts, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state):
return ("difference", [("newMessages", newMessages as Any), ("newEncryptedMessages", newEncryptedMessages as Any), ("otherUpdates", otherUpdates as Any), ("chats", chats as Any), ("users", users as Any), ("state", state as Any)])
case .differenceEmpty(let date, let seq):
return ("differenceEmpty", [("date", date as Any), ("seq", seq as Any)])
case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState):
return ("differenceSlice", [("newMessages", newMessages as Any), ("newEncryptedMessages", newEncryptedMessages as Any), ("otherUpdates", otherUpdates as Any), ("chats", chats as Any), ("users", users as Any), ("intermediateState", intermediateState as Any)])
case .differenceTooLong(let pts):
return ("differenceTooLong", [("pts", pts as Any)])
}
}
public static func parse_difference(_ reader: BufferReader) -> Difference? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.EncryptedMessage]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self)
}
var _3: [Api.Update]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self)
}
var _4: [Api.Chat]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _6: Api.updates.State?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.updates.State
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.updates.Difference.difference(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, state: _6!)
}
else {
return nil
}
}
public static func parse_differenceEmpty(_ reader: BufferReader) -> Difference? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.updates.Difference.differenceEmpty(date: _1!, seq: _2!)
}
else {
return nil
}
}
public static func parse_differenceSlice(_ reader: BufferReader) -> Difference? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.EncryptedMessage]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self)
}
var _3: [Api.Update]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self)
}
var _4: [Api.Chat]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _6: Api.updates.State?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.updates.State
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.updates.Difference.differenceSlice(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, intermediateState: _6!)
}
else {
return nil
}
}
public static func parse_differenceTooLong(_ reader: BufferReader) -> Difference? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.updates.Difference.differenceTooLong(pts: _1!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,207 @@
public extension Api.updates {
enum Difference: TypeConstructorDescription {
case difference(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], state: Api.updates.State)
case differenceEmpty(date: Int32, seq: Int32)
case differenceSlice(newMessages: [Api.Message], newEncryptedMessages: [Api.EncryptedMessage], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User], intermediateState: Api.updates.State)
case differenceTooLong(pts: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state):
if boxed {
buffer.appendInt32(16030880)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newMessages.count))
for item in newMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newEncryptedMessages.count))
for item in newEncryptedMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(otherUpdates.count))
for item in otherUpdates {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
state.serialize(buffer, true)
break
case .differenceEmpty(let date, let seq):
if boxed {
buffer.appendInt32(1567990072)
}
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(seq, buffer: buffer, boxed: false)
break
case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState):
if boxed {
buffer.appendInt32(-1459938943)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newMessages.count))
for item in newMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(newEncryptedMessages.count))
for item in newEncryptedMessages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(otherUpdates.count))
for item in otherUpdates {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
intermediateState.serialize(buffer, true)
break
case .differenceTooLong(let pts):
if boxed {
buffer.appendInt32(1258196845)
}
serializeInt32(pts, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .difference(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let state):
return ("difference", [("newMessages", newMessages as Any), ("newEncryptedMessages", newEncryptedMessages as Any), ("otherUpdates", otherUpdates as Any), ("chats", chats as Any), ("users", users as Any), ("state", state as Any)])
case .differenceEmpty(let date, let seq):
return ("differenceEmpty", [("date", date as Any), ("seq", seq as Any)])
case .differenceSlice(let newMessages, let newEncryptedMessages, let otherUpdates, let chats, let users, let intermediateState):
return ("differenceSlice", [("newMessages", newMessages as Any), ("newEncryptedMessages", newEncryptedMessages as Any), ("otherUpdates", otherUpdates as Any), ("chats", chats as Any), ("users", users as Any), ("intermediateState", intermediateState as Any)])
case .differenceTooLong(let pts):
return ("differenceTooLong", [("pts", pts as Any)])
}
}
public static func parse_difference(_ reader: BufferReader) -> Difference? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.EncryptedMessage]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self)
}
var _3: [Api.Update]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self)
}
var _4: [Api.Chat]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _6: Api.updates.State?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.updates.State
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.updates.Difference.difference(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, state: _6!)
}
else {
return nil
}
}
public static func parse_differenceEmpty(_ reader: BufferReader) -> Difference? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.updates.Difference.differenceEmpty(date: _1!, seq: _2!)
}
else {
return nil
}
}
public static func parse_differenceSlice(_ reader: BufferReader) -> Difference? {
var _1: [Api.Message]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _2: [Api.EncryptedMessage]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.EncryptedMessage.self)
}
var _3: [Api.Update]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Update.self)
}
var _4: [Api.Chat]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _6: Api.updates.State?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.updates.State
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.updates.Difference.differenceSlice(newMessages: _1!, newEncryptedMessages: _2!, otherUpdates: _3!, chats: _4!, users: _5!, intermediateState: _6!)
}
else {
return nil
}
}
public static func parse_differenceTooLong(_ reader: BufferReader) -> Difference? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.updates.Difference.differenceTooLong(pts: _1!)
}
else {
return nil
}
}
}
}
public extension Api.updates {
enum State: TypeConstructorDescription {
case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32)

View File

@ -438,40 +438,14 @@ private func cleanupAccount(networkArguments: NetworkInitializationArguments, ac
return .single(nil)
}
|> mapToSignal { result -> Signal<Void, NoError> in
let _ = (accountManager.transaction { transaction -> Void in
var tokens = transaction.getStoredLoginTokens()
switch result {
case let .loggedOut(_, futureAuthToken):
if let futureAuthToken = futureAuthToken {
tokens.insert(futureAuthToken.makeData(), at: 0)
}
default:
break
switch result {
case let .loggedOut(_, futureAuthToken):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
var cloudValue: [Data] = []
if let list = NSUbiquitousKeyValueStore.default.object(forKey: "T_SLTokens") as? [String] {
cloudValue = list.compactMap { string -> Data? in
guard let stringData = string.data(using: .utf8) else {
return nil
}
return Data(base64Encoded: stringData)
}
}
for data in cloudValue {
if !tokens.contains(data) {
tokens.insert(data, at: 0)
}
}
if tokens.count > 20 {
tokens.removeLast(tokens.count - 20)
}
NSUbiquitousKeyValueStore.default.set(tokens.map { $0.base64EncodedString() }, forKey: "T_SLTokens")
NSUbiquitousKeyValueStore.default.synchronize()
transaction.setStoredLoginTokens(tokens)
}).start()
default:
break
}
account.shouldBeServiceTaskMaster.set(.single(.never))
return accountManager.transaction { transaction -> Void in
transaction.updateRecord(id, { _ in

View File

@ -2,16 +2,20 @@ import Foundation
import Postbox
import TelegramApi
extension TelegramChatBannedRights {
init(apiBannedRights: Api.ChatBannedRights) {
switch apiBannedRights {
case let .chatBannedRights(flags, untilDate):
self.init(flags: TelegramChatBannedRightsFlags(rawValue: flags), untilDate: untilDate)
var effectiveFlags = TelegramChatBannedRightsFlags(rawValue: flags)
effectiveFlags.remove(.banSendMedia)
self.init(flags: effectiveFlags, untilDate: untilDate)
}
}
var apiBannedRights: Api.ChatBannedRights {
return .chatBannedRights(flags: self.flags.rawValue, untilDate: self.untilDate)
var effectiveFlags = self.flags
effectiveFlags.remove(.banSendMedia)
return .chatBannedRights(flags: effectiveFlags.rawValue, untilDate: self.untilDate)
}
}

View File

@ -71,7 +71,42 @@ private func ~=<T: RegularExpressionMatchable>(pattern: Regex, matchable: T) ->
return matchable.match(pattern)
}
public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, syncContacts: Bool) -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> {
public enum SendAuthorizationCodeResult {
case sentCode(UnauthorizedAccount)
case loggedIn
}
func storeFutureLoginToken(accountManager: AccountManager<TelegramAccountManagerTypes>, token: Data) {
let _ = (accountManager.transaction { transaction -> Void in
var tokens = transaction.getStoredLoginTokens()
tokens.insert(token, at: 0)
var cloudValue: [Data] = []
if let list = NSUbiquitousKeyValueStore.default.object(forKey: "T_SLTokens") as? [String] {
cloudValue = list.compactMap { string -> Data? in
guard let stringData = string.data(using: .utf8) else {
return nil
}
return Data(base64Encoded: stringData)
}
}
for data in cloudValue {
if !tokens.contains(data) {
tokens.insert(data, at: 0)
}
}
if tokens.count > 20 {
tokens.removeLast(tokens.count - 20)
}
NSUbiquitousKeyValueStore.default.set(tokens.map { $0.base64EncodedString() }, forKey: "T_SLTokens")
NSUbiquitousKeyValueStore.default.synchronize()
transaction.setStoredLoginTokens(tokens)
}).start()
}
public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, syncContacts: Bool, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> {
var cloudValue: [Data] = []
if let list = NSUbiquitousKeyValueStore.default.object(forKey: "T_SLTokens") as? [String] {
cloudValue = list.compactMap { string -> Data? in
@ -85,7 +120,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
return transaction.getStoredLoginTokens()
}
|> castError(AuthorizationCodeRequestError.self)
|> mapToSignal { localAuthTokens -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> in
|> mapToSignal { localAuthTokens -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> in
var authTokens = localAuthTokens
for data in cloudValue {
if !authTokens.contains(data) {
@ -168,11 +203,12 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|> timeout(20.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.timeout))
return codeAndAccount
|> mapToSignal { result, account -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> in
return account.postbox.transaction { transaction -> UnauthorizedAccount in
|> mapToSignal { result, account -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> in
return account.postbox.transaction { transaction -> Signal<SendAuthorizationCodeResult, AuthorizationCodeRequestError> in
switch result {
case let .password(hint):
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts)))
return .single(.sentCode(account))
case let .sentCode(sentCode):
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
@ -182,12 +218,35 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
}
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, syncContacts: syncContacts)))
case let .sentCodeSuccess(authorization):
switch authorization {
case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
transaction.setState(state)
if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) {
transaction.setNoticeEntry(key: value.0, value: value.1)
}
return accountManager.transaction { transaction -> SendAuthorizationCodeResult in
switchToAuthorizedAccount(transaction: transaction, account: account)
return .loggedIn
}
|> castError(AuthorizationCodeRequestError.self)
case .authorizationSignUpRequired:
return .never()
}
}
return .single(.sentCode(account))
}
return account
}
|> mapError { _ -> AuthorizationCodeRequestError in
}
|> switchToLatest
}
}
}
@ -215,17 +274,18 @@ public func resendAuthorizationCode(account: UnauthorizedAccount) -> Signal<Void
|> mapToSignal { sentCode -> Signal<Void, AuthorizationCodeRequestError> in
return account.postbox.transaction { transaction -> Void in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, syncContacts: syncContacts)))
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: number, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, syncContacts: syncContacts)))
case .sentCodeSuccess:
break
}
} |> mapError { _ -> AuthorizationCodeRequestError in }
} |> mapError { _ -> AuthorizationCodeRequestError in }
}
} else {
return .fail(.generic(info: nil))
@ -496,6 +556,8 @@ public func verifyLoginEmailSetup(account: UnauthorizedAccount, code: Authorizat
}
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, syncContacts: syncContacts)))
case .sentCodeSuccess:
break
}
case .emailVerified:
break
@ -594,7 +656,11 @@ public func authorizeWithCode(accountManager: AccountManager<TelegramAccountMana
return .single(.loggedIn)
case let .authorization(authorization):
switch authorization {
case let .authorization(_, otherwiseReloginDays, _, user):
case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
@ -654,7 +720,11 @@ public func authorizeWithPassword(accountManager: AccountManager<TelegramAccount
|> mapToSignal { result -> Signal<Void, AuthorizationPasswordVerificationError> in
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
switch result {
case let .authorization(_, _, _, user):
case let .authorization(_, _, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
/*transaction.updatePeersInternal([user], update: { current, peer -> Peer? in
@ -720,7 +790,11 @@ public final class RecoveredAccountData {
public func loginWithRecoveredAccountData(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, recoveredAccountData: RecoveredAccountData, syncContacts: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
switch recoveredAccountData.authorization {
case let .authorization(_, _, _, user):
case let .authorization(_, _, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
@ -856,7 +930,11 @@ public func signUpWithName(accountManager: AccountManager<TelegramAccountManager
}
|> mapToSignal { result -> Signal<Void, SignUpError> in
switch result {
case let .authorization(_, otherwiseReloginDays, _, user):
case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
let user = TelegramUser(user: user)
let appliedState = account.postbox.transaction { transaction -> Void in
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)

View File

@ -240,12 +240,14 @@ public struct NetworkUsageStats: Equatable {
public let audio: NetworkUsageStatsConnectionsEntry
public let file: NetworkUsageStatsConnectionsEntry
public let call: NetworkUsageStatsConnectionsEntry
public let sticker: NetworkUsageStatsConnectionsEntry
public let voiceMessage: NetworkUsageStatsConnectionsEntry
public let resetWifiTimestamp: Int32
public let resetCellularTimestamp: Int32
public static func ==(lhs: NetworkUsageStats, rhs: NetworkUsageStats) -> Bool {
return lhs.generic == rhs.generic && lhs.image == rhs.image && lhs.video == rhs.video && lhs.audio == rhs.audio && lhs.file == rhs.file && lhs.call == rhs.call && lhs.resetWifiTimestamp == rhs.resetWifiTimestamp && lhs.resetCellularTimestamp == rhs.resetCellularTimestamp
return lhs.generic == rhs.generic && lhs.image == rhs.image && lhs.video == rhs.video && lhs.audio == rhs.audio && lhs.file == rhs.file && lhs.call == rhs.call && lhs.resetWifiTimestamp == rhs.resetWifiTimestamp && lhs.resetCellularTimestamp == rhs.resetCellularTimestamp && lhs.sticker == rhs.sticker && lhs.voiceMessage == rhs.voiceMessage
}
}
@ -386,6 +388,20 @@ func networkUsageStats(basePath: String, reset: ResetNetworkUsageStats) -> Signa
wifi: NetworkUsageStatsDirectionsEntry(
incoming: dict[UsageCalculationTag(connection: .wifi, direction: .incoming, category: .call).key]!,
outgoing: dict[UsageCalculationTag(connection: .wifi, direction: .outgoing, category: .call).key]!)),
sticker: NetworkUsageStatsConnectionsEntry(
cellular: NetworkUsageStatsDirectionsEntry(
incoming: 0,
outgoing: 0),
wifi: NetworkUsageStatsDirectionsEntry(
incoming: 0,
outgoing: 0)),
voiceMessage: NetworkUsageStatsConnectionsEntry(
cellular: NetworkUsageStatsDirectionsEntry(
incoming: 0,
outgoing: 0),
wifi: NetworkUsageStatsDirectionsEntry(
incoming: 0,
outgoing: 0)),
resetWifiTimestamp: Int32(dict[UsageCalculationResetKey.wifi.rawValue]!),
resetCellularTimestamp: Int32(dict[UsageCalculationResetKey.cellular.rawValue]!)
))

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 151
return 152
}
public func parseMessage(_ data: Data!) -> Any! {

View File

@ -24,6 +24,12 @@ public struct TelegramChatBannedRightsFlags: OptionSet, Hashable {
public static let banAddMembers = TelegramChatBannedRightsFlags(rawValue: 1 << 15)
public static let banPinMessages = TelegramChatBannedRightsFlags(rawValue: 1 << 17)
public static let banManageTopics = TelegramChatBannedRightsFlags(rawValue: 1 << 18)
public static let banSendPhotos = TelegramChatBannedRightsFlags(rawValue: 1 << 19)
public static let banSendVideos = TelegramChatBannedRightsFlags(rawValue: 1 << 20)
public static let banSendInstantVideos = TelegramChatBannedRightsFlags(rawValue: 1 << 21)
public static let banSendMusic = TelegramChatBannedRightsFlags(rawValue: 1 << 22)
public static let banSendVoice = TelegramChatBannedRightsFlags(rawValue: 1 << 23)
public static let banSendFiles = TelegramChatBannedRightsFlags(rawValue: 1 << 24)
}
public struct TelegramChatBannedRights: PostboxCoding, Equatable {

View File

@ -51,14 +51,16 @@ func _internal_requestChangeAccountPhoneNumberVerification(account: Account, pho
return .generic
}
}
|> map { sentCode -> ChangeAccountPhoneNumberData in
|> mapToSignal { sentCode -> Signal<ChangeAccountPhoneNumberData, RequestChangeAccountPhoneNumberVerificationError> in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType))
case .sentCodeSuccess:
return .never()
}
}
}
@ -76,15 +78,17 @@ func _internal_requestNextChangeAccountPhoneNumberVerification(account: Account,
return .generic
}
}
|> map { sentCode -> ChangeAccountPhoneNumberData in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)
|> mapToSignal { sentCode -> Signal<ChangeAccountPhoneNumberData, RequestChangeAccountPhoneNumberVerificationError> in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType))
case .sentCodeSuccess:
return .never()
}
}
}

View File

@ -92,7 +92,11 @@ func _internal_exportAuthTransferToken(accountManager: AccountManager<TelegramAc
switch result {
case let .loginTokenSuccess(authorization):
switch authorization {
case let .authorization(_, _, _, user):
case let .authorization(_, _, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
return updatedAccount.postbox.transaction { transaction -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: updatedAccount.testingEnvironment, masterDatacenterId: updatedAccount.masterDatacenterId, peerId: user.id, state: nil)
@ -116,7 +120,11 @@ func _internal_exportAuthTransferToken(accountManager: AccountManager<TelegramAc
}
case let .loginTokenSuccess(authorization):
switch authorization {
case let .authorization(_, _, _, user):
case let .authorization(_, _, _, futureAuthToken, user):
if let futureAuthToken = futureAuthToken {
storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData())
}
return account.postbox.transaction { transaction -> Signal<ExportAuthTransferTokenResult, ExportAuthTransferTokenError> in
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)

View File

@ -26,14 +26,16 @@ func _internal_requestCancelAccountResetData(network: Network, hash: String) ->
return .generic
}
}
|> map { sentCode -> CancelAccountResetData in
|> mapToSignal { sentCode -> Signal<CancelAccountResetData, RequestCancelAccountResetDataError> in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return .single(CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType))
case .sentCodeSuccess:
return .never()
}
}
}
@ -47,14 +49,16 @@ func _internal_requestNextCancelAccountResetOption(network: Network, phoneNumber
return .generic
}
}
|> map { sentCode -> CancelAccountResetData in
|> mapToSignal { sentCode -> Signal<CancelAccountResetData, RequestCancelAccountResetDataError> in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
var parsedNextType: AuthorizationCodeNextType?
if let nextType = nextType {
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
}
return .single(CancelAccountResetData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType))
case .sentCodeSuccess:
return .never()
}
}
}

View File

@ -142,6 +142,38 @@ private extension StorageUsageStats {
}
}
private func statForDirectory(path: String) -> Int64 {
var s = darwin_dirstat()
var result = dirstat_np(path, 1, &s, MemoryLayout<darwin_dirstat>.size)
if result != -1 {
return Int64(s.total_size)
} else {
result = dirstat_np(path, 0, &s, MemoryLayout<darwin_dirstat>.size)
if result != -1 {
return Int64(s.total_size)
} else {
return 0
}
}
}
public func collectRawStorageUsageReport(containerPath: String) -> String {
var log = ""
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let documentsSize = statForDirectory(path: documentsPath)
log.append("Documents (\(documentsPath)): \(documentsSize)\n")
let systemCachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
let systemCacheSize = statForDirectory(path: systemCachePath)
log.append("System Cache (\(systemCachePath)): \(systemCacheSize)\n")
let containerSize = statForDirectory(path: containerPath)
log.append("Container (\(containerPath)): \(containerSize)\n")
return log
}
func _internal_collectStorageUsageStats(account: Account) -> Signal<AllStorageUsageStats, NoError> {
/*let additionalStats = Signal<Int64, NoError> { subscriber in
DispatchQueue.global().async {

View File

@ -26,10 +26,12 @@ public func secureIdPreparePhoneVerification(network: Network, value: SecureIdPh
}
return .generic
}
|> map { sentCode -> SecureIdPreparePhoneVerificationPayload in
|> mapToSignal { sentCode -> Signal<SecureIdPreparePhoneVerificationPayload, SecureIdPreparePhoneVerificationError> in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
return SecureIdPreparePhoneVerificationPayload(type: SentAuthorizationCodeType(apiType: type), nextType: nextType.flatMap(AuthorizationCodeNextType.init), timeout: timeout, phone: value.phone, phoneCodeHash: phoneCodeHash)
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
return .single(SecureIdPreparePhoneVerificationPayload(type: SentAuthorizationCodeType(apiType: type), nextType: nextType.flatMap(AuthorizationCodeNextType.init), timeout: timeout, phone: value.phone, phoneCodeHash: phoneCodeHash))
case .sentCodeSuccess:
return .never()
}
}
}

View File

@ -100,7 +100,7 @@ public final class ChatControllerInteraction {
public let sendCurrentMessage: (Bool) -> Void
public let sendMessage: (String) -> Void
public let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool
public let sendEmoji: (String, ChatTextInputTextCustomEmojiAttribute) -> Void
public let sendEmoji: (String, ChatTextInputTextCustomEmojiAttribute, Bool) -> Void
public let sendGif: (FileMediaReference, UIView, CGRect, Bool, Bool) -> Bool
public let sendBotContextResultAsGif: (ChatContextResultCollection, ChatContextResult, UIView, CGRect, Bool) -> Bool
public let requestMessageActionCallback: (MessageId, MemoryBuffer?, Bool, Bool) -> Void
@ -210,7 +210,7 @@ public final class ChatControllerInteraction {
sendCurrentMessage: @escaping (Bool) -> Void,
sendMessage: @escaping (String) -> Void,
sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool,
sendEmoji: @escaping (String, ChatTextInputTextCustomEmojiAttribute) -> Void,
sendEmoji: @escaping (String, ChatTextInputTextCustomEmojiAttribute, Bool) -> Void,
sendGif: @escaping (FileMediaReference, UIView, CGRect, Bool, Bool) -> Bool,
sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, UIView, CGRect, Bool) -> Bool,
requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool, Bool) -> Void,

View File

@ -29,6 +29,7 @@ import TelegramUIPreferences
import MultiplexedVideoNode
import ChatControllerInteraction
import FeaturedStickersScreen
import Pasteboard
public struct ChatMediaInputPaneScrollState {
let absoluteOffset: CGFloat?
@ -533,6 +534,87 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
self.externalTopPanelContainerImpl = PagerExternalTopPanelContainer()
var stickerPeekBehavior: EmojiContentPeekBehaviorImpl?
if let controllerInteraction = controllerInteraction {
let context = self.context
stickerPeekBehavior = EmojiContentPeekBehaviorImpl(
context: self.context,
interaction: EmojiContentPeekBehaviorImpl.Interaction(
sendSticker: controllerInteraction.sendSticker,
sendEmoji: { file in
var text = "."
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
case let .CustomEmoji(_, _, displayText, stickerPackReference):
text = displayText
var packId: ItemCollectionId?
if case let .id(id, _) = stickerPackReference {
packId = ItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id)
}
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: packId, fileId: file.fileId.id, file: file)
break loop
default:
break
}
}
if let emojiAttribute {
controllerInteraction.sendEmoji(text, emojiAttribute, true)
}
},
setStatus: { [weak self] file in
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.accountData.setEmojiStatus(file: file, expirationDate: nil).start()
var animateInAsReplacement = false
if let currentUndoOverlayController = strongSelf.currentUndoOverlayController {
currentUndoOverlayController.dismissWithCommitActionAndReplacementAnimation()
strongSelf.currentUndoOverlayController = nil
animateInAsReplacement = true
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize
let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Your emoji status has been updated.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false })
strongSelf.currentUndoOverlayController = controller
controllerInteraction.presentController(controller, nil)
},
copyEmoji: { file in
var text = "."
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
case let .CustomEmoji(_, _, displayText, _):
text = displayText
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
break loop
default:
break
}
}
if let _ = emojiAttribute {
storeMessageTextInPasteboard(text, entities: [MessageTextEntity(range: 0 ..< (text as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: file.fileId.id))])
}
},
presentController: controllerInteraction.presentController,
presentGlobalOverlayController: controllerInteraction.presentGlobalOverlayController,
navigationController: controllerInteraction.navigationController
),
chatPeerId: chatPeerId,
present: { c, a in
controllerInteraction.presentGlobalOverlayController(c, a)
}
)
}
var premiumToastCounter = 0
self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak self, weak interfaceInteraction, weak controllerInteraction] groupId, item, _, _, _, _ in
@ -879,7 +961,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
updateScrollingToItemGroup: {
},
chatPeerId: chatPeerId,
peekBehavior: nil,
peekBehavior: stickerPeekBehavior,
customLayout: nil,
externalBackground: nil,
externalExpansionView: nil,
@ -887,17 +969,6 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
hideBackground: false
)
var stickerPeekBehavior: EmojiContentPeekBehaviorImpl?
if let controllerInteraction = controllerInteraction {
stickerPeekBehavior = EmojiContentPeekBehaviorImpl(
context: self.context,
interaction: EmojiContentPeekBehaviorImpl.Interaction(sendSticker: controllerInteraction.sendSticker, presentController: controllerInteraction.presentController, presentGlobalOverlayController: controllerInteraction.presentGlobalOverlayController, navigationController: controllerInteraction.navigationController),
chatPeerId: chatPeerId,
present: { c, a in
controllerInteraction.presentGlobalOverlayController(c, a)
}
)
}
self.stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak controllerInteraction, weak interfaceInteraction] groupId, item, view, rect, layer, _ in
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: false) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
@ -1988,24 +2059,40 @@ public final class EntityInputView: UIInputView, AttachmentTextInputPanelInputVi
public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
public class Interaction {
public let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool
public let sendEmoji: (TelegramMediaFile) -> Void
public let setStatus: (TelegramMediaFile) -> Void
public let copyEmoji: (TelegramMediaFile) -> Void
public let presentController: (ViewController, Any?) -> Void
public let presentGlobalOverlayController: (ViewController, Any?) -> Void
public let navigationController: () -> NavigationController?
public init(sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool, presentController: @escaping (ViewController, Any?) -> Void, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?) {
public init(sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool, sendEmoji: @escaping (TelegramMediaFile) -> Void, setStatus: @escaping (TelegramMediaFile) -> Void, copyEmoji: @escaping (TelegramMediaFile) -> Void, presentController: @escaping (ViewController, Any?) -> Void, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?) {
self.sendSticker = sendSticker
self.sendEmoji = sendEmoji
self.setStatus = setStatus
self.copyEmoji = copyEmoji
self.presentController = presentController
self.presentGlobalOverlayController = presentGlobalOverlayController
self.navigationController = navigationController
}
}
private final class ViewRecord {
weak var view: UIView?
let peekRecognizer: PeekControllerGestureRecognizer
init(view: UIView, peekRecognizer: PeekControllerGestureRecognizer) {
self.view = view
self.peekRecognizer = peekRecognizer
}
}
private let context: AccountContext
private let interaction: Interaction?
private let chatPeerId: EnginePeer.Id?
private let present: (ViewController, Any?) -> Void
private var peekRecognizer: PeekControllerGestureRecognizer?
private var viewRecords: [ViewRecord] = []
private weak var peekController: PeekController?
public init(context: AccountContext, interaction: Interaction?, chatPeerId: EnginePeer.Id?, present: @escaping (ViewController, Any?) -> Void) {
@ -2016,7 +2103,13 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
}
public func setGestureRecognizerEnabled(view: UIView, isEnabled: Bool, itemAtPoint: @escaping (CGPoint) -> (AnyHashable, EmojiPagerContentComponent.View.ItemLayer, TelegramMediaFile)?) {
if self.peekRecognizer == nil {
self.viewRecords = self.viewRecords.filter({ $0.view != nil })
let viewRecord = self.viewRecords.first(where: { $0.view === view })
if let viewRecord = viewRecord {
viewRecord.peekRecognizer.isEnabled = isEnabled
} else {
let peekRecognizer = PeekControllerGestureRecognizer(contentAtPoint: { [weak self, weak view] point in
guard let strongSelf = self else {
return nil
@ -2032,133 +2125,242 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
let context = strongSelf.context
let accountPeerId = context.account.peerId
return combineLatest(
context.engine.stickers.isStickerSaved(id: file.fileId),
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: accountPeerId)) |> map { peer -> Bool in
let chatPeerId = strongSelf.chatPeerId
if file.isCustomEmoji {
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: accountPeerId)) |> map { peer -> Bool in
var hasPremium = false
if case let .user(user) = peer, user.isPremium {
hasPremium = true
}
return hasPremium
}
)
|> deliverOnMainQueue
|> map { [weak itemLayer] isStarred, hasPremium -> (UIView, CGRect, PeekControllerContent)? in
guard let strongSelf = self, let itemLayer = itemLayer else {
return nil
}
var menuItems: [ContextMenuItem] = []
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let isLocked = file.isPremiumSticker && !hasPremium
if let interaction = strongSelf.interaction {
let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?) -> Void = { fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
let _ = interaction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets)
|> deliverOnMainQueue
|> map { [weak itemLayer] hasPremium -> (UIView, CGRect, PeekControllerContent)? in
guard let strongSelf = self, let itemLayer = itemLayer else {
return nil
}
if let chatPeerId = strongSelf.chatPeerId, !isLocked {
if chatPeerId != strongSelf.context.account.peerId && chatPeerId.namespace != Namespaces.Peer.SecretChat {
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_SendSilently, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
var menuItems: [ContextMenuItem] = []
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var isLocked = false
if !hasPremium {
isLocked = file.isPremiumEmoji
if isLocked && chatPeerId == context.account.peerId {
isLocked = false
}
}
if let interaction = strongSelf.interaction {
let sendEmoji: (TelegramMediaFile) -> Void = { file in
interaction.sendEmoji(file)
}
let setStatus: (TelegramMediaFile) -> Void = { file in
interaction.setStatus(file)
}
let copyEmoji: (TelegramMediaFile) -> Void = { file in
interaction.copyEmoji(file)
}
if let _ = strongSelf.chatPeerId, !isLocked {
//TODO:localize
menuItems.append(.action(ContextMenuActionItem(text: "Send Emoji", icon: { theme in
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) {
return generateImage(image.size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
if let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(), size: size))
}
})
} else {
return nil
}
}, action: { _, f in
sendEmoji(file)
f(.default)
})))
//TODO:localize
menuItems.append(.action(ContextMenuActionItem(text: "Set as Status", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Smile"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.default)
guard let strongSelf = self else {
return
}
if hasPremium {
setStatus(file)
} else {
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumDemoScreen(context: context, subject: .animatedEmoji, action: {
let controller = PremiumIntroScreen(context: context, source: .animatedEmoji)
replaceImpl?(controller)
})
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
strongSelf.interaction?.navigationController()?.pushViewController(controller)
}
})))
//TODO:localize
menuItems.append(.action(ContextMenuActionItem(text: "Copy Emoji", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
copyEmoji(file)
f(.default)
})))
}
}
if menuItems.isEmpty {
return nil
}
guard let view = view else {
return nil
}
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked, menu: menuItems, openPremiumIntro: {
guard let strongSelf = self, let interaction = strongSelf.interaction else {
return
}
let controller = PremiumIntroScreen(context: context, source: .stickers)
interaction.navigationController()?.pushViewController(controller)
}))
}
} else {
return combineLatest(
context.engine.stickers.isStickerSaved(id: file.fileId),
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: accountPeerId)) |> map { peer -> Bool in
var hasPremium = false
if case let .user(user) = peer, user.isPremium {
hasPremium = true
}
return hasPremium
}
)
|> deliverOnMainQueue
|> map { [weak itemLayer] isStarred, hasPremium -> (UIView, CGRect, PeekControllerContent)? in
guard let strongSelf = self, let itemLayer = itemLayer else {
return nil
}
var menuItems: [ContextMenuItem] = []
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let isLocked = file.isPremiumSticker && !hasPremium
if let interaction = strongSelf.interaction {
let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?) -> Void = { fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
let _ = interaction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets)
}
if let chatPeerId = strongSelf.chatPeerId, !isLocked {
if chatPeerId != strongSelf.context.account.peerId && chatPeerId.namespace != Namespaces.Peer.SecretChat {
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_SendSilently, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
if let strongSelf = self, let peekController = strongSelf.peekController {
if let animationNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.animationNode {
sendSticker(.standalone(media: file), true, false, nil, false, animationNode.view, animationNode.bounds, nil)
} else if let imageNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.imageNode {
sendSticker(.standalone(media: file), true, false, nil, false, imageNode.view, imageNode.bounds, nil)
}
}
f(.default)
})))
}
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/ScheduleIcon"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
if let strongSelf = self, let peekController = strongSelf.peekController {
if let animationNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.animationNode {
sendSticker(.standalone(media: file), true, false, nil, false, animationNode.view, animationNode.bounds, nil)
let _ = sendSticker(.standalone(media: file), false, true, nil, false, animationNode.view, animationNode.bounds, nil)
} else if let imageNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.imageNode {
sendSticker(.standalone(media: file), true, false, nil, false, imageNode.view, imageNode.bounds, nil)
let _ = sendSticker(.standalone(media: file), false, true, nil, false, imageNode.view, imageNode.bounds, nil)
}
}
f(.default)
})))
}
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/ScheduleIcon"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
if let strongSelf = self, let peekController = strongSelf.peekController {
if let animationNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.animationNode {
let _ = sendSticker(.standalone(media: file), false, true, nil, false, animationNode.view, animationNode.bounds, nil)
} else if let imageNode = (peekController.contentNode as? StickerPreviewPeekContentNode)?.imageNode {
let _ = sendSticker(.standalone(media: file), false, true, nil, false, imageNode.view, imageNode.bounds, nil)
}
}
f(.default)
})))
}
menuItems.append(
.action(ContextMenuActionItem(text: isStarred ? presentationData.strings.Stickers_RemoveFromFavorites : presentationData.strings.Stickers_AddToFavorites, icon: { theme in generateTintedImage(image: isStarred ? UIImage(bundleImageName: "Chat/Context Menu/Unfave") : UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let _ = (context.engine.stickers.toggleStickerSaved(file: file, saved: !isStarred)
|> deliverOnMainQueue).start(next: { result in
switch result {
case .generic:
interaction.presentGlobalOverlayController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: !isStarred ? presentationData.strings.Conversation_StickerAddedToFavorites : presentationData.strings.Conversation_StickerRemovedFromFavorites, undoText: nil, customAction: nil), elevatedLayout: false, action: { _ in return false }), nil)
case let .limitExceeded(limit, premiumLimit):
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let text: String
if limit == premiumLimit || premiumConfiguration.isPremiumDisabled {
text = presentationData.strings.Premium_MaxFavedStickersFinalText
} else {
text = presentationData.strings.Premium_MaxFavedStickersText("\(premiumLimit)").string
}
interaction.presentGlobalOverlayController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: presentationData.strings.Premium_MaxFavedStickersTitle("\(limit)").string, text: text, undoText: nil, customAction: nil), elevatedLayout: false, action: { action in
if case .info = action {
let controller = PremiumIntroScreen(context: context, source: .savedStickers)
interaction.navigationController()?.pushViewController(controller)
return true
menuItems.append(
.action(ContextMenuActionItem(text: isStarred ? presentationData.strings.Stickers_RemoveFromFavorites : presentationData.strings.Stickers_AddToFavorites, icon: { theme in generateTintedImage(image: isStarred ? UIImage(bundleImageName: "Chat/Context Menu/Unfave") : UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let _ = (context.engine.stickers.toggleStickerSaved(file: file, saved: !isStarred)
|> deliverOnMainQueue).start(next: { result in
switch result {
case .generic:
interaction.presentGlobalOverlayController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: !isStarred ? presentationData.strings.Conversation_StickerAddedToFavorites : presentationData.strings.Conversation_StickerRemovedFromFavorites, undoText: nil, customAction: nil), elevatedLayout: false, action: { _ in return false }), nil)
case let .limitExceeded(limit, premiumLimit):
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let text: String
if limit == premiumLimit || premiumConfiguration.isPremiumDisabled {
text = presentationData.strings.Premium_MaxFavedStickersFinalText
} else {
text = presentationData.strings.Premium_MaxFavedStickersText("\(premiumLimit)").string
}
return false
}), nil)
interaction.presentGlobalOverlayController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: presentationData.strings.Premium_MaxFavedStickersTitle("\(limit)").string, text: text, undoText: nil, customAction: nil), elevatedLayout: false, action: { action in
if case .info = action {
let controller = PremiumIntroScreen(context: context, source: .savedStickers)
interaction.navigationController()?.pushViewController(controller)
return true
}
return false
}), nil)
}
})
}))
)
menuItems.append(
.action(ContextMenuActionItem(text: presentationData.strings.StickerPack_ViewPack, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Sticker"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.default)
guard let strongSelf = self else {
return
}
})
}))
)
menuItems.append(
.action(ContextMenuActionItem(text: presentationData.strings.StickerPack_ViewPack, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Sticker"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.default)
guard let strongSelf = self else {
return
}
loop: for attribute in file.attributes {
switch attribute {
case let .CustomEmoji(_, _, _, packReference), let .Sticker(_, packReference, _):
if let packReference = packReference {
let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: interaction.navigationController(), sendSticker: { file, sourceView, sourceRect in
sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil)
return true
})
interaction.navigationController()?.view.window?.endEditing(true)
interaction.presentController(controller, nil)
loop: for attribute in file.attributes {
switch attribute {
case let .CustomEmoji(_, _, _, packReference), let .Sticker(_, packReference, _):
if let packReference = packReference {
let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: interaction.navigationController(), sendSticker: { file, sourceView, sourceRect in
sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil)
return true
})
interaction.navigationController()?.view.window?.endEditing(true)
interaction.presentController(controller, nil)
}
break loop
default:
break
}
break loop
default:
break
}
}
}))
)
}
guard let view = view else {
return nil
}
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked && !isStarred, menu: menuItems, openPremiumIntro: {
guard let strongSelf = self, let interaction = strongSelf.interaction else {
return
}))
)
}
let controller = PremiumIntroScreen(context: context, source: .stickers)
interaction.navigationController()?.pushViewController(controller)
}))
guard let view = view else {
return nil
}
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked && !isStarred, menu: menuItems, openPremiumIntro: {
guard let strongSelf = self, let interaction = strongSelf.interaction else {
return
}
let controller = PremiumIntroScreen(context: context, source: .stickers)
interaction.navigationController()?.pushViewController(controller)
}))
}
}
}, present: { [weak self] content, sourceView, sourceRect in
guard let strongSelf = self else {
@ -2184,11 +2386,9 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
let _ = strongSelf
})
self.peekRecognizer = peekRecognizer
self.viewRecords.append(ViewRecord(view: view, peekRecognizer: peekRecognizer))
view.addGestureRecognizer(peekRecognizer)
peekRecognizer.isEnabled = isEnabled
} else {
self.peekRecognizer?.isEnabled = isEnabled
}
}
}

View File

@ -672,6 +672,7 @@ final class EmojiStatusPreviewScreenComponent: Component {
}
))))
}
//TODO:localize
menuItems.append(AnyComponentWithIdentity(id: "Other", component: AnyComponent(ContextMenuActionItem(
title: component.strings.EmojiStatusSetup_TimerOther,
action: { [weak self] in

View File

@ -5766,7 +5766,7 @@ public final class EmojiPagerContentComponent: Component {
self.component = component
self.state = state
component.inputInteractionHolder.inputInteraction?.peekBehavior?.setGestureRecognizerEnabled(view: self, isEnabled: component.itemLayoutType == .detailed, itemAtPoint: { [weak self] point in
component.inputInteractionHolder.inputInteraction?.peekBehavior?.setGestureRecognizerEnabled(view: self, isEnabled: true, itemAtPoint: { [weak self] point in
guard let strongSelf = self else {
return nil
}

View File

@ -40,6 +40,7 @@ swift_library(
"//submodules/TelegramAnimatedStickerNode",
"//submodules/LegacyComponents",
"//submodules/GalleryData",
"//submodules/SegmentedControlNode",
],
visibility = [
"//visibility:public",

View File

@ -0,0 +1,140 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import ComponentFlow
import SwiftSignalKit
import ViewControllerComponent
import ComponentDisplayAdapters
import TelegramPresentationData
import AccountContext
import TelegramCore
import MultilineTextComponent
import EmojiStatusComponent
import Postbox
import TelegramStringFormatting
import CheckNode
final class DataButtonComponent: Component {
let theme: PresentationTheme
let title: String
let action: () -> Void
init(
theme: PresentationTheme,
title: String,
action: @escaping () -> Void
) {
self.theme = theme
self.title = title
self.action = action
}
static func ==(lhs: DataButtonComponent, rhs: DataButtonComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.title != rhs.title {
return false
}
return true
}
class View: HighlightTrackingButton {
private let title = ComponentView<Empty>()
private var component: DataButtonComponent?
private var highlightBackgroundFrame: CGRect?
private var highlightBackgroundLayer: SimpleLayer?
override init(frame: CGRect) {
super.init(frame: frame)
self.clipsToBounds = true
self.layer.cornerRadius = 10.0
self.highligthedChanged = { [weak self] isHighlighted in
guard let self, let component = self.component, let highlightBackgroundFrame = self.highlightBackgroundFrame else {
return
}
if isHighlighted {
self.superview?.bringSubviewToFront(self)
let highlightBackgroundLayer: SimpleLayer
if let current = self.highlightBackgroundLayer {
highlightBackgroundLayer = current
} else {
highlightBackgroundLayer = SimpleLayer()
self.highlightBackgroundLayer = highlightBackgroundLayer
self.layer.insertSublayer(highlightBackgroundLayer, at: 0)
highlightBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
}
highlightBackgroundLayer.frame = highlightBackgroundFrame
highlightBackgroundLayer.opacity = 1.0
} else {
if let highlightBackgroundLayer = self.highlightBackgroundLayer {
self.highlightBackgroundLayer = nil
highlightBackgroundLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak highlightBackgroundLayer] _ in
highlightBackgroundLayer?.removeFromSuperlayer()
})
}
}
}
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func pressed() {
guard let component = self.component else {
return
}
component.action()
}
func update(component: DataButtonComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let themeUpdated = self.component?.theme !== component.theme
self.component = component
if themeUpdated {
self.backgroundColor = component.theme.list.itemBlocksBackgroundColor
}
let titleSize = self.title.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.title, font: Font.regular(17.0), textColor: component.theme.list.itemDestructiveColor)))),
environment: {},
containerSize: CGSize(width: availableSize.width, height: 100.0)
)
let height: CGFloat = 44.0
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) / 2.0), y: floor((height - titleSize.height) / 2.0)), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
transition.setFrame(view: titleView, frame: titleFrame)
}
self.highlightBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height))
return CGSize(width: availableSize.width, height: height)
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View File

@ -0,0 +1,192 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import ComponentFlow
import SwiftSignalKit
import ViewControllerComponent
import ComponentDisplayAdapters
import TelegramPresentationData
import AccountContext
import TelegramCore
import MultilineTextComponent
import EmojiStatusComponent
import Postbox
import CheckNode
import SolidRoundedButtonComponent
final class DataCategoriesComponent: Component {
struct CategoryData: Equatable {
var key: DataUsageScreenComponent.Category
var color: UIColor
var title: String
var size: Int64
var sizeFraction: Double
var incoming: Int64
var outgoing: Int64
var isSeparable: Bool
var isExpanded: Bool
init(key: DataUsageScreenComponent.Category, color: UIColor, title: String, size: Int64, sizeFraction: Double, incoming: Int64, outgoing: Int64, isSeparable: Bool, isExpanded: Bool) {
self.key = key
self.title = title
self.color = color
self.size = size
self.sizeFraction = sizeFraction
self.incoming = incoming
self.outgoing = outgoing
self.isSeparable = isSeparable
self.isExpanded = isExpanded
}
}
let theme: PresentationTheme
let strings: PresentationStrings
let categories: [CategoryData]
let toggleCategoryExpanded: (DataUsageScreenComponent.Category) -> Void
init(
theme: PresentationTheme,
strings: PresentationStrings,
categories: [CategoryData],
toggleCategoryExpanded: @escaping (DataUsageScreenComponent.Category) -> Void
) {
self.theme = theme
self.strings = strings
self.categories = categories
self.toggleCategoryExpanded = toggleCategoryExpanded
}
static func ==(lhs: DataCategoriesComponent, rhs: DataCategoriesComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.categories != rhs.categories {
return false
}
return true
}
class View: UIView {
private let containerView: UIView
private var itemViews: [DataUsageScreenComponent.Category: ComponentView<Empty>] = [:]
private var component: DataCategoriesComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
self.containerView = UIView()
super.init(frame: frame)
self.clipsToBounds = true
self.layer.cornerRadius = 10.0
self.addSubview(self.containerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: DataCategoriesComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
self.component = component
self.state = state
var itemsTransition = transition
if let animationHint = transition.userData(DataUsageScreenComponent.AnimationHint.self) {
switch animationHint.value {
case .clearedItems, .modeChanged:
if let copyView = self.containerView.snapshotView(afterScreenUpdates: false) {
itemsTransition = .immediate
self.addSubview(copyView)
self.containerView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.16)
copyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak copyView] _ in
copyView?.removeFromSuperview()
})
}
}
}
var contentHeight: CGFloat = 0.0
var validKeys = Set<DataUsageScreenComponent.Category>()
for i in 0 ..< component.categories.count {
let category = component.categories[i]
validKeys.insert(category.key)
var itemTransition = itemsTransition
let itemView: ComponentView<Empty>
if let current = self.itemViews[category.key] {
itemView = current
} else {
itemTransition = .immediate
itemView = ComponentView()
itemView.parentState = state
self.itemViews[category.key] = itemView
}
let itemSize = itemView.update(
transition: itemTransition,
component: AnyComponent(DataCategoryItemComponent(
theme: component.theme,
strings: component.strings,
category: category,
isExpanded: category.isExpanded,
hasNext: i != component.categories.count - 1,
action: { [weak self] key in
guard let self, let component = self.component else {
return
}
component.toggleCategoryExpanded(key)
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width, height: 1000.0)
)
let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: itemSize)
if let itemComponentView = itemView.view {
if itemComponentView.superview == nil {
self.containerView.addSubview(itemComponentView)
}
itemTransition.setFrame(view: itemComponentView, frame: itemFrame)
}
contentHeight += itemSize.height
}
var removeKeys: [DataUsageScreenComponent.Category] = []
for (key, itemView) in self.itemViews {
if !validKeys.contains(key) {
if let itemComponentView = itemView.view {
transition.setAlpha(view: itemComponentView, alpha: 0.0, completion: { [weak itemComponentView] _ in
itemComponentView?.removeFromSuperview()
})
}
removeKeys.append(key)
}
}
for key in removeKeys {
self.itemViews.removeValue(forKey: key)
}
self.backgroundColor = component.theme.list.itemBlocksBackgroundColor
self.containerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: contentHeight))
return CGSize(width: availableSize.width, height: contentHeight)
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View File

@ -0,0 +1,611 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import ComponentFlow
import SwiftSignalKit
import ViewControllerComponent
import ComponentDisplayAdapters
import TelegramPresentationData
import AccountContext
import TelegramCore
import MultilineTextComponent
import EmojiStatusComponent
import Postbox
import TelegramStringFormatting
import CheckNode
private final class SubItemComponent: Component {
let theme: PresentationTheme
let strings: PresentationStrings
let isIncoming: Bool
let value: Int64
let hasNext: Bool
init(
theme: PresentationTheme,
strings: PresentationStrings,
isIncoming: Bool,
value: Int64,
hasNext: Bool
) {
self.theme = theme
self.strings = strings
self.isIncoming = isIncoming
self.value = value
self.hasNext = hasNext
}
static func ==(lhs: SubItemComponent, rhs: SubItemComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.isIncoming != rhs.isIncoming {
return false
}
if lhs.value != rhs.value {
return false
}
return true
}
class View: HighlightTrackingButton {
private let iconView: UIImageView
private let title = ComponentView<Empty>()
private let titleValue = ComponentView<Empty>()
private let label = ComponentView<Empty>()
private let separatorLayer: SimpleLayer
private var component: SubItemComponent?
private var highlightBackgroundFrame: CGRect?
private var highlightBackgroundLayer: SimpleLayer?
override init(frame: CGRect) {
self.iconView = UIImageView()
self.separatorLayer = SimpleLayer()
super.init(frame: frame)
self.layer.addSublayer(self.separatorLayer)
self.addSubview(self.iconView)
self.highligthedChanged = { [weak self] isHighlighted in
guard let self, let component = self.component, let highlightBackgroundFrame = self.highlightBackgroundFrame else {
return
}
if isHighlighted {
self.superview?.bringSubviewToFront(self)
let highlightBackgroundLayer: SimpleLayer
if let current = self.highlightBackgroundLayer {
highlightBackgroundLayer = current
} else {
highlightBackgroundLayer = SimpleLayer()
self.highlightBackgroundLayer = highlightBackgroundLayer
self.layer.insertSublayer(highlightBackgroundLayer, above: self.separatorLayer)
highlightBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
}
highlightBackgroundLayer.frame = highlightBackgroundFrame
highlightBackgroundLayer.opacity = 1.0
} else {
if let highlightBackgroundLayer = self.highlightBackgroundLayer {
self.highlightBackgroundLayer = nil
highlightBackgroundLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak highlightBackgroundLayer] _ in
highlightBackgroundLayer?.removeFromSuperlayer()
})
}
}
}
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
self.isUserInteractionEnabled = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func pressed() {
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let result = super.hitTest(point, with: event) else {
return nil
}
return result
}
func update(component: SubItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let themeUpdated = self.component?.theme !== component.theme || self.component?.isIncoming != component.isIncoming
self.component = component
if themeUpdated {
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: component.isIncoming ? "Settings/Menu/DataExpandedIn" : "Settings/Menu/DataExpandedOut"), color: component.theme.list.itemPrimaryTextColor)
}
var leftInset: CGFloat = 62.0
var additionalLeftInset: CGFloat = 0.0
additionalLeftInset += 45.0
leftInset += additionalLeftInset
let rightInset: CGFloat = 16.0
var availableWidth: CGFloat = availableSize.width - leftInset - rightInset
let fractionString: String = ""
/*if component.category.sizeFraction != 0.0 {
let fractionValue: Double = floor(component.category.sizeFraction * 100.0 * 10.0) / 10.0
if fractionValue < 0.1 {
fractionString = "<0.1%"
} else if abs(Double(Int(fractionValue)) - fractionValue) < 0.001 {
fractionString = "\(Int(fractionValue))%"
} else {
fractionString = "\(fractionValue)%"
}
} else {
fractionString = ""
}*/
let labelSize = self.label.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: dataSizeString(Int(component.value), formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: ".")), font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
availableWidth = max(1.0, availableWidth - labelSize.width - 1.0)
let titleValueSize = self.titleValue.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: fractionString, font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
availableWidth = max(1.0, availableWidth - titleValueSize.width - 4.0)
//TODO:localize
let titleSize = self.title.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.isIncoming ? "Incoming" : "Outgoing", font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
let height: CGFloat = 44.0
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
let titleValueFrame = CGRect(origin: CGPoint(x: titleFrame.maxX + 4.0, y: floor((height - titleValueSize.height) / 2.0)), size: titleValueSize)
let labelFrame = CGRect(origin: CGPoint(x: availableSize.width - rightInset - labelSize.width, y: floor((height - labelSize.height) / 2.0)), size: labelSize)
if let image = self.iconView.image {
transition.setFrame(view: self.iconView, frame: CGRect(origin: CGPoint(x: leftInset - additionalLeftInset + floor((additionalLeftInset - image.size.width) * 0.5), y: floor((height - image.size.height) * 0.5)), size: image.size))
}
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
transition.setFrame(view: titleView, frame: titleFrame)
}
if let titleValueView = self.titleValue.view {
if titleValueView.superview == nil {
titleValueView.isUserInteractionEnabled = false
self.addSubview(titleValueView)
}
if titleValueView.bounds.size != titleValueFrame.size {
titleValueView.frame = titleValueFrame
} else {
transition.setFrame(view: titleValueView, frame: titleValueFrame)
}
}
if let labelView = self.label.view {
if labelView.superview == nil {
labelView.isUserInteractionEnabled = false
self.addSubview(labelView)
}
transition.setFrame(view: labelView, frame: labelFrame)
}
if themeUpdated {
self.separatorLayer.backgroundColor = component.theme.list.itemBlocksSeparatorColor.cgColor
}
transition.setFrame(layer: self.separatorLayer, frame: CGRect(origin: CGPoint(x: leftInset, y: height), size: CGSize(width: availableSize.width - leftInset, height: UIScreenPixel)))
transition.setAlpha(layer: self.separatorLayer, alpha: (component.hasNext) ? 1.0 : 0.0)
self.highlightBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height + ((component.hasNext) ? UIScreenPixel : 0.0)))
return CGSize(width: availableSize.width, height: height)
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
final class DataCategoryItemComponent: Component {
let theme: PresentationTheme
let strings: PresentationStrings
let category: DataCategoriesComponent.CategoryData
let isExpanded: Bool
let hasNext: Bool
let action: (DataUsageScreenComponent.Category) -> Void
init(
theme: PresentationTheme,
strings: PresentationStrings,
category: DataCategoriesComponent.CategoryData,
isExpanded: Bool,
hasNext: Bool,
action: @escaping (DataUsageScreenComponent.Category) -> Void
) {
self.theme = theme
self.strings = strings
self.category = category
self.isExpanded = isExpanded
self.hasNext = hasNext
self.action = action
}
static func ==(lhs: DataCategoryItemComponent, rhs: DataCategoryItemComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.category != rhs.category {
return false
}
if lhs.isExpanded != rhs.isExpanded {
return false
}
if lhs.hasNext != rhs.hasNext {
return false
}
return true
}
class View: HighlightTrackingButton {
private let iconView: UIImageView
private var expandIconView: UIImageView?
private let title = ComponentView<Empty>()
private let titleValue = ComponentView<Empty>()
private let label = ComponentView<Empty>()
private let separatorLayer: SimpleLayer
private let subcategoryClippingContainer: UIView
private var itemViews: [AnyHashable: ComponentView<Empty>] = [:]
private var component: DataCategoryItemComponent?
private var highlightBackgroundFrame: CGRect?
private var highlightBackgroundLayer: SimpleLayer?
override init(frame: CGRect) {
self.iconView = UIImageView()
self.separatorLayer = SimpleLayer()
self.subcategoryClippingContainer = UIView()
self.subcategoryClippingContainer.clipsToBounds = true
super.init(frame: frame)
self.addSubview(self.subcategoryClippingContainer)
self.layer.addSublayer(self.separatorLayer)
self.addSubview(self.iconView)
self.highligthedChanged = { [weak self] isHighlighted in
guard let self, let component = self.component, let highlightBackgroundFrame = self.highlightBackgroundFrame else {
return
}
if isHighlighted {
self.superview?.bringSubviewToFront(self)
let highlightBackgroundLayer: SimpleLayer
if let current = self.highlightBackgroundLayer {
highlightBackgroundLayer = current
} else {
highlightBackgroundLayer = SimpleLayer()
self.highlightBackgroundLayer = highlightBackgroundLayer
self.layer.insertSublayer(highlightBackgroundLayer, above: self.separatorLayer)
highlightBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
}
highlightBackgroundLayer.frame = highlightBackgroundFrame
highlightBackgroundLayer.opacity = 1.0
} else {
if let highlightBackgroundLayer = self.highlightBackgroundLayer {
self.highlightBackgroundLayer = nil
highlightBackgroundLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak highlightBackgroundLayer] _ in
highlightBackgroundLayer?.removeFromSuperlayer()
})
}
}
}
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func pressed() {
guard let component = self.component else {
return
}
component.action(component.category.key)
}
@objc private func checkPressed() {
guard let component = self.component else {
return
}
component.action(component.category.key)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let result = super.hitTest(point, with: event) else {
return nil
}
if result === self.subcategoryClippingContainer {
return self
}
return result
}
func update(component: DataCategoryItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let themeUpdated = self.component?.theme !== component.theme || self.component?.category.color != component.category.color
self.component = component
if themeUpdated {
let imageName: String
switch component.category.key {
case .photos:
imageName = "Settings/Menu/DataPhotos"
case .videos:
imageName = "Settings/Menu/DataVideo"
case .files:
imageName = "Settings/Menu/DataFiles"
case .music:
imageName = "Settings/Menu/DataMusic"
case .messages:
imageName = "Settings/Menu/DataMessages"
case .stickers:
imageName = "Settings/Menu/DataStickers"
case .voiceMessages:
imageName = "Settings/Menu/DataVoice"
case .calls:
imageName = "Settings/Menu/DataCalls"
case .totalIn:
imageName = "Settings/Menu/DataIn"
case .totalOut:
imageName = "Settings/Menu/DataOut"
}
self.iconView.image = UIImage(bundleImageName: imageName)
}
var leftInset: CGFloat = 62.0
let additionalLeftInset: CGFloat = 0.0
leftInset += additionalLeftInset
let rightInset: CGFloat = 16.0
var availableWidth: CGFloat = availableSize.width - leftInset - rightInset
if component.category.isSeparable {
let expandIconView: UIImageView
if let current = self.expandIconView {
expandIconView = current
if themeUpdated {
expandIconView.image = PresentationResourcesItemList.disclosureArrowImage(component.theme)
}
} else {
expandIconView = UIImageView()
expandIconView.image = PresentationResourcesItemList.disclosureArrowImage(component.theme)
self.expandIconView = expandIconView
self.addSubview(expandIconView)
}
if let image = expandIconView.image {
availableWidth -= image.size.width + 6.0
transition.setBounds(view: expandIconView, bounds: CGRect(origin: CGPoint(), size: image.size))
}
} else if let expandIconView = self.expandIconView {
self.expandIconView = nil
expandIconView.removeFromSuperview()
}
let fractionString: String
if component.category.sizeFraction != 0.0 {
let fractionValue: Double = floor(component.category.sizeFraction * 100.0 * 10.0) / 10.0
if fractionValue < 0.1 {
fractionString = "<0.1%"
} else if abs(Double(Int(fractionValue)) - fractionValue) < 0.001 {
fractionString = "\(Int(fractionValue))%"
} else {
fractionString = "\(fractionValue)%"
}
} else {
fractionString = ""
}
let labelSize = self.label.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: dataSizeString(Int(component.category.size), formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: ".")), font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
availableWidth = max(1.0, availableWidth - labelSize.width - 1.0)
let titleValueSize = self.titleValue.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: fractionString, font: Font.regular(17.0), textColor: component.theme.list.itemSecondaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
availableWidth = max(1.0, availableWidth - titleValueSize.width - 4.0)
let titleSize = self.title.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.category.title, font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor)))),
environment: {},
containerSize: CGSize(width: availableWidth, height: 100.0)
)
var height: CGFloat = 44.0
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
let titleValueFrame = CGRect(origin: CGPoint(x: titleFrame.maxX + 4.0, y: floor((height - titleValueSize.height) / 2.0)), size: titleValueSize)
var labelFrame = CGRect(origin: CGPoint(x: availableSize.width - rightInset - labelSize.width, y: floor((height - labelSize.height) / 2.0)), size: labelSize)
if let expandIconView = self.expandIconView, let image = expandIconView.image {
labelFrame.origin.x -= image.size.width - 6.0
transition.setPosition(view: expandIconView, position: CGPoint(x: availableSize.width - rightInset + 6.0 - floor(image.size.width * 0.5), y: floor(height * 0.5)))
let angle: CGFloat = component.isExpanded ? CGFloat.pi : 0.0
transition.setTransform(view: expandIconView, transform: CATransform3DMakeRotation(CGFloat.pi * 0.5 - angle, 0.0, 0.0, 1.0))
}
if let image = self.iconView.image {
transition.setFrame(view: self.iconView, frame: CGRect(origin: CGPoint(x: floor((leftInset - image.size.width) * 0.5), y: floor((height - image.size.height) * 0.5)), size: image.size))
}
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
transition.setFrame(view: titleView, frame: titleFrame)
}
if let titleValueView = self.titleValue.view {
if titleValueView.superview == nil {
titleValueView.isUserInteractionEnabled = false
self.addSubview(titleValueView)
}
if titleValueView.bounds.size != titleValueFrame.size {
titleValueView.frame = titleValueFrame
} else {
transition.setFrame(view: titleValueView, frame: titleValueFrame)
}
}
if let labelView = self.label.view {
if labelView.superview == nil {
labelView.isUserInteractionEnabled = false
self.addSubview(labelView)
}
transition.setFrame(view: labelView, frame: labelFrame)
}
if themeUpdated {
self.separatorLayer.backgroundColor = component.theme.list.itemBlocksSeparatorColor.cgColor
}
transition.setFrame(layer: self.separatorLayer, frame: CGRect(origin: CGPoint(x: leftInset, y: height), size: CGSize(width: availableSize.width - leftInset, height: UIScreenPixel)))
transition.setAlpha(layer: self.separatorLayer, alpha: (component.isExpanded || component.hasNext) ? 1.0 : 0.0)
self.highlightBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height + ((component.isExpanded || component.hasNext) ? UIScreenPixel : 0.0)))
var validKeys = Set<AnyHashable>()
if component.isExpanded, component.category.isSeparable {
struct SubItem {
var id: AnyHashable
var isIncoming: Bool
var value: Int64
}
let items: [SubItem] = [
SubItem(id: "in", isIncoming: true, value: component.category.incoming),
SubItem(id: "out", isIncoming: false, value: component.category.outgoing)
]
for i in 0 ..< items.count {
let item = items[i]
validKeys.insert(item.id)
var itemTransition = transition
let itemView: ComponentView<Empty>
if let current = self.itemViews[item.id] {
itemView = current
} else {
itemTransition = .immediate
itemView = ComponentView()
self.itemViews[item.id] = itemView
}
itemView.parentState = state
let itemSize = itemView.update(
transition: itemTransition,
component: AnyComponent(SubItemComponent(
theme: component.theme,
strings: component.strings,
isIncoming: item.isIncoming,
value: item.value,
hasNext: i != items.count - 1
)),
environment: {},
containerSize: CGSize(width: availableSize.width, height: 1000.0)
)
let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: height), size: itemSize)
if let itemComponentView = itemView.view {
if itemComponentView.superview == nil {
self.subcategoryClippingContainer.addSubview(itemComponentView)
if !transition.animation.isImmediate {
itemComponentView.alpha = 0.0
transition.setAlpha(view: itemComponentView, alpha: 1.0)
}
}
itemTransition.setFrame(view: itemComponentView, frame: itemFrame)
}
height += itemSize.height
}
}
var removeKeys: [AnyHashable] = []
for (key, itemView) in self.itemViews {
if !validKeys.contains(key) {
if let itemComponentView = itemView.view {
transition.setAlpha(view: itemComponentView, alpha: 0.0, completion: { [weak itemComponentView] _ in
itemComponentView?.removeFromSuperview()
})
}
removeKeys.append(key)
}
}
for key in removeKeys {
self.itemViews.removeValue(forKey: key)
}
transition.setFrame(view: self.subcategoryClippingContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height)))
return CGSize(width: availableSize.width, height: height)
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -210,20 +210,24 @@ private final class ChartLabel: UIView {
final class PieChartComponent: Component {
struct ChartData: Equatable {
struct Item: Equatable {
var id: StorageUsageScreenComponent.Category
var id: AnyHashable
var displayValue: Double
var displaySize: Int64
var value: Double
var color: UIColor
var particle: String?
var title: String
var mergeable: Bool
var mergeFactor: CGFloat
init(id: StorageUsageScreenComponent.Category, displayValue: Double, displaySize: Int64, value: Double, color: UIColor, mergeable: Bool, mergeFactor: CGFloat) {
init(id: AnyHashable, displayValue: Double, displaySize: Int64, value: Double, color: UIColor, particle: String?, title: String, mergeable: Bool, mergeFactor: CGFloat) {
self.id = id
self.displayValue = displayValue
self.displaySize = displaySize
self.value = value
self.color = color
self.particle = particle
self.title = title
self.mergeable = mergeable
self.mergeFactor = mergeFactor
}
@ -296,8 +300,10 @@ final class PieChartComponent: Component {
}
private struct CalculatedSection {
var id: StorageUsageScreenComponent.Category
var id: AnyHashable
var color: UIColor
var particle: String?
var title: String
var innerAngle: Range<CGFloat>
var outerAngle: Range<CGFloat>
var innerRadius: CGFloat
@ -305,8 +311,10 @@ final class PieChartComponent: Component {
var label: CalculatedLabel?
init(
id: StorageUsageScreenComponent.Category,
id: AnyHashable,
color: UIColor,
particle: String?,
title: String,
innerAngle: Range<CGFloat>,
outerAngle: Range<CGFloat>,
innerRadius: CGFloat,
@ -315,6 +323,8 @@ final class PieChartComponent: Component {
) {
self.id = id
self.color = color
self.particle = particle
self.title = title
self.innerAngle = innerAngle
self.outerAngle = outerAngle
self.innerRadius = innerRadius
@ -361,6 +371,8 @@ final class PieChartComponent: Component {
self.sections.append(CalculatedSection(
id: right.id,
color: left.color.interpolateTo(right.color, fraction: progress) ?? right.color,
particle: right.particle,
title: right.title,
innerAngle: innerAngle,
outerAngle: outerAngle,
innerRadius: left.innerRadius.interpolate(to: right.innerRadius, amount: progress),
@ -440,6 +452,8 @@ final class PieChartComponent: Component {
self.sections.append(CalculatedSection(
id: item.id,
color: itemColor,
particle: item.particle,
title: item.title,
innerAngle: arcInnerStartAngle ..< arcInnerEndAngle,
outerAngle: arcOuterStartAngle ..< arcOuterEndAngle,
innerRadius: innerDiameter * 0.5,
@ -782,7 +796,7 @@ final class PieChartComponent: Component {
private var particleImage: UIImage?
private var particleLayers: [SimpleLayer] = []
init(category: StorageUsageScreenComponent.Category) {
init(particle: String?) {
self.maskLayer = SimpleShapeLayer()
self.maskLayer.fillColor = UIColor.white.cgColor
@ -799,23 +813,8 @@ final class PieChartComponent: Component {
self.addSublayer(self.gradientLayer)
self.addSublayer(self.labelLayer)
switch category {
case .photos:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticlePhotos")?.precomposed()
case .videos:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleVideos")?.precomposed()
case .files:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleDocuments")?.precomposed()
case .music:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleMusic")?.precomposed()
case .other:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleOther")?.precomposed()
case .stickers:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleStickers")?.precomposed()
case .avatars:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleAvatars")?.precomposed()
case .misc:
self.particleImage = UIImage(bundleImageName: "Settings/Storage/ParticleOther")?.precomposed()
if let particle {
self.particleImage = UIImage(bundleImageName: particle)?.precomposed()
}
}
@ -1069,9 +1068,9 @@ final class PieChartComponent: Component {
return nil
}
func tooltipLocation(forKey key: StorageUsageScreenComponent.Category) -> CGPoint? {
func tooltipLocation(forKey key: AnyHashable) -> CGPoint? {
for (id, itemLayer) in self.sectionLayers {
if id == AnyHashable(key) {
if id == key {
return itemLayer.tooltipLocation()
}
}
@ -1117,7 +1116,7 @@ final class PieChartComponent: Component {
if data.items.isEmpty {
self.currentLayout = CalculatedLayout(
size: CGSize(width: 200.0, height: 200.0),
items: [.init(id: .other, displayValue: 0.0, displaySize: 0, value: 1.0, color: .green, mergeable: false, mergeFactor: 1.0)],
items: [.init(id: AnyHashable(StorageUsageScreenComponent.Category.other), displayValue: 0.0, displaySize: 0, value: 1.0, color: .green, particle: "Settings/Storage/ParticleOther", title: "", mergeable: false, mergeFactor: 1.0)],
selectedKey: self.selectedKey,
isEmpty: true
)
@ -1217,7 +1216,7 @@ final class PieChartComponent: Component {
if let current = self.sectionLayers[section.id] {
sectionLayer = current
} else {
sectionLayer = SectionLayer(category: section.id)
sectionLayer = SectionLayer(particle: section.particle)
self.sectionLayers[section.id] = sectionLayer
self.layer.addSublayer(sectionLayer)
}
@ -1296,7 +1295,7 @@ final class PieChartComponent: Component {
transition.setFrame(view: self.dataView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - 200.0) / 2.0), y: 0.0), size: CGSize(width: 200.0, height: 200.0)))
self.dataView.setItems(theme: component.theme, data: component.chartData, selectedKey: self.selectedKey, animated: !transition.animation.isImmediate)
if let selectedKey = self.selectedKey?.base as? StorageUsageScreenComponent.Category, let item = component.chartData.items.first(where: { $0.id == selectedKey }) {
if let selectedKey = self.selectedKey, let item = component.chartData.items.first(where: { $0.id == selectedKey }) {
let tooltip: ComponentView<Empty>
var tooltipTransition = transition
var animateIn = false
@ -1334,7 +1333,7 @@ final class PieChartComponent: Component {
component: AnyComponent(ChartSelectionTooltip(
theme: component.theme,
fractionText: fractionString,
title: selectedKey.title(strings: component.strings),
title: item.title,
sizeText: dataSizeString(Int(item.displaySize), formatting: DataSizeStringFormatting(strings: component.strings, decimalSeparator: "."))
)),
environment: {},

View File

@ -0,0 +1,113 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import ComponentFlow
import SwiftSignalKit
import ViewControllerComponent
import ComponentDisplayAdapters
import TelegramPresentationData
import AccountContext
import TelegramCore
import MultilineTextComponent
import EmojiStatusComponent
import Postbox
import TelegramStringFormatting
import CheckNode
import SegmentedControlNode
final class SegmentControlComponent: Component {
struct Item: Equatable {
var id: AnyHashable
var title: String
}
let theme: PresentationTheme
let items: [Item]
let selectedId: AnyHashable?
let action: (AnyHashable) -> Void
init(
theme: PresentationTheme,
items: [Item],
selectedId: AnyHashable?,
action: @escaping (AnyHashable) -> Void
) {
self.theme = theme
self.items = items
self.selectedId = selectedId
self.action = action
}
static func ==(lhs: SegmentControlComponent, rhs: SegmentControlComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.items != rhs.items {
return false
}
if lhs.selectedId != rhs.selectedId {
return false
}
return true
}
class View: UIView {
private let title = ComponentView<Empty>()
private var component: SegmentControlComponent?
private var segmentedNode: SegmentedControlNode?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: SegmentControlComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let themeUpdated = self.component?.theme !== component.theme
self.component = component
let segmentedNode: SegmentedControlNode
if let current = self.segmentedNode {
segmentedNode = current
if themeUpdated {
segmentedNode.updateTheme(SegmentedControlTheme(theme: component.theme))
}
} else {
let mappedItems: [SegmentedControlItem] = component.items.map { item -> SegmentedControlItem in
return SegmentedControlItem(title: item.title)
}
segmentedNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: component.theme), items: mappedItems, selectedIndex: component.items.firstIndex(where: { $0.id == component.selectedId }) ?? 0)
self.segmentedNode = segmentedNode
self.addSubnode(segmentedNode)
segmentedNode.selectedIndexChanged = { [weak self] index in
guard let self, let component = self.component else {
return
}
self.component?.action(component.items[index].id)
}
}
let controlSize = segmentedNode.updateLayout(SegmentedControlLayout.sizeToFit(maximumWidth: availableSize.width, minimumWidth: min(availableSize.width, 296.0), height: 31.0), transition: transition.containedViewLayoutTransition)
transition.containedViewLayoutTransition.updateFrame(node: segmentedNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: controlSize))
return controlSize
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View File

@ -305,6 +305,27 @@ final class StorageUsageScreenComponent: Component {
return strings.StorageManagement_SectionMiscellaneous
}
}
var particle: String? {
switch self {
case .photos:
return "Settings/Storage/ParticlePhotos"
case .videos:
return "Settings/Storage/ParticleVideos"
case .files:
return "Settings/Storage/ParticleDocuments"
case .music:
return "Settings/Storage/ParticleMusic"
case .other:
return "Settings/Storage/ParticleOther"
case .stickers:
return "Settings/Storage/ParticleStickers"
case .avatars:
return "Settings/Storage/ParticleAvatars"
case .misc:
return "Settings/Storage/ParticleOther"
}
}
}
private final class AggregatedData {
@ -1306,7 +1327,7 @@ final class StorageUsageScreenComponent: Component {
if let aggregatedData = self.aggregatedData, !aggregatedData.selectedCategories.isEmpty && !aggregatedData.selectedCategories.contains(listCategory.key) {
categoryChartFraction = 0.0
}
chartItems.append(PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, displaySize: listCategory.size, value: categoryChartFraction, color: listCategory.color, mergeable: false, mergeFactor: 1.0))
chartItems.append(PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, displaySize: listCategory.size, value: categoryChartFraction, color: listCategory.color, particle: listCategory.key.particle, title: listCategory.key.title(strings: environment.strings), mergeable: false, mergeFactor: 1.0))
}
var totalOtherSize: Int64 = 0
@ -1339,7 +1360,7 @@ final class StorageUsageScreenComponent: Component {
categoryChartFraction = 0.0
}
var chartItem = PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, displaySize: listCategory.size, value: categoryChartFraction, color: listCategory.color, mergeable: false, mergeFactor: 1.0)
var chartItem = PieChartComponent.ChartData.Item(id: listCategory.key, displayValue: listCategory.sizeFraction, displaySize: listCategory.size, value: categoryChartFraction, color: listCategory.color, particle: listCategory.key.particle, title: listCategory.key.title(strings: environment.strings), mergeable: false, mergeFactor: 1.0)
if chartItem.value > 0.00001 {
chartItem.value = max(chartItem.value, 0.01)
@ -1355,7 +1376,7 @@ final class StorageUsageScreenComponent: Component {
}
if !listCategories.isEmpty {
chartItems.append(PieChartComponent.ChartData.Item(id: .other, displayValue: otherRealSum, displaySize: totalOtherSize, value: self.isOtherCategoryExpanded ? 0.0 : otherSum, color: Category.misc.color, mergeable: false, mergeFactor: 1.0))
chartItems.append(PieChartComponent.ChartData.Item(id: AnyHashable(Category.other), displayValue: otherRealSum, displaySize: totalOtherSize, value: self.isOtherCategoryExpanded ? 0.0 : otherSum, color: Category.misc.color, particle: Category.misc.particle, title: Category.misc.title(strings: environment.strings), mergeable: false, mergeFactor: 1.0))
}
let chartData = PieChartComponent.ChartData(items: chartItems)

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "smile_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,175 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 3.000000 1.669922 cm
0.000000 0.000000 0.000000 scn
17.334999 10.330078 m
17.334999 5.726785 13.603293 1.995079 9.000000 1.995079 c
9.000000 0.665077 l
14.337832 0.665077 18.665001 4.992246 18.665001 10.330078 c
17.334999 10.330078 l
h
9.000000 1.995079 m
4.396707 1.995079 0.665000 5.726785 0.665000 10.330078 c
-0.665000 10.330078 l
-0.665000 4.992246 3.662168 0.665077 9.000000 0.665077 c
9.000000 1.995079 l
h
0.665000 10.330078 m
0.665000 14.933372 4.396707 18.665077 9.000000 18.665077 c
9.000000 19.995079 l
3.662168 19.995079 -0.665000 15.667911 -0.665000 10.330078 c
0.665000 10.330078 l
h
9.000000 18.665077 m
13.603293 18.665077 17.334999 14.933372 17.334999 10.330078 c
18.665001 10.330078 l
18.665001 15.667911 14.337832 19.995079 9.000000 19.995079 c
9.000000 18.665077 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 7.660156 12.477661 cm
0.000000 0.000000 0.000000 scn
2.347826 1.369570 m
2.347826 0.613180 1.822247 0.000005 1.173913 0.000005 c
0.525579 0.000005 0.000000 0.613180 0.000000 1.369570 c
0.000000 2.125960 0.525579 2.739136 1.173913 2.739136 c
1.822247 2.739136 2.347826 2.125960 2.347826 1.369570 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 14.000000 12.477661 cm
0.000000 0.000000 0.000000 scn
2.347826 1.369570 m
2.347826 0.613180 1.822247 0.000005 1.173913 0.000005 c
0.525579 0.000005 0.000000 0.613180 0.000000 1.369570 c
0.000000 2.125960 0.525579 2.739136 1.173913 2.739136 c
1.822247 2.739136 2.347826 2.125960 2.347826 1.369570 c
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.500000 6.076050 cm
0.000000 0.000000 0.000000 scn
7.572875 3.015941 m
7.759379 3.332331 7.654087 3.740008 7.337697 3.926513 c
7.021306 4.113018 6.613629 4.007725 6.427125 3.691334 c
7.572875 3.015941 l
h
0.572875 3.691335 m
0.386370 4.007725 -0.021307 4.113018 -0.337697 3.926513 c
-0.654087 3.740008 -0.759380 3.332331 -0.572875 3.015941 c
0.572875 3.691335 l
h
7.000000 3.353638 m
6.427125 3.691334 6.427270 3.691582 6.427412 3.691822 c
6.427454 3.691892 6.427591 3.692125 6.427674 3.692266 c
6.427841 3.692548 6.427992 3.692801 6.428125 3.693027 c
6.428393 3.693477 6.428595 3.693815 6.428731 3.694042 c
6.429003 3.694496 6.429012 3.694507 6.428758 3.694089 c
6.428248 3.693253 6.426688 3.690706 6.424076 3.686561 c
6.418847 3.678266 6.409435 3.663620 6.395833 3.643527 c
6.368581 3.603271 6.324809 3.541589 6.264480 3.465568 c
6.143271 3.312833 5.958584 3.106452 5.710678 2.900174 c
5.216724 2.489165 4.487087 2.089347 3.500000 2.089347 c
3.500000 0.759347 l
4.875639 0.759347 5.896002 1.324174 6.561367 1.877810 c
6.893120 2.153855 7.140421 2.429797 7.306286 2.638804 c
7.389494 2.743654 7.453030 2.832698 7.497203 2.897951 c
7.519312 2.930611 7.536642 2.957415 7.549225 2.977380 c
7.555520 2.987366 7.560634 2.995653 7.564572 3.002117 c
7.566542 3.005350 7.568218 3.008128 7.569601 3.010437 c
7.570293 3.011591 7.570911 3.012628 7.571457 3.013546 c
7.571730 3.014005 7.571984 3.014434 7.572220 3.014833 c
7.572339 3.015033 7.572502 3.015310 7.572561 3.015410 c
7.572720 3.015679 7.572875 3.015941 7.000000 3.353638 c
h
3.500000 2.089347 m
2.512913 2.089347 1.783276 2.489165 1.289322 2.900174 c
1.041416 3.106452 0.856728 3.312833 0.735520 3.465568 c
0.675191 3.541589 0.631418 3.603271 0.604167 3.643527 c
0.590564 3.663620 0.581153 3.678266 0.575924 3.686562 c
0.573312 3.690706 0.571751 3.693253 0.571242 3.694089 c
0.570987 3.694507 0.570996 3.694496 0.571268 3.694042 c
0.571404 3.693815 0.571606 3.693477 0.571874 3.693027 c
0.572008 3.692801 0.572158 3.692548 0.572325 3.692266 c
0.572408 3.692125 0.572546 3.691892 0.572588 3.691822 c
0.572729 3.691582 0.572875 3.691335 0.000000 3.353638 c
-0.572875 3.015941 -0.572721 3.015679 -0.572562 3.015410 c
-0.572503 3.015310 -0.572339 3.015033 -0.572221 3.014833 c
-0.571985 3.014434 -0.571730 3.014005 -0.571457 3.013546 c
-0.570912 3.012628 -0.570293 3.011591 -0.569602 3.010437 c
-0.568218 3.008128 -0.566542 3.005350 -0.564573 3.002117 c
-0.560634 2.995653 -0.555520 2.987366 -0.549226 2.977380 c
-0.536642 2.957415 -0.519313 2.930610 -0.497203 2.897950 c
-0.453030 2.832698 -0.389495 2.743654 -0.306287 2.638804 c
-0.140421 2.429797 0.106880 2.153855 0.438633 1.877810 c
1.103997 1.324174 2.124361 0.759347 3.500000 0.759347 c
3.500000 2.089347 l
h
f
n
Q
endstream
endobj
3 0 obj
4309
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000004399 00000 n
0000004422 00000 n
0000004595 00000 n
0000004669 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
4728
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "calls.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,111 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
1.000000 0.584314 0.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 6.000000 6.000000 cm
1.000000 1.000000 1.000000 scn
4.868853 4.891197 m
2.124590 7.636960 0.000000 11.022417 0.000000 13.837070 c
0.000000 15.086933 0.413115 16.218699 1.357377 17.133953 c
1.927869 17.694916 2.596721 18.000000 3.216393 18.000000 c
3.747541 18.000000 4.229508 17.783487 4.573771 17.301258 c
6.244052 14.601130 l
6.749065 13.784742 6.700242 12.741879 6.121165 11.976244 c
4.939975 10.414518 l
4.831778 10.306263 4.792434 10.188166 4.792434 10.060226 c
4.792434 9.942129 4.841614 9.814191 4.890794 9.705935 c
5.176040 9.105606 6.031778 8.062413 7.035057 7.058586 c
8.028500 6.054759 9.090795 5.218237 9.671123 4.913152 c
9.779319 4.863944 9.907188 4.814737 10.044893 4.814737 c
10.182598 4.814737 10.310467 4.854102 10.418663 4.962358 c
11.944046 6.134850 l
12.711500 6.724756 13.764204 6.777284 14.586570 6.266706 c
17.340984 4.556588 l
17.822952 4.221979 18.000000 3.769273 18.000000 3.296884 c
18.000000 2.637506 17.626228 1.948606 17.124590 1.417168 c
16.219671 0.442865 15.118032 0.000000 13.829508 0.000000 c
11.016394 0.000000 7.603279 2.155275 4.868853 4.891197 c
h
f*
n
Q
endstream
endobj
3 0 obj
2078
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002168 00000 n
0000002191 00000 n
0000002364 00000 n
0000002438 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2497
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "down.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,159 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 0.000000 -1.000000 5.500061 11.394928 cm
0.000000 0.000000 0.000000 scn
-0.470226 1.865154 m
-0.729925 1.605455 -0.729925 1.184401 -0.470226 0.924702 c
-0.210527 0.665003 0.210527 0.665003 0.470226 0.924702 c
-0.470226 1.865154 l
h
3.500000 4.894928 m
3.970228 5.365152 l
3.845517 5.489864 3.676371 5.559927 3.500001 5.559928 c
3.323632 5.559928 3.154486 5.489866 3.029774 5.365154 c
3.500000 4.894928 l
h
6.529741 0.924704 m
6.789439 0.665004 7.210494 0.665002 7.470193 0.924700 c
7.729893 1.184397 7.729895 1.605452 7.470198 1.865152 c
6.529741 0.924704 l
h
0.470226 0.924702 m
3.970226 4.424702 l
3.029774 5.365154 l
-0.470226 1.865154 l
0.470226 0.924702 l
h
3.029772 4.424704 m
6.529741 0.924704 l
7.470198 1.865152 l
3.970228 5.365152 l
3.029772 4.424704 l
h
f
n
Q
q
-1.000000 -0.000000 0.000000 -1.000000 9.000031 16.825317 cm
0.000000 0.000000 0.000000 scn
-0.665000 1.330017 m
-0.665000 0.962748 -0.367269 0.665017 0.000000 0.665017 c
0.367269 0.665017 0.665000 0.962748 0.665000 1.330017 c
-0.665000 1.330017 l
h
0.665000 9.330017 m
0.665000 9.697287 0.367269 9.995017 -0.000000 9.995017 c
-0.367269 9.995017 -0.665000 9.697287 -0.665000 9.330017 c
0.665000 9.330017 l
h
0.665000 1.330017 m
0.665000 9.330017 l
-0.665000 9.330017 l
-0.665000 1.330017 l
0.665000 1.330017 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.000000 1.665283 cm
0.000000 0.000000 0.000000 scn
0.000000 1.995017 m
-0.367269 1.995017 -0.665000 1.697286 -0.665000 1.330017 c
-0.665000 0.962748 -0.367269 0.665017 0.000000 0.665017 c
0.000000 1.995017 l
h
10.000000 0.665017 m
10.367270 0.665017 10.665000 0.962748 10.665000 1.330017 c
10.665000 1.697286 10.367270 1.995017 10.000000 1.995017 c
10.000000 0.665017 l
h
0.000000 0.665017 m
10.000000 0.665017 l
10.000000 1.995017 l
0.000000 1.995017 l
0.000000 0.665017 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.000000 1.665283 cm
0.000000 0.000000 0.000000 scn
0.000000 1.995017 m
-0.367269 1.995017 -0.665000 1.697286 -0.665000 1.330017 c
-0.665000 0.962748 -0.367269 0.665017 0.000000 0.665017 c
0.000000 1.995017 l
h
10.000000 0.665017 m
10.367270 0.665017 10.665000 0.962748 10.665000 1.330017 c
10.665000 1.697286 10.367270 1.995017 10.000000 1.995017 c
10.000000 0.665017 l
h
0.000000 0.665017 m
10.000000 0.665017 l
10.000000 1.995017 l
0.000000 1.995017 l
0.000000 0.665017 l
h
f
n
Q
endstream
endobj
3 0 obj
2383
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 18.000000 18.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002473 00000 n
0000002496 00000 n
0000002669 00000 n
0000002743 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2802
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "up.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,207 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
-1.000000 0.000000 0.000000 1.000000 12.500031 10.598022 cm
0.000000 0.000000 0.000000 scn
-0.470226 1.865154 m
-0.729925 1.605455 -0.729925 1.184401 -0.470226 0.924702 c
-0.210527 0.665003 0.210527 0.665003 0.470226 0.924702 c
-0.470226 1.865154 l
h
3.500000 4.894928 m
3.970228 5.365152 l
3.845517 5.489864 3.676371 5.559927 3.500001 5.559928 c
3.323632 5.559928 3.154486 5.489866 3.029774 5.365154 c
3.500000 4.894928 l
h
6.529741 0.924704 m
6.789439 0.665004 7.210494 0.665002 7.470193 0.924700 c
7.729893 1.184397 7.729895 1.605452 7.470198 1.865152 c
6.529741 0.924704 l
h
0.470226 0.924702 m
3.970226 4.424702 l
3.029774 5.365154 l
-0.470226 1.865154 l
0.470226 0.924702 l
h
3.029772 4.424704 m
6.529741 0.924704 l
7.470198 1.865152 l
3.970228 5.365152 l
3.029772 4.424704 l
h
f
n
Q
q
-1.000000 -0.000000 0.000000 -1.000000 9.000031 15.822968 cm
0.000000 0.000000 0.000000 scn
-0.665000 1.330017 m
-0.665000 0.962748 -0.367269 0.665017 0.000000 0.665017 c
0.367269 0.665017 0.665000 0.962748 0.665000 1.330017 c
-0.665000 1.330017 l
h
0.665000 9.330017 m
0.665000 9.697287 0.367269 9.995017 -0.000000 9.995017 c
-0.367269 9.995017 -0.665000 9.697287 -0.665000 9.330017 c
0.665000 9.330017 l
h
0.665000 1.330017 m
0.665000 9.330017 l
-0.665000 9.330017 l
-0.665000 1.330017 l
0.665000 1.330017 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.000000 1.662933 cm
0.000000 0.000000 0.000000 scn
0.665000 3.330017 m
0.665000 3.697286 0.367269 3.995017 0.000000 3.995017 c
-0.367269 3.995017 -0.665000 3.697286 -0.665000 3.330017 c
0.665000 3.330017 l
h
10.665000 3.330017 m
10.665000 3.697286 10.367270 3.995017 10.000000 3.995017 c
9.632730 3.995017 9.335000 3.697286 9.335000 3.330017 c
10.665000 3.330017 l
h
1.000000 0.665017 m
9.000000 0.665017 l
9.000000 1.995017 l
1.000000 1.995017 l
1.000000 0.665017 l
h
0.665000 2.330017 m
0.665000 3.330017 l
-0.665000 3.330017 l
-0.665000 2.330017 l
0.665000 2.330017 l
h
10.665000 2.330017 m
10.665000 3.330017 l
9.335000 3.330017 l
9.335000 2.330017 l
10.665000 2.330017 l
h
9.000000 0.665017 m
9.919554 0.665017 10.665000 1.410463 10.665000 2.330017 c
9.335000 2.330017 l
9.335000 2.145002 9.185016 1.995017 9.000000 1.995017 c
9.000000 0.665017 l
h
1.000000 1.995017 m
0.814985 1.995017 0.665000 2.145002 0.665000 2.330017 c
-0.665000 2.330017 l
-0.665000 1.410463 0.080446 0.665017 1.000000 0.665017 c
1.000000 1.995017 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.000000 1.662933 cm
0.000000 0.000000 0.000000 scn
0.665000 3.330017 m
0.665000 3.697286 0.367269 3.995017 0.000000 3.995017 c
-0.367269 3.995017 -0.665000 3.697286 -0.665000 3.330017 c
0.665000 3.330017 l
h
10.665000 3.330017 m
10.665000 3.697286 10.367270 3.995017 10.000000 3.995017 c
9.632730 3.995017 9.335000 3.697286 9.335000 3.330017 c
10.665000 3.330017 l
h
1.000000 0.665017 m
9.000000 0.665017 l
9.000000 1.995017 l
1.000000 1.995017 l
1.000000 0.665017 l
h
0.665000 2.330017 m
0.665000 3.330017 l
-0.665000 3.330017 l
-0.665000 2.330017 l
0.665000 2.330017 l
h
10.665000 2.330017 m
10.665000 3.330017 l
9.335000 3.330017 l
9.335000 2.330017 l
10.665000 2.330017 l
h
9.000000 0.665017 m
9.919554 0.665017 10.665000 1.410463 10.665000 2.330017 c
9.335000 2.330017 l
9.335000 2.145002 9.185016 1.995017 9.000000 1.995017 c
9.000000 0.665017 l
h
1.000000 1.995017 m
0.814985 1.995017 0.665000 2.145002 0.665000 2.330017 c
-0.665000 2.330017 l
-0.665000 1.410463 0.080446 0.665017 1.000000 0.665017 c
1.000000 1.995017 l
h
f
n
Q
endstream
endobj
3 0 obj
3492
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 18.000000 18.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003582 00000 n
0000003605 00000 n
0000003778 00000 n
0000003852 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3911
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "files.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,143 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.203922 0.780392 0.349020 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 7.000000 6.000000 cm
1.000000 1.000000 1.000000 scn
5.330000 18.000000 m
5.807298 18.000000 6.123703 17.999550 6.367812 17.982895 c
6.604466 17.966749 6.711959 17.938187 6.777740 17.910938 c
7.064423 17.792191 7.292191 17.564423 7.410939 17.277740 c
7.438186 17.211960 7.466748 17.104465 7.482895 16.867813 c
7.499550 16.623703 7.500000 16.307299 7.500000 15.830000 c
7.500000 13.530003 l
7.500000 13.496872 l
7.499987 12.965037 7.499976 12.516354 7.530005 12.148819 c
7.561447 11.763987 7.629904 11.395631 7.808452 11.045210 c
8.079773 10.512712 8.512709 10.079777 9.045207 9.808455 c
9.395627 9.629908 9.763983 9.561451 10.148815 9.530008 c
10.516351 9.499980 10.965034 9.499990 11.496870 9.500004 c
11.530001 9.500004 l
13.829997 9.500004 l
14.307296 9.500004 14.623703 9.499555 14.867812 9.482899 c
15.104466 9.466752 15.211960 9.438190 15.277740 9.410942 c
15.564423 9.292194 15.792191 9.064426 15.910938 8.777744 c
15.938186 8.711964 15.966748 8.604470 15.982895 8.367816 c
15.999551 8.123706 16.000000 7.807300 16.000000 7.330000 c
16.000000 4.800000 l
16.000000 3.119843 16.000000 2.279763 15.673019 1.638029 c
15.385400 1.073542 14.926457 0.614601 14.361972 0.326981 c
13.720237 0.000000 12.880157 0.000000 11.200000 0.000000 c
4.800000 0.000000 l
3.119843 0.000000 2.279764 0.000000 1.638029 0.326981 c
1.073542 0.614601 0.614601 1.073542 0.326980 1.638029 c
0.000000 2.279763 0.000000 3.119843 0.000000 4.800000 c
0.000000 13.200001 l
0.000000 14.880157 0.000000 15.720236 0.326980 16.361971 c
0.614601 16.926458 1.073542 17.385399 1.638029 17.673019 c
2.279764 18.000000 3.119843 18.000000 4.800000 18.000000 c
5.330000 18.000000 l
h
15.621112 11.042418 m
15.558301 11.176268 15.488032 11.306717 15.410561 11.433140 c
15.163194 11.836806 14.817290 12.182710 14.125484 12.874516 c
10.874516 16.125484 l
10.182710 16.817291 9.836806 17.163193 9.433140 17.410561 c
9.306716 17.488033 9.176266 17.558304 9.042415 17.621115 c
9.097363 17.412268 9.124138 17.199299 9.139045 16.980810 c
9.160017 16.673437 9.160009 16.300030 9.160000 15.857494 c
9.160000 15.830000 l
9.160000 13.530003 l
9.160000 12.956255 9.160645 12.575861 9.184492 12.283996 c
9.207546 12.001820 9.248083 11.876238 9.287522 11.798835 c
9.399694 11.578686 9.578682 11.399698 9.798831 11.287526 c
9.876234 11.248087 10.001816 11.207550 10.283993 11.184496 c
10.575858 11.160649 10.956251 11.160004 11.530001 11.160004 c
13.829997 11.160004 l
13.857491 11.160004 l
14.300028 11.160013 14.673436 11.160021 14.980811 11.139048 c
15.199297 11.124141 15.412265 11.097366 15.621112 11.042418 c
h
f*
n
Q
endstream
endobj
3 0 obj
3553
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003643 00000 n
0000003666 00000 n
0000003839 00000 n
0000003913 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3972
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "datain.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,148 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.203922 0.780392 0.349020 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
0.000000 1.000000 -1.000000 0.000000 22.778702 10.334999 cm
1.000000 1.000000 1.000000 scn
0.341218 6.954933 m
-0.113739 7.409894 -0.113739 8.147528 0.341218 8.602488 c
5.841218 14.102518 l
6.296178 14.557480 7.033815 14.557482 7.488777 14.102523 c
7.943739 13.647563 7.943741 12.909925 7.488781 12.454964 c
3.977601 8.943764 l
13.165000 8.943764 l
13.808412 8.943764 14.330000 8.422175 14.330000 7.778764 c
14.330000 7.135352 13.808412 6.613764 13.165000 6.613764 c
3.977494 6.613764 l
7.488781 3.102457 l
7.943741 2.647495 7.943739 1.909858 7.488777 1.454898 c
7.033815 0.999939 6.296178 0.999941 5.841218 1.454903 c
0.341218 6.954933 l
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.000000 4.669998 cm
0.000000 0.000000 0.000000 scn
0.000000 3.495002 m
-0.643412 3.495002 -1.165000 2.973413 -1.165000 2.330002 c
-1.165000 1.686590 -0.643412 1.165002 0.000000 1.165002 c
0.000000 3.495002 l
h
14.000000 1.165002 m
14.643412 1.165002 15.165000 1.686590 15.165000 2.330002 c
15.165000 2.973413 14.643412 3.495002 14.000000 3.495002 c
14.000000 1.165002 l
h
0.000000 1.165002 m
14.000000 1.165002 l
14.000000 3.495002 l
0.000000 3.495002 l
0.000000 1.165002 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.000000 4.669998 cm
1.000000 1.000000 1.000000 scn
0.000000 3.495002 m
-0.643412 3.495002 -1.165000 2.973413 -1.165000 2.330002 c
-1.165000 1.686590 -0.643412 1.165002 0.000000 1.165002 c
0.000000 3.495002 l
h
14.000000 1.165002 m
14.643412 1.165002 15.165000 1.686590 15.165000 2.330002 c
15.165000 2.973413 14.643412 3.495002 14.000000 3.495002 c
14.000000 1.165002 l
h
0.000000 1.165002 m
14.000000 1.165002 l
14.000000 3.495002 l
0.000000 3.495002 l
0.000000 1.165002 l
h
f
n
Q
endstream
endobj
3 0 obj
2638
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002728 00000 n
0000002751 00000 n
0000002924 00000 n
0000002998 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3057
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "messages.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,100 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.345098 0.337255 0.839216 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.000000 4.484375 cm
1.000000 1.000000 1.000000 scn
20.000000 11.044711 m
20.000000 16.065481 15.522848 20.135620 10.000000 20.135620 c
4.477152 20.135620 0.000000 16.065481 0.000000 11.044711 c
0.000000 8.181209 1.337573 5.834022 3.613619 4.167677 c
3.904685 3.954580 4.172771 2.770550 3.523984 1.775995 c
2.875197 0.781441 2.066323 0.326941 2.471971 0.156790 c
2.722059 0.051889 4.199766 -0.000002 5.266314 0.598131 c
6.791368 1.453400 7.217727 2.304844 7.545889 2.229574 c
8.331102 2.049473 9.153261 1.953802 10.000000 1.953802 c
15.522848 1.953802 20.000000 6.023941 20.000000 11.044711 c
h
f
n
Q
endstream
endobj
3 0 obj
1584
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001674 00000 n
0000001697 00000 n
0000001870 00000 n
0000001944 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2003
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "music.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,103 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
1.000000 0.176471 0.333333 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.000000 5.000000 cm
1.000000 1.000000 1.000000 scn
10.000000 0.000000 m
15.522847 0.000000 20.000000 4.477153 20.000000 10.000000 c
20.000000 15.522848 15.522847 20.000000 10.000000 20.000000 c
4.477152 20.000000 0.000000 15.522848 0.000000 10.000000 c
0.000000 4.477153 4.477152 0.000000 10.000000 0.000000 c
h
14.751925 9.167950 m
8.554701 5.036467 l
7.890146 4.593431 7.000000 5.069821 7.000000 5.868517 c
7.000000 14.131483 l
7.000000 14.930179 7.890145 15.406569 8.554700 14.963533 c
14.751925 10.832050 l
15.345657 10.436228 15.345657 9.563771 14.751925 9.167950 c
h
f*
n
Q
endstream
endobj
3 0 obj
1564
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001654 00000 n
0000001677 00000 n
0000001850 00000 n
0000001924 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1983
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "dataout.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,197 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.000000 0.478431 1.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
0.000000 -1.000000 1.000000 0.000000 7.335037 24.665001 cm
1.000000 1.000000 1.000000 scn
0.341223 6.841220 m
0.122742 7.059700 0.000000 7.356022 0.000000 7.665000 c
0.000000 7.973978 0.122740 8.270301 0.341221 8.488781 c
5.841220 13.988781 l
6.296181 14.443742 7.033819 14.443742 7.488780 13.988781 c
7.943740 13.533820 7.943740 12.796184 7.488780 12.341223 c
3.977603 8.830046 l
13.165001 8.830046 l
13.808413 8.830046 14.330001 8.308458 14.330001 7.665046 c
14.330001 7.021635 13.808413 6.500046 13.165001 6.500046 c
3.977525 6.500046 l
7.488777 2.988814 l
7.943739 2.533854 7.943741 1.796217 7.488781 1.341255 c
7.033822 0.886293 6.296185 0.886292 5.841223 1.341250 c
0.341223 6.841220 l
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.000000 4.669998 cm
0.000000 0.000000 0.000000 scn
1.165000 4.330002 m
1.165000 4.973413 0.643412 5.495002 0.000000 5.495002 c
-0.643412 5.495002 -1.165000 4.973413 -1.165000 4.330002 c
1.165000 4.330002 l
h
15.165000 4.330002 m
15.165000 4.973413 14.643412 5.495002 14.000000 5.495002 c
13.356588 5.495002 12.835000 4.973413 12.835000 4.330002 c
15.165000 4.330002 l
h
1.000000 1.165002 m
13.000000 1.165002 l
13.000000 3.495002 l
1.000000 3.495002 l
1.000000 1.165002 l
h
1.165000 3.330002 m
1.165000 4.330002 l
-1.165000 4.330002 l
-1.165000 3.330002 l
1.165000 3.330002 l
h
15.165000 3.330002 m
15.165000 4.330002 l
12.835000 4.330002 l
12.835000 3.330002 l
15.165000 3.330002 l
h
13.000000 1.165002 m
14.195696 1.165002 15.165000 2.134305 15.165000 3.330002 c
12.835000 3.330002 l
12.835000 3.421129 12.908874 3.495002 13.000000 3.495002 c
13.000000 1.165002 l
h
1.000000 3.495002 m
1.091127 3.495002 1.165000 3.421129 1.165000 3.330002 c
-1.165000 3.330002 l
-1.165000 2.134305 -0.195696 1.165002 1.000000 1.165002 c
1.000000 3.495002 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.000000 4.669998 cm
1.000000 1.000000 1.000000 scn
1.165000 4.330002 m
1.165000 4.973413 0.643412 5.495002 0.000000 5.495002 c
-0.643412 5.495002 -1.165000 4.973413 -1.165000 4.330002 c
1.165000 4.330002 l
h
15.165000 4.330002 m
15.165000 4.973413 14.643412 5.495002 14.000000 5.495002 c
13.356588 5.495002 12.835000 4.973413 12.835000 4.330002 c
15.165000 4.330002 l
h
1.000000 1.165002 m
13.000000 1.165002 l
13.000000 3.495002 l
1.000000 3.495002 l
1.000000 1.165002 l
h
1.165000 3.330002 m
1.165000 4.330002 l
-1.165000 4.330002 l
-1.165000 3.330002 l
1.165000 3.330002 l
h
15.165000 3.330002 m
15.165000 4.330002 l
12.835000 4.330002 l
12.835000 3.330002 l
15.165000 3.330002 l
h
13.000000 1.165002 m
14.195696 1.165002 15.165000 2.134305 15.165000 3.330002 c
12.835000 3.330002 l
12.835000 3.421129 12.908874 3.495002 13.000000 3.495002 c
13.000000 1.165002 l
h
1.000000 3.495002 m
1.091127 3.495002 1.165000 3.421129 1.165000 3.330002 c
-1.165000 3.330002 l
-1.165000 2.134305 -0.195696 1.165002 1.000000 1.165002 c
1.000000 3.495002 l
h
f
n
Q
endstream
endobj
3 0 obj
3829
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003919 00000 n
0000003942 00000 n
0000004115 00000 n
0000004189 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
4248
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "photos.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,155 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.352941 0.784314 0.980392 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 6.000000 6.000000 cm
1.000000 1.000000 1.000000 scn
0.326980 16.361971 m
0.000000 15.720236 0.000000 14.880157 0.000000 13.200001 c
0.000000 7.873625 l
2.719312 10.802114 l
2.739366 10.823713 l
2.739403 10.823753 l
2.739418 10.823770 l
2.925786 11.024508 3.099065 11.211145 3.256842 11.354792 c
3.426955 11.509670 3.635908 11.669102 3.908790 11.762256 c
4.292071 11.893097 4.707929 11.893097 5.091210 11.762256 c
5.364092 11.669102 5.573045 11.509670 5.743158 11.354791 c
5.900949 11.211132 6.074247 11.024471 6.260634 10.823713 c
6.280688 10.802114 l
10.392858 6.373626 l
11.719312 7.802115 l
11.739367 7.823714 l
11.925754 8.024473 12.099051 8.211132 12.256842 8.354791 c
12.426956 8.509670 12.635908 8.669102 12.908790 8.762256 c
13.292071 8.893097 13.707929 8.893097 14.091210 8.762256 c
14.364092 8.669102 14.573045 8.509670 14.743158 8.354791 c
14.900943 8.211139 15.074232 8.024488 15.260609 7.823739 c
15.260634 7.823713 l
15.280688 7.802114 l
18.000000 4.873625 l
18.000000 13.200000 l
18.000000 14.880157 18.000000 15.720236 17.673019 16.361971 c
17.385399 16.926458 16.926458 17.385399 16.361971 17.673019 c
15.720237 18.000000 14.880157 18.000000 13.200001 18.000000 c
4.800000 18.000000 l
3.119843 18.000000 2.279764 18.000000 1.638029 17.673019 c
1.073542 17.385399 0.614601 16.926458 0.326980 16.361971 c
h
16.108553 0.218262 m
11.525509 5.153847 l
12.935749 6.672566 l
13.149095 6.902323 13.274549 7.036421 13.374386 7.127316 c
13.419220 7.168135 13.445271 7.187207 13.456385 7.194696 c
13.484964 7.202284 13.515036 7.202284 13.543615 7.194696 c
13.554729 7.187207 13.580781 7.168135 13.625614 7.127316 c
13.725451 7.036421 13.850905 6.902323 14.064251 6.672565 c
17.925373 2.514434 l
17.877884 2.167143 17.800177 1.887589 17.673019 1.638029 c
17.385399 1.073542 16.926458 0.614601 16.361971 0.326981 c
16.281078 0.285763 16.197035 0.249743 16.108553 0.218262 c
h
14.044044 0.002020 m
5.064251 9.672565 l
4.850905 9.902323 4.725451 10.036421 4.625614 10.127316 c
4.580781 10.168135 4.554729 10.187207 4.543615 10.194696 c
4.515036 10.202284 4.484964 10.202284 4.456385 10.194696 c
4.445271 10.187207 4.419219 10.168135 4.374386 10.127316 c
4.274549 10.036421 4.149095 9.902323 3.935749 9.672565 c
0.000000 5.434067 l
0.000000 4.800000 l
0.000000 3.119843 0.000000 2.279763 0.326980 1.638029 c
0.614601 1.073542 1.073542 0.614601 1.638029 0.326981 c
2.279764 0.000000 3.119842 0.000000 4.800000 0.000000 c
13.200000 0.000000 l
13.508314 0.000000 13.788341 0.000000 14.044044 0.002020 c
h
13.500000 12.000000 m
14.328427 12.000000 15.000000 12.671573 15.000000 13.500000 c
15.000000 14.328427 14.328427 15.000000 13.500000 15.000000 c
12.671573 15.000000 12.000000 14.328427 12.000000 13.500000 c
12.000000 12.671573 12.671573 12.000000 13.500000 12.000000 c
h
f*
n
Q
endstream
endobj
3 0 obj
3765
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003855 00000 n
0000003878 00000 n
0000004051 00000 n
0000004125 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
4184
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "stickers.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,173 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
1.000000 0.800000 0.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 6.000000 6.000000 cm
1.000000 1.000000 1.000000 scn
0.435974 15.815962 m
0.000000 14.960315 0.000000 13.840210 0.000000 11.600000 c
0.000000 5.538462 l
0.000000 4.106961 0.000000 3.391212 0.181116 2.809988 c
0.572199 1.554960 1.554961 0.572199 2.809988 0.181116 c
3.391211 0.000000 4.106961 0.000000 5.538461 0.000000 c
7.132836 0.000000 8.332593 0.000000 9.296358 0.049431 c
9.392109 0.065231 9.458178 0.084789 9.510882 0.106621 c
9.837995 0.242115 10.097885 0.502007 10.233379 0.829117 c
10.269915 0.917324 10.300633 1.046162 10.317467 1.296604 c
10.334650 1.552246 10.335000 1.881901 10.335000 2.365276 c
10.335000 2.390583 l
10.334996 3.020454 10.334994 3.541773 10.356327 3.976810 c
9.927901 3.881188 9.474939 3.834996 8.999999 3.834996 c
7.566772 3.834998 6.432307 4.408777 5.671366 4.962191 c
5.289614 5.239828 4.994541 5.517408 4.793315 5.727383 c
4.692429 5.832656 4.614337 5.921766 4.559963 5.986553 c
4.532754 6.018972 4.511416 6.045382 4.496066 6.064772 c
4.477521 6.088497 l
4.471629 6.096197 l
4.469531 6.098966 l
4.468694 6.100076 l
4.468329 6.100561 l
4.468162 6.100784 4.468000 6.101000 5.000000 6.500000 c
5.532000 6.899000 l
5.531705 6.899393 l
5.538846 6.890306 l
5.546690 6.880400 5.560019 6.863840 5.578709 6.841572 c
5.616131 6.796984 5.674759 6.729844 5.753560 6.647617 c
5.911709 6.482592 6.147886 6.260172 6.453634 6.037808 c
7.067693 5.591221 7.933228 5.164998 9.000001 5.164996 c
9.630135 5.164996 10.171014 5.264124 10.633532 5.448587 c
10.639013 5.461485 10.644600 5.474353 10.650297 5.487185 c
11.018882 6.317377 11.682623 6.981118 12.512815 7.349703 c
12.904016 7.523386 13.325486 7.596285 13.811561 7.631045 c
14.286482 7.665009 14.873948 7.665005 15.609417 7.665000 c
15.634724 7.665000 l
16.118099 7.665000 16.447754 7.665350 16.703396 7.682533 c
16.953838 7.699367 17.082676 7.730085 17.170883 7.766621 c
17.497993 7.902115 17.757885 8.162005 17.893379 8.489118 c
17.915211 8.541822 17.934769 8.607892 17.950569 8.703643 c
18.000000 9.667408 18.000000 10.867164 18.000000 12.461538 c
18.000000 13.893039 18.000000 14.608788 17.818884 15.190012 c
17.427801 16.445040 16.445040 17.427801 15.190012 17.818884 c
14.608788 18.000000 13.893039 18.000000 12.461538 18.000000 c
6.400000 18.000000 l
4.159790 18.000000 3.039685 18.000000 2.184038 17.564026 c
1.431390 17.180532 0.819467 16.568611 0.435974 15.815962 c
h
17.652130 6.526627 m
17.381193 6.419186 17.097967 6.376053 16.792589 6.355527 c
16.487034 6.334990 16.112497 6.334994 15.657384 6.335000 c
15.634724 6.335000 l
14.868204 6.335000 14.328320 6.334603 13.906430 6.304433 c
13.490259 6.274672 13.242615 6.218527 13.052504 6.134122 c
12.523582 5.899294 12.100706 5.476418 11.865878 4.947496 c
11.781473 4.757385 11.725328 4.509741 11.695567 4.093570 c
11.665397 3.671680 11.665000 3.131796 11.665000 2.365276 c
11.665000 2.342616 l
11.665006 1.887503 11.665010 1.512966 11.644473 1.207411 c
11.623947 0.902033 11.580814 0.618807 11.473373 0.347870 c
11.542342 0.366713 11.610334 0.386574 11.677527 0.407513 c
14.501338 1.287447 16.712553 3.498662 17.592487 6.322473 c
17.613426 6.389666 17.633287 6.457658 17.652130 6.526627 c
h
5.531581 6.899558 m
5.311111 7.192892 4.894629 7.252222 4.601000 7.032000 c
4.307185 6.811639 4.247638 6.394815 4.468000 6.101000 c
5.000000 6.500000 l
5.532000 6.899000 5.531850 6.899200 5.531705 6.899393 c
5.531581 6.899558 l
h
7.500000 11.187500 m
7.500000 10.324555 6.940356 9.625000 6.250000 9.625000 c
5.559644 9.625000 5.000000 10.324555 5.000000 11.187500 c
5.000000 12.050446 5.559644 12.750000 6.250000 12.750000 c
6.940356 12.750000 7.500000 12.050446 7.500000 11.187500 c
h
13.000000 11.187500 m
13.000000 10.324555 12.440355 9.625000 11.750000 9.625000 c
11.059645 9.625000 10.500000 10.324555 10.500000 11.187500 c
10.500000 12.050446 11.059645 12.750000 11.750000 12.750000 c
12.440355 12.750000 13.000000 12.050446 13.000000 11.187500 c
h
f*
n
Q
endstream
endobj
3 0 obj
4865
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000004955 00000 n
0000004978 00000 n
0000005151 00000 n
0000005225 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
5284
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "video.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,123 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.000000 0.478431 1.000000 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.000000 8.000000 cm
1.000000 1.000000 1.000000 scn
0.435974 11.815962 m
0.000000 10.960315 0.000000 9.840210 0.000000 7.599999 c
0.000000 6.400000 l
0.000000 4.159790 0.000000 3.039685 0.435974 2.184038 c
0.819467 1.431390 1.431390 0.819468 2.184038 0.435974 c
3.039685 0.000000 4.159790 0.000000 6.400001 0.000000 c
7.600000 0.000000 l
9.840210 0.000000 10.960316 0.000000 11.815962 0.435974 c
12.568610 0.819468 13.180532 1.431390 13.564026 2.184038 c
14.000000 3.039685 14.000000 4.159790 14.000000 6.400001 c
14.000000 7.600000 l
14.000000 9.840210 14.000000 10.960315 13.564026 11.815962 c
13.180532 12.568610 12.568610 13.180532 11.815962 13.564026 c
10.960316 14.000000 9.840210 14.000000 7.599999 14.000000 c
6.400000 14.000000 l
4.159790 14.000000 3.039685 14.000000 2.184038 13.564026 c
1.431390 13.180532 0.819467 12.568610 0.435974 11.815962 c
h
20.495096 10.957284 m
20.443178 11.542397 19.985497 12.000000 19.428572 12.000000 c
19.196747 12.000000 18.971174 11.919026 18.785715 11.769232 c
16.071428 9.000020 l
15.977040 8.916782 l
15.674964 8.626339 15.500000 8.209476 15.500000 7.769259 c
15.500000 6.230808 l
15.505201 6.099547 l
15.539715 5.665031 15.744408 5.264177 16.071428 5.000048 c
18.785715 2.230835 l
18.871206 2.168387 l
19.337015 1.862048 19.951559 1.981793 20.285713 2.461603 c
20.424809 2.661328 20.500000 2.904249 20.500000 3.153906 c
20.500000 10.846162 l
20.495096 10.957284 l
h
f*
n
Q
endstream
endobj
3 0 obj
2403
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002493 00000 n
0000002516 00000 n
0000002689 00000 n
0000002763 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2822
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "voice.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,156 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.686275 0.321569 0.870588 scn
0.000000 18.799999 m
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
18.799999 30.000000 l
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
30.000000 11.200001 l
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
11.200000 0.000000 l
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
0.000000 18.799999 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 11.000000 12.000000 cm
1.000000 1.000000 1.000000 scn
0.000000 10.000000 m
0.000000 12.209139 1.790861 14.000000 4.000000 14.000000 c
4.000000 14.000000 l
6.209139 14.000000 8.000000 12.209139 8.000000 10.000000 c
8.000000 4.000000 l
8.000000 1.790861 6.209139 0.000000 4.000000 0.000000 c
4.000000 0.000000 l
1.790861 0.000000 0.000000 1.790861 0.000000 4.000000 c
0.000000 10.000000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 8.000000 7.000000 cm
1.000000 1.000000 1.000000 scn
1.000000 9.500000 m
1.000000 10.052285 0.552285 10.500000 0.000000 10.500000 c
-0.552285 10.500000 -1.000000 10.052285 -1.000000 9.500000 c
1.000000 9.500000 l
h
15.000000 9.500000 m
15.000000 10.052285 14.552285 10.500000 14.000000 10.500000 c
13.447716 10.500000 13.000000 10.052285 13.000000 9.500000 c
15.000000 9.500000 l
h
-1.000000 9.500000 m
-1.000000 9.000000 l
1.000000 9.000000 l
1.000000 9.500000 l
-1.000000 9.500000 l
h
15.000000 9.000000 m
15.000000 9.500000 l
13.000000 9.500000 l
13.000000 9.000000 l
15.000000 9.000000 l
h
7.000000 1.000000 m
11.418278 1.000000 15.000000 4.581722 15.000000 9.000000 c
13.000000 9.000000 l
13.000000 5.686292 10.313708 3.000000 7.000000 3.000000 c
7.000000 1.000000 l
h
-1.000000 9.000000 m
-1.000000 4.581722 2.581722 1.000000 7.000000 1.000000 c
7.000000 3.000000 l
3.686292 3.000000 1.000000 5.686292 1.000000 9.000000 c
-1.000000 9.000000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 15.000000 4.000000 cm
1.000000 1.000000 1.000000 scn
-1.000000 1.000000 m
-1.000000 0.447715 -0.552285 0.000000 0.000000 0.000000 c
0.552285 0.000000 1.000000 0.447715 1.000000 1.000000 c
-1.000000 1.000000 l
h
-1.000000 5.000000 m
-1.000000 1.000000 l
1.000000 1.000000 l
1.000000 5.000000 l
-1.000000 5.000000 l
h
f
n
Q
endstream
endobj
3 0 obj
2734
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002824 00000 n
0000002847 00000 n
0000003020 00000 n
0000003094 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3153
%%EOF

View File

@ -911,7 +911,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, sendSticker: canSendMessagesToChat(strongSelf.presentationInterfaceState) ? { fileReference, sourceNode, sourceRect in
return self?.controllerInteraction?.sendSticker(fileReference, false, false, nil, false, sourceNode, sourceRect, nil, []) ?? false
} : nil, sendEmoji: canSendMessagesToChat(strongSelf.presentationInterfaceState) ? { text, attribute in
self?.controllerInteraction?.sendEmoji(text, attribute)
self?.controllerInteraction?.sendEmoji(text, attribute, false)
} : nil, setupTemporaryHiddenMedia: { signal, centralIndex, galleryMedia in
if let strongSelf = self {
strongSelf.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).start(next: { entry in
@ -2032,28 +2032,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.sendMessages(transformedMessages)
}
return true
}, sendEmoji: { [weak self] text, attribute in
}, sendEmoji: { [weak self] text, attribute, immediately in
if let strongSelf = self {
strongSelf.interfaceInteraction?.insertText(NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: attribute]))
strongSelf.updateChatPresentationInterfaceState(interactive: true, { state in
return state.updatedInputMode({ _ in
return .text
})
})
let _ = (ApplicationSpecificNotice.getEmojiTooltip(accountManager: strongSelf.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { count in
guard let strongSelf = self else {
return
if immediately {
if let file = attribute.file {
var bubbleUpEmojiOrStickersets: [ItemCollectionId] = []
for attribute in file.attributes {
if case let .CustomEmoji(_, _, _, packReference) = attribute {
if case let .id(id, _) = packReference {
bubbleUpEmojiOrStickersets.append(ItemCollectionId(namespace: Namespaces.ItemCollection.CloudEmojiPacks, id: id))
}
}
}
strongSelf.sendMessages([.message(text: text, attributes: [TextEntitiesMessageAttribute(entities: [MessageTextEntity(range: 0 ..< (text as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: file.fileId.id))])], inlineStickers: [file.fileId : file], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets)], commit: false)
}
if count < 2 {
let _ = ApplicationSpecificNotice.incrementEmojiTooltip(accountManager: strongSelf.context.sharedContext.accountManager).start()
Queue.mainQueue().after(0.5, {
strongSelf.displayEmojiTooltip()
} else {
strongSelf.interfaceInteraction?.insertText(NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: attribute]))
strongSelf.updateChatPresentationInterfaceState(interactive: true, { state in
return state.updatedInputMode({ _ in
return .text
})
}
})
})
let _ = (ApplicationSpecificNotice.getEmojiTooltip(accountManager: strongSelf.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { count in
guard let strongSelf = self else {
return
}
if count < 2 {
let _ = ApplicationSpecificNotice.incrementEmojiTooltip(accountManager: strongSelf.context.sharedContext.accountManager).start()
Queue.mainQueue().after(0.5, {
strongSelf.displayEmojiTooltip()
})
}
})
}
}
}, sendGif: { [weak self] fileReference, sourceView, sourceRect, silentPosting, schedule in
if let strongSelf = self {
@ -10261,11 +10276,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else if self.presentationInterfaceState.interfaceState.mediaRecordingMode == .audio {
var canSendMedia = false
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
if channel.hasBannedPermission(.banSendMedia) == nil {
if channel.hasBannedPermission(.banSendMedia) == nil && channel.hasBannedPermission(.banSendVoice) == nil {
canSendMedia = true
}
} else if let group = self.presentationInterfaceState.renderedPeer?.peer as? TelegramGroup {
if !group.hasBannedPermission(.banSendMedia) {
if !group.hasBannedPermission(.banSendMedia) && !group.hasBannedPermission(.banSendVoice) {
canSendMedia = true
}
} else {
@ -11932,22 +11947,37 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatDisplayNode.dismissInput()
var bannedSendMedia: (Int32, Bool)?
var bannedSendPhotos: (Int32, Bool)?
var bannedSendVideos: (Int32, Bool)?
var bannedSendFiles: (Int32, Bool)?
var canSendPolls = true
if let peer = peer as? TelegramUser, peer.botInfo == nil {
canSendPolls = false
} else if peer is TelegramSecretChat {
canSendPolls = false
} else if let channel = peer as? TelegramChannel {
if let value = channel.hasBannedPermission(.banSendMedia) {
bannedSendMedia = value
if let value = channel.hasBannedPermission(.banSendPhotos) {
bannedSendPhotos = value
}
if let value = channel.hasBannedPermission(.banSendVideos) {
bannedSendVideos = value
}
if let value = channel.hasBannedPermission(.banSendFiles) {
bannedSendFiles = value
}
if channel.hasBannedPermission(.banSendPolls) != nil {
canSendPolls = false
}
} else if let group = peer as? TelegramGroup {
if group.hasBannedPermission(.banSendMedia) {
bannedSendMedia = (Int32.max, false)
if group.hasBannedPermission(.banSendPhotos) {
bannedSendPhotos = (Int32.max, false)
}
if group.hasBannedPermission(.banSendVideos) {
bannedSendVideos = (Int32.max, false)
}
if group.hasBannedPermission(.banSendFiles) {
bannedSendFiles = (Int32.max, false)
}
if group.hasBannedPermission(.banSendPolls) {
canSendPolls = false
@ -12097,7 +12127,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controller.prepareForReuse()
return
}
strongSelf.presentMediaPicker(saveEditedPhotos: dataSettings.storeEditedPhotos, bannedSendMedia: bannedSendMedia, present: { controller, mediaPickerContext in
strongSelf.presentMediaPicker(saveEditedPhotos: dataSettings.storeEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, present: { controller, mediaPickerContext in
let _ = currentMediaController.swap(controller)
if !inputText.string.isEmpty {
mediaPickerContext?.setCaption(inputText)
@ -12119,7 +12149,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controller.prepareForReuse()
return
}
let controller = attachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, bannedSendMedia: bannedSendMedia, presentGallery: { [weak self, weak attachmentController] in
let controller = attachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, bannedSendMedia: bannedSendFiles, presentGallery: { [weak self, weak attachmentController] in
attachmentController?.dismiss(animated: true)
self?.presentFileGallery()
}, presentFiles: { [weak self, weak attachmentController] in
@ -12796,11 +12826,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.present(actionSheet, in: .window(.root))
}
private func presentMediaPicker(subject: MediaPickerScreen.Subject = .assets(nil), saveEditedPhotos: Bool, bannedSendMedia: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) {
private func presentMediaPicker(subject: MediaPickerScreen.Subject = .assets(nil), saveEditedPhotos: Bool, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, present: @escaping (MediaPickerScreen, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping ([Any], Bool, Int32?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) {
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return
}
let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), threadTitle: self.threadInfo?.title, chatLocation: self.chatLocation, bannedSendMedia: bannedSendMedia, subject: subject, saveEditedPhotos: saveEditedPhotos)
let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), threadTitle: self.threadInfo?.title, chatLocation: self.chatLocation, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, subject: subject, saveEditedPhotos: saveEditedPhotos)
let mediaPickerContext = controller.mediaPickerContext
controller.openCamera = { [weak self] cameraView in
self?.openCamera(cameraView: cameraView)
@ -13616,7 +13646,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if let stickerPackReference = stickerPackReference {
let _ = (self.context.engine.stickers.loadedStickerPack(reference: stickerPackReference, forceActualized: false)
self.presentEmojiList(references: [stickerPackReference])
/*let _ = (self.context.engine.stickers.loadedStickerPack(reference: stickerPackReference, forceActualized: false)
|> deliverOnMainQueue).start(next: { [weak self] stickerPack in
if let strongSelf = self, case let .result(info, _, _) = stickerPack {
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: nil, text: strongSelf.presentationData.strings.Stickers_EmojiPackInfoText(info.title).string, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView, customAction: nil), elevatedLayout: false, action: { [weak self] action in
@ -13626,7 +13658,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return false
}), in: .current)
}
})
})*/
}
}
@ -13894,9 +13926,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
updatedPresentationData: strongSelf.updatedPresentationData,
peer: EnginePeer(peer),
subjects: subjects,
presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendMedia, present in
presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendPhotos, bannedSendVideos, present in
if let strongSelf = self {
strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendMedia: bannedSendMedia, present: present, updateMediaPickerContext: { _ in }, completion: { [weak self] signals, silentPosting, scheduleTime, getAnimatedTransitionSource, completion in
strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, present: present, updateMediaPickerContext: { _ in }, completion: { [weak self] signals, silentPosting, scheduleTime, getAnimatedTransitionSource, completion in
self?.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
})
}
@ -17390,7 +17422,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let presentationData = self.presentationData
let controller = StickerPackScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(references), parentNavigationController: self.effectiveNavigationController, sendEmoji: canSendMessagesToChat(self.presentationInterfaceState) ? { [weak self] text, attribute in
if let strongSelf = self {
strongSelf.controllerInteraction?.sendEmoji(text, attribute)
strongSelf.controllerInteraction?.sendEmoji(text, attribute, false)
}
} : nil, actionPerformed: { [weak self] actions in
guard let strongSelf = self else {

View File

@ -274,7 +274,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openMessageContextActions: { _, _, _, _ in
}, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
}, navigateToThreadMessage: { _, _, _ in
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { [weak self] url, _, _, _ in
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { [weak self] url, _, _, _ in
self?.openUrl(url)
}, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in
if let strongSelf = self, let navigationController = strongSelf.getNavigationController() {

View File

@ -84,7 +84,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, sendMessage: { _ in
}, sendSticker: { _, _, _, _, _, _, _, _, _ in
return false
}, sendEmoji: { _, _ in
}, sendEmoji: { _, _, _ in
}, sendGif: { _, _, _, _, _ in
return false
}, sendBotContextResultAsGif: { _, _, _, _, _ in

View File

@ -1751,8 +1751,14 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
if let defaultBannedRights = channel.defaultBannedRights {
var count = 0
for (right, _) in allGroupPermissionList(peer: .channel(channel)) {
if !defaultBannedRights.flags.contains(right) {
count += 1
if right == .banSendMedia {
if banSendMediaSubList().allSatisfy({ !defaultBannedRights.flags.contains($0.0) }) {
count += 1
}
} else {
if !defaultBannedRights.flags.contains(right) {
count += 1
}
}
}
activePermissionCount = count
@ -1868,8 +1874,14 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
if let defaultBannedRights = group.defaultBannedRights {
var count = 0
for (right, _) in allGroupPermissionList(peer: .legacyGroup(group)) {
if !defaultBannedRights.flags.contains(right) {
count += 1
if right == .banSendMedia {
if banSendMediaSubList().allSatisfy({ !defaultBannedRights.flags.contains($0.0) }) {
count += 1
}
} else {
if !defaultBannedRights.flags.contains(right) {
count += 1
}
}
}
activePermissionCount = count
@ -2563,7 +2575,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}, sendMessage: { _ in
}, sendSticker: { _, _, _, _, _, _, _, _, _ in
return false
}, sendEmoji: { _, _ in
}, sendEmoji: { _, _, _ in
}, sendGif: { _, _, _, _, _ in
return false
}, sendBotContextResultAsGif: { _, _, _, _, _ in

View File

@ -1301,7 +1301,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
tapMessage?(message)
}, clickThroughMessage: {
clickThroughMessage?()
}, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in
}, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in
return false
}, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
}, presentController: { _, _ in