mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Various improvements
This commit is contained in:
parent
9abee7dc1f
commit
4ac9d1cb57
@ -9054,6 +9054,8 @@ Sorry for the inconvenience.";
|
||||
"Login.Email.WillBeResetIn" = "Email will be reset %@";
|
||||
"Login.Email.PremiumRequiredTitle" = "Telegram Premium Required";
|
||||
"Login.Email.PremiumRequiredText" = "Due to high cost of SMS in your country, you need to have a **Telegram Premium** account to reset this email via an SMS code.\n\nYou can ask a friend to gift a Premium subscription for your account\n**%@**";
|
||||
"Login.Email.ElapsedTime" = "in %@";
|
||||
"Login.Email.ResetingNow" = "Please wait...";
|
||||
|
||||
"ChatList.StartMessaging" = "Select a chat to start messaging";
|
||||
|
||||
@ -9092,3 +9094,11 @@ Sorry for the inconvenience.";
|
||||
"StickerPacksSettings.SuggestAnimatedEmojiInfo" = "Each time you enter an emoji you can replace it with an animated emoji.";
|
||||
|
||||
"DialogList.DeleteBotClearHistory" = "Clear Chat History";
|
||||
|
||||
"TextFormat.EditLinkTitle" = "Edit Link";
|
||||
|
||||
"PeerInfo.Username" = "Username";
|
||||
"Username.BotLinksOrderInfo" = "Drag and drop links to change the order in which they will be displayed on the bot info page.";
|
||||
|
||||
"Wallpaper.ApplyForAll" = "Apply For All Chats";
|
||||
"Wallpaper.ApplyForChat" = "Apply For This Chat";
|
||||
|
@ -804,7 +804,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
let pathPrefix = item.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(resource.id)
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
|
@ -822,6 +822,8 @@ private func appearanceSearchableItems(context: AccountContext) -> [SettingsSear
|
||||
SettingsSearchableItem(id: .appearance(4), title: strings.Wallpaper_SetCustomBackground, alternate: synonyms(strings.SettingsSearch_Synonyms_Appearance_ChatBackground_Custom), icon: icon, breadcrumbs: [strings.Settings_Appearance, strings.Settings_ChatBackground], present: { context, _, present in
|
||||
presentCustomWallpaperPicker(context: context, present: { controller in
|
||||
present(.immediate, controller)
|
||||
}, push: { controller in
|
||||
present(.push, controller)
|
||||
})
|
||||
}),
|
||||
SettingsSearchableItem(id: .appearance(5), title: strings.Appearance_AutoNightTheme, alternate: synonyms(strings.SettingsSearch_Synonyms_Appearance_AutoNightTheme), icon: icon, breadcrumbs: [strings.Settings_Appearance], present: { context, _, present in
|
||||
|
@ -12,7 +12,7 @@ import LegacyUI
|
||||
import LegacyMediaPickerUI
|
||||
import LocalMediaResources
|
||||
|
||||
func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (ViewController) -> Void) {
|
||||
func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let _ = legacyWallpaperPicker(context: context, presentationData: presentationData).start(next: { generator in
|
||||
let legacyController = LegacyController(presentation: .modal(animateIn: true), theme: presentationData.theme)
|
||||
@ -34,7 +34,7 @@ func presentCustomWallpaperPicker(context: AccountContext, present: @escaping (V
|
||||
})
|
||||
}
|
||||
}
|
||||
present(controller)
|
||||
push(controller)
|
||||
}
|
||||
}
|
||||
controller.dismissalBlock = { [weak legacyController] in
|
||||
|
@ -1180,12 +1180,12 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.colorPanelNode, frame: colorPanelFrame)
|
||||
self.colorPanelNode.updateLayout(size: colorPanelFrame.size, transition: transition)
|
||||
self.colorPanelNode.updateLayout(size: colorPanelFrame.size, bottomInset: 0.0, transition: transition)
|
||||
|
||||
let patternPanelAlpha: CGFloat = self.state.displayPatternPanel ? 1.0 : 0.0
|
||||
let patternPanelFrame = colorPanelFrame
|
||||
transition.updateFrame(node: self.patternPanelNode, frame: patternPanelFrame)
|
||||
self.patternPanelNode.updateLayout(size: patternPanelFrame.size, transition: transition)
|
||||
self.patternPanelNode.updateLayout(size: patternPanelFrame.size, bottomInset: 0.0, transition: transition)
|
||||
self.patternPanelNode.isUserInteractionEnabled = self.state.displayPatternPanel
|
||||
transition.updateAlpha(node: self.patternPanelNode, alpha: patternPanelAlpha)
|
||||
|
||||
|
@ -15,13 +15,13 @@ import SearchUI
|
||||
import HexColor
|
||||
import PresentationDataUtils
|
||||
|
||||
final class ThemeGridController: ViewController {
|
||||
public final class ThemeGridController: ViewController {
|
||||
private var controllerNode: ThemeGridControllerNode {
|
||||
return self.displayNode as! ThemeGridControllerNode
|
||||
}
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override var ready: Promise<Bool> {
|
||||
public override var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
}
|
||||
|
||||
@ -38,13 +38,13 @@ final class ThemeGridController: ViewController {
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
override var navigationBarRequiresEntireLayoutUpdate: Bool {
|
||||
public override var navigationBarRequiresEntireLayoutUpdate: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
private var previousContentOffset: GridNodeVisibleContentOffset?
|
||||
|
||||
init(context: AccountContext) {
|
||||
public init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.presentationDataPromise.set(.single(self.presentationData))
|
||||
@ -115,7 +115,7 @@ final class ThemeGridController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
public override func loadDisplayNode() {
|
||||
self.displayNode = ThemeGridControllerNode(context: self.context, presentationData: self.presentationData, presentPreviewController: { [weak self] source in
|
||||
if let strongSelf = self {
|
||||
let controller = WallpaperGalleryController(context: strongSelf.context, source: source)
|
||||
@ -137,12 +137,14 @@ final class ThemeGridController: ViewController {
|
||||
})
|
||||
}
|
||||
}
|
||||
self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
|
||||
self?.push(controller)
|
||||
}
|
||||
}, presentGallery: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
presentCustomWallpaperPicker(context: strongSelf.context, present: { [weak self] controller in
|
||||
self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
|
||||
}, push: { [weak self] controller in
|
||||
self?.push(controller)
|
||||
})
|
||||
}
|
||||
}, presentColors: { [weak self] in
|
||||
@ -408,7 +410,7 @@ final class ThemeGridController: ViewController {
|
||||
self.donePressed()
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.cleanNavigationHeight, transition: transition)
|
||||
|
@ -401,7 +401,7 @@ final class WallpaperColorPanelNode: ASDisplayNode {
|
||||
var colorAdded: (() -> Void)?
|
||||
var colorRemoved: (() -> Void)?
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings) {
|
||||
self.theme = theme
|
||||
@ -439,6 +439,8 @@ final class WallpaperColorPanelNode: ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = .white
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.topSeparatorNode)
|
||||
self.addSubnode(self.bottomSeparatorNode)
|
||||
@ -537,8 +539,8 @@ final class WallpaperColorPanelNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
if updateLayout, let size = self.validLayout {
|
||||
self.updateLayout(size: size, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
||||
if updateLayout, let (size, bottomInset) = self.validLayout {
|
||||
self.updateLayout(size: size, bottomInset: bottomInset, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
||||
}
|
||||
|
||||
if let index = self.state.selection {
|
||||
@ -558,8 +560,8 @@ final class WallpaperColorPanelNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, bottomInset)
|
||||
|
||||
let condensedLayout = size.width < 375.0
|
||||
let separatorHeight = UIScreenPixel
|
||||
|
@ -100,6 +100,14 @@ class WallpaperGalleryControllerNode: GalleryControllerNode {
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.scrollView.isScrollEnabled = false
|
||||
self.view.interactiveTransitionGestureRecognizerTest = { point in
|
||||
if point.x < 44.0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//self.view.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:))))
|
||||
}
|
||||
@ -208,10 +216,12 @@ public class WallpaperGalleryController: ViewController {
|
||||
self.source = source
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
self.title = self.presentationData.strings.WallpaperPreview_Title
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
//self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
||||
var entries: [WallpaperGalleryEntry] = []
|
||||
@ -323,11 +333,11 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
|
||||
func dismiss(forceAway: Bool) {
|
||||
let completion: () -> Void = { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
|
||||
self.galleryNode.modalAnimateOut(completion: completion)
|
||||
// let completion: () -> Void = { [weak self] in
|
||||
// self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
// }
|
||||
self.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
//self.galleryNode.modalAnimateOut(completion: completion)
|
||||
}
|
||||
|
||||
private func updateTransaction(entries: [WallpaperGalleryEntry], arguments: WallpaperGalleryItemArguments) -> GalleryPagerTransaction {
|
||||
@ -603,7 +613,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
self.galleryNode.modalAnimateIn()
|
||||
//self.galleryNode.modalAnimateIn()
|
||||
self.bindCentralItemNode(animated: false, updated: false)
|
||||
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
|
||||
@ -642,7 +652,6 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
strongSelf.patternPanelNode?.serviceBackgroundColor = serviceColor(for: (initialWallpaper, nil))
|
||||
strongSelf.patternPanelEnabled = enabled
|
||||
strongSelf.galleryNode.scrollView.isScrollEnabled = !enabled
|
||||
if enabled {
|
||||
strongSelf.patternPanelNode?.updateWallpapers()
|
||||
strongSelf.patternPanelNode?.didAppear(initialWallpaper: strongSelf.savedPatternWallpaper, intensity: strongSelf.savedPatternIntensity)
|
||||
@ -670,7 +679,6 @@ public class WallpaperGalleryController: ViewController {
|
||||
if let strongSelf = self, let (layout, _) = strongSelf.validLayout, let colors = colors, let itemNode = strongSelf.galleryNode.pager.centralItemNode() as? WallpaperGalleryItemNode {
|
||||
strongSelf.patternPanelEnabled = false
|
||||
strongSelf.colorsPanelEnabled = !strongSelf.colorsPanelEnabled
|
||||
strongSelf.galleryNode.scrollView.isScrollEnabled = !strongSelf.colorsPanelEnabled
|
||||
if !strongSelf.colorsPanelEnabled {
|
||||
strongSelf.colorsPanelNode?.view.endEditing(true)
|
||||
}
|
||||
@ -804,8 +812,6 @@ public class WallpaperGalleryController: ViewController {
|
||||
self.galleryNode.pager.transaction(self.updateTransaction(entries: updatedEntries, arguments: WallpaperGalleryItemArguments(colorPreview: preview, isColorsList: true, patternEnabled: self.patternPanelEnabled)))
|
||||
}
|
||||
|
||||
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
let hadLayout = self.validLayout != nil
|
||||
|
||||
@ -823,10 +829,11 @@ public class WallpaperGalleryController: ViewController {
|
||||
self.galleryNode.containerLayoutUpdated(pagerLayout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
self.overlayNode?.frame = self.galleryNode.bounds
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode!, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width, height: 49.0 + layout.intrinsicInsets.bottom)))
|
||||
self.toolbarNode!.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
|
||||
let toolbarHeight: CGFloat = 66.0
|
||||
transition.updateFrame(node: self.toolbarNode!, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width, height: toolbarHeight + layout.intrinsicInsets.bottom)))
|
||||
self.toolbarNode!.updateLayout(size: CGSize(width: layout.size.width, height: toolbarHeight), layout: layout, transition: transition)
|
||||
|
||||
var bottomInset = layout.intrinsicInsets.bottom + 49.0
|
||||
var bottomInset = toolbarHeight + layout.intrinsicInsets.bottom
|
||||
|
||||
let currentPatternPanelNode: WallpaperPatternPanelNode
|
||||
if let patternPanelNode = self.patternPanelNode {
|
||||
@ -899,6 +906,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
let originalBottomInset = bottomInset
|
||||
var patternPanelFrame = CGRect(x: 0.0, y: layout.size.height, width: layout.size.width, height: panelHeight)
|
||||
if self.patternPanelEnabled {
|
||||
patternPanelFrame.origin = CGPoint(x: 0.0, y: layout.size.height - max((layout.inputHeight ?? 0.0) - panelHeight + 44.0, bottomInset) - panelHeight)
|
||||
@ -906,7 +914,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
}
|
||||
|
||||
transition.updateFrame(node: currentPatternPanelNode, frame: patternPanelFrame)
|
||||
currentPatternPanelNode.updateLayout(size: patternPanelFrame.size, transition: transition)
|
||||
currentPatternPanelNode.updateLayout(size: patternPanelFrame.size, bottomInset: originalBottomInset, transition: transition)
|
||||
|
||||
var colorsPanelFrame = CGRect(x: 0.0, y: layout.size.height, width: layout.size.width, height: panelHeight)
|
||||
if self.colorsPanelEnabled {
|
||||
@ -914,8 +922,10 @@ public class WallpaperGalleryController: ViewController {
|
||||
bottomInset += panelHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: currentColorsPanelNode, frame: colorsPanelFrame)
|
||||
currentColorsPanelNode.updateLayout(size: colorsPanelFrame.size, transition: transition)
|
||||
transition.updateFrame(node: currentColorsPanelNode, frame: CGRect(origin: colorsPanelFrame.origin, size: CGSize(width: colorsPanelFrame.width, height: colorsPanelFrame.height + originalBottomInset)))
|
||||
currentColorsPanelNode.updateLayout(size: colorsPanelFrame.size, bottomInset: originalBottomInset, transition: transition)
|
||||
|
||||
self.toolbarNode?.setDoneIsSolid(self.patternPanelEnabled || self.colorsPanelEnabled, transition: transition)
|
||||
|
||||
bottomInset += 66.0
|
||||
|
||||
|
@ -95,6 +95,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
private let blurredNode: BlurredImageNode
|
||||
let cropNode: WallpaperCropNode
|
||||
|
||||
private let cancelButtonBackgroundNode: NavigationBackgroundNode
|
||||
private var cancelButtonNode: HighlightableButtonNode
|
||||
|
||||
private let shareButtonBackgroundNode: NavigationBackgroundNode
|
||||
private var shareButtonNode: HighlightableButtonNode
|
||||
|
||||
private var blurButtonNode: WallpaperOptionButtonNode
|
||||
private var motionButtonNode: WallpaperOptionButtonNode
|
||||
private var patternButtonNode: WallpaperOptionButtonNode
|
||||
@ -157,6 +163,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
self.colorsButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_WallpaperColors, value: .colors(false, [.clear]))
|
||||
|
||||
self.cancelButtonBackgroundNode = NavigationBackgroundNode(color: UIColor(white: 0.0, alpha: 0.3))
|
||||
self.cancelButtonNode = HighlightableButtonNode()
|
||||
self.cancelButtonNode.insertSubnode(self.cancelButtonBackgroundNode, at: 0)
|
||||
self.cancelButtonNode.setAttributedTitle(NSAttributedString(string: self.presentationData.strings.Common_Cancel, font: Font.semibold(15.0), textColor: .white), for: .normal)
|
||||
self.cancelButtonNode.titleNode.textShadowColor = UIColor(rgb: 0x000000, alpha: 0.1)
|
||||
|
||||
self.shareButtonBackgroundNode = NavigationBackgroundNode(color: UIColor(white: 0.0, alpha: 0.3))
|
||||
self.shareButtonNode = HighlightableButtonNode()
|
||||
self.shareButtonNode.insertSubnode(self.shareButtonBackgroundNode, at: 0)
|
||||
self.shareButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Share"), color: .white), for: .normal)
|
||||
|
||||
self.playButtonBackgroundNode = NavigationBackgroundNode(color: UIColor(white: 0.0, alpha: 0.3))
|
||||
self.playButtonNode = HighlightableButtonNode()
|
||||
self.playButtonNode.insertSubnode(self.playButtonBackgroundNode, at: 0)
|
||||
@ -219,12 +236,16 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.addSubnode(self.patternButtonNode)
|
||||
self.addSubnode(self.colorsButtonNode)
|
||||
self.addSubnode(self.playButtonNode)
|
||||
self.addSubnode(self.cancelButtonNode)
|
||||
self.addSubnode(self.shareButtonNode)
|
||||
|
||||
self.blurButtonNode.addTarget(self, action: #selector(self.toggleBlur), forControlEvents: .touchUpInside)
|
||||
self.motionButtonNode.addTarget(self, action: #selector(self.toggleMotion), forControlEvents: .touchUpInside)
|
||||
self.patternButtonNode.addTarget(self, action: #selector(self.togglePattern), forControlEvents: .touchUpInside)
|
||||
self.colorsButtonNode.addTarget(self, action: #selector(self.toggleColors), forControlEvents: .touchUpInside)
|
||||
self.playButtonNode.addTarget(self, action: #selector(self.togglePlay), forControlEvents: .touchUpInside)
|
||||
self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||
self.shareButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -254,6 +275,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.action?()
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
func setEntry(_ entry: WallpaperGalleryEntry, arguments: WallpaperGalleryItemArguments, source: WallpaperListSource) {
|
||||
let previousArguments = self.arguments
|
||||
self.arguments = arguments
|
||||
@ -443,6 +468,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
} else {
|
||||
actionSignal = .single(defaultAction)
|
||||
}
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
case let .image(representations, _):
|
||||
if let largestSize = largestImageRepresentation(representations) {
|
||||
contentSize = largestSize.dimensions.cgSize
|
||||
@ -494,6 +520,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
statusSignal = .single(.Local)
|
||||
subtitleSignal = .single(nil)
|
||||
}
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
}
|
||||
self.cropNode.removeFromSupernode()
|
||||
case let .asset(asset):
|
||||
@ -504,6 +531,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
fetchSignal = .complete()
|
||||
statusSignal = .single(.Local)
|
||||
subtitleSignal = .single(nil)
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
self.wrapperNode.addSubnode(self.cropNode)
|
||||
case let .contextResult(result):
|
||||
var imageDimensions: CGSize?
|
||||
@ -556,6 +584,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
fetchSignal = .complete()
|
||||
statusSignal = .single(.Local)
|
||||
}
|
||||
colorSignal = .single(UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
subtitleSignal = .single(nil)
|
||||
self.wrapperNode.addSubnode(self.cropNode)
|
||||
}
|
||||
@ -628,7 +657,15 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
strongSelf.motionButtonNode.buttonColor = color
|
||||
strongSelf.colorsButtonNode.buttonColor = color
|
||||
|
||||
strongSelf.playButtonBackgroundNode.updateColor(color: color, transition: .immediate)
|
||||
if color == UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
strongSelf.playButtonBackgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.45), transition: .immediate)
|
||||
strongSelf.cancelButtonBackgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.45), transition: .immediate)
|
||||
strongSelf.shareButtonBackgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.45), transition: .immediate)
|
||||
} else {
|
||||
strongSelf.playButtonBackgroundNode.updateColor(color: color, transition: .immediate)
|
||||
strongSelf.cancelButtonBackgroundNode.updateColor(color: color, transition: .immediate)
|
||||
strongSelf.shareButtonBackgroundNode.updateColor(color: color, transition: .immediate)
|
||||
}
|
||||
}))
|
||||
} else if self.arguments.patternEnabled != previousArguments.patternEnabled {
|
||||
self.patternButtonNode.isSelected = self.arguments.patternEnabled
|
||||
@ -901,9 +938,11 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
let buttonSpacing: CGFloat = 18.0
|
||||
|
||||
let leftButtonFrame = CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0 - buttonSize.width - buttonSpacing) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
let centerButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
let rightButtonFrame = CGRect(origin: CGPoint(x: ceil(layout.size.width / 2.0 + buttonSpacing) + offset.x, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
let toolbarHeight: CGFloat = 66.0
|
||||
|
||||
let leftButtonFrame = CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0 - buttonSize.width - buttonSpacing) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
let centerButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
let rightButtonFrame = CGRect(origin: CGPoint(x: ceil(layout.size.width / 2.0 + buttonSpacing) + offset.x, y: layout.size.height - toolbarHeight - layout.intrinsicInsets.bottom - 54.0 + offset.y + additionalYOffset), size: buttonSize)
|
||||
|
||||
var patternAlpha: CGFloat = 0.0
|
||||
var patternFrame = centerButtonFrame
|
||||
@ -919,7 +958,14 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
let playFrame = CGRect(origin: CGPoint(x: centerButtonFrame.midX - playButtonSize.width / 2.0, y: centerButtonFrame.midY - playButtonSize.height / 2.0), size: playButtonSize)
|
||||
var playAlpha: CGFloat = 0.0
|
||||
|
||||
|
||||
var cancelSize = self.cancelButtonNode.measure(layout.size)
|
||||
cancelSize.width += 16.0
|
||||
cancelSize.height = 28.0
|
||||
let cancelFrame = CGRect(origin: CGPoint(x: 16.0 + offset.x, y: 16.0), size: cancelSize)
|
||||
|
||||
let shareFrame = CGRect(origin: CGPoint(x: layout.size.width - 16.0 - 28.0 + offset.x, y: 16.0), size: CGSize(width: 28.0, height: 28.0))
|
||||
|
||||
let centerOffset: CGFloat = 32.0
|
||||
|
||||
if let entry = self.entry {
|
||||
@ -1019,10 +1065,18 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.playButtonBackgroundNode.update(size: playFrame.size, cornerRadius: playFrame.size.height / 2.0, transition: transition)
|
||||
transition.updateAlpha(node: self.playButtonNode, alpha: playAlpha * alpha)
|
||||
transition.updateSublayerTransformScale(node: self.playButtonNode, scale: max(0.1, playAlpha))
|
||||
|
||||
transition.updateFrame(node: self.cancelButtonNode, frame: cancelFrame)
|
||||
transition.updateFrame(node: self.cancelButtonBackgroundNode, frame: CGRect(origin: CGPoint(), size: cancelFrame.size))
|
||||
self.cancelButtonBackgroundNode.update(size: cancelFrame.size, cornerRadius: cancelFrame.size.height / 2.0, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.shareButtonNode, frame: shareFrame)
|
||||
transition.updateFrame(node: self.shareButtonBackgroundNode, frame: CGRect(origin: CGPoint(), size: shareFrame.size))
|
||||
self.shareButtonBackgroundNode.update(size: shareFrame.size, cornerRadius: shareFrame.size.height / 2.0, transition: transition)
|
||||
}
|
||||
|
||||
private func updateMessagesLayout(layout: ContainerViewLayout, offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
||||
let bottomInset: CGFloat = 115.0
|
||||
let bottomInset: CGFloat = 132.0
|
||||
|
||||
if self.patternButtonNode.isSelected || self.colorsButtonNode.isSelected {
|
||||
//bottomInset = 350.0
|
||||
|
@ -31,13 +31,13 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private let cancelButton = HighlightTrackingButtonNode()
|
||||
private let cancelHighlightBackgroundNode = ASDisplayNode()
|
||||
private let doneButton = HighlightTrackingButtonNode()
|
||||
private let doneHighlightBackgroundNode = ASDisplayNode()
|
||||
private let backgroundNode = NavigationBackgroundNode(color: .clear)
|
||||
private let separatorNode = ASDisplayNode()
|
||||
private let topSeparatorNode = ASDisplayNode()
|
||||
private let doneButtonBackgroundNode: NavigationBackgroundNode
|
||||
private let doneButtonBackgroundView: UIVisualEffectView
|
||||
private let doneButtonTitleNode: ImmediateTextNode
|
||||
|
||||
private let doneButtonSolidBackgroundNode: ASDisplayNode
|
||||
private let doneButtonSolidTitleNode: ImmediateTextNode
|
||||
|
||||
var cancel: (() -> Void)?
|
||||
var done: (() -> Void)?
|
||||
@ -48,46 +48,82 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
self.cancelButtonType = cancelButtonType
|
||||
self.doneButtonType = doneButtonType
|
||||
|
||||
self.cancelHighlightBackgroundNode.alpha = 0.0
|
||||
self.doneHighlightBackgroundNode.alpha = 0.0
|
||||
self.doneButtonBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0xf2f2f2, alpha: 0.45))
|
||||
self.doneButtonBackgroundNode.cornerRadius = 14.0
|
||||
|
||||
let blurEffect: UIBlurEffect
|
||||
if #available(iOS 13.0, *) {
|
||||
blurEffect = UIBlurEffect(style: .systemUltraThinMaterialLight)
|
||||
} else {
|
||||
blurEffect = UIBlurEffect(style: .light)
|
||||
}
|
||||
|
||||
self.doneButtonBackgroundView = UIVisualEffectView(effect: blurEffect)
|
||||
self.doneButtonBackgroundView.clipsToBounds = true
|
||||
self.doneButtonBackgroundView.layer.cornerRadius = 14.0
|
||||
self.doneButtonBackgroundView.isUserInteractionEnabled = false
|
||||
|
||||
self.doneButtonTitleNode = ImmediateTextNode()
|
||||
self.doneButtonTitleNode.displaysAsynchronously = false
|
||||
self.doneButtonTitleNode.textShadowColor = UIColor(rgb: 0x000000, alpha: 0.1)
|
||||
self.doneButtonTitleNode.isUserInteractionEnabled = false
|
||||
|
||||
self.doneButtonSolidBackgroundNode = ASDisplayNode()
|
||||
self.doneButtonSolidBackgroundNode.alpha = 0.0
|
||||
self.doneButtonSolidBackgroundNode.clipsToBounds = true
|
||||
self.doneButtonSolidBackgroundNode.layer.cornerRadius = 14.0
|
||||
if #available(iOS 13.0, *) {
|
||||
self.doneButtonSolidBackgroundNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
self.doneButtonSolidBackgroundNode.isUserInteractionEnabled = false
|
||||
|
||||
self.doneButtonSolidTitleNode = ImmediateTextNode()
|
||||
self.doneButtonSolidTitleNode.alpha = 0.0
|
||||
self.doneButtonSolidTitleNode.displaysAsynchronously = false
|
||||
self.doneButtonSolidTitleNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.cancelHighlightBackgroundNode)
|
||||
self.addSubnode(self.cancelButton)
|
||||
self.addSubnode(self.doneHighlightBackgroundNode)
|
||||
self.addSubnode(self.doneButtonBackgroundNode)
|
||||
self.addSubnode(self.doneButtonTitleNode)
|
||||
|
||||
self.addSubnode(self.doneButtonSolidBackgroundNode)
|
||||
self.addSubnode(self.doneButtonSolidTitleNode)
|
||||
|
||||
self.addSubnode(self.doneButton)
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.topSeparatorNode)
|
||||
|
||||
self.updateThemeAndStrings(theme: theme, strings: strings)
|
||||
|
||||
self.cancelButton.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.cancelHighlightBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.cancelHighlightBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
strongSelf.cancelHighlightBackgroundNode.alpha = 0.0
|
||||
strongSelf.cancelHighlightBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.doneButton.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.doneHighlightBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.doneHighlightBackgroundNode.alpha = 1.0
|
||||
if strongSelf.isSolid {
|
||||
strongSelf.doneButtonSolidBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.doneButtonSolidBackgroundNode.alpha = 0.55
|
||||
strongSelf.doneButtonSolidTitleNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.doneButtonSolidTitleNode.alpha = 0.55
|
||||
} else {
|
||||
strongSelf.doneButtonBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.doneButtonBackgroundNode.alpha = 0.55
|
||||
strongSelf.doneButtonTitleNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.doneButtonTitleNode.alpha = 0.55
|
||||
}
|
||||
} else {
|
||||
strongSelf.doneHighlightBackgroundNode.alpha = 0.0
|
||||
strongSelf.doneHighlightBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
if strongSelf.isSolid {
|
||||
strongSelf.doneButtonSolidBackgroundNode.alpha = 1.0
|
||||
strongSelf.doneButtonSolidBackgroundNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
|
||||
strongSelf.doneButtonSolidTitleNode.alpha = 1.0
|
||||
strongSelf.doneButtonSolidTitleNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
|
||||
} else {
|
||||
strongSelf.doneButtonBackgroundNode.alpha = 1.0
|
||||
strongSelf.doneButtonBackgroundNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
|
||||
strongSelf.doneButtonTitleNode.alpha = 1.0
|
||||
strongSelf.doneButtonTitleNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||
self.doneButton.addTarget(self, action: #selector(self.donePressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
@ -96,25 +132,26 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
self.doneButton.isUserInteractionEnabled = enabled
|
||||
}
|
||||
|
||||
private var isSolid = false
|
||||
func setDoneIsSolid(_ isSolid: Bool, transition: ContainedViewLayoutTransition) {
|
||||
guard self.isSolid != isSolid else {
|
||||
return
|
||||
}
|
||||
self.isSolid = isSolid
|
||||
|
||||
transition.updateAlpha(node: self.doneButtonBackgroundNode, alpha: isSolid ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: self.doneButtonSolidBackgroundNode, alpha: isSolid ? 1.0 : 0.0)
|
||||
transition.updateAlpha(node: self.doneButtonTitleNode, alpha: isSolid ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: self.doneButtonSolidTitleNode, alpha: isSolid ? 1.0 : 0.0)
|
||||
}
|
||||
|
||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
||||
self.theme = theme
|
||||
self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||
self.separatorNode.backgroundColor = theme.rootController.tabBar.separatorColor
|
||||
self.topSeparatorNode.backgroundColor = theme.rootController.tabBar.separatorColor
|
||||
self.cancelHighlightBackgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor
|
||||
self.doneHighlightBackgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor
|
||||
|
||||
let cancelTitle: String
|
||||
switch self.cancelButtonType {
|
||||
case .cancel:
|
||||
cancelTitle = strings.Common_Cancel
|
||||
case .discard:
|
||||
cancelTitle = strings.WallpaperPreview_PatternPaternDiscard
|
||||
}
|
||||
|
||||
let doneTitle: String
|
||||
switch self.doneButtonType {
|
||||
case .set:
|
||||
doneTitle = strings.Wallpaper_Set
|
||||
doneTitle = strings.Wallpaper_ApplyForAll
|
||||
case .proceed:
|
||||
doneTitle = strings.Theme_Colors_Proceed
|
||||
case .apply:
|
||||
@ -123,19 +160,30 @@ final class WallpaperGalleryToolbarNode: ASDisplayNode {
|
||||
doneTitle = ""
|
||||
self.doneButton.isUserInteractionEnabled = false
|
||||
}
|
||||
self.cancelButton.setTitle(cancelTitle, with: Font.regular(17.0), with: theme.list.itemPrimaryTextColor, for: [])
|
||||
self.doneButton.setTitle(doneTitle, with: Font.regular(17.0), with: theme.list.itemPrimaryTextColor, for: [])
|
||||
self.doneButtonTitleNode.attributedText = NSAttributedString(string: doneTitle, font: Font.semibold(17.0), textColor: .white)
|
||||
|
||||
self.doneButtonSolidBackgroundNode.backgroundColor = theme.list.itemCheckColors.fillColor
|
||||
self.doneButtonSolidTitleNode.attributedText = NSAttributedString(string: doneTitle, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
self.cancelButton.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height))
|
||||
self.cancelHighlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width / 2.0), height: size.height))
|
||||
self.doneButton.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height))
|
||||
self.doneHighlightBackgroundNode.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: size.width - floor(size.width / 2.0), height: size.height))
|
||||
self.separatorNode.frame = CGRect(origin: CGPoint(x: floor(size.width / 2.0), y: 0.0), size: CGSize(width: UIScreenPixel, height: size.height + layout.intrinsicInsets.bottom))
|
||||
self.topSeparatorNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: UIScreenPixel))
|
||||
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.backgroundNode.update(size: CGSize(width: size.width, height: size.height + layout.intrinsicInsets.bottom), transition: .immediate)
|
||||
let inset: CGFloat = 16.0
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
|
||||
let doneFrame = CGRect(origin: CGPoint(x: inset, y: 2.0), size: CGSize(width: size.width - inset * 2.0, height: buttonHeight))
|
||||
self.doneButton.frame = doneFrame
|
||||
self.doneButtonBackgroundNode.frame = doneFrame
|
||||
self.doneButtonBackgroundNode.update(size: doneFrame.size, cornerRadius: 14.0, transition: transition)
|
||||
self.doneButtonBackgroundView.frame = doneFrame
|
||||
|
||||
self.doneButtonSolidBackgroundNode.frame = doneFrame
|
||||
|
||||
let doneTitleSize = self.doneButtonTitleNode.updateLayout(doneFrame.size)
|
||||
self.doneButtonTitleNode.frame = CGRect(origin: CGPoint(x: doneFrame.minX + floorToScreenPixels((doneFrame.width - doneTitleSize.width) / 2.0), y: doneFrame.minY + floorToScreenPixels((doneFrame.height - doneTitleSize.height) / 2.0)), size: doneTitleSize)
|
||||
|
||||
let _ = self.doneButtonSolidTitleNode.updateLayout(doneFrame.size)
|
||||
self.doneButtonSolidTitleNode.frame = self.doneButtonTitleNode.frame
|
||||
|
||||
}
|
||||
|
||||
@objc func cancelPressed() {
|
||||
|
@ -38,7 +38,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let checkNode: CheckNode
|
||||
private let colorNode: ASImageNode
|
||||
private let textNode: ASTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
private var textSize: CGSize?
|
||||
|
||||
@ -73,16 +73,17 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
self._value = value
|
||||
self.title = title
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x000000, alpha: 0.3))
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0xffffff, alpha: 0.4))
|
||||
self.backgroundNode.cornerRadius = 14.0
|
||||
|
||||
self.checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: .white, strokeColor: .clear, borderColor: .white, overlayBorder: false, hasInset: false, hasShadow: false, borderWidth: 1.5))
|
||||
self.checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: .white, strokeColor: .clear, borderColor: .white, overlayBorder: false, hasInset: false, hasShadow: true, borderWidth: 1.5))
|
||||
self.checkNode.isUserInteractionEnabled = false
|
||||
|
||||
self.colorNode = ASImageNode()
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.attributedText = NSAttributedString(string: title, font: Font.medium(13), textColor: .white)
|
||||
self.textNode.textShadowColor = UIColor(rgb: 0x000000, alpha: 0.1)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -139,7 +140,11 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
|
||||
var buttonColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
didSet {
|
||||
self.backgroundNode.updateColor(color: self.buttonColor, transition: .immediate)
|
||||
if self.buttonColor == UIColor(rgb: 0x000000, alpha: 0.3) {
|
||||
self.backgroundNode.updateColor(color: UIColor(rgb: 0xf2f2f2, alpha: 0.45), transition: .immediate)
|
||||
} else {
|
||||
self.backgroundNode.updateColor(color: self.buttonColor, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +226,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
|
||||
override func measure(_ constrainedSize: CGSize) -> CGSize {
|
||||
let size = self.textNode.measure(constrainedSize)
|
||||
let size = self.textNode.updateLayout(constrainedSize)
|
||||
self.textSize = size
|
||||
return CGSize(width: ceil(size.width) + 48.0, height: 30.0)
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
|
||||
var patternChanged: ((TelegramWallpaper?, Int32?, Bool) -> Void)?
|
||||
|
||||
@ -401,8 +401,8 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.labelNode.attributedText?.string ?? "", font: Font.bold(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
self.labelNode.attributedText = NSAttributedString(string: self.labelNode.attributedText?.string ?? "", font: Font.regular(14.0), textColor: self.theme.rootController.navigationBar.primaryTextColor)
|
||||
|
||||
if let size = self.validLayout {
|
||||
self.updateLayout(size: size, transition: .immediate)
|
||||
if let (size, bottomInset) = self.validLayout {
|
||||
self.updateLayout(size: size, bottomInset: bottomInset, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,11 +478,12 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, bottomInset)
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
|
||||
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
|
||||
let backgroundFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height + bottomInset)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
self.backgroundNode.update(size: backgroundFrame.size, transition: transition)
|
||||
transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: UIScreenPixel))
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(self.bounds.size)
|
||||
|
@ -55,7 +55,7 @@ private enum UsernameSetupEntryId: Hashable {
|
||||
|
||||
private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
case publicLinkHeader(PresentationTheme, String)
|
||||
case editablePublicLink(PresentationTheme, PresentationStrings, String, String?, String)
|
||||
case editablePublicLink(PresentationTheme, PresentationStrings, String, String?, String, Bool)
|
||||
case publicLinkStatus(PresentationTheme, String, AddressNameValidationStatus, String, String)
|
||||
case publicLinkInfo(PresentationTheme, String)
|
||||
|
||||
@ -99,8 +99,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .editablePublicLink(lhsTheme, lhsStrings, lhsPrefix, lhsCurrentText, lhsText):
|
||||
if case let .editablePublicLink(rhsTheme, rhsStrings, rhsPrefix, rhsCurrentText, rhsText) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsPrefix == rhsPrefix, lhsCurrentText == rhsCurrentText, lhsText == rhsText {
|
||||
case let .editablePublicLink(lhsTheme, lhsStrings, lhsPrefix, lhsCurrentText, lhsText, lhsEnabled):
|
||||
if case let .editablePublicLink(rhsTheme, rhsStrings, rhsPrefix, rhsCurrentText, rhsText, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsPrefix == rhsPrefix, lhsCurrentText == rhsCurrentText, lhsText == rhsText, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -197,8 +197,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case let .publicLinkHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .editablePublicLink(theme, _, prefix, currentText, text):
|
||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, clearType: .always, tag: UsernameEntryTag.username, sectionId: self.section, textUpdated: { updatedText in
|
||||
case let .editablePublicLink(theme, _, prefix, currentText, text, enabled):
|
||||
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: enabled ? prefix : "", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, clearType: enabled ? .always : .none, enabled: enabled, tag: UsernameEntryTag.username, sectionId: self.section, textUpdated: { updatedText in
|
||||
arguments.updatePublicLinkText(currentText, updatedText)
|
||||
}, action: {
|
||||
})
|
||||
@ -292,7 +292,7 @@ private struct UsernameSetupControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func usernameSetupControllerEntries(presentationData: PresentationData, view: PeerView, state: UsernameSetupControllerState, temporaryOrder: [String]?) -> [UsernameSetupEntry] {
|
||||
private func usernameSetupControllerEntries(presentationData: PresentationData, view: PeerView, state: UsernameSetupControllerState, temporaryOrder: [String]?, mode: UsernameSetupMode) -> [UsernameSetupEntry] {
|
||||
var entries: [UsernameSetupEntry] = []
|
||||
|
||||
if let peer = view.peers[view.peerId] as? TelegramUser {
|
||||
@ -308,7 +308,7 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
|
||||
entries.append(.publicLinkHeader(presentationData.theme, presentationData.strings.Username_Username))
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings, presentationData.strings.Username_Title, peer.editableUsername, currentUsername))
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings, presentationData.strings.Username_Title, peer.editableUsername, currentUsername, mode == .account))
|
||||
if let status = state.addressNameValidationStatus {
|
||||
let statusText: String
|
||||
switch status {
|
||||
@ -348,16 +348,18 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
entries.append(.publicLinkStatus(presentationData.theme, currentUsername, status, statusText, currentUsername))
|
||||
}
|
||||
|
||||
var infoText = presentationData.strings.Username_Help
|
||||
|
||||
let otherUsernames = peer.usernames.filter { !$0.flags.contains(.isEditable) }
|
||||
|
||||
if otherUsernames.isEmpty {
|
||||
infoText += "\n\n"
|
||||
let hintText = presentationData.strings.Username_LinkHint(currentUsername.replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "")).string.replacingOccurrences(of: "]", with: "]()")
|
||||
infoText += hintText
|
||||
if case .bot = mode {
|
||||
entries.append(.publicLinkInfo(presentationData.theme, "This username cannot be edited."))
|
||||
} else {
|
||||
var infoText = presentationData.strings.Username_Help
|
||||
if otherUsernames.isEmpty {
|
||||
infoText += "\n\n"
|
||||
let hintText = presentationData.strings.Username_LinkHint(currentUsername.replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "")).string.replacingOccurrences(of: "]", with: "]()")
|
||||
infoText += hintText
|
||||
}
|
||||
entries.append(.publicLinkInfo(presentationData.theme, infoText))
|
||||
}
|
||||
entries.append(.publicLinkInfo(presentationData.theme, infoText))
|
||||
|
||||
if !otherUsernames.isEmpty {
|
||||
entries.append(.additionalLinkHeader(presentationData.theme, presentationData.strings.Username_LinksOrder))
|
||||
@ -382,14 +384,26 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
i += 1
|
||||
}
|
||||
|
||||
entries.append(.additionalLinkInfo(presentationData.theme, presentationData.strings.Username_LinksOrderInfo))
|
||||
let text: String
|
||||
switch mode {
|
||||
case .account:
|
||||
text = presentationData.strings.Username_LinksOrderInfo
|
||||
case .bot:
|
||||
text = presentationData.strings.Username_BotLinksOrderInfo
|
||||
}
|
||||
entries.append(.additionalLinkInfo(presentationData.theme, text))
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
public enum UsernameSetupMode: Equatable {
|
||||
case account
|
||||
case bot(PeerId)
|
||||
}
|
||||
|
||||
public func usernameSetupController(context: AccountContext, mode: UsernameSetupMode = .account) -> ViewController {
|
||||
let statePromise = ValuePromise(UsernameSetupControllerState(), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: UsernameSetupControllerState())
|
||||
let updateState: ((UsernameSetupControllerState) -> UsernameSetupControllerState) -> Void = { f in
|
||||
@ -408,6 +422,17 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
let updateAddressNameDisposable = MetaDisposable()
|
||||
actionsDisposable.add(updateAddressNameDisposable)
|
||||
|
||||
let peerId: PeerId
|
||||
let domain: AddressNameDomain
|
||||
switch mode {
|
||||
case .account:
|
||||
domain = .account
|
||||
peerId = context.account.peerId
|
||||
case let .bot(botPeerId):
|
||||
domain = .bot(botPeerId)
|
||||
peerId = botPeerId
|
||||
}
|
||||
|
||||
let arguments = UsernameSetupControllerArguments(account: context.account, updatePublicLinkText: { currentText, text in
|
||||
if text.isEmpty {
|
||||
checkAddressNameDisposable.set(nil)
|
||||
@ -424,7 +449,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
return state.withUpdatedEditingPublicLinkText(text)
|
||||
}
|
||||
|
||||
checkAddressNameDisposable.set((context.engine.peers.validateAddressNameInteractive(domain: .account, name: text)
|
||||
checkAddressNameDisposable.set((context.engine.peers.validateAddressNameInteractive(domain: domain, name: text)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
updateState { state in
|
||||
return state.withUpdatedAddressNameValidationStatus(result)
|
||||
@ -432,7 +457,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
}))
|
||||
}
|
||||
}, shareLink: {
|
||||
let _ = (context.account.postbox.loadedPeerWithId(context.account.peerId)
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
var currentAddressName: String = peer.addressName ?? ""
|
||||
@ -456,7 +481,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
dismissInputImpl?()
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Username_ActivateAlertTitle, text: presentationData.strings.Username_ActivateAlertText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Username_ActivateAlertShow, action: {
|
||||
let _ = (context.engine.peers.toggleAddressNameActive(domain: .account, name: name, active: true)
|
||||
let _ = (context.engine.peers.toggleAddressNameActive(domain: domain, name: name, active: true)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
let errorText: String
|
||||
switch error {
|
||||
@ -472,7 +497,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
dismissInputImpl?()
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Username_DeactivateAlertTitle, text: presentationData.strings.Username_DeactivateAlertText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Username_DeactivateAlertHide, action: {
|
||||
let _ = context.engine.peers.toggleAddressNameActive(domain: .account, name: name, active: false).start()
|
||||
let _ = context.engine.peers.toggleAddressNameActive(domain: domain, name: name, active: false).start()
|
||||
})]), nil)
|
||||
}, openAuction: { username in
|
||||
dismissInputImpl?()
|
||||
@ -481,8 +506,8 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
})
|
||||
|
||||
let temporaryOrder = Promise<[String]?>(nil)
|
||||
|
||||
let peerView = context.account.viewTracker.peerView(context.account.peerId)
|
||||
|
||||
let peerView = context.account.viewTracker.peerView(peerId)
|
||||
|> deliverOnMainQueue
|
||||
|
||||
let signal = combineLatest(
|
||||
@ -522,7 +547,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
}
|
||||
|
||||
if let updatedAddressNameValue = updatedAddressNameValue {
|
||||
updateAddressNameDisposable.set((context.engine.peers.updateAddressName(domain: .account, name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue)
|
||||
updateAddressNameDisposable.set((context.engine.peers.updateAddressName(domain: domain, name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
updateState { state in
|
||||
return state.withUpdatedUpdatingAddressName(false)
|
||||
@ -545,7 +570,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
})
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Username_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: usernameSetupControllerEntries(presentationData: presentationData, view: view, state: state, temporaryOrder: temporaryOrder), style: .blocks, focusItemTag: UsernameEntryTag.username, animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: usernameSetupControllerEntries(presentationData: presentationData, view: view, state: state, temporaryOrder: temporaryOrder, mode: mode), style: .blocks, focusItemTag: mode == .account ? UsernameEntryTag.username : nil, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
} |> afterDisposed {
|
||||
@ -667,7 +692,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
||||
break
|
||||
}
|
||||
}
|
||||
let _ = (context.engine.peers.reorderAddressNames(domain: .account, names: currentUsernames)
|
||||
let _ = (context.engine.peers.reorderAddressNames(domain: domain, names: currentUsernames)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
temporaryOrder.set(.single(nil))
|
||||
})
|
||||
|
@ -2,6 +2,7 @@
|
||||
public enum Api {
|
||||
public enum account {}
|
||||
public enum auth {}
|
||||
public enum bots {}
|
||||
public enum channels {}
|
||||
public enum communities {}
|
||||
public enum community {}
|
||||
@ -991,11 +992,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-2113903484] = { return Api.auth.SentCodeType.parse_sentCodeTypeMissedCall($0) }
|
||||
dict[-1521934870] = { return Api.auth.SentCodeType.parse_sentCodeTypeSetUpEmailRequired($0) }
|
||||
dict[-1073693790] = { return Api.auth.SentCodeType.parse_sentCodeTypeSms($0) }
|
||||
dict[-391678544] = { return Api.bots.BotInfo.parse_botInfo($0) }
|
||||
dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) }
|
||||
dict[-541588713] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) }
|
||||
dict[-1699676497] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) }
|
||||
dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) }
|
||||
dict[-191450938] = { return Api.channels.SendAsPeers.parse_sendAsPeers($0) }
|
||||
dict[-414818125] = { return Api.communities.CommunityUpdates.parse_communityUpdates($0) }
|
||||
dict[1805101290] = { return Api.communities.ExportedCommunityInvite.parse_exportedCommunityInvite($0) }
|
||||
dict[-2662489] = { return Api.communities.ExportedInvites.parse_exportedInvites($0) }
|
||||
dict[988463765] = { return Api.community.CommunityInvite.parse_communityInvite($0) }
|
||||
@ -1789,6 +1792,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.auth.SentCodeType:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.bots.BotInfo:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.channels.AdminLogResults:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.channels.ChannelParticipant:
|
||||
@ -1797,6 +1802,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.channels.SendAsPeers:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.communities.CommunityUpdates:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.communities.ExportedCommunityInvite:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.communities.ExportedInvites:
|
||||
|
@ -590,6 +590,50 @@ public extension Api.auth {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.bots {
|
||||
enum BotInfo: TypeConstructorDescription {
|
||||
case botInfo(name: String, about: String, description: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botInfo(let name, let about, let description):
|
||||
if boxed {
|
||||
buffer.appendInt32(-391678544)
|
||||
}
|
||||
serializeString(name, buffer: buffer, boxed: false)
|
||||
serializeString(about, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botInfo(let name, let about, let description):
|
||||
return ("botInfo", [("name", name as Any), ("about", about as Any), ("description", description as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botInfo(_ reader: BufferReader) -> BotInfo? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.bots.BotInfo.botInfo(name: _1!, about: _2!, description: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.channels {
|
||||
enum AdminLogResults: TypeConstructorDescription {
|
||||
case adminLogResults(events: [Api.ChannelAdminLogEvent], chats: [Api.Chat], users: [Api.User])
|
||||
@ -850,6 +894,68 @@ public extension Api.channels {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.communities {
|
||||
enum CommunityUpdates: TypeConstructorDescription {
|
||||
case communityUpdates(missingPeers: [Api.Peer], chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .communityUpdates(let missingPeers, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-414818125)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(missingPeers.count))
|
||||
for item in missingPeers {
|
||||
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 .communityUpdates(let missingPeers, let chats, let users):
|
||||
return ("communityUpdates", [("missingPeers", missingPeers as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_communityUpdates(_ reader: BufferReader) -> CommunityUpdates? {
|
||||
var _1: [Api.Peer]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.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.communities.CommunityUpdates.communityUpdates(missingPeers: _1!, chats: _2!, users: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.communities {
|
||||
enum ExportedCommunityInvite: TypeConstructorDescription {
|
||||
case exportedCommunityInvite(filter: Api.DialogFilter, invite: Api.ExportedCommunityInvite)
|
||||
@ -1072,115 +1178,3 @@ public extension Api.community {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.contacts {
|
||||
enum Blocked: TypeConstructorDescription {
|
||||
case blocked(blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
||||
case blockedSlice(count: Int32, blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .blocked(let blocked, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(182326673)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(blocked.count))
|
||||
for item in blocked {
|
||||
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 .blockedSlice(let count, let blocked, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-513392236)
|
||||
}
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(blocked.count))
|
||||
for item in blocked {
|
||||
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 .blocked(let blocked, let chats, let users):
|
||||
return ("blocked", [("blocked", blocked as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
case .blockedSlice(let count, let blocked, let chats, let users):
|
||||
return ("blockedSlice", [("count", count as Any), ("blocked", blocked as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_blocked(_ reader: BufferReader) -> Blocked? {
|
||||
var _1: [Api.PeerBlocked]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerBlocked.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.contacts.Blocked.blocked(blocked: _1!, chats: _2!, users: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_blockedSlice(_ reader: BufferReader) -> Blocked? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: [Api.PeerBlocked]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerBlocked.self)
|
||||
}
|
||||
var _3: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _4: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = 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
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.contacts.Blocked.blockedSlice(count: _1!, blocked: _2!, chats: _3!, users: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,115 @@
|
||||
public extension Api.contacts {
|
||||
enum Blocked: TypeConstructorDescription {
|
||||
case blocked(blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
||||
case blockedSlice(count: Int32, blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .blocked(let blocked, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(182326673)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(blocked.count))
|
||||
for item in blocked {
|
||||
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 .blockedSlice(let count, let blocked, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-513392236)
|
||||
}
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(blocked.count))
|
||||
for item in blocked {
|
||||
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 .blocked(let blocked, let chats, let users):
|
||||
return ("blocked", [("blocked", blocked as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
case .blockedSlice(let count, let blocked, let chats, let users):
|
||||
return ("blockedSlice", [("count", count as Any), ("blocked", blocked as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_blocked(_ reader: BufferReader) -> Blocked? {
|
||||
var _1: [Api.PeerBlocked]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerBlocked.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.contacts.Blocked.blocked(blocked: _1!, chats: _2!, users: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_blockedSlice(_ reader: BufferReader) -> Blocked? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: [Api.PeerBlocked]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PeerBlocked.self)
|
||||
}
|
||||
var _3: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _4: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = 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
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.contacts.Blocked.blockedSlice(count: _1!, blocked: _2!, chats: _3!, users: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.contacts {
|
||||
enum Contacts: TypeConstructorDescription {
|
||||
case contacts(contacts: [Api.Contact], savedCount: Int32, users: [Api.User])
|
||||
@ -1264,69 +1376,3 @@ public extension Api.help {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum UserInfo: TypeConstructorDescription {
|
||||
case userInfo(message: String, entities: [Api.MessageEntity], author: String, date: Int32)
|
||||
case userInfoEmpty
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .userInfo(let message, let entities, let author, let date):
|
||||
if boxed {
|
||||
buffer.appendInt32(32192344)
|
||||
}
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities.count))
|
||||
for item in entities {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
serializeString(author, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .userInfoEmpty:
|
||||
if boxed {
|
||||
buffer.appendInt32(-206688531)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .userInfo(let message, let entities, let author, let date):
|
||||
return ("userInfo", [("message", message as Any), ("entities", entities as Any), ("author", author as Any), ("date", date as Any)])
|
||||
case .userInfoEmpty:
|
||||
return ("userInfoEmpty", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_userInfo(_ reader: BufferReader) -> UserInfo? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: [Api.MessageEntity]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
}
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.help.UserInfo.userInfo(message: _1!, entities: _2!, author: _3!, date: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_userInfoEmpty(_ reader: BufferReader) -> UserInfo? {
|
||||
return Api.help.UserInfo.userInfoEmpty
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,69 @@
|
||||
public extension Api.help {
|
||||
enum UserInfo: TypeConstructorDescription {
|
||||
case userInfo(message: String, entities: [Api.MessageEntity], author: String, date: Int32)
|
||||
case userInfoEmpty
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .userInfo(let message, let entities, let author, let date):
|
||||
if boxed {
|
||||
buffer.appendInt32(32192344)
|
||||
}
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities.count))
|
||||
for item in entities {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
serializeString(author, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .userInfoEmpty:
|
||||
if boxed {
|
||||
buffer.appendInt32(-206688531)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .userInfo(let message, let entities, let author, let date):
|
||||
return ("userInfo", [("message", message as Any), ("entities", entities as Any), ("author", author as Any), ("date", date as Any)])
|
||||
case .userInfoEmpty:
|
||||
return ("userInfoEmpty", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_userInfo(_ reader: BufferReader) -> UserInfo? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: [Api.MessageEntity]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
}
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.help.UserInfo.userInfo(message: _1!, entities: _2!, author: _3!, date: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_userInfoEmpty(_ reader: BufferReader) -> UserInfo? {
|
||||
return Api.help.UserInfo.userInfoEmpty
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum AffectedFoundMessages: TypeConstructorDescription {
|
||||
case affectedFoundMessages(pts: Int32, ptsCount: Int32, offset: Int32, messages: [Int32])
|
||||
@ -1312,87 +1378,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum FeaturedStickers: TypeConstructorDescription {
|
||||
case featuredStickers(flags: Int32, hash: Int64, count: Int32, sets: [Api.StickerSetCovered], unread: [Int64])
|
||||
case featuredStickersNotModified(count: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .featuredStickers(let flags, let hash, let count, let sets, let unread):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1103615738)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(unread.count))
|
||||
for item in unread {
|
||||
serializeInt64(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
break
|
||||
case .featuredStickersNotModified(let count):
|
||||
if boxed {
|
||||
buffer.appendInt32(-958657434)
|
||||
}
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .featuredStickers(let flags, let hash, let count, let sets, let unread):
|
||||
return ("featuredStickers", [("flags", flags as Any), ("hash", hash as Any), ("count", count as Any), ("sets", sets as Any), ("unread", unread as Any)])
|
||||
case .featuredStickersNotModified(let count):
|
||||
return ("featuredStickersNotModified", [("count", count as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_featuredStickers(_ reader: BufferReader) -> FeaturedStickers? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: [Api.StickerSetCovered]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
||||
}
|
||||
var _5: [Int64]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.messages.FeaturedStickers.featuredStickers(flags: _1!, hash: _2!, count: _3!, sets: _4!, unread: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_featuredStickersNotModified(_ reader: BufferReader) -> FeaturedStickers? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.FeaturedStickers.featuredStickersNotModified(count: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,87 @@
|
||||
public extension Api.messages {
|
||||
enum FeaturedStickers: TypeConstructorDescription {
|
||||
case featuredStickers(flags: Int32, hash: Int64, count: Int32, sets: [Api.StickerSetCovered], unread: [Int64])
|
||||
case featuredStickersNotModified(count: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .featuredStickers(let flags, let hash, let count, let sets, let unread):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1103615738)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(unread.count))
|
||||
for item in unread {
|
||||
serializeInt64(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
break
|
||||
case .featuredStickersNotModified(let count):
|
||||
if boxed {
|
||||
buffer.appendInt32(-958657434)
|
||||
}
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .featuredStickers(let flags, let hash, let count, let sets, let unread):
|
||||
return ("featuredStickers", [("flags", flags as Any), ("hash", hash as Any), ("count", count as Any), ("sets", sets as Any), ("unread", unread as Any)])
|
||||
case .featuredStickersNotModified(let count):
|
||||
return ("featuredStickersNotModified", [("count", count as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_featuredStickers(_ reader: BufferReader) -> FeaturedStickers? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: [Api.StickerSetCovered]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
||||
}
|
||||
var _5: [Int64]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.messages.FeaturedStickers.featuredStickers(flags: _1!, hash: _2!, count: _3!, sets: _4!, unread: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_featuredStickersNotModified(_ reader: BufferReader) -> FeaturedStickers? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.FeaturedStickers.featuredStickersNotModified(count: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum ForumTopics: TypeConstructorDescription {
|
||||
case forumTopics(flags: Int32, count: Int32, topics: [Api.ForumTopic], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], pts: Int32)
|
||||
@ -1456,57 +1540,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum StickerSetInstallResult: TypeConstructorDescription {
|
||||
case stickerSetInstallResultArchive(sets: [Api.StickerSetCovered])
|
||||
case stickerSetInstallResultSuccess
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .stickerSetInstallResultArchive(let sets):
|
||||
if boxed {
|
||||
buffer.appendInt32(904138920)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .stickerSetInstallResultSuccess:
|
||||
if boxed {
|
||||
buffer.appendInt32(946083368)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .stickerSetInstallResultArchive(let sets):
|
||||
return ("stickerSetInstallResultArchive", [("sets", sets as Any)])
|
||||
case .stickerSetInstallResultSuccess:
|
||||
return ("stickerSetInstallResultSuccess", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_stickerSetInstallResultArchive(_ reader: BufferReader) -> StickerSetInstallResult? {
|
||||
var _1: [Api.StickerSetCovered]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.StickerSetInstallResult.stickerSetInstallResultArchive(sets: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_stickerSetInstallResultSuccess(_ reader: BufferReader) -> StickerSetInstallResult? {
|
||||
return Api.messages.StickerSetInstallResult.stickerSetInstallResultSuccess
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,57 @@
|
||||
public extension Api.messages {
|
||||
enum StickerSetInstallResult: TypeConstructorDescription {
|
||||
case stickerSetInstallResultArchive(sets: [Api.StickerSetCovered])
|
||||
case stickerSetInstallResultSuccess
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .stickerSetInstallResultArchive(let sets):
|
||||
if boxed {
|
||||
buffer.appendInt32(904138920)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sets.count))
|
||||
for item in sets {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .stickerSetInstallResultSuccess:
|
||||
if boxed {
|
||||
buffer.appendInt32(946083368)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .stickerSetInstallResultArchive(let sets):
|
||||
return ("stickerSetInstallResultArchive", [("sets", sets as Any)])
|
||||
case .stickerSetInstallResultSuccess:
|
||||
return ("stickerSetInstallResultSuccess", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_stickerSetInstallResultArchive(_ reader: BufferReader) -> StickerSetInstallResult? {
|
||||
var _1: [Api.StickerSetCovered]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.StickerSetInstallResult.stickerSetInstallResultArchive(sets: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_stickerSetInstallResultSuccess(_ reader: BufferReader) -> StickerSetInstallResult? {
|
||||
return Api.messages.StickerSetInstallResult.stickerSetInstallResultSuccess
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum Stickers: TypeConstructorDescription {
|
||||
case stickers(hash: Int64, stickers: [Api.Document])
|
||||
|
@ -1819,15 +1819,17 @@ public extension Api.functions.bots {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func getBotInfo(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[String]>) {
|
||||
static func getBotInfo(flags: Int32, bot: Api.InputUser?, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.bots.BotInfo>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1978405606)
|
||||
buffer.appendInt32(-589753091)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {bot!.serialize(buffer, true)}
|
||||
serializeString(langCode, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "bots.getBotInfo", parameters: [("langCode", String(describing: langCode))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [String]? in
|
||||
return (FunctionDescription(name: "bots.getBotInfo", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("langCode", String(describing: langCode))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.bots.BotInfo? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: [String]?
|
||||
if let _ = reader.readInt32() {
|
||||
result = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self)
|
||||
var result: Api.bots.BotInfo?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.bots.BotInfo
|
||||
}
|
||||
return result
|
||||
})
|
||||
@ -1848,6 +1850,26 @@ public extension Api.functions.bots {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func reorderUsernames(bot: Api.InputUser, order: [String]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1760972350)
|
||||
bot.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(order.count))
|
||||
for item in order {
|
||||
serializeString(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
return (FunctionDescription(name: "bots.reorderUsernames", parameters: [("bot", String(describing: bot)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func resetBotCommands(scope: Api.BotCommandScope, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
@ -1932,14 +1954,16 @@ public extension Api.functions.bots {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func setBotInfo(flags: Int32, langCode: String, about: String?, description: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
static func setBotInfo(flags: Int32, bot: Api.InputUser?, langCode: String, name: String?, about: String?, description: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1553604742)
|
||||
buffer.appendInt32(282013987)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {bot!.serialize(buffer, true)}
|
||||
serializeString(langCode, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 3) != 0 {serializeString(name!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(about!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "bots.setBotInfo", parameters: [("flags", String(describing: flags)), ("langCode", String(describing: langCode)), ("about", String(describing: about)), ("description", String(describing: description))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
return (FunctionDescription(name: "bots.setBotInfo", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("langCode", String(describing: langCode)), ("name", String(describing: name)), ("about", String(describing: about)), ("description", String(describing: description))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -1965,6 +1989,23 @@ public extension Api.functions.bots {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func toggleUsername(bot: Api.InputUser, username: String, active: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(87861619)
|
||||
bot.serialize(buffer, true)
|
||||
serializeString(username, buffer: buffer, boxed: false)
|
||||
active.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "bots.toggleUsername", parameters: [("bot", String(describing: bot)), ("username", String(describing: username)), ("active", String(describing: active))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func checkUsername(channel: Api.InputChannel, username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
@ -2986,6 +3027,21 @@ public extension Api.functions.communities {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.communities {
|
||||
static func getCommunityUpdates(community: Api.InputCommunity) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.communities.CommunityUpdates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(693556789)
|
||||
community.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "communities.getCommunityUpdates", parameters: [("community", String(describing: community))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.communities.CommunityUpdates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.communities.CommunityUpdates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.communities.CommunityUpdates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.communities {
|
||||
static func getExportedInvites(community: Api.InputCommunity) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.communities.ExportedInvites>) {
|
||||
let buffer = Buffer()
|
||||
@ -3001,6 +3057,21 @@ public extension Api.functions.communities {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.communities {
|
||||
static func hideCommunityUpdates(community: Api.InputCommunity) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(224889775)
|
||||
community.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "communities.hideCommunityUpdates", parameters: [("community", String(describing: community))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.communities {
|
||||
static func joinCommunityInvite(slug: String, peers: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
@ -3391,21 +3462,6 @@ public extension Api.functions.contacts {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.folders {
|
||||
static func deleteFolder(folderId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(472471681)
|
||||
serializeInt32(folderId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "folders.deleteFolder", parameters: [("folderId", String(describing: folderId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.folders {
|
||||
static func editPeerFolders(folderPeers: [Api.InputFolderPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
@ -7959,12 +8015,13 @@ public extension Api.functions.photos {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.photos {
|
||||
static func updateProfilePhoto(flags: Int32, id: Api.InputPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
static func updateProfilePhoto(flags: Int32, bot: Api.InputUser?, id: Api.InputPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(473782614)
|
||||
buffer.appendInt32(166207545)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {bot!.serialize(buffer, true)}
|
||||
id.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "photos.updateProfilePhoto", parameters: [("flags", String(describing: flags)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
return (FunctionDescription(name: "photos.updateProfilePhoto", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.photos.Photo?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -7995,15 +8052,16 @@ public extension Api.functions.photos {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.photos {
|
||||
static func uploadProfilePhoto(flags: Int32, file: Api.InputFile?, video: Api.InputFile?, videoStartTs: Double?, videoEmojiMarkup: Api.VideoSize?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
static func uploadProfilePhoto(flags: Int32, bot: Api.InputUser?, file: Api.InputFile?, video: Api.InputFile?, videoStartTs: Double?, videoEmojiMarkup: Api.VideoSize?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.photos.Photo>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(154966609)
|
||||
buffer.appendInt32(59286453)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 5) != 0 {bot!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {file!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {video!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeDouble(videoStartTs!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {videoEmojiMarkup!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "photos.uploadProfilePhoto", parameters: [("flags", String(describing: flags)), ("file", String(describing: file)), ("video", String(describing: video)), ("videoStartTs", String(describing: videoStartTs)), ("videoEmojiMarkup", String(describing: videoEmojiMarkup))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
return (FunctionDescription(name: "photos.uploadProfilePhoto", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot)), ("file", String(describing: file)), ("video", String(describing: video)), ("videoStartTs", String(describing: videoStartTs)), ("videoEmojiMarkup", String(describing: videoEmojiMarkup))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.photos.Photo? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.photos.Photo?
|
||||
if let signature = reader.readInt32() {
|
||||
|
@ -85,8 +85,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return TelegramMediaAction(action: .joinedByRequest)
|
||||
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
|
||||
return TelegramMediaAction(action: .webViewData(text))
|
||||
case let .messageActionGiftPremium(_, currency, amount, months, _, _):
|
||||
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months))
|
||||
case let .messageActionGiftPremium(_, currency, amount, months, cryptoCurrency, cryptoAmount):
|
||||
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount))
|
||||
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):
|
||||
return TelegramMediaAction(action: .topicCreated(title: title, iconColor: iconColor, iconFileId: iconEmojiId))
|
||||
case let .messageActionTopicEdit(flags, title, iconEmojiId, closed, hidden):
|
||||
|
@ -36,7 +36,7 @@ extension TelegramPeerUsername {
|
||||
extension TelegramUser {
|
||||
convenience init(user: Api.User) {
|
||||
switch user {
|
||||
case let .user(flags, _, id, accessHash, firstName, lastName, username, phone, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, usernames):
|
||||
case let .user(flags, flags2, id, accessHash, firstName, lastName, username, phone, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, usernames):
|
||||
let representations: [TelegramMediaImageRepresentation] = photo.flatMap(parsedTelegramProfilePhoto) ?? []
|
||||
|
||||
let isMin = (flags & (1 << 20)) != 0
|
||||
@ -80,6 +80,9 @@ extension TelegramUser {
|
||||
if (flags & (1 << 27)) != 0 {
|
||||
botFlags.insert(.canBeAddedToAttachMenu)
|
||||
}
|
||||
if (flags2 & (1 << 1)) != 0 {
|
||||
botFlags.insert(.canEdit)
|
||||
}
|
||||
botInfo = BotUserInfo(flags: botFlags, inlinePlaceholder: botInlinePlaceholder)
|
||||
}
|
||||
|
||||
@ -93,7 +96,7 @@ extension TelegramUser {
|
||||
|
||||
static func merge(_ lhs: TelegramUser?, rhs: Api.User) -> TelegramUser? {
|
||||
switch rhs {
|
||||
case let .user(flags, _, _, rhsAccessHash, _, _, _, _, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, usernames):
|
||||
case let .user(flags, _, _, rhsAccessHash, _, _, _, _, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, _):
|
||||
let isMin = (flags & (1 << 20)) != 0
|
||||
if !isMin {
|
||||
return TelegramUser(user: rhs)
|
||||
@ -142,6 +145,9 @@ extension TelegramUser {
|
||||
if (flags & (1 << 27)) != 0 {
|
||||
botFlags.insert(.canBeAddedToAttachMenu)
|
||||
}
|
||||
if let botInfo = lhs.botInfo, botInfo.flags.contains(.canEdit) {
|
||||
botFlags.insert(.canEdit)
|
||||
}
|
||||
botInfo = BotUserInfo(flags: botFlags, inlinePlaceholder: botInlinePlaceholder)
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,35 @@ public struct CachedUserFlags: OptionSet {
|
||||
public static let translationHidden = CachedUserFlags(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
public final class EditableBotInfo: PostboxCoding, Equatable {
|
||||
public let name: String
|
||||
public let about: String
|
||||
public let description: String
|
||||
|
||||
public init(name: String, about: String, description: String) {
|
||||
self.name = name
|
||||
self.about = about
|
||||
self.description = description
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.name = decoder.decodeStringForKey("n", orElse: "")
|
||||
self.about = decoder.decodeStringForKey("a", orElse: "")
|
||||
self.description = decoder.decodeStringForKey("d", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.name, forKey: "n")
|
||||
encoder.encodeString(self.about, forKey: "a")
|
||||
encoder.encodeString(self.description, forKey: "d")
|
||||
}
|
||||
|
||||
public static func ==(lhs: EditableBotInfo, rhs: EditableBotInfo) -> Bool {
|
||||
return lhs.name == rhs.name && lhs.about == rhs.about && lhs.description == rhs.description
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final class CachedUserData: CachedPeerData {
|
||||
public let about: String?
|
||||
public let botInfo: BotInfo?
|
||||
|
@ -95,7 +95,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case setChatTheme(emoji: String)
|
||||
case joinedByRequest
|
||||
case webViewData(String)
|
||||
case giftPremium(currency: String, amount: Int64, months: Int32)
|
||||
case giftPremium(currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?)
|
||||
case topicCreated(title: String, iconColor: Int32, iconFileId: Int64?)
|
||||
case topicEdited(components: [ForumTopicEditComponent])
|
||||
case suggestedProfilePhoto(image: TelegramMediaImage?)
|
||||
@ -170,7 +170,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case 26:
|
||||
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
|
||||
case 27:
|
||||
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0))
|
||||
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"))
|
||||
case 28:
|
||||
self = .topicCreated(title: decoder.decodeStringForKey("title", orElse: ""), iconColor: decoder.decodeInt32ForKey("iconColor", orElse: 0), iconFileId: decoder.decodeOptionalInt64ForKey("iconFileId"))
|
||||
case 29:
|
||||
@ -310,11 +310,15 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case let .webViewData(text):
|
||||
encoder.encodeInt32(26, forKey: "_rawValue")
|
||||
encoder.encodeString(text, forKey: "t")
|
||||
case let .giftPremium(currency, amount, months):
|
||||
case let .giftPremium(currency, amount, months, cryptoCurrency, cryptoAmount):
|
||||
encoder.encodeInt32(27, forKey: "_rawValue")
|
||||
encoder.encodeString(currency, forKey: "currency")
|
||||
encoder.encodeInt64(amount, forKey: "amount")
|
||||
encoder.encodeInt32(months, forKey: "months")
|
||||
if let cryptoCurrency = cryptoCurrency, let cryptoAmount = cryptoAmount {
|
||||
encoder.encodeString(cryptoCurrency, forKey: "cryptoCurrency")
|
||||
encoder.encodeInt64(cryptoAmount, forKey: "cryptoAmount")
|
||||
}
|
||||
case let .topicCreated(title, iconColor, iconFileId):
|
||||
encoder.encodeInt32(28, forKey: "_rawValue")
|
||||
encoder.encodeString(title, forKey: "title")
|
||||
|
@ -33,6 +33,7 @@ public struct BotUserInfoFlags: OptionSet {
|
||||
public static let worksWithGroups = BotUserInfoFlags(rawValue: (1 << 1))
|
||||
public static let requiresGeolocationForInlineRequests = BotUserInfoFlags(rawValue: (1 << 3))
|
||||
public static let canBeAddedToAttachMenu = BotUserInfoFlags(rawValue: (1 << 4))
|
||||
public static let canEdit = BotUserInfoFlags(rawValue: (1 << 5))
|
||||
}
|
||||
|
||||
public struct BotUserInfo: PostboxCoding, Equatable {
|
||||
|
@ -23,6 +23,7 @@ public enum AddressNameAvailability: Equatable {
|
||||
public enum AddressNameDomain {
|
||||
case account
|
||||
case peer(PeerId)
|
||||
case bot(PeerId)
|
||||
case theme(TelegramTheme)
|
||||
}
|
||||
|
||||
@ -55,8 +56,26 @@ func _internal_checkAddressNameFormat(_ value: String, canEmpty: Bool = false) -
|
||||
func _internal_addressNameAvailability(account: Account, domain: AddressNameDomain, name: String) -> Signal<AddressNameAvailability, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<AddressNameAvailability, NoError> in
|
||||
switch domain {
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.checkUsername(username: name))
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.checkUsername(username: name))
|
||||
|> map { result -> AddressNameAvailability in
|
||||
switch result {
|
||||
case .boolTrue:
|
||||
return .available
|
||||
case .boolFalse:
|
||||
return .taken
|
||||
}
|
||||
}
|
||||
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
|
||||
if error.errorDescription == "USERNAME_PURCHASE_AVAILABLE" {
|
||||
return .single(.purchaseAvailable)
|
||||
} else {
|
||||
return .single(.invalid)
|
||||
}
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.checkUsername(channel: inputChannel, username: name))
|
||||
|> map { result -> AddressNameAvailability in
|
||||
switch result {
|
||||
case .boolTrue:
|
||||
@ -72,58 +91,42 @@ func _internal_addressNameAvailability(account: Account, domain: AddressNameDoma
|
||||
return .single(.invalid)
|
||||
}
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.checkUsername(channel: inputChannel, username: name))
|
||||
|> map { result -> AddressNameAvailability in
|
||||
switch result {
|
||||
case .boolTrue:
|
||||
return .available
|
||||
case .boolFalse:
|
||||
return .taken
|
||||
}
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
return account.network.request(Api.functions.channels.checkUsername(channel: .inputChannelEmpty, username: name))
|
||||
|> map { result -> AddressNameAvailability in
|
||||
switch result {
|
||||
case .boolTrue:
|
||||
return .available
|
||||
case .boolFalse:
|
||||
return .taken
|
||||
}
|
||||
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
|
||||
if error.errorDescription == "USERNAME_PURCHASE_AVAILABLE" {
|
||||
return .single(.purchaseAvailable)
|
||||
} else {
|
||||
return .single(.invalid)
|
||||
}
|
||||
}
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
return account.network.request(Api.functions.channels.checkUsername(channel: .inputChannelEmpty, username: name))
|
||||
|> map { result -> AddressNameAvailability in
|
||||
switch result {
|
||||
case .boolTrue:
|
||||
return .available
|
||||
case .boolFalse:
|
||||
return .taken
|
||||
}
|
||||
}
|
||||
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
|
||||
if error.errorDescription == "USERNAME_PURCHASE_AVAILABLE" {
|
||||
return .single(.purchaseAvailable)
|
||||
} else {
|
||||
return .single(.invalid)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.invalid)
|
||||
}
|
||||
case .theme:
|
||||
return account.network.request(Api.functions.account.createTheme(flags: 0, slug: name, title: "", document: .inputDocumentEmpty, settings: nil))
|
||||
|> map { _ -> AddressNameAvailability in
|
||||
return .available
|
||||
}
|
||||
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
|
||||
if error.errorDescription == "THEME_SLUG_OCCUPIED" {
|
||||
return .single(.taken)
|
||||
} else if error.errorDescription == "THEME_SLUG_INVALID" {
|
||||
return .single(.invalid)
|
||||
if error.errorDescription == "USERNAME_PURCHASE_AVAILABLE" {
|
||||
return .single(.purchaseAvailable)
|
||||
} else {
|
||||
return .single(.available)
|
||||
return .single(.invalid)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.invalid)
|
||||
}
|
||||
case .bot:
|
||||
return .single(.invalid)
|
||||
case .theme:
|
||||
return account.network.request(Api.functions.account.createTheme(flags: 0, slug: name, title: "", document: .inputDocumentEmpty, settings: nil))
|
||||
|> map { _ -> AddressNameAvailability in
|
||||
return .available
|
||||
}
|
||||
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
|
||||
if error.errorDescription == "THEME_SLUG_OCCUPIED" {
|
||||
return .single(.taken)
|
||||
} else if error.errorDescription == "THEME_SLUG_INVALID" {
|
||||
return .single(.invalid)
|
||||
} else {
|
||||
return .single(.available)
|
||||
}
|
||||
}
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
@ -172,6 +175,8 @@ func _internal_updateAddressName(account: Account, domain: AddressNameDomain, na
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
case .bot:
|
||||
return .fail(.generic)
|
||||
case let .theme(theme):
|
||||
let flags: Int32 = 1 << 0
|
||||
return account.network.request(Api.functions.account.updateTheme(flags: flags, format: telegramThemeFormat, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), slug: nil, title: nil, document: nil, settings: nil))
|
||||
@ -233,126 +238,187 @@ public enum ToggleAddressNameActiveError {
|
||||
func _internal_toggleAddressNameActive(account: Account, domain: AddressNameDomain, name: String, active: Bool) -> Signal<Void, ToggleAddressNameActiveError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
switch domain {
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.toggleUsername(username: name, active: active ? .boolTrue : .boolFalse), automaticFloodWait: false)
|
||||
|> mapError { error -> ToggleAddressNameActiveError in
|
||||
if error.errorDescription == "USERNAMES_ACTIVE_TOO_MUCH" {
|
||||
return .activeLimitReached
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(account.peerId) as? TelegramUser {
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedUser = peer.withUpdatedUsernames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in }
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.toggleUsername(channel: inputChannel, username: name, active: active ? .boolTrue : .boolFalse), automaticFloodWait: false)
|
||||
|> mapError { error -> ToggleAddressNameActiveError in
|
||||
if error.errorDescription == "USERNAMES_ACTIVE_TOO_MUCH" {
|
||||
return .activeLimitReached
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedPeer = peer.withUpdatedAddressNames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in }
|
||||
}
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.toggleUsername(username: name, active: active ? .boolTrue : .boolFalse), automaticFloodWait: false)
|
||||
|> mapError { error -> ToggleAddressNameActiveError in
|
||||
if error.errorDescription == "USERNAMES_ACTIVE_TOO_MUCH" {
|
||||
return .activeLimitReached
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
return .generic
|
||||
}
|
||||
case .theme:
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(account.peerId) as? TelegramUser {
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedUser = peer.withUpdatedUsernames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in }
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.toggleUsername(channel: inputChannel, username: name, active: active ? .boolTrue : .boolFalse), automaticFloodWait: false)
|
||||
|> mapError { error -> ToggleAddressNameActiveError in
|
||||
if error.errorDescription == "USERNAMES_ACTIVE_TOO_MUCH" {
|
||||
return .activeLimitReached
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedPeer = peer.withUpdatedAddressNames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
case let .bot(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
return account.network.request(Api.functions.bots.toggleUsername(bot: inputUser, username: name, active: active ? .boolTrue : .boolFalse), automaticFloodWait: false)
|
||||
|> mapError { error -> ToggleAddressNameActiveError in
|
||||
if error.errorDescription == "USERNAMES_ACTIVE_TOO_MUCH" {
|
||||
return .activeLimitReached
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ToggleAddressNameActiveError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
var updatedNames = peer.usernames
|
||||
if let index = updatedNames.firstIndex(where: { $0.username == name }) {
|
||||
var updatedFlags = updatedNames[index].flags
|
||||
var updateOrder = true
|
||||
var updatedIndex = index
|
||||
if active {
|
||||
if updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.insert(.isActive)
|
||||
} else {
|
||||
if !updatedFlags.contains(.isActive) {
|
||||
updateOrder = false
|
||||
}
|
||||
updatedFlags.remove(.isActive)
|
||||
}
|
||||
let updatedName = TelegramPeerUsername(flags: updatedFlags, username: name)
|
||||
updatedNames.remove(at: index)
|
||||
if updateOrder {
|
||||
if active {
|
||||
updatedIndex = 0
|
||||
} else {
|
||||
updatedIndex = updatedNames.count
|
||||
}
|
||||
var i = 0
|
||||
for name in updatedNames {
|
||||
if active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
} else if !active && !name.flags.contains(.isActive) {
|
||||
updatedIndex = i
|
||||
break
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
updatedNames.insert(updatedName, at: updatedIndex)
|
||||
}
|
||||
let updatedPeer = peer.withUpdatedAddressNames(updatedNames)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
case .theme:
|
||||
return .fail(.generic)
|
||||
}
|
||||
} |> mapError { _ -> ToggleAddressNameActiveError in } |> switchToLatest
|
||||
}
|
||||
@ -364,42 +430,61 @@ public enum ReorderAddressNamesError {
|
||||
func _internal_reorderAddressNames(account: Account, domain: AddressNameDomain, names: [TelegramPeerUsername]) -> Signal<Void, ReorderAddressNamesError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, ReorderAddressNamesError> in
|
||||
switch domain {
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.reorderUsernames(order: names.filter { $0.isActive }.map { $0.username }), automaticFloodWait: false)
|
||||
case .account:
|
||||
return account.network.request(Api.functions.account.reorderUsernames(order: names.filter { $0.isActive }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ReorderAddressNamesError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(account.peerId) as? TelegramUser {
|
||||
let updatedUser = peer.withUpdatedUsernames(names)
|
||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ReorderAddressNamesError in }
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.reorderUsernames(channel: inputChannel, order: names.filter { $0.isActive }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ReorderAddressNamesError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(account.peerId) as? TelegramUser {
|
||||
let updatedUser = peer.withUpdatedUsernames(names)
|
||||
updatePeers(transaction: transaction, peers: [updatedUser], update: { _, updated in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
let updatedPeer = peer.withUpdatedAddressNames(names)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ReorderAddressNamesError in }
|
||||
}
|
||||
case let .peer(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.reorderUsernames(channel: inputChannel, order: names.filter { $0.isActive }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, ReorderAddressNamesError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
let updatedPeer = peer.withUpdatedAddressNames(names)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ReorderAddressNamesError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
case let .bot(peerId):
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
return account.network.request(Api.functions.bots.reorderUsernames(bot: inputUser, order: names.filter { $0.isActive }.map { $0.username }), automaticFloodWait: false)
|
||||
|> mapError { _ -> ReorderAddressNamesError in
|
||||
return .generic
|
||||
}
|
||||
case .theme:
|
||||
return .complete()
|
||||
|> mapToSignal { result -> Signal<Void, ReorderAddressNamesError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result, let peer = transaction.getPeer(peerId) as? TelegramChannel {
|
||||
let updatedPeer = peer.withUpdatedAddressNames(names)
|
||||
updatePeers(transaction: transaction, peers: [updatedPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
} |> mapError { _ -> ReorderAddressNamesError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
case .theme:
|
||||
return .fail(.generic)
|
||||
}
|
||||
} |> mapError { _ -> ReorderAddressNamesError in } |> switchToLatest
|
||||
}
|
||||
|
@ -198,7 +198,16 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
if let _ = videoEmojiMarkup {
|
||||
flags |= (1 << 4)
|
||||
}
|
||||
request = network.request(Api.functions.photos.uploadProfilePhoto(flags: flags, file: photoFile, video: videoFile, videoStartTs: videoStartTimestamp, videoEmojiMarkup: videoEmojiMarkup))
|
||||
request = network.request(Api.functions.photos.uploadProfilePhoto(flags: flags, bot: nil, file: photoFile, video: videoFile, videoStartTs: videoStartTimestamp, videoEmojiMarkup: videoEmojiMarkup))
|
||||
} else if let user = peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit), let inputUser = apiInputUser(peer) {
|
||||
if fallback {
|
||||
flags |= (1 << 3)
|
||||
}
|
||||
if let _ = videoEmojiMarkup {
|
||||
flags |= (1 << 4)
|
||||
}
|
||||
flags |= (1 << 5)
|
||||
request = network.request(Api.functions.photos.uploadProfilePhoto(flags: flags, bot: inputUser, file: photoFile, video: videoFile, videoStartTs: videoStartTimestamp, videoEmojiMarkup: videoEmojiMarkup))
|
||||
} else if let inputUser = apiInputUser(peer) {
|
||||
if let customPeerPhotoMode = customPeerPhotoMode {
|
||||
switch customPeerPhotoMode {
|
||||
@ -408,14 +417,20 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let _ = peer as? TelegramUser {
|
||||
if let user = peer as? TelegramUser {
|
||||
let request: Signal<Api.photos.Photo, MTRpcError>
|
||||
if peer.id == accountPeerId {
|
||||
var flags: Int32 = 0
|
||||
if fallback {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(flags: flags, id: Api.InputPhoto.inputPhotoEmpty))
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(flags: flags, bot: nil, id: Api.InputPhoto.inputPhotoEmpty))
|
||||
} else if let botInfo = user.botInfo, botInfo.flags.contains(.canEdit), let inputUser = apiInputUser(peer) {
|
||||
var flags: Int32 = (1 << 1)
|
||||
if fallback {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
request = network.request(Api.functions.photos.updateProfilePhoto(flags: flags, bot: inputUser, id: Api.InputPhoto.inputPhotoEmpty))
|
||||
} else if let inputUser = apiInputUser(peer) {
|
||||
let flags: Int32 = (1 << 4)
|
||||
request = network.request(Api.functions.photos.uploadContactProfilePhoto(flags: flags, userId: inputUser, file: nil, video: nil, videoStartTs: nil, videoEmojiMarkup: nil))
|
||||
@ -557,18 +572,18 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state
|
||||
|
||||
func _internal_updatePeerPhotoExisting(network: Network, reference: TelegramMediaImageReference) -> Signal<TelegramMediaImage?, NoError> {
|
||||
switch reference {
|
||||
case let .cloud(imageId, accessHash, fileReference):
|
||||
return network.request(Api.functions.photos.updateProfilePhoto(flags: 0, id: .inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))))
|
||||
|> `catch` { _ -> Signal<Api.photos.Photo, NoError> in
|
||||
case let .cloud(imageId, accessHash, fileReference):
|
||||
return network.request(Api.functions.photos.updateProfilePhoto(flags: 0, bot: nil, id: .inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference))))
|
||||
|> `catch` { _ -> Signal<Api.photos.Photo, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { photo -> Signal<TelegramMediaImage?, NoError> in
|
||||
if case let .photo(photo, _) = photo {
|
||||
return .single(telegramMediaImageFromApiPhoto(photo))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { photo -> Signal<TelegramMediaImage?, NoError> in
|
||||
if case let .photo(photo, _) = photo {
|
||||
return .single(telegramMediaImageFromApiPhoto(photo))
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,7 +608,7 @@ func _internal_removeAccountPhoto(account: Account, reference: TelegramMediaImag
|
||||
if fallback {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
let api = Api.functions.photos.updateProfilePhoto(flags: flags, id: Api.InputPhoto.inputPhotoEmpty)
|
||||
let api = Api.functions.photos.updateProfilePhoto(flags: flags, bot: nil, id: Api.InputPhoto.inputPhotoEmpty)
|
||||
return account.network.request(api)
|
||||
|> map { _ in }
|
||||
|> retryRequest
|
||||
|
@ -628,6 +628,14 @@ public extension TelegramEngine {
|
||||
public func updatePeerDescription(peerId: PeerId, description: String?) -> Signal<Void, UpdatePeerDescriptionError> {
|
||||
return _internal_updatePeerDescription(account: self.account, peerId: peerId, description: description)
|
||||
}
|
||||
|
||||
public func updateBotName(peerId: PeerId, name: String) -> Signal<Void, UpdateBotInfoError> {
|
||||
return _internal_updateBotName(account: self.account, peerId: peerId, name: name)
|
||||
}
|
||||
|
||||
public func updateBotAbout(peerId: PeerId, about: String) -> Signal<Void, UpdateBotInfoError> {
|
||||
return _internal_updateBotAbout(account: self.account, peerId: peerId, about: about)
|
||||
}
|
||||
|
||||
public func getNextUnreadChannel(peerId: PeerId, chatListFilterId: Int32?, getFilterPredicate: @escaping (ChatListFilterData) -> ChatListFilterPredicate) -> Signal<(peer: EnginePeer, unreadCount: Int, location: NextUnreadChannelLocation)?, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> (peer: EnginePeer, unreadCount: Int, location: NextUnreadChannelLocation)? in
|
||||
|
@ -0,0 +1,105 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
public enum UpdateBotInfoError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_updateBotName(account: Account, peerId: PeerId, name: String) -> Signal<Void, UpdateBotInfoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, UpdateBotInfoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
var flags: Int32 = 1 << 2
|
||||
flags |= (1 << 3)
|
||||
return account.network.request(Api.functions.bots.setBotInfo(flags: flags, bot: inputUser, langCode: "", name: name, about: nil, description: nil))
|
||||
|> mapError { _ -> UpdateBotInfoError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, UpdateBotInfoError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result {
|
||||
updatePeers(transaction: transaction, peers: [peer]) { _, peer in
|
||||
var updatedPeer = peer
|
||||
if let user = peer as? TelegramUser {
|
||||
updatedPeer = user.withUpdatedNames(firstName: name, lastName: nil)
|
||||
}
|
||||
return updatedPeer
|
||||
}
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
func _internal_updateBotAbout(account: Account, peerId: PeerId, about: String) -> Signal<Void, UpdateBotInfoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, UpdateBotInfoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
var flags: Int32 = 1 << 2
|
||||
flags |= (1 << 0)
|
||||
return account.network.request(Api.functions.bots.setBotInfo(flags: flags, bot: inputUser, langCode: "", name: nil, about: about, description: nil))
|
||||
|> mapError { _ -> UpdateBotInfoError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, UpdateBotInfoError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result {
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedAbout(about)
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
|
||||
func _internal_updateBotDescription(account: Account, peerId: PeerId, description: String) -> Signal<Void, UpdateBotInfoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, UpdateBotInfoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) {
|
||||
var flags: Int32 = 1 << 2
|
||||
flags |= (1 << 1)
|
||||
return account.network.request(Api.functions.bots.setBotInfo(flags: flags, bot: inputUser, langCode: "", name: nil, about: nil, description: description))
|
||||
|> mapError { _ -> UpdateBotInfoError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, UpdateBotInfoError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if case .boolTrue = result {
|
||||
// transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
// if let current = current as? CachedChannelData {
|
||||
// return current.withUpdatedAbout(description)
|
||||
// } else if let current = current as? CachedGroupData {
|
||||
// return current.withUpdatedAbout(description)
|
||||
// } else {
|
||||
// return current
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> UpdateBotInfoError in }
|
||||
|> switchToLatest
|
||||
}
|
@ -181,16 +181,41 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
}
|
||||
|
||||
if rawPeerId == accountPeerId {
|
||||
return (.inputUserSelf, transaction.getPeer(rawPeerId), rawPeerId)
|
||||
return (.inputUserSelf, rawPeer, rawPeerId)
|
||||
} else {
|
||||
return (apiInputUser(peer), peer, peer.id)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { inputUser, maybePeer, peerId -> Signal<Bool, NoError> in
|
||||
if let inputUser = inputUser {
|
||||
return network.request(Api.functions.users.getFullUser(id: inputUser))
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
let editableBotInfo: Signal<EditableBotInfo?, NoError>
|
||||
if let user = maybePeer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
|
||||
let flags: Int32 = (1 << 0)
|
||||
editableBotInfo = network.request(Api.functions.bots.getBotInfo(flags: flags, bot: inputUser, langCode: ""))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.bots.BotInfo?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<EditableBotInfo?, NoError> in
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .botInfo(name, about, description):
|
||||
return .single(EditableBotInfo(name: name, about: about, description: description))
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
editableBotInfo = .single(nil)
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
network.request(Api.functions.users.getFullUser(id: inputUser))
|
||||
|> retryRequest,
|
||||
editableBotInfo
|
||||
)
|
||||
|> mapToSignal { result, editableBotInfo -> Signal<Bool, NoError> in
|
||||
return postbox.transaction { transaction -> Bool in
|
||||
switch result {
|
||||
case let .userFull(fullUser, chats, users):
|
||||
@ -241,7 +266,6 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
let canPinMessages = (userFullFlags & (1 << 7)) != 0
|
||||
let pinnedMessageId = userFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
||||
|
||||
|
||||
let peerStatusSettings = PeerStatusSettings(apiSettings: userFullSettings)
|
||||
|
||||
let hasScheduledMessages = (userFullFlags & 1 << 12) != 0
|
||||
@ -266,7 +290,17 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
premiumGiftOptions = []
|
||||
}
|
||||
|
||||
return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||
return previous.withUpdatedAbout(userFullAbout)
|
||||
.withUpdatedBotInfo(botInfo)
|
||||
.withUpdatedCommonGroupCount(userFullCommonChatsCount)
|
||||
.withUpdatedIsBlocked(isBlocked)
|
||||
.withUpdatedVoiceCallsAvailable(voiceCallsAvailable)
|
||||
.withUpdatedVideoCallsAvailable(videoCallsAvailable)
|
||||
.withUpdatedCallsPrivate(callsPrivate)
|
||||
.withUpdatedCanPinMessages(canPinMessages)
|
||||
.withUpdatedPeerStatusSettings(peerStatusSettings)
|
||||
.withUpdatedPinnedMessageId(pinnedMessageId)
|
||||
.withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
|
||||
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
||||
.withUpdatedPhoto(.known(photo))
|
||||
|
@ -710,7 +710,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
case let .webViewData(text):
|
||||
attributedString = NSAttributedString(string: strings.Notification_WebAppSentData(text).string, font: titleFont, textColor: primaryTextColor)
|
||||
case let .giftPremium(currency, amount, _):
|
||||
case let .giftPremium(currency, amount, _, _, _):
|
||||
let price = formatCurrencyAmount(amount, currency: currency)
|
||||
if message.author?.id == accountPeerId {
|
||||
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_SentYou(price)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||
|
@ -102,7 +102,7 @@ public final class ChatControllerInteraction {
|
||||
public let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool
|
||||
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 sendBotContextResultAsGif: (ChatContextResultCollection, ChatContextResult, UIView, CGRect, Bool, Bool) -> Bool
|
||||
public let requestMessageActionCallback: (MessageId, MemoryBuffer?, Bool, Bool) -> Void
|
||||
public let requestMessageActionUrlAuth: (String, MessageActionUrlSubject) -> Void
|
||||
public let activateSwitchInline: (PeerId?, String) -> Void
|
||||
@ -214,7 +214,7 @@ public final class ChatControllerInteraction {
|
||||
sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool,
|
||||
sendEmoji: @escaping (String, ChatTextInputTextCustomEmojiAttribute, Bool) -> Void,
|
||||
sendGif: @escaping (FileMediaReference, UIView, CGRect, Bool, Bool) -> Bool,
|
||||
sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, UIView, CGRect, Bool) -> Bool,
|
||||
sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, UIView, CGRect, Bool, Bool) -> Bool,
|
||||
requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool, Bool) -> Void,
|
||||
requestMessageActionUrlAuth: @escaping (String, MessageActionUrlSubject) -> Void,
|
||||
activateSwitchInline: @escaping (PeerId?, String) -> Void,
|
||||
|
@ -1620,7 +1620,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
|
||||
if let (collection, result) = item.contextResult {
|
||||
let _ = controllerInteraction.sendBotContextResultAsGif(collection, result, view, rect, false)
|
||||
let _ = controllerInteraction.sendBotContextResultAsGif(collection, result, view, rect, false, false)
|
||||
} else {
|
||||
let _ = controllerInteraction.sendGif(item.file, view, rect, false, false)
|
||||
}
|
||||
@ -2078,7 +2078,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
if isSaved {
|
||||
let _ = self?.controllerInteraction?.sendGif(file, sourceView, sourceRect, false, false)
|
||||
} else if let (collection, result) = contextResult {
|
||||
let _ = self?.controllerInteraction?.sendBotContextResultAsGif(collection, result, sourceView, sourceRect, false)
|
||||
let _ = self?.controllerInteraction?.sendBotContextResultAsGif(collection, result, sourceView, sourceRect, false, false)
|
||||
}
|
||||
})))
|
||||
|
||||
@ -2099,7 +2099,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
if isSaved {
|
||||
let _ = self?.controllerInteraction?.sendGif(file, sourceView, sourceRect, true, false)
|
||||
} else if let (collection, result) = contextResult {
|
||||
let _ = self?.controllerInteraction?.sendBotContextResultAsGif(collection, result, sourceView, sourceRect, true)
|
||||
let _ = self?.controllerInteraction?.sendBotContextResultAsGif(collection, result, sourceView, sourceRect, true, false)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ final class GifPaneSearchContentNode: ASDisplayNode & PaneSearchContentNode {
|
||||
|
||||
multiplexedNode.fileSelected = { [weak self] file, sourceNode, sourceRect in
|
||||
if let (collection, result) = file.contextResult {
|
||||
let _ = self?.controllerInteraction.sendBotContextResultAsGif(collection, result, sourceNode.view, sourceRect, false)
|
||||
let _ = self?.controllerInteraction.sendBotContextResultAsGif(collection, result, sourceNode.view, sourceRect, false, false)
|
||||
} else {
|
||||
let _ = self?.controllerInteraction.sendGif(file.file, sourceNode.view, sourceRect, false, false)
|
||||
}
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotCommands.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotCommands.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_command.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
301
submodules/TelegramUI/Images.xcassets/Peer Info/BotCommands.imageset/ic_command.pdf
vendored
Normal file
301
submodules/TelegramUI/Images.xcassets/Peer Info/BotCommands.imageset/ic_command.pdf
vendored
Normal file
@ -0,0 +1,301 @@
|
||||
%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 6.000000 15.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
7.000000 1.330078 m
|
||||
7.000000 0.665078 l
|
||||
7.665000 0.665078 l
|
||||
7.665000 1.330078 l
|
||||
7.000000 1.330078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
3.132731 8.995078 2.835000 8.697348 2.835000 8.330078 c
|
||||
2.835000 7.962809 3.132731 7.665078 3.500000 7.665078 c
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
3.500000 0.665078 m
|
||||
7.000000 0.665078 l
|
||||
7.000000 1.995078 l
|
||||
3.500000 1.995078 l
|
||||
3.500000 0.665078 l
|
||||
h
|
||||
7.665000 1.330078 m
|
||||
7.665000 4.830078 l
|
||||
6.335000 4.830078 l
|
||||
6.335000 1.330078 l
|
||||
7.665000 1.330078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
1.199734 8.995078 -0.665000 7.130344 -0.665000 4.830078 c
|
||||
0.665000 4.830078 l
|
||||
0.665000 6.395805 1.934273 7.665078 3.500000 7.665078 c
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 7.130344 5.800266 8.995078 3.500000 8.995078 c
|
||||
3.500000 7.665078 l
|
||||
5.065727 7.665078 6.335000 6.395805 6.335000 4.830078 c
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
3.500000 1.995078 m
|
||||
1.934273 1.995078 0.665000 3.264351 0.665000 4.830078 c
|
||||
-0.665000 4.830078 l
|
||||
-0.665000 2.529812 1.199734 0.665078 3.500000 0.665078 c
|
||||
3.500000 1.995078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 6.000000 4.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
7.000000 8.330078 m
|
||||
7.665000 8.330078 l
|
||||
7.665000 8.995078 l
|
||||
7.000000 8.995078 l
|
||||
7.000000 8.330078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 8.330078 l
|
||||
6.335000 8.330078 l
|
||||
6.335000 4.830078 l
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
7.000000 8.995078 m
|
||||
3.500000 8.995078 l
|
||||
3.500000 7.665078 l
|
||||
7.000000 7.665078 l
|
||||
7.000000 8.995078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
1.199734 8.995078 -0.665000 7.130344 -0.665000 4.830078 c
|
||||
0.665000 4.830078 l
|
||||
0.665000 6.395805 1.934273 7.665078 3.500000 7.665078 c
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
3.500000 0.665078 m
|
||||
5.800266 0.665078 7.665000 2.529812 7.665000 4.830078 c
|
||||
6.335000 4.830078 l
|
||||
6.335000 3.264351 5.065727 1.995078 3.500000 1.995078 c
|
||||
3.500000 0.665078 l
|
||||
h
|
||||
3.500000 1.995078 m
|
||||
1.934273 1.995078 0.665000 3.264351 0.665000 4.830078 c
|
||||
-0.665000 4.830078 l
|
||||
-0.665000 2.529812 1.199734 0.665078 3.500000 0.665078 c
|
||||
3.500000 1.995078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 17.000000 4.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 8.330078 m
|
||||
0.000000 8.995078 l
|
||||
-0.665000 8.995078 l
|
||||
-0.665000 8.330078 l
|
||||
0.000000 8.330078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 5.197348 7.367270 5.495078 7.000000 5.495078 c
|
||||
6.632730 5.495078 6.335000 5.197348 6.335000 4.830078 c
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
0.000000 8.995078 l
|
||||
0.000000 7.665078 l
|
||||
3.500000 7.665078 l
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
-0.665000 8.330078 m
|
||||
-0.665000 4.830078 l
|
||||
0.665000 4.830078 l
|
||||
0.665000 8.330078 l
|
||||
-0.665000 8.330078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 7.130344 5.800266 8.995078 3.500000 8.995078 c
|
||||
3.500000 7.665078 l
|
||||
5.065727 7.665078 6.335000 6.395805 6.335000 4.830078 c
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
3.500000 0.665078 m
|
||||
5.800266 0.665078 7.665000 2.529812 7.665000 4.830078 c
|
||||
6.335000 4.830078 l
|
||||
6.335000 3.264351 5.065727 1.995078 3.500000 1.995078 c
|
||||
3.500000 0.665078 l
|
||||
h
|
||||
3.500000 1.995078 m
|
||||
1.934273 1.995078 0.665000 3.264351 0.665000 4.830078 c
|
||||
-0.665000 4.830078 l
|
||||
-0.665000 2.529812 1.199734 0.665078 3.500000 0.665078 c
|
||||
3.500000 1.995078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 17.000000 15.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 1.330078 m
|
||||
-0.665000 1.330078 l
|
||||
-0.665000 0.665078 l
|
||||
0.000000 0.665078 l
|
||||
0.000000 1.330078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
3.132731 8.995078 2.835000 8.697348 2.835000 8.330078 c
|
||||
2.835000 7.962809 3.132731 7.665078 3.500000 7.665078 c
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 5.197348 7.367270 5.495078 7.000000 5.495078 c
|
||||
6.632730 5.495078 6.335000 5.197348 6.335000 4.830078 c
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
0.000000 0.665078 m
|
||||
3.500000 0.665078 l
|
||||
3.500000 1.995078 l
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
h
|
||||
-0.665000 4.830078 m
|
||||
-0.665000 1.330078 l
|
||||
0.665000 1.330078 l
|
||||
0.665000 4.830078 l
|
||||
-0.665000 4.830078 l
|
||||
h
|
||||
3.500000 8.995078 m
|
||||
1.199734 8.995078 -0.665000 7.130344 -0.665000 4.830078 c
|
||||
0.665000 4.830078 l
|
||||
0.665000 6.395805 1.934273 7.665078 3.500000 7.665078 c
|
||||
3.500000 8.995078 l
|
||||
h
|
||||
7.665000 4.830078 m
|
||||
7.665000 7.130344 5.800266 8.995078 3.500000 8.995078 c
|
||||
3.500000 7.665078 l
|
||||
5.065727 7.665078 6.335000 6.395805 6.335000 4.830078 c
|
||||
7.665000 4.830078 l
|
||||
h
|
||||
3.500000 0.665078 m
|
||||
5.800266 0.665078 7.665000 2.529812 7.665000 4.830078 c
|
||||
6.335000 4.830078 l
|
||||
6.335000 3.264351 5.065727 1.995078 3.500000 1.995078 c
|
||||
3.500000 0.665078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 13.000000 11.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 5.330078 m
|
||||
0.000000 5.995078 l
|
||||
-0.665000 5.995078 l
|
||||
-0.665000 5.330078 l
|
||||
0.000000 5.330078 l
|
||||
h
|
||||
4.000000 5.330078 m
|
||||
4.665000 5.330078 l
|
||||
4.665000 5.995078 l
|
||||
4.000000 5.995078 l
|
||||
4.000000 5.330078 l
|
||||
h
|
||||
4.000000 1.330078 m
|
||||
4.000000 0.665078 l
|
||||
4.665000 0.665078 l
|
||||
4.665000 1.330078 l
|
||||
4.000000 1.330078 l
|
||||
h
|
||||
0.000000 1.330078 m
|
||||
-0.665000 1.330078 l
|
||||
-0.665000 0.665078 l
|
||||
0.000000 0.665078 l
|
||||
0.000000 1.330078 l
|
||||
h
|
||||
0.000000 4.665078 m
|
||||
4.000000 4.665078 l
|
||||
4.000000 5.995078 l
|
||||
0.000000 5.995078 l
|
||||
0.000000 4.665078 l
|
||||
h
|
||||
3.335000 5.330078 m
|
||||
3.335000 1.330078 l
|
||||
4.665000 1.330078 l
|
||||
4.665000 5.330078 l
|
||||
3.335000 5.330078 l
|
||||
h
|
||||
4.000000 1.995078 m
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
4.000000 0.665078 l
|
||||
4.000000 1.995078 l
|
||||
h
|
||||
0.665000 1.330078 m
|
||||
0.665000 5.330078 l
|
||||
-0.665000 5.330078 l
|
||||
-0.665000 1.330078 l
|
||||
0.665000 1.330078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5291
|
||||
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
|
||||
0000005381 00000 n
|
||||
0000005404 00000 n
|
||||
0000005577 00000 n
|
||||
0000005651 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
5710
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotIntro.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotIntro.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_info.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
271
submodules/TelegramUI/Images.xcassets/Peer Info/BotIntro.imageset/ic_info.pdf
vendored
Normal file
271
submodules/TelegramUI/Images.xcassets/Peer Info/BotIntro.imageset/ic_info.pdf
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
%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 6.000000 4.668945 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
2.184038 18.895081 m
|
||||
1.882134 19.487600 l
|
||||
2.184038 18.895081 l
|
||||
h
|
||||
0.435974 17.147017 m
|
||||
-0.156545 17.448921 l
|
||||
0.435974 17.147017 l
|
||||
h
|
||||
17.564026 17.147017 m
|
||||
18.156546 17.448921 l
|
||||
17.564026 17.147017 l
|
||||
h
|
||||
15.815962 1.767029 m
|
||||
15.514058 2.359549 l
|
||||
15.815962 1.767029 l
|
||||
h
|
||||
17.564026 3.515093 m
|
||||
16.971506 3.816997 l
|
||||
17.564026 3.515093 l
|
||||
h
|
||||
2.184038 1.767029 m
|
||||
1.882134 1.174509 l
|
||||
2.184038 1.767029 l
|
||||
h
|
||||
0.435974 3.515093 m
|
||||
-0.156545 3.213190 l
|
||||
0.435974 3.515093 l
|
||||
h
|
||||
6.400000 0.666056 m
|
||||
11.600000 0.666056 l
|
||||
11.600000 1.996056 l
|
||||
6.400000 1.996056 l
|
||||
6.400000 0.666056 l
|
||||
h
|
||||
18.664999 7.731055 m
|
||||
18.664999 12.931055 l
|
||||
17.334999 12.931055 l
|
||||
17.334999 7.731055 l
|
||||
18.664999 7.731055 l
|
||||
h
|
||||
11.599999 19.996056 m
|
||||
6.400000 19.996056 l
|
||||
6.400000 18.666054 l
|
||||
11.599999 18.666054 l
|
||||
11.599999 19.996056 l
|
||||
h
|
||||
-0.665000 12.931055 m
|
||||
-0.665000 7.731054 l
|
||||
0.665000 7.731054 l
|
||||
0.665000 12.931055 l
|
||||
-0.665000 12.931055 l
|
||||
h
|
||||
6.400000 19.996056 m
|
||||
5.290868 19.996056 4.419025 19.996572 3.718656 19.939350 c
|
||||
3.010523 19.881493 2.419329 19.761314 1.882134 19.487600 c
|
||||
2.485942 18.302561 l
|
||||
2.804394 18.464821 3.201076 18.562630 3.826960 18.613766 c
|
||||
4.460607 18.665537 5.268921 18.666054 6.400000 18.666054 c
|
||||
6.400000 19.996056 l
|
||||
h
|
||||
0.665000 12.931055 m
|
||||
0.665000 14.062133 0.665517 14.870447 0.717288 15.504095 c
|
||||
0.768425 16.129978 0.866234 16.526661 1.028493 16.845114 c
|
||||
-0.156545 17.448921 l
|
||||
-0.430260 16.911726 -0.550438 16.320532 -0.608295 15.612399 c
|
||||
-0.665517 14.912029 -0.665000 14.040186 -0.665000 12.931055 c
|
||||
0.665000 12.931055 l
|
||||
h
|
||||
1.882134 19.487600 m
|
||||
1.004358 19.040350 0.290704 18.326696 -0.156545 17.448921 c
|
||||
1.028493 16.845114 l
|
||||
1.348231 17.472633 1.858421 17.982824 2.485942 18.302561 c
|
||||
1.882134 19.487600 l
|
||||
h
|
||||
18.664999 12.931055 m
|
||||
18.664999 14.040187 18.665518 14.912029 18.608295 15.612399 c
|
||||
18.550438 16.320532 18.430260 16.911726 18.156546 17.448921 c
|
||||
16.971506 16.845114 l
|
||||
17.133766 16.526661 17.231575 16.129978 17.282711 15.504095 c
|
||||
17.334482 14.870447 17.334999 14.062134 17.334999 12.931055 c
|
||||
18.664999 12.931055 l
|
||||
h
|
||||
11.599999 18.666054 m
|
||||
12.731078 18.666054 13.539392 18.665537 14.173039 18.613766 c
|
||||
14.798923 18.562630 15.195606 18.464821 15.514058 18.302561 c
|
||||
16.117865 19.487600 l
|
||||
15.580671 19.761314 14.989477 19.881493 14.281344 19.939350 c
|
||||
13.580975 19.996572 12.709131 19.996056 11.599999 19.996056 c
|
||||
11.599999 18.666054 l
|
||||
h
|
||||
18.156546 17.448921 m
|
||||
17.709295 18.326696 16.995642 19.040350 16.117865 19.487600 c
|
||||
15.514058 18.302561 l
|
||||
16.141579 17.982824 16.651770 17.472633 16.971506 16.845114 c
|
||||
18.156546 17.448921 l
|
||||
h
|
||||
11.600000 0.666056 m
|
||||
12.709132 0.666056 13.580975 0.665537 14.281344 0.722759 c
|
||||
14.989477 0.780617 15.580671 0.900795 16.117865 1.174509 c
|
||||
15.514058 2.359549 l
|
||||
15.195606 2.197289 14.798923 2.099480 14.173039 2.048344 c
|
||||
13.539392 1.996572 12.731078 1.996056 11.600000 1.996056 c
|
||||
11.600000 0.666056 l
|
||||
h
|
||||
17.334999 7.731055 m
|
||||
17.334999 6.599977 17.334482 5.791662 17.282711 5.158015 c
|
||||
17.231575 4.532131 17.133766 4.135448 16.971506 3.816997 c
|
||||
18.156546 3.213190 l
|
||||
18.430260 3.750383 18.550438 4.341578 18.608295 5.049710 c
|
||||
18.665518 5.750080 18.664999 6.621923 18.664999 7.731055 c
|
||||
17.334999 7.731055 l
|
||||
h
|
||||
16.117865 1.174509 m
|
||||
16.995642 1.621759 17.709295 2.335413 18.156546 3.213190 c
|
||||
16.971506 3.816997 l
|
||||
16.651770 3.189476 16.141579 2.679285 15.514058 2.359549 c
|
||||
16.117865 1.174509 l
|
||||
h
|
||||
6.400000 1.996056 m
|
||||
5.268922 1.996056 4.460608 1.996572 3.826960 2.048344 c
|
||||
3.201076 2.099480 2.804394 2.197289 2.485942 2.359549 c
|
||||
1.882134 1.174509 l
|
||||
2.419329 0.900795 3.010523 0.780617 3.718656 0.722759 c
|
||||
4.419025 0.665537 5.290868 0.666056 6.400000 0.666056 c
|
||||
6.400000 1.996056 l
|
||||
h
|
||||
-0.665000 7.731054 m
|
||||
-0.665000 6.621922 -0.665517 5.750080 -0.608295 5.049710 c
|
||||
-0.550438 4.341578 -0.430260 3.750383 -0.156545 3.213190 c
|
||||
1.028493 3.816997 l
|
||||
0.866234 4.135448 0.768425 4.532131 0.717288 5.158015 c
|
||||
0.665517 5.791662 0.665000 6.599977 0.665000 7.731054 c
|
||||
-0.665000 7.731054 l
|
||||
h
|
||||
2.485942 2.359549 m
|
||||
1.858421 2.679285 1.348231 3.189476 1.028493 3.816997 c
|
||||
-0.156545 3.213190 l
|
||||
0.290704 2.335413 1.004358 1.621759 1.882134 1.174509 c
|
||||
2.485942 2.359549 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 10.000000 17.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 1.995078 m
|
||||
-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c
|
||||
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||
0.000000 1.995078 l
|
||||
h
|
||||
10.000000 0.665078 m
|
||||
10.367270 0.665078 10.665000 0.962809 10.665000 1.330078 c
|
||||
10.665000 1.697348 10.367270 1.995078 10.000000 1.995078 c
|
||||
10.000000 0.665078 l
|
||||
h
|
||||
0.000000 0.665078 m
|
||||
10.000000 0.665078 l
|
||||
10.000000 1.995078 l
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 10.000000 13.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 1.995078 m
|
||||
-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c
|
||||
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||
0.000000 1.995078 l
|
||||
h
|
||||
10.000000 0.665078 m
|
||||
10.367270 0.665078 10.665000 0.962809 10.665000 1.330078 c
|
||||
10.665000 1.697348 10.367270 1.995078 10.000000 1.995078 c
|
||||
10.000000 0.665078 l
|
||||
h
|
||||
0.000000 0.665078 m
|
||||
10.000000 0.665078 l
|
||||
10.000000 1.995078 l
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 10.000000 9.669922 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 1.995078 m
|
||||
-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c
|
||||
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||
0.000000 1.995078 l
|
||||
h
|
||||
5.000000 0.665078 m
|
||||
5.367270 0.665078 5.665000 0.962809 5.665000 1.330078 c
|
||||
5.665000 1.697348 5.367270 1.995078 5.000000 1.995078 c
|
||||
5.000000 0.665078 l
|
||||
h
|
||||
0.000000 0.665078 m
|
||||
5.000000 0.665078 l
|
||||
5.000000 1.995078 l
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5728
|
||||
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
|
||||
0000005818 00000 n
|
||||
0000005841 00000 n
|
||||
0000006014 00000 n
|
||||
0000006088 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
6147
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotSettings.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/BotSettings.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_bot.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
172
submodules/TelegramUI/Images.xcassets/Peer Info/BotSettings.imageset/ic_bot.pdf
vendored
Normal file
172
submodules/TelegramUI/Images.xcassets/Peer Info/BotSettings.imageset/ic_bot.pdf
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
%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.335022 4.334961 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
12.330000 22.165077 m
|
||||
12.330000 22.532347 12.032269 22.830078 11.664999 22.830078 c
|
||||
11.297730 22.830078 11.000000 22.532349 11.000000 22.165077 c
|
||||
10.999999 20.329762 l
|
||||
9.808650 20.327427 9.056338 20.308790 8.406540 20.163544 c
|
||||
5.792393 19.579212 3.750866 17.537685 3.166535 14.923538 c
|
||||
3.037604 14.346734 3.008435 13.689154 3.001877 12.715419 c
|
||||
3.000633 12.698801 3.000000 12.682014 3.000000 12.665078 c
|
||||
2.999991 12.604896 l
|
||||
2.999971 12.514796 2.999953 12.430834 3.000363 12.352024 c
|
||||
2.999973 12.169721 2.999984 11.977092 2.999996 11.772916 c
|
||||
3.000000 11.665075 l
|
||||
3.000000 11.325851 l
|
||||
1.328710 11.240018 0.000000 9.857716 0.000000 8.165078 c
|
||||
0.000000 4.665077 l
|
||||
0.000000 4.297810 0.297731 4.000078 0.665000 4.000078 c
|
||||
1.032269 4.000078 1.330000 4.297810 1.330000 4.665077 c
|
||||
1.330000 8.165078 l
|
||||
1.330000 9.122908 2.063866 9.909335 3.000000 9.992761 c
|
||||
3.000000 6.665073 l
|
||||
3.000000 6.635679 l
|
||||
2.999995 5.610479 2.999991 4.800386 3.053299 4.147926 c
|
||||
3.107750 3.481483 3.221116 2.921162 3.481206 2.410706 c
|
||||
3.904487 1.579967 4.579896 0.904560 5.410632 0.481277 c
|
||||
5.921087 0.221188 6.481411 0.107822 7.147855 0.053371 c
|
||||
7.800317 0.000061 8.610416 0.000065 9.635623 0.000072 c
|
||||
9.664999 0.000072 l
|
||||
13.664999 0.000072 l
|
||||
13.694375 0.000072 l
|
||||
14.719583 0.000065 15.529682 0.000061 16.182144 0.053371 c
|
||||
16.848589 0.107822 17.408913 0.221188 17.919367 0.481277 c
|
||||
18.750103 0.904560 19.425512 1.579967 19.848793 2.410706 c
|
||||
20.108883 2.921162 20.222248 3.481483 20.276699 4.147928 c
|
||||
20.330009 4.800388 20.330006 5.610489 20.329998 6.635696 c
|
||||
20.329998 6.665073 l
|
||||
20.329998 9.992761 l
|
||||
21.266134 9.909336 22.000000 9.122909 22.000000 8.165078 c
|
||||
22.000000 4.665077 l
|
||||
22.000000 4.297810 22.297731 4.000078 22.665001 4.000078 c
|
||||
23.032270 4.000078 23.330002 4.297810 23.330002 4.665077 c
|
||||
23.330002 8.165078 l
|
||||
23.330002 9.857717 22.001289 11.240019 20.329998 11.325851 c
|
||||
20.329998 11.665077 l
|
||||
20.330002 11.772936 l
|
||||
20.330002 11.776800 l
|
||||
20.330002 11.777779 l
|
||||
20.330002 11.778754 l
|
||||
20.330002 11.779727 l
|
||||
20.330002 11.780697 l
|
||||
20.330013 11.981822 20.330025 12.171724 20.329638 12.351577 c
|
||||
20.330050 12.430517 20.330030 12.514627 20.330009 12.604898 c
|
||||
20.330002 12.665078 l
|
||||
20.328440 12.665078 l
|
||||
20.322536 13.666592 20.294603 14.336849 20.163464 14.923538 c
|
||||
19.579132 17.537685 17.537605 19.579212 14.923459 20.163544 c
|
||||
14.273661 20.308790 13.521349 20.327427 12.329999 20.329762 c
|
||||
12.330000 22.165077 l
|
||||
h
|
||||
18.865494 14.633408 m
|
||||
18.976515 14.136731 18.995987 13.539755 18.999325 12.348469 c
|
||||
18.997746 12.092189 18.992702 11.974581 18.977409 11.878021 c
|
||||
18.853046 11.092838 18.237240 10.477031 17.452057 10.352671 c
|
||||
17.322449 10.332142 17.154915 10.330078 16.665001 10.330078 c
|
||||
6.665000 10.330078 l
|
||||
6.175085 10.330078 6.007552 10.332142 5.877943 10.352670 c
|
||||
5.092760 10.477031 4.476953 11.092838 4.352592 11.878021 c
|
||||
4.337297 11.974588 4.332253 12.092207 4.330675 12.348530 c
|
||||
4.334013 13.539776 4.353486 14.136740 4.464505 14.633408 c
|
||||
4.936448 16.744762 6.585317 18.393631 8.696671 18.865574 c
|
||||
9.280350 18.996040 10.002544 19.000078 11.664999 19.000078 c
|
||||
13.327456 19.000078 14.049649 18.996040 14.633328 18.865574 c
|
||||
16.744682 18.393631 18.393551 16.744762 18.865494 14.633408 c
|
||||
h
|
||||
4.330000 6.665073 m
|
||||
4.330000 9.586203 l
|
||||
4.719618 9.308791 5.175268 9.117384 5.669886 9.039044 c
|
||||
5.916926 8.999917 6.198448 8.999979 6.604819 9.000070 c
|
||||
6.665000 9.000078 l
|
||||
16.665001 9.000078 l
|
||||
16.725180 9.000070 l
|
||||
17.131554 8.999979 17.413074 8.999917 17.660114 9.039044 c
|
||||
18.154732 9.117384 18.610382 9.308791 19.000000 9.586202 c
|
||||
19.000000 6.665073 l
|
||||
19.000000 5.604002 18.999481 4.848192 18.951117 4.256233 c
|
||||
18.903385 3.672035 18.812389 3.306225 18.663754 3.014511 c
|
||||
18.367985 2.434032 17.896040 1.962086 17.315559 1.666317 c
|
||||
17.023846 1.517681 16.658035 1.426685 16.073839 1.378956 c
|
||||
15.481880 1.330589 14.726070 1.330074 13.664999 1.330074 c
|
||||
9.664999 1.330074 l
|
||||
8.603928 1.330074 7.848119 1.330589 7.256159 1.378956 c
|
||||
6.671964 1.426685 6.306152 1.517681 6.014440 1.666317 c
|
||||
5.433959 1.962086 4.962014 2.434032 4.666245 3.014511 c
|
||||
4.517610 3.306225 4.426613 3.672035 4.378882 4.256233 c
|
||||
4.330517 4.848190 4.330000 5.604000 4.330000 6.665073 c
|
||||
h
|
||||
8.539999 12.540078 m
|
||||
9.230355 12.540078 9.789999 13.099722 9.789999 13.790078 c
|
||||
9.789999 14.480434 9.230355 15.040078 8.539999 15.040078 c
|
||||
7.849643 15.040078 7.289999 14.480434 7.289999 13.790078 c
|
||||
7.289999 13.099722 7.849643 12.540078 8.539999 12.540078 c
|
||||
h
|
||||
16.040001 13.790078 m
|
||||
16.040001 13.099722 15.480356 12.540078 14.790000 12.540078 c
|
||||
14.099644 12.540078 13.540000 13.099722 13.540000 13.790078 c
|
||||
13.540000 14.480434 14.099644 15.040078 14.790000 15.040078 c
|
||||
15.480356 15.040078 16.040001 14.480434 16.040001 13.790078 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
4761
|
||||
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
|
||||
0000004851 00000 n
|
||||
0000004874 00000 n
|
||||
0000005047 00000 n
|
||||
0000005121 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
5180
|
||||
%%EOF
|
@ -837,7 +837,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case .setChatTheme:
|
||||
strongSelf.presentThemeSelection()
|
||||
return true
|
||||
case let .giftPremium(_, _, duration):
|
||||
case let .giftPremium(_, _, duration, _, _):
|
||||
let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId
|
||||
let toPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? message.id.peerId : strongSelf.context.account.peerId
|
||||
let controller = PremiumIntroScreen(context: strongSelf.context, source: .gift(from: fromPeerId, to: toPeerId, duration: duration))
|
||||
@ -2183,7 +2183,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, sendBotContextResultAsGif: { [weak self] collection, result, sourceView, sourceRect, silentPosting in
|
||||
}, sendBotContextResultAsGif: { [weak self] collection, result, sourceView, sourceRect, silentPosting, resetTextInputState in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
@ -2195,7 +2195,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
|
||||
strongSelf.enqueueChatContextResult(collection, result, hideVia: true, closeMediaInput: true, silentPosting: silentPosting)
|
||||
strongSelf.enqueueChatContextResult(collection, result, hideVia: true, closeMediaInput: true, silentPosting: silentPosting, resetTextInputState: resetTextInputState)
|
||||
|
||||
return true
|
||||
}, requestMessageActionCallback: { [weak self] messageId, data, isGame, requiresPassword in
|
||||
@ -2604,7 +2604,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
self?.push(c)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -15040,7 +15040,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
}
|
||||
|
||||
private func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false) {
|
||||
private func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, resetTextInputState: Bool = true) {
|
||||
if !canSendMessagesToChat(self.presentationInterfaceState) {
|
||||
return
|
||||
}
|
||||
@ -15066,12 +15066,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||
var state = state
|
||||
state = state.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageId(nil)
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: "")))
|
||||
interfaceState = interfaceState.withUpdatedComposeDisableUrlPreview(nil)
|
||||
return interfaceState
|
||||
if resetTextInputState {
|
||||
state = state.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageId(nil)
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: "")))
|
||||
interfaceState = interfaceState.withUpdatedComposeDisableUrlPreview(nil)
|
||||
return interfaceState
|
||||
}
|
||||
}
|
||||
state = state.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
@ -18430,22 +18432,42 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let selectedEmoticon: String? = themeEmoticon
|
||||
|
||||
let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", previewTheme: { [weak self] emoticon, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))
|
||||
}
|
||||
}, completion: { [weak self] emoticon in
|
||||
guard let strongSelf = self, let peerId = peerId else {
|
||||
return
|
||||
}
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil)))
|
||||
let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).start(completed: { [weak self] in
|
||||
let controller = ChatThemeScreen(
|
||||
context: context,
|
||||
updatedPresentationData: strongSelf.updatedPresentationData,
|
||||
animatedEmojiStickers: animatedEmojiStickers,
|
||||
initiallySelectedEmoticon: selectedEmoticon,
|
||||
peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "",
|
||||
previewTheme: { [weak self] emoticon, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
changeWallpaper: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let themeController = strongSelf.themeScreen {
|
||||
strongSelf.themeScreen = nil
|
||||
themeController.dimTapped()
|
||||
}
|
||||
let controller = ThemeGridController(context: strongSelf.context)
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.push(controller)
|
||||
},
|
||||
completion: { [weak self] emoticon in
|
||||
guard let strongSelf = self, let peerId = peerId else {
|
||||
return
|
||||
}
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil)))
|
||||
let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).start(completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((nil, nil)))
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
controller.passthroughHitTestImpl = { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
return strongSelf.chatDisplayNode.historyNode.view
|
||||
|
@ -185,7 +185,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
for media in item.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
case let .giftPremium(_, _, months):
|
||||
case let .giftPremium(_, _, months, _, _):
|
||||
duration = item.presentationData.strings.Notification_PremiumGift_Subtitle(item.presentationData.strings.Notification_PremiumGift_Months(months)).string
|
||||
switch months {
|
||||
case 12:
|
||||
|
@ -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() {
|
||||
@ -283,7 +283,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, openWallpaper: { [weak self] message in
|
||||
if let strongSelf = self{
|
||||
openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in
|
||||
self?.presentController(c, .window(.root), a)
|
||||
self?.pushController(c)
|
||||
})
|
||||
}
|
||||
}, openTheme: { _ in
|
||||
|
@ -555,6 +555,7 @@ final class ChatThemeScreen: ViewController {
|
||||
private let initiallySelectedEmoticon: String?
|
||||
private let peerName: String
|
||||
private let previewTheme: (String?, Bool?) -> Void
|
||||
fileprivate let changeWallpaper: () -> Void
|
||||
private let completion: (String?) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
@ -570,13 +571,23 @@ final class ChatThemeScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, peerName: String, previewTheme: @escaping (String?, Bool?) -> Void, completion: @escaping (String?) -> Void) {
|
||||
init(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
|
||||
animatedEmojiStickers: [String: [StickerPackItem]],
|
||||
initiallySelectedEmoticon: String?,
|
||||
peerName: String,
|
||||
previewTheme: @escaping (String?, Bool?) -> Void,
|
||||
changeWallpaper: @escaping () -> Void,
|
||||
completion: @escaping (String?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.presentationData = updatedPresentationData.initial
|
||||
self.animatedEmojiStickers = animatedEmojiStickers
|
||||
self.initiallySelectedEmoticon = initiallySelectedEmoticon
|
||||
self.peerName = peerName
|
||||
self.previewTheme = previewTheme
|
||||
self.changeWallpaper = changeWallpaper
|
||||
self.completion = completion
|
||||
|
||||
super.init(navigationBarPresentationData: nil)
|
||||
@ -713,6 +724,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
private let animationContainerNode: ASDisplayNode
|
||||
private var animationNode: AnimationNode
|
||||
private let doneButton: SolidRoundedButtonNode
|
||||
private let wallpaperButton: HighlightableButtonNode
|
||||
|
||||
private let listNode: ListView
|
||||
private var entries: [ThemeSettingsThemeEntry]?
|
||||
@ -807,6 +819,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false)
|
||||
self.doneButton.title = initiallySelectedEmoticon == nil ? self.presentationData.strings.Conversation_Theme_DontSetTheme : self.presentationData.strings.Conversation_Theme_Apply
|
||||
|
||||
self.wallpaperButton = HighlightableButtonNode()
|
||||
self.wallpaperButton.setTitle("Set Background from Gallery", with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
|
||||
@ -829,6 +844,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.contentContainerNode.addSubnode(self.titleNode)
|
||||
self.contentContainerNode.addSubnode(self.textNode)
|
||||
self.contentContainerNode.addSubnode(self.doneButton)
|
||||
self.contentContainerNode.addSubnode(self.wallpaperButton)
|
||||
|
||||
self.topContentContainerNode.addSubnode(self.animationContainerNode)
|
||||
self.animationContainerNode.addSubnode(self.animationNode)
|
||||
@ -844,6 +860,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
strongSelf.completion?(strongSelf.selectedEmoticon)
|
||||
}
|
||||
}
|
||||
self.wallpaperButton.addTarget(self, action: #selector(self.wallpaperButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.disposable.set(combineLatest(queue: Queue.mainQueue(), self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), self.selectedEmoticonPromise.get(), self.isDarkAppearancePromise.get()).start(next: { [weak self] themes, selectedEmoticon, isDarkAppearance in
|
||||
guard let strongSelf = self else {
|
||||
@ -1020,6 +1037,10 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
self.cancel?()
|
||||
}
|
||||
|
||||
@objc func wallpaperButtonPressed() {
|
||||
self.controller?.changeWallpaper()
|
||||
}
|
||||
|
||||
func dimTapped() {
|
||||
if self.selectedEmoticon == self.initiallySelectedEmoticon {
|
||||
self.cancelButtonPressed()
|
||||
@ -1197,7 +1218,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom
|
||||
let titleHeight: CGFloat = 54.0
|
||||
let contentHeight = titleHeight + bottomInset + 188.0
|
||||
let contentHeight = titleHeight + bottomInset + 188.0 + 50.0
|
||||
|
||||
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 0.0)
|
||||
|
||||
@ -1235,7 +1256,10 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
let buttonInset: CGFloat = 16.0
|
||||
let doneButtonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
||||
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight))
|
||||
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - 50.0 - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight))
|
||||
|
||||
let wallpaperButtonSize = self.wallpaperButton.measure(CGSize(width: contentFrame.width - buttonInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrame(node: self.wallpaperButton, frame: CGRect(origin: CGPoint(x: floor((contentFrame.width - wallpaperButtonSize.width) / 2.0), y: contentHeight - wallpaperButtonSize.height - insets.bottom - 6.0 - 9.0), size: wallpaperButtonSize))
|
||||
|
||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
||||
transition.updateFrame(node: self.topContentContainerNode, frame: contentContainerFrame)
|
||||
|
@ -385,7 +385,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] wallpaper in
|
||||
controller?.dismiss()
|
||||
let galleryController = WallpaperGalleryController(context: context, source: .wallpaper(wallpaper, options, colors, intensity, rotation, nil))
|
||||
present(galleryController, nil)
|
||||
navigationController?.pushViewController(galleryController)
|
||||
}, error: { [weak controller] error in
|
||||
controller?.dismiss()
|
||||
})
|
||||
|
@ -93,7 +93,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}, sendEmoji: { _, _, _ in
|
||||
}, sendGif: { _, _, _, _, _ in
|
||||
return false
|
||||
}, sendBotContextResultAsGif: { _, _, _, _, _ in
|
||||
}, sendBotContextResultAsGif: { _, _, _, _, _, _ in
|
||||
return false
|
||||
}, requestMessageActionCallback: { _, _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _ in
|
||||
|
@ -1,6 +1,8 @@
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
final class PeerInfoScreenCommentItem: PeerInfoScreenItem {
|
||||
let id: AnyHashable
|
||||
@ -47,8 +49,16 @@ private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode {
|
||||
let verticalInset: CGFloat = 7.0
|
||||
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), textColor: presentationData.theme.list.freeTextColor)
|
||||
self.activateArea.accessibilityLabel = item.text
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize)
|
||||
let textColor = presentationData.theme.list.freeTextColor
|
||||
|
||||
let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: textFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: presentationData.theme.list.itemAccentColor), linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
}))
|
||||
|
||||
self.textNode.attributedText = attributedText
|
||||
self.activateArea.accessibilityLabel = attributedText.string
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
|
@ -991,7 +991,9 @@ func canEditPeerInfo(context: AccountContext, peer: Peer?, chatLocation: ChatLoc
|
||||
if context.account.peerId == peer?.id {
|
||||
return true
|
||||
}
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if let user = peer as? TelegramUser, let botInfo = user.botInfo {
|
||||
return botInfo.flags.contains(.canEdit)
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if let threadData = threadData {
|
||||
if chatLocation.threadId == 1 {
|
||||
return false
|
||||
@ -1270,6 +1272,9 @@ func peerInfoCanEdit(peer: Peer?, chatLocation: ChatLocation, threadData: Messag
|
||||
if user.isDeleted {
|
||||
return false
|
||||
}
|
||||
if let botInfo = user.botInfo {
|
||||
return botInfo.flags.contains(.canEdit)
|
||||
}
|
||||
if let isContact = isContact, !isContact {
|
||||
return false
|
||||
}
|
||||
|
@ -2120,11 +2120,17 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
contentHeight += 32.0
|
||||
}
|
||||
|
||||
var isEditableBot = false
|
||||
if let user = peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
|
||||
isEditableBot = true
|
||||
}
|
||||
var fieldKeys: [PeerInfoHeaderTextFieldNodeKey] = []
|
||||
if let user = peer as? TelegramUser {
|
||||
if !user.isDeleted {
|
||||
fieldKeys.append(.firstName)
|
||||
if user.botInfo == nil {
|
||||
if isEditableBot {
|
||||
fieldKeys.append(.description)
|
||||
} else if user.botInfo == nil {
|
||||
fieldKeys.append(.lastName)
|
||||
}
|
||||
}
|
||||
@ -2160,6 +2166,8 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
updateText = cachedData.about ?? ""
|
||||
} else if let cachedData = cachedData as? CachedGroupData {
|
||||
updateText = cachedData.about ?? ""
|
||||
} else if let cachedData = cachedData as? CachedUserData {
|
||||
updateText = cachedData.about ?? ""
|
||||
} else {
|
||||
updateText = ""
|
||||
}
|
||||
@ -2179,7 +2187,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
switch key {
|
||||
case .firstName:
|
||||
placeholder = presentationData.strings.UserInfo_FirstNamePlaceholder
|
||||
isEnabled = isContact || isSettings
|
||||
isEnabled = isContact || isSettings || isEditableBot
|
||||
case .lastName:
|
||||
placeholder = presentationData.strings.UserInfo_LastNamePlaceholder
|
||||
isEnabled = isContact || isSettings
|
||||
@ -2192,7 +2200,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer, chatLocation: chatLocation, threadData: threadData)
|
||||
case .description:
|
||||
placeholder = presentationData.strings.Channel_Edit_AboutItem
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer, chatLocation: chatLocation, threadData: threadData)
|
||||
isEnabled = canEditPeerInfo(context: self.context, peer: peer, chatLocation: chatLocation, threadData: threadData) || isEditableBot
|
||||
}
|
||||
let itemHeight = itemNode.update(width: width, safeInset: safeInset, isSettings: isSettings, hasPrevious: hasPrevious, hasNext: key != fieldKeys.last, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText)
|
||||
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)))
|
||||
|
@ -540,6 +540,7 @@ private final class PeerInfoInteraction {
|
||||
let dismissInput: () -> Void
|
||||
let toggleForumTopics: (Bool) -> Void
|
||||
let displayTopicsLimited: (TopicsLimitedReason) -> Void
|
||||
let openPeerMention: (String, ChatControllerInteractionNavigateToPeer) -> Void
|
||||
|
||||
init(
|
||||
openUsername: @escaping (String) -> Void,
|
||||
@ -588,7 +589,8 @@ private final class PeerInfoInteraction {
|
||||
editingOpenReactionsSetup: @escaping () -> Void,
|
||||
dismissInput: @escaping () -> Void,
|
||||
toggleForumTopics: @escaping (Bool) -> Void,
|
||||
displayTopicsLimited: @escaping (TopicsLimitedReason) -> Void
|
||||
displayTopicsLimited: @escaping (TopicsLimitedReason) -> Void,
|
||||
openPeerMention: @escaping (String, ChatControllerInteractionNavigateToPeer) -> Void
|
||||
) {
|
||||
self.openUsername = openUsername
|
||||
self.openPhone = openPhone
|
||||
@ -637,6 +639,7 @@ private final class PeerInfoInteraction {
|
||||
self.dismissInput = dismissInput
|
||||
self.toggleForumTopics = toggleForumTopics
|
||||
self.displayTopicsLimited = displayTopicsLimited
|
||||
self.openPeerMention = openPeerMention
|
||||
}
|
||||
}
|
||||
|
||||
@ -1390,8 +1393,29 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
let ItemReset = 2
|
||||
let ItemInfo = 3
|
||||
let ItemDelete = 4
|
||||
let ItemUsername = 5
|
||||
|
||||
if !user.flags.contains(.isSupport) {
|
||||
let ItemIntro = 6
|
||||
let ItemCommands = 7
|
||||
let ItemBotSettings = 8
|
||||
let ItemBotInfo = 9
|
||||
|
||||
if let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: .text("@\(user.addressName ?? "")"), text: presentationData.strings.PeerInfo_Username, icon: nil, action: {
|
||||
interaction.editingOpenPublicLinkSetup()
|
||||
}))
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemIntro, text: "Edit Intro", icon: UIImage(bundleImageName: "Peer Info/BotIntro"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: user.addressName ?? "", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemCommands, text: "Edit Commands", icon: UIImage(bundleImageName: "Peer Info/BotCommands"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: "\(user.addressName ?? "")-commands", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemBotSettings, text: "Change Bot Settings", icon: UIImage(bundleImageName: "Peer Info/BotSettings"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: user.addressName ?? "", behavior: .interactive)))
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenCommentItem(id: ItemBotInfo, text: "Use [@BotFather]() to manage this bot."))
|
||||
} else if !user.flags.contains(.isSupport) {
|
||||
let compactName = EnginePeer(user).compactDisplayTitle
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenActionItem(id: ItemSuggest, text: presentationData.strings.UserInfo_SuggestPhoto(compactName).string, color: .accent, icon: UIImage(bundleImageName: "Peer Info/SuggestAvatar"), action: {
|
||||
interaction.suggestPhoto()
|
||||
@ -2244,6 +2268,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
text = self.presentationData.strings.PeerInfo_TopicsLimitedDiscussionGroups
|
||||
}
|
||||
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_topics", scale: 0.066, colors: [:], title: nil, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
},
|
||||
openPeerMention: { [weak self] mention, navigation in
|
||||
self?.openPeerMention(mention, navigation: navigation)
|
||||
}
|
||||
)
|
||||
|
||||
@ -2616,7 +2643,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}, sendEmoji: { _, _, _ in
|
||||
}, sendGif: { _, _, _, _, _ in
|
||||
return false
|
||||
}, sendBotContextResultAsGif: { _, _, _, _, _ in
|
||||
}, sendBotContextResultAsGif: { _, _, _, _, _, _ in
|
||||
return false
|
||||
}, requestMessageActionCallback: { _, _, _, _ in
|
||||
}, requestMessageActionUrlAuth: { _, _ in
|
||||
@ -3123,8 +3150,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let peerBio = cachedData.about ?? ""
|
||||
|
||||
if (peer.firstName ?? "") != firstName || (peer.lastName ?? "") != lastName || (bio ?? "") != (cachedData.about ?? "") {
|
||||
if (peer.firstName ?? "") != firstName || (peer.lastName ?? "") != lastName || (bio ?? "") != peerBio {
|
||||
var updateNameSignal: Signal<Void, NoError> = .complete()
|
||||
var hasProgress = false
|
||||
if peer.firstName != firstName || peer.lastName != lastName {
|
||||
@ -3140,6 +3169,62 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
hasProgress = true
|
||||
}
|
||||
|
||||
var dismissStatus: (() -> Void)?
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: {
|
||||
dismissStatus?()
|
||||
}))
|
||||
dismissStatus = { [weak statusController] in
|
||||
self?.activeActionDisposable.set(nil)
|
||||
statusController?.dismiss()
|
||||
}
|
||||
if hasProgress {
|
||||
strongSelf.controller?.present(statusController, in: .window(.root))
|
||||
}
|
||||
strongSelf.activeActionDisposable.set((combineLatest(updateNameSignal, updateBioSignal) |> deliverOnMainQueue
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
dismissStatus?()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
||||
}))
|
||||
} else {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel, nil, nil)
|
||||
}
|
||||
} else if let botInfo = peer.botInfo, botInfo.flags.contains(.canEdit), let cachedData = data.cachedData as? CachedUserData {
|
||||
let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? ""
|
||||
let bio = strongSelf.headerNode.editingContentNode.editingTextForKey(.description)
|
||||
if let bio = bio {
|
||||
if Int32(bio.count) > strongSelf.context.userLimits.maxAboutLength {
|
||||
for (_, section) in strongSelf.editingSections {
|
||||
section.animateErrorIfNeeded()
|
||||
}
|
||||
strongSelf.hapticFeedback.error()
|
||||
return
|
||||
}
|
||||
}
|
||||
let peerBio = cachedData.about ?? ""
|
||||
|
||||
if (peer.firstName ?? "") != firstName || (bio ?? "") != peerBio {
|
||||
var updateNameSignal: Signal<Void, NoError> = .complete()
|
||||
var hasProgress = false
|
||||
if peer.firstName != firstName {
|
||||
updateNameSignal = context.engine.peers.updateBotName(peerId: peer.id, name: firstName)
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
hasProgress = true
|
||||
}
|
||||
var updateBioSignal: Signal<Void, NoError> = .complete()
|
||||
if let bio = bio, bio != cachedData.about {
|
||||
updateBioSignal = context.engine.peers.updateBotAbout(peerId: peer.id, about: bio)
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
hasProgress = true
|
||||
}
|
||||
|
||||
var dismissStatus: (() -> Void)?
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: {
|
||||
dismissStatus?()
|
||||
@ -4009,8 +4094,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
switch navigation {
|
||||
case let .chat(_, subject, peekData):
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), subject: subject, keepStack: .always, peekData: peekData))
|
||||
case let .chat(inputState, subject, peekData):
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), subject: subject, updateTextInputState: inputState, activateInput: inputState != nil ? .text : nil, keepStack: .always, peekData: peekData))
|
||||
case .info:
|
||||
if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil {
|
||||
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
@ -4640,7 +4725,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.botInfo == nil && strongSelf.data?.encryptionKeyFingerprint == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_ChangeColors, icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: "Change Background", icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
@ -6483,16 +6568,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
private func editingOpenPublicLinkSetup() {
|
||||
var upgradedToSupergroupImpl: (() -> Void)?
|
||||
let controller = channelVisibilityController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, mode: .generic, upgradedToSupergroup: { _, f in
|
||||
upgradedToSupergroupImpl?()
|
||||
f()
|
||||
})
|
||||
self.controller?.push(controller)
|
||||
|
||||
upgradedToSupergroupImpl = { [weak controller] in
|
||||
if let controller = controller, let navigationController = controller.navigationController as? NavigationController {
|
||||
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
|
||||
if let peer = self.data?.peer as? TelegramUser, peer.botInfo != nil {
|
||||
let controller = usernameSetupController(context: self.context, mode: .bot(self.peerId))
|
||||
self.controller?.push(controller)
|
||||
} else {
|
||||
var upgradedToSupergroupImpl: (() -> Void)?
|
||||
let controller = channelVisibilityController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, mode: .generic, upgradedToSupergroup: { _, f in
|
||||
upgradedToSupergroupImpl?()
|
||||
f()
|
||||
})
|
||||
self.controller?.push(controller)
|
||||
|
||||
upgradedToSupergroupImpl = { [weak controller] in
|
||||
if let controller = controller, let navigationController = controller.navigationController as? NavigationController {
|
||||
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1441,7 +1441,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
|
||||
|
@ -125,7 +125,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
private let scrollingContainer: ASDisplayNode
|
||||
private let containerNode: ASDisplayNode
|
||||
private let backgroundContainerNode: ASDisplayNode
|
||||
private let backgroundNode: ASImageNode
|
||||
private let backgroundClipNode: ASDisplayNode
|
||||
private let backgroundMaskNode: ASDisplayNode
|
||||
private var effectView: UIView?
|
||||
private var gradientNode: ASDisplayNode?
|
||||
private var arrowGradientNode: ASDisplayNode?
|
||||
@ -155,14 +156,14 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
self.containerNode = ASDisplayNode()
|
||||
self.backgroundContainerNode = ASDisplayNode()
|
||||
self.backgroundMaskNode = ASDisplayNode()
|
||||
self.backgroundClipNode = ASDisplayNode()
|
||||
self.backgroundClipNode.backgroundColor = .white
|
||||
|
||||
let fillColor = UIColor(white: 0.0, alpha: 0.8)
|
||||
|
||||
self.scrollingContainer = ASDisplayNode()
|
||||
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.image = generateAdjustedStretchableFilledCircleImage(diameter: 15.0, color: fillColor)
|
||||
|
||||
func svgPath(_ path: StaticString, scale: CGPoint = CGPoint(x: 1.0, y: 1.0), offset: CGPoint = CGPoint()) throws -> UIBezierPath {
|
||||
var index: UnsafePointer<UInt8> = path.utf8Start
|
||||
let end = path.utf8Start.advanced(by: path.utf8CodeUnitCount)
|
||||
@ -210,42 +211,20 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.arrowContainer = ASDisplayNode()
|
||||
|
||||
let fontSize: CGFloat
|
||||
if case .light = style {
|
||||
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
self.backgroundContainerNode.clipsToBounds = true
|
||||
self.backgroundContainerNode.cornerRadius = 14.0
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundContainerNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
fontSize = 17.0
|
||||
|
||||
self.arrowEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
self.arrowContainer.view.addSubview(self.arrowEffectView!)
|
||||
|
||||
let maskLayer = CAShapeLayer()
|
||||
if let path = try? svgPath("M85.882251,0 C79.5170552,0 73.4125613,2.52817247 68.9116882,7.02834833 L51.4264069,24.5109211 C46.7401154,29.1964866 39.1421356,29.1964866 34.4558441,24.5109211 L16.9705627,7.02834833 C12.4696897,2.52817247 6.36519576,0 0,0 L85.882251,0 ", scale: CGPoint(x: 0.333333, y: 0.333333), offset: CGPoint()) {
|
||||
maskLayer.path = path.cgPath
|
||||
}
|
||||
maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowContainer.layer.mask = maskLayer
|
||||
} else if case .default = style {
|
||||
if case .top = location {
|
||||
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||
self.backgroundContainerNode.clipsToBounds = true
|
||||
self.backgroundContainerNode.cornerRadius = 14.0
|
||||
self.backgroundMaskNode.addSubnode(self.backgroundClipNode)
|
||||
self.backgroundClipNode.clipsToBounds = true
|
||||
if case let .point(_, arrowPosition) = location, case .right = arrowPosition {
|
||||
self.backgroundClipNode.cornerRadius = 8.5
|
||||
} else {
|
||||
self.backgroundClipNode.cornerRadius = 14.0
|
||||
}
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundContainerNode.layer.cornerCurve = .continuous
|
||||
self.backgroundClipNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
|
||||
fontSize = 14.0
|
||||
|
||||
self.arrowEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||
self.arrowContainer.view.addSubview(self.arrowEffectView!)
|
||||
|
||||
let maskLayer = CAShapeLayer()
|
||||
if let path = try? svgPath("M85.882251,0 C79.5170552,0 73.4125613,2.52817247 68.9116882,7.02834833 L51.4264069,24.5109211 C46.7401154,29.1964866 39.1421356,29.1964866 34.4558441,24.5109211 L16.9705627,7.02834833 C12.4696897,2.52817247 6.36519576,0 0,0 L85.882251,0 ", scale: CGPoint(x: 0.333333, y: 0.333333), offset: CGPoint()) {
|
||||
maskLayer.path = path.cgPath
|
||||
}
|
||||
maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowContainer.layer.mask = maskLayer
|
||||
} else if case let .gradient(leftColor, rightColor) = style {
|
||||
self.gradientNode = ASDisplayNode()
|
||||
self.gradientNode?.setLayerBlock({
|
||||
@ -278,16 +257,39 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowContainer.layer.mask = maskLayer
|
||||
} else if case .top = location {
|
||||
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||
self.containerNode.clipsToBounds = true
|
||||
self.containerNode.cornerRadius = 14.0
|
||||
if #available(iOS 13.0, *) {
|
||||
self.containerNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
fontSize = 14.0
|
||||
} else {
|
||||
let effect: UIBlurEffect
|
||||
if case .light = style {
|
||||
effect = UIBlurEffect(style: .light)
|
||||
} else {
|
||||
effect = UIBlurEffect(style: .dark)
|
||||
}
|
||||
self.effectView = UIVisualEffectView(effect: effect)
|
||||
|
||||
self.backgroundMaskNode.addSubnode(self.backgroundClipNode)
|
||||
self.backgroundClipNode.clipsToBounds = true
|
||||
if case let .point(_, arrowPosition) = location, case .right = arrowPosition {
|
||||
self.backgroundClipNode.cornerRadius = 8.5
|
||||
} else {
|
||||
self.backgroundClipNode.cornerRadius = 14.0
|
||||
}
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundClipNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
self.backgroundMaskNode.addSubnode(self.arrowContainer)
|
||||
|
||||
fontSize = 14.0
|
||||
|
||||
let maskLayer = CAShapeLayer()
|
||||
if let path = try? svgPath("M85.882251,0 C79.5170552,0 73.4125613,2.52817247 68.9116882,7.02834833 L51.4264069,24.5109211 C46.7401154,29.1964866 39.1421356,29.1964866 34.4558441,24.5109211 L16.9705627,7.02834833 C12.4696897,2.52817247 6.36519576,0 0,0 L85.882251,0 ", scale: CGPoint(x: 0.333333, y: 0.333333), offset: CGPoint()) {
|
||||
maskLayer.path = path.cgPath
|
||||
}
|
||||
maskLayer.frame = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
maskLayer.fillColor = UIColor.white.cgColor
|
||||
self.arrowContainer.layer.addSublayer(maskLayer)
|
||||
|
||||
self.backgroundMaskNode.layer.shouldRasterize = true
|
||||
self.backgroundMaskNode.layer.rasterizationScale = UIScreen.main.scale
|
||||
}
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
@ -313,21 +315,12 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
super.init()
|
||||
|
||||
self.containerNode.addSubnode(self.backgroundContainerNode)
|
||||
self.arrowContainer.addSubnode(self.arrowNode)
|
||||
self.backgroundNode.addSubnode(self.arrowContainer)
|
||||
if let gradientNode = self.gradientNode {
|
||||
self.backgroundContainerNode.addSubnode(gradientNode)
|
||||
self.containerNode.addSubnode(self.arrowContainer)
|
||||
self.arrowNode.removeFromSupernode()
|
||||
}
|
||||
else if let effectView = self.effectView {
|
||||
} else if let effectView = self.effectView {
|
||||
self.backgroundContainerNode.view.addSubview(effectView)
|
||||
if let _ = self.arrowEffectView {
|
||||
self.containerNode.addSubnode(self.arrowContainer)
|
||||
self.arrowNode.removeFromSupernode()
|
||||
}
|
||||
} else {
|
||||
self.backgroundContainerNode.addSubnode(self.backgroundNode)
|
||||
self.backgroundContainerNode.layer.mask = self.backgroundMaskNode.layer
|
||||
}
|
||||
self.containerNode.addSubnode(self.textNode)
|
||||
self.containerNode.addSubnode(self.animatedStickerNode)
|
||||
@ -476,9 +469,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
transition.updateFrame(node: self.containerNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.backgroundContainerNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
transition.updateFrame(node: self.backgroundMaskNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0))
|
||||
transition.updateFrame(node: self.backgroundClipNode, frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: backgroundFrame.size))
|
||||
|
||||
if let effectView = self.effectView {
|
||||
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0))
|
||||
}
|
||||
if let gradientNode = self.gradientNode {
|
||||
transition.updateFrame(node: gradientNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
@ -490,31 +485,35 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
let arrowFrame: CGRect
|
||||
|
||||
switch arrowPosition {
|
||||
case .bottom, .top:
|
||||
if invertArrow {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: -arrowSize.height), size: arrowSize)
|
||||
} else {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: backgroundFrame.height), size: arrowSize)
|
||||
}
|
||||
ContainedViewLayoutTransition.immediate.updateTransformScale(node: self.arrowContainer, scale: CGPoint(x: 1.0, y: invertArrow ? -1.0 : 1.0))
|
||||
|
||||
case .bottom, .top:
|
||||
if invertArrow {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: -arrowSize.height), size: arrowSize)
|
||||
} else {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: backgroundFrame.height), size: arrowSize)
|
||||
}
|
||||
ContainedViewLayoutTransition.immediate.updateTransformScale(node: self.arrowContainer, scale: CGPoint(x: 1.0, y: invertArrow ? -1.0 : 1.0))
|
||||
|
||||
if case .gradient = self.tooltipStyle {
|
||||
transition.updateFrame(node: self.arrowContainer, frame: arrowFrame.offsetBy(dx: -backgroundFrame.minX, dy: 0.0))
|
||||
|
||||
let arrowBounds = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = CGRect(origin: CGPoint(x: -arrowFrame.minX + backgroundFrame.minX, y: 0.0), size: backgroundFrame.size)
|
||||
case .right:
|
||||
arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.width + arrowSize.height, y: rect.midY), size: CGSize(width: arrowSize.height, height: arrowSize.width))
|
||||
|
||||
ContainedViewLayoutTransition.immediate.updateTransformRotation(node: self.arrowContainer, angle: -CGFloat.pi / 2.0)
|
||||
|
||||
transition.updateFrame(node: self.arrowContainer, frame: arrowFrame.offsetBy(dx: 0.0, dy: -backgroundFrame.minY - floorToScreenPixels((backgroundFrame.height - arrowSize.width) / 2.0)))
|
||||
|
||||
let arrowBounds = CGRect(origin: CGPoint(x: 0.0, y: -0.5), size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = arrowBounds
|
||||
} else {
|
||||
transition.updateFrame(node: self.arrowContainer, frame: arrowFrame.offsetBy(dx: -backgroundFrame.minX + 10.0, dy: 10.0))
|
||||
}
|
||||
|
||||
let arrowBounds = CGRect(origin: CGPoint(), size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = CGRect(origin: CGPoint(x: -arrowFrame.minX + backgroundFrame.minX, y: 0.0), size: backgroundFrame.size)
|
||||
case .right:
|
||||
arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.width + arrowSize.height, y: rect.midY), size: CGSize(width: arrowSize.height, height: arrowSize.width))
|
||||
|
||||
ContainedViewLayoutTransition.immediate.updateTransformRotation(node: self.arrowContainer, angle: -CGFloat.pi / 2.0)
|
||||
|
||||
transition.updateFrame(node: self.arrowContainer, frame: arrowFrame.offsetBy(dx: 8.0 - UIScreenPixel, dy: 16.0 + -backgroundFrame.minY - floorToScreenPixels((backgroundFrame.height + 20.0 - arrowSize.width) / 2.0)))
|
||||
|
||||
let arrowBounds = CGRect(origin: .zero, size: arrowSize)
|
||||
self.arrowNode.frame = arrowBounds
|
||||
self.arrowEffectView?.frame = arrowBounds
|
||||
self.arrowGradientNode?.frame = arrowBounds
|
||||
}
|
||||
} else {
|
||||
self.arrowNode.isHidden = true
|
||||
@ -566,7 +565,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.containerNode.layer.animateScale(from: 0.96, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
if let _ = self.validLayout {
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -13.0 - self.backgroundNode.frame.height), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -13.0 - self.backgroundContainerNode.frame.height), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
}
|
||||
case let .point(_, arrowPosition):
|
||||
self.containerNode.layer.animateSpring(from: NSNumber(value: Float(0.01)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.4, damping: 105.0)
|
||||
@ -607,7 +606,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
})
|
||||
self.containerNode.layer.animateScale(from: 1.0, to: 0.96, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||
if let _ = self.validLayout {
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -13.0 - self.backgroundNode.frame.height), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -13.0 - self.backgroundContainerNode.frame.height), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||
}
|
||||
case let .point(_, arrowPosition):
|
||||
self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||
|
@ -23,7 +23,7 @@ public extension CharacterSet {
|
||||
}
|
||||
|
||||
public func isValidUrl(_ url: String, validSchemes: [String: Bool] = ["http": true, "https": true]) -> Bool {
|
||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), let scheme = url.scheme, let requiresTopLevelDomain = validSchemes[scheme], let host = url.host, (!requiresTopLevelDomain || host.contains(".")) && url.user == nil {
|
||||
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), let scheme = url.scheme?.lowercased(), let requiresTopLevelDomain = validSchemes[scheme], let host = url.host, (!requiresTopLevelDomain || host.contains(".")) && url.user == nil {
|
||||
if requiresTopLevelDomain {
|
||||
let components = host.components(separatedBy: ".")
|
||||
let domain = (components.first ?? "")
|
||||
|
Loading…
x
Reference in New Issue
Block a user