[WIP] Stars reactions

This commit is contained in:
Isaac 2024-07-30 23:44:19 +08:00
parent 83be782893
commit 05372b578c
85 changed files with 2271 additions and 1115 deletions

View File

@ -2171,6 +2171,8 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
messageText = item.presentationData.strings.ChatList_UserReacted(value).string messageText = item.presentationData.strings.ChatList_UserReacted(value).string
case .custom: case .custom:
break break
case .stars:
break
} }
break loop break loop
} }

View File

@ -175,6 +175,10 @@ public final class ReactionIconView: PortalSourceView {
iconSize = CGSize(width: floor(size.width * 1.25), height: floor(size.height * 1.25)) iconSize = CGSize(width: floor(size.width * 1.25), height: floor(size.height * 1.25))
animationLayer.masksToBounds = true animationLayer.masksToBounds = true
animationLayer.cornerRadius = floor(size.width * 0.2) animationLayer.cornerRadius = floor(size.width * 0.2)
case .stars:
iconSize = CGSize(width: floor(size.width * 2.0), height: floor(size.height * 2.0))
animationLayer.masksToBounds = false
animationLayer.cornerRadius = 0.0
} }
transition.updateFrame(layer: animationLayer, frame: CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)) transition.updateFrame(layer: animationLayer, frame: CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
@ -207,6 +211,8 @@ public final class ReactionIconView: PortalSourceView {
iconSize = CGSize(width: floor(size.width * 2.0), height: floor(size.height * 2.0)) iconSize = CGSize(width: floor(size.width * 2.0), height: floor(size.height * 2.0))
case .custom: case .custom:
iconSize = CGSize(width: floor(size.width * 1.25), height: floor(size.height * 1.25)) iconSize = CGSize(width: floor(size.width * 1.25), height: floor(size.height * 1.25))
case .stars:
iconSize = CGSize(width: floor(size.width * 2.0), height: floor(size.height * 2.0))
} }
let animationLayer = InlineStickerItemLayer( let animationLayer = InlineStickerItemLayer(
@ -234,6 +240,9 @@ public final class ReactionIconView: PortalSourceView {
case .custom: case .custom:
animationLayer.masksToBounds = true animationLayer.masksToBounds = true
animationLayer.cornerRadius = floor(size.width * 0.3) animationLayer.cornerRadius = floor(size.width * 0.3)
case .stars:
animationLayer.masksToBounds = false
animationLayer.cornerRadius = 0.0
} }
animationLayer.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize) animationLayer.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
@ -766,7 +775,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
let backgroundColors: ReactionButtonAsyncNode.ContainerButtonNode.Colors let backgroundColors: ReactionButtonAsyncNode.ContainerButtonNode.Colors
if case .custom(MessageReaction.starsReactionId) = spec.component.reaction.value { if case .stars = spec.component.reaction.value {
backgroundColors = ReactionButtonAsyncNode.ContainerButtonNode.Colors( backgroundColors = ReactionButtonAsyncNode.ContainerButtonNode.Colors(
background: spec.component.chosenOrder != nil ? spec.component.colors.selectedStarsBackground : spec.component.colors.deselectedStarsBackground, background: spec.component.chosenOrder != nil ? spec.component.colors.selectedStarsBackground : spec.component.colors.deselectedStarsBackground,
foreground: spec.component.chosenOrder != nil ? spec.component.colors.selectedStarsForeground : spec.component.colors.deselectedStarsForeground, foreground: spec.component.chosenOrder != nil ? spec.component.colors.selectedStarsForeground : spec.component.colors.deselectedStarsForeground,
@ -821,6 +830,8 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
private let iconImageDisposable = MetaDisposable() private let iconImageDisposable = MetaDisposable()
private var ignoreButtonTap: Bool = false
public var activateAfterCompletion: Bool = false { public var activateAfterCompletion: Bool = false {
didSet { didSet {
if self.activateAfterCompletion { if self.activateAfterCompletion {
@ -881,6 +892,20 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
} }
} }
} }
self.contextGesture?.cancelGesturesOnActivation = { [weak self] in
guard let self else {
return
}
self.buttonNode.isUserInteractionEnabled = false
self.buttonNode.cancelTracking(with: nil)
DispatchQueue.main.async { [weak self] in
guard let self else {
return
}
self.buttonNode.isUserInteractionEnabled = true
}
}
} }
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
@ -902,6 +927,9 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
guard let layout = self.layout else { guard let layout = self.layout else {
return return
} }
if self.ignoreButtonTap {
return
}
layout.spec.component.action(self, layout.spec.component.reaction.value, self.containerView) layout.spec.component.action(self, layout.spec.component.reaction.value, self.containerView)
} }
@ -911,7 +939,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
self.containerView.contentRect = CGRect(origin: CGPoint(), size: layout.size) self.containerView.contentRect = CGRect(origin: CGPoint(), size: layout.size)
animation.animator.updateFrame(layer: self.buttonNode.layer, frame: CGRect(origin: CGPoint(), size: layout.size), completion: nil) animation.animator.updateFrame(layer: self.buttonNode.layer, frame: CGRect(origin: CGPoint(), size: layout.size), completion: nil)
if case .custom(MessageReaction.starsReactionId) = layout.spec.component.reaction.value { if case .stars = layout.spec.component.reaction.value {
let starsEffectLayer: StarsButtonEffectLayer let starsEffectLayer: StarsButtonEffectLayer
if let current = self.starsEffectLayer { if let current = self.starsEffectLayer {
starsEffectLayer = current starsEffectLayer = current
@ -1319,7 +1347,7 @@ public final class ReactionButtonsAsyncLayoutContainer {
}) })
if let index = reactions.firstIndex(where: { if let index = reactions.firstIndex(where: {
if case .custom(MessageReaction.starsReactionId) = $0.reaction.value { if case .stars = $0.reaction.value {
return true return true
} else { } else {
return false return false

View File

@ -164,6 +164,16 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
strongSelf.file = file strongSelf.file = file
strongSelf.updateReactionLayer() strongSelf.updateReactionLayer()
}).strict() }).strict()
case .stars:
if let availableReactions = availableReactions {
for availableReaction in availableReactions.reactions {
if availableReaction.value == reaction {
self.file = availableReaction.centerAnimation
self.updateReactionLayer()
break
}
}
}
} }
} else { } else {
let iconNode = ASImageNode() let iconNode = ASImageNode()
@ -574,6 +584,17 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
strongSelf.updateReactionLayer() strongSelf.updateReactionLayer()
strongSelf.updateReactionAccentColor(theme: presentationData.theme) strongSelf.updateReactionAccentColor(theme: presentationData.theme)
}).strict() }).strict()
case .stars:
if let availableReactions = self.availableReactions {
for availableReaction in availableReactions.reactions {
if availableReaction.value == reaction {
self.file = availableReaction.centerAnimation
self.updateReactionLayer()
self.updateReactionAccentColor(theme: presentationData.theme)
break
}
}
}
} }
} else { } else {
self.file = nil self.file = nil
@ -598,6 +619,8 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
reactionStringValue = value reactionStringValue = value
case .custom: case .custom:
reactionStringValue = "" reactionStringValue = ""
case .stars:
reactionStringValue = "Star"
} }
} else { } else {
reactionStringValue = "" reactionStringValue = ""

View File

@ -1329,9 +1329,9 @@ final class ContextControllerNode: ViewControllerTracingNode, ASScrollViewDelega
} }
} }
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) { func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: @escaping () -> Void) {
if let sourceContainer = self.sourceContainer { if let sourceContainer = self.sourceContainer {
sourceContainer.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: completion) sourceContainer.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, onHit: onHit, completion: completion)
} }
} }
@ -2604,7 +2604,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
} else if let args = self.dismissToReactionOnInputClose { } else if let args = self.dismissToReactionOnInputClose {
self.dismissToReactionOnInputClose = nil self.dismissToReactionOnInputClose = nil
DispatchQueue.main.async { DispatchQueue.main.async {
self.dismissWithReactionImpl(value: args.value, targetView: args.targetView, hideNode: args.hideNode, animateTargetContainer: args.animateTargetContainer, addStandaloneReactionAnimation: args.addStandaloneReactionAnimation, reducedCurve: true, completion: args.completion) self.dismissWithReactionImpl(value: args.value, targetView: args.targetView, hideNode: args.hideNode, animateTargetContainer: args.animateTargetContainer, addStandaloneReactionAnimation: args.addStandaloneReactionAnimation, reducedCurve: true, onHit: nil, completion: args.completion)
} }
} }
} }
@ -2706,11 +2706,11 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.dismissed?() self.dismissed?()
} }
public func dismissWithReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: (() -> Void)?) { public func dismissWithReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, onHit: (() -> Void)?, completion: (() -> Void)?) {
self.dismissWithReactionImpl(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: false, completion: completion) self.dismissWithReactionImpl(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: false, onHit: onHit, completion: completion)
} }
private func dismissWithReactionImpl(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: (() -> Void)?) { private func dismissWithReactionImpl(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: (() -> Void)?) {
if viewTreeContainsFirstResponder(view: self.view) { if viewTreeContainsFirstResponder(view: self.view) {
self.dismissToReactionOnInputClose = (value, targetView, hideNode, animateTargetContainer, addStandaloneReactionAnimation, completion) self.dismissToReactionOnInputClose = (value, targetView, hideNode, animateTargetContainer, addStandaloneReactionAnimation, completion)
self.view.endEditing(true) self.view.endEditing(true)
@ -2719,7 +2719,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
if !self.wasDismissed { if !self.wasDismissed {
self.wasDismissed = true self.wasDismissed = true
self.controllerNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: { [weak self] in self.controllerNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, onHit: onHit, completion: { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil) self?.presentingViewController?.dismiss(animated: false, completion: nil)
completion?() completion?()
}) })

View File

@ -1668,7 +1668,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
} }
} }
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) { func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: @escaping () -> Void) {
guard let reactionContextNode = self.reactionContextNode else { guard let reactionContextNode = self.reactionContextNode else {
self.requestAnimateOut(.default, completion) self.requestAnimateOut(.default, completion)
return return
@ -1697,7 +1697,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
intermediateCompletion() intermediateCompletion()
}) })
reactionContextNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, completion: { [weak self] in reactionContextNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, onHit: onHit, completion: { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }

View File

@ -28,7 +28,7 @@ protocol ContextControllerPresentationNode: ASDisplayNode {
stateTransition: ContextControllerPresentationNodeStateTransition? stateTransition: ContextControllerPresentationNodeStateTransition?
) )
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: @escaping () -> Void)
func cancelReactionAnimation() func cancelReactionAnimation()
func highlightGestureMoved(location: CGPoint, hover: Bool) func highlightGestureMoved(location: CGPoint, hover: Bool)

View File

@ -269,8 +269,8 @@ final class ContextSourceContainer: ASDisplayNode {
self.presentationNode.cancelReactionAnimation() self.presentationNode.cancelReactionAnimation()
} }
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) { func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: @escaping () -> Void) {
self.presentationNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: completion) self.presentationNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, onHit: onHit, completion: completion)
} }
func setItems(items: Signal<ContextController.Items, NoError>, animated: Bool) { func setItems(items: Signal<ContextController.Items, NoError>, animated: Bool) {
@ -543,9 +543,9 @@ final class ContextSourceContainer: ASDisplayNode {
} }
} }
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) { func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, onHit: (() -> Void)?, completion: @escaping () -> Void) {
if let activeSource = self.activeSource { if let activeSource = self.activeSource {
activeSource.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: completion) activeSource.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, onHit: onHit, completion: completion)
} else { } else {
completion() completion()
} }

View File

@ -264,6 +264,24 @@ public class DrawingReactionEntityView: DrawingStickerEntityView {
} }
}) })
} }
case .stars:
let _ = (self.context.engine.stickers.availableReactions()
|> take(1)
|> deliverOnMainQueue).start(next: { availableReactions in
guard let availableReactions else {
return
}
var animation: TelegramMediaFile?
for reaction in availableReactions.reactions {
if reaction.value == updateReaction.reaction {
animation = reaction.selectAnimation
break
}
}
if let animation {
continueWithAnimationFile(animation)
}
})
} }
} }

View File

@ -538,7 +538,7 @@ public func peerAllowedReactionListController(
} }
if initialAllowedReactions != .known(updatedValue) { if initialAllowedReactions != .known(updatedValue) {
let _ = context.engine.peers.updatePeerReactionSettings(peerId: peerId, reactionSettings: PeerReactionSettings(allowedReactions: updatedValue, maxReactionCount: 11)).start() let _ = context.engine.peers.updatePeerReactionSettings(peerId: peerId, reactionSettings: PeerReactionSettings(allowedReactions: updatedValue, maxReactionCount: 11, starsAllowed: nil)).start()
} }
}) })
} }

View File

@ -69,6 +69,8 @@ public final class ReactionItem {
return .builtin(value) return .builtin(value)
case let .custom(fileId): case let .custom(fileId):
return .custom(fileId: fileId, file: self.listAnimation) return .custom(fileId: fileId, file: self.listAnimation)
case .stars:
return .stars
} }
} }
} }
@ -965,6 +967,8 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
break break
case .custom: case .custom:
loopIdle = true loopIdle = true
case .stars:
break
} }
} }
} }
@ -1668,6 +1672,8 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
updateReaction = .builtin(value) updateReaction = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
updateReaction = .custom(fileId: fileId, file: nil) updateReaction = .custom(fileId: fileId, file: nil)
case .stars:
updateReaction = .stars
} }
let reactionItem = ReactionItem( let reactionItem = ReactionItem(
@ -2604,7 +2610,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
} }
} }
public func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, forceSwitchToInlineImmediately: Bool = false, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) { public func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, forceSwitchToInlineImmediately: Bool = false, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, onHit: (() -> Void)?, completion: @escaping () -> Void) {
self.isAnimatingOutToReaction = true self.isAnimatingOutToReaction = true
var foundItemNode: ReactionNode? var foundItemNode: ReactionNode?
@ -2639,6 +2645,8 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
switchToInlineImmediately = forceSwitchToInlineImmediately switchToInlineImmediately = forceSwitchToInlineImmediately
case .custom: case .custom:
switchToInlineImmediately = !self.didTriggerExpandedReaction switchToInlineImmediately = !self.didTriggerExpandedReaction
case .stars:
switchToInlineImmediately = forceSwitchToInlineImmediately
} }
} else { } else {
switchToInlineImmediately = !self.didTriggerExpandedReaction switchToInlineImmediately = !self.didTriggerExpandedReaction
@ -2853,6 +2861,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
strongSelf.hapticFeedback = HapticFeedback() strongSelf.hapticFeedback = HapticFeedback()
} }
strongSelf.hapticFeedback?.tap() strongSelf.hapticFeedback?.tap()
onHit?()
if let targetView = targetView as? ReactionIconView { if let targetView = targetView as? ReactionIconView {
if switchToInlineImmediately { if switchToInlineImmediately {
@ -3283,13 +3292,13 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
self.isUserInteractionEnabled = false self.isUserInteractionEnabled = false
} }
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) { public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, onHit: (() -> Void)? = nil, completion: @escaping () -> Void) {
self.animateReactionSelection(context: context, theme: theme, animationCache: animationCache, reaction: reaction, customEffectResource: customEffectResource, avatarPeers: avatarPeers, playHaptic: playHaptic, isLarge: isLarge, playCenterReaction: playCenterReaction, forceSmallEffectAnimation: forceSmallEffectAnimation, hideCenterAnimation: hideCenterAnimation, targetView: targetView, addStandaloneReactionAnimation: addStandaloneReactionAnimation, currentItemNode: nil, completion: completion) self.animateReactionSelection(context: context, theme: theme, animationCache: animationCache, reaction: reaction, customEffectResource: customEffectResource, avatarPeers: avatarPeers, playHaptic: playHaptic, isLarge: isLarge, playCenterReaction: playCenterReaction, forceSmallEffectAnimation: forceSmallEffectAnimation, hideCenterAnimation: hideCenterAnimation, targetView: targetView, addStandaloneReactionAnimation: addStandaloneReactionAnimation, currentItemNode: nil, onHit: onHit, completion: completion)
} }
public var currentDismissAnimation: (() -> Void)? public var currentDismissAnimation: (() -> Void)?
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, currentItemNode: ReactionNode?, completion: @escaping () -> Void) { public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, currentItemNode: ReactionNode?, onHit: (() -> Void)? = nil, completion: @escaping () -> Void) {
guard let sourceSnapshotView = targetView.snapshotContentTree() else { guard let sourceSnapshotView = targetView.snapshotContentTree() else {
completion() completion()
return return
@ -3298,6 +3307,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
if playHaptic { if playHaptic {
self.hapticFeedback.tap() self.hapticFeedback.tap()
} }
onHit?()
self.targetView = targetView self.targetView = targetView
@ -3322,6 +3332,8 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
switchToInlineImmediately = false switchToInlineImmediately = false
case .custom: case .custom:
switchToInlineImmediately = true switchToInlineImmediately = true
case .stars:
switchToInlineImmediately = false
} }
} else { } else {
switchToInlineImmediately = false switchToInlineImmediately = false
@ -3708,12 +3720,16 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
var selfTargetBounds = targetView.bounds var selfTargetBounds = targetView.bounds
if let itemNode = self.itemNode, case .builtin = itemNode.item.reaction.rawValue { if let itemNode = self.itemNode, case .builtin = itemNode.item.reaction.rawValue {
selfTargetBounds = selfTargetBounds.insetBy(dx: -selfTargetBounds.width * 0.5, dy: -selfTargetBounds.height * 0.5) selfTargetBounds = selfTargetBounds.insetBy(dx: -selfTargetBounds.width * 0.5, dy: -selfTargetBounds.height * 0.5)
} else if let itemNode = self.itemNode, case .stars = itemNode.item.reaction.rawValue {
selfTargetBounds = selfTargetBounds.insetBy(dx: -selfTargetBounds.width * 0.5, dy: -selfTargetBounds.height * 0.5)
} }
var targetFrame = self.view.convert(targetView.convert(selfTargetBounds, to: nil), from: nil) var targetFrame = self.view.convert(targetView.convert(selfTargetBounds, to: nil), from: nil)
if let itemNode = self.itemNode, case .builtin = itemNode.item.reaction.rawValue { if let itemNode = self.itemNode, case .builtin = itemNode.item.reaction.rawValue {
targetFrame = targetFrame.insetBy(dx: -targetFrame.width * 0.5, dy: -targetFrame.height * 0.5) targetFrame = targetFrame.insetBy(dx: -targetFrame.width * 0.5, dy: -targetFrame.height * 0.5)
} else if let itemNode = self.itemNode, case .stars = itemNode.item.reaction.rawValue {
targetFrame = targetFrame.insetBy(dx: -targetFrame.width * 0.5, dy: -targetFrame.height * 0.5)
} }
targetSnapshotView.frame = targetFrame targetSnapshotView.frame = targetFrame

View File

@ -60,7 +60,7 @@ private final class StarsReactionEffectLayer: SimpleLayer {
override init() { override init() {
super.init() super.init()
self.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2).cgColor //self.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2).cgColor
} }
override init(layer: Any) { override init(layer: Any) {
@ -150,7 +150,7 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
super.init() super.init()
if case .custom(MessageReaction.starsReactionId) = item.reaction.rawValue { if case .stars = item.reaction.rawValue {
let starsEffectLayer = StarsReactionEffectLayer() let starsEffectLayer = StarsReactionEffectLayer()
self.starsEffectLayer = starsEffectLayer self.starsEffectLayer = starsEffectLayer
self.layer.addSublayer(starsEffectLayer) self.layer.addSublayer(starsEffectLayer)

View File

@ -178,12 +178,12 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) } dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) }
dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) } dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) }
dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) } dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) }
dict[-1072953408] = { return Api.ChannelParticipant.parse_channelParticipant($0) } dict[-885426663] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
dict[885242707] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) } dict[885242707] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
dict[1844969806] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) } dict[1844969806] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) }
dict[803602899] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) } dict[803602899] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
dict[453242886] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) } dict[453242886] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) }
dict[900251559] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } dict[1331723247] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
dict[-1268741783] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsAdmins($0) } dict[-1268741783] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsAdmins($0) }
dict[338142689] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBanned($0) } dict[338142689] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBanned($0) }
dict[-1328445861] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBots($0) } dict[-1328445861] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBots($0) }
@ -192,7 +192,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-531931925] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsMentions($0) } dict[-531931925] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsMentions($0) }
dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) } dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) }
dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) } dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) }
dict[179174543] = { return Api.Chat.parse_channel($0) } dict[-29067075] = { return Api.Chat.parse_channel($0) }
dict[399807445] = { return Api.Chat.parse_channelForbidden($0) } dict[399807445] = { return Api.Chat.parse_channelForbidden($0) }
dict[1103884886] = { return Api.Chat.parse_chat($0) } dict[1103884886] = { return Api.Chat.parse_chat($0) }
dict[693512293] = { return Api.Chat.parse_chatEmpty($0) } dict[693512293] = { return Api.Chat.parse_chatEmpty($0) }
@ -202,7 +202,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) }
dict[-1146407795] = { return Api.ChatFull.parse_channelFull($0) } dict[-1146407795] = { return Api.ChatFull.parse_channelFull($0) }
dict[640893467] = { return Api.ChatFull.parse_chatFull($0) } dict[640893467] = { return Api.ChatFull.parse_chatFull($0) }
dict[-840897472] = { return Api.ChatInvite.parse_chatInvite($0) } dict[-26920803] = { return Api.ChatInvite.parse_chatInvite($0) }
dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) } dict[1516793212] = { return Api.ChatInvite.parse_chatInviteAlready($0) }
dict[1634294960] = { return Api.ChatInvite.parse_chatInvitePeek($0) } dict[1634294960] = { return Api.ChatInvite.parse_chatInvitePeek($0) }
dict[-1940201511] = { return Api.ChatInviteImporter.parse_chatInviteImporter($0) } dict[-1940201511] = { return Api.ChatInviteImporter.parse_chatInviteImporter($0) }
@ -274,7 +274,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1038136962] = { return Api.EncryptedFile.parse_encryptedFileEmpty($0) } dict[-1038136962] = { return Api.EncryptedFile.parse_encryptedFileEmpty($0) }
dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) } dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) }
dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) } dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) }
dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } dict[-1812799720] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) }
dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) } dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) }
dict[206668204] = { return Api.ExportedChatlistInvite.parse_exportedChatlistInvite($0) } dict[206668204] = { return Api.ExportedChatlistInvite.parse_exportedChatlistInvite($0) }
dict[1103040667] = { return Api.ExportedContactToken.parse_exportedContactToken($0) } dict[1103040667] = { return Api.ExportedContactToken.parse_exportedContactToken($0) }
@ -372,6 +372,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) } dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[-659913713] = { return Api.InputGroupCall.parse_inputGroupCall($0) } dict[-659913713] = { return Api.InputGroupCall.parse_inputGroupCall($0) }
dict[887591921] = { return Api.InputInvoice.parse_inputInvoiceChatInviteSubscription($0) }
dict[-977967015] = { return Api.InputInvoice.parse_inputInvoiceMessage($0) } dict[-977967015] = { return Api.InputInvoice.parse_inputInvoiceMessage($0) }
dict[-1734841331] = { return Api.InputInvoice.parse_inputInvoicePremiumGiftCode($0) } dict[-1734841331] = { return Api.InputInvoice.parse_inputInvoicePremiumGiftCode($0) }
dict[-1020867857] = { return Api.InputInvoice.parse_inputInvoiceSlug($0) } dict[-1020867857] = { return Api.InputInvoice.parse_inputInvoiceSlug($0) }
@ -618,7 +619,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1959634180] = { return Api.MessagePeerVote.parse_messagePeerVoteInputOption($0) } dict[1959634180] = { return Api.MessagePeerVote.parse_messagePeerVoteInputOption($0) }
dict[1177089766] = { return Api.MessagePeerVote.parse_messagePeerVoteMultiple($0) } dict[1177089766] = { return Api.MessagePeerVote.parse_messagePeerVoteMultiple($0) }
dict[182649427] = { return Api.MessageRange.parse_messageRange($0) } dict[182649427] = { return Api.MessageRange.parse_messageRange($0) }
dict[1328256121] = { return Api.MessageReactions.parse_messageReactions($0) } dict[171155211] = { return Api.MessageReactions.parse_messageReactions($0) }
dict[-285158328] = { return Api.MessageReactor.parse_messageReactor($0) }
dict[-2083123262] = { return Api.MessageReplies.parse_messageReplies($0) } dict[-2083123262] = { return Api.MessageReplies.parse_messageReplies($0) }
dict[-1346631205] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) } dict[-1346631205] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
dict[240843065] = { return Api.MessageReplyHeader.parse_messageReplyStoryHeader($0) } dict[240843065] = { return Api.MessageReplyHeader.parse_messageReplyStoryHeader($0) }
@ -767,6 +769,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1992950669] = { return Api.Reaction.parse_reactionCustomEmoji($0) } dict[-1992950669] = { return Api.Reaction.parse_reactionCustomEmoji($0) }
dict[455247544] = { return Api.Reaction.parse_reactionEmoji($0) } dict[455247544] = { return Api.Reaction.parse_reactionEmoji($0) }
dict[2046153753] = { return Api.Reaction.parse_reactionEmpty($0) } dict[2046153753] = { return Api.Reaction.parse_reactionEmpty($0) }
dict[1379771627] = { return Api.Reaction.parse_reactionPaid($0) }
dict[-1546531968] = { return Api.ReactionCount.parse_reactionCount($0) } dict[-1546531968] = { return Api.ReactionCount.parse_reactionCount($0) }
dict[1268654752] = { return Api.ReactionNotificationsFrom.parse_reactionNotificationsFromAll($0) } dict[1268654752] = { return Api.ReactionNotificationsFrom.parse_reactionNotificationsFromAll($0) }
dict[-1161583078] = { return Api.ReactionNotificationsFrom.parse_reactionNotificationsFromContacts($0) } dict[-1161583078] = { return Api.ReactionNotificationsFrom.parse_reactionNotificationsFromContacts($0) }
@ -881,8 +884,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) } dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
dict[1577421297] = { return Api.StarsGiftOption.parse_starsGiftOption($0) } dict[1577421297] = { return Api.StarsGiftOption.parse_starsGiftOption($0) }
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) } dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
dict[-797707802] = { return Api.StarsSubscription.parse_starsSubscription($0) }
dict[88173912] = { return Api.StarsSubscriptionPricing.parse_starsSubscriptionPricing($0) }
dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) } dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) }
dict[766853519] = { return Api.StarsTransaction.parse_starsTransaction($0) } dict[1127934763] = { return Api.StarsTransaction.parse_starsTransaction($0) }
dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) } dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) }
dict[1617438738] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAds($0) } dict[1617438738] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAds($0) }
dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) } dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) }
@ -1327,7 +1332,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[961445665] = { return Api.payments.StarsRevenueAdsAccountUrl.parse_starsRevenueAdsAccountUrl($0) } dict[961445665] = { return Api.payments.StarsRevenueAdsAccountUrl.parse_starsRevenueAdsAccountUrl($0) }
dict[-919881925] = { return Api.payments.StarsRevenueStats.parse_starsRevenueStats($0) } dict[-919881925] = { return Api.payments.StarsRevenueStats.parse_starsRevenueStats($0) }
dict[497778871] = { return Api.payments.StarsRevenueWithdrawalUrl.parse_starsRevenueWithdrawalUrl($0) } dict[497778871] = { return Api.payments.StarsRevenueWithdrawalUrl.parse_starsRevenueWithdrawalUrl($0) }
dict[-1930105248] = { return Api.payments.StarsStatus.parse_starsStatus($0) } dict[-1141231252] = { return Api.payments.StarsStatus.parse_starsStatus($0) }
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
dict[541839704] = { return Api.phone.ExportedGroupCallInvite.parse_exportedGroupCallInvite($0) } dict[541839704] = { return Api.phone.ExportedGroupCallInvite.parse_exportedGroupCallInvite($0) }
dict[-1636664659] = { return Api.phone.GroupCall.parse_groupCall($0) } dict[-1636664659] = { return Api.phone.GroupCall.parse_groupCall($0) }
@ -1402,7 +1407,7 @@ public extension Api {
return parser(reader) return parser(reader)
} }
else { else {
telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found") telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found")
return nil return nil
} }
} }
@ -1824,6 +1829,8 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.MessageReactions: case let _1 as Api.MessageReactions:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.MessageReactor:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageReplies: case let _1 as Api.MessageReplies:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.MessageReplyHeader: case let _1 as Api.MessageReplyHeader:
@ -2000,6 +2007,10 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StarsRevenueStatus: case let _1 as Api.StarsRevenueStatus:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StarsSubscription:
_1.serialize(buffer, boxed)
case let _1 as Api.StarsSubscriptionPricing:
_1.serialize(buffer, boxed)
case let _1 as Api.StarsTopupOption: case let _1 as Api.StarsTopupOption:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StarsTransaction: case let _1 as Api.StarsTransaction:

View File

@ -1,5 +1,6 @@
public extension Api { public extension Api {
indirect enum InputInvoice: TypeConstructorDescription { indirect enum InputInvoice: TypeConstructorDescription {
case inputInvoiceChatInviteSubscription(hash: String)
case inputInvoiceMessage(peer: Api.InputPeer, msgId: Int32) case inputInvoiceMessage(peer: Api.InputPeer, msgId: Int32)
case inputInvoicePremiumGiftCode(purpose: Api.InputStorePaymentPurpose, option: Api.PremiumGiftCodeOption) case inputInvoicePremiumGiftCode(purpose: Api.InputStorePaymentPurpose, option: Api.PremiumGiftCodeOption)
case inputInvoiceSlug(slug: String) case inputInvoiceSlug(slug: String)
@ -7,6 +8,12 @@ public extension Api {
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .inputInvoiceChatInviteSubscription(let hash):
if boxed {
buffer.appendInt32(887591921)
}
serializeString(hash, buffer: buffer, boxed: false)
break
case .inputInvoiceMessage(let peer, let msgId): case .inputInvoiceMessage(let peer, let msgId):
if boxed { if boxed {
buffer.appendInt32(-977967015) buffer.appendInt32(-977967015)
@ -38,6 +45,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .inputInvoiceChatInviteSubscription(let hash):
return ("inputInvoiceChatInviteSubscription", [("hash", hash as Any)])
case .inputInvoiceMessage(let peer, let msgId): case .inputInvoiceMessage(let peer, let msgId):
return ("inputInvoiceMessage", [("peer", peer as Any), ("msgId", msgId as Any)]) return ("inputInvoiceMessage", [("peer", peer as Any), ("msgId", msgId as Any)])
case .inputInvoicePremiumGiftCode(let purpose, let option): case .inputInvoicePremiumGiftCode(let purpose, let option):
@ -49,6 +58,17 @@ public extension Api {
} }
} }
public static func parse_inputInvoiceChatInviteSubscription(_ reader: BufferReader) -> InputInvoice? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.InputInvoice.inputInvoiceChatInviteSubscription(hash: _1!)
}
else {
return nil
}
}
public static func parse_inputInvoiceMessage(_ reader: BufferReader) -> InputInvoice? { public static func parse_inputInvoiceMessage(_ reader: BufferReader) -> InputInvoice? {
var _1: Api.InputPeer? var _1: Api.InputPeer?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -920,113 +940,3 @@ public extension Api {
} }
} }
public extension Api {
enum InputPaymentCredentials: TypeConstructorDescription {
case inputPaymentCredentials(flags: Int32, data: Api.DataJSON)
case inputPaymentCredentialsApplePay(paymentData: Api.DataJSON)
case inputPaymentCredentialsGooglePay(paymentToken: Api.DataJSON)
case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputPaymentCredentials(let flags, let data):
if boxed {
buffer.appendInt32(873977640)
}
serializeInt32(flags, buffer: buffer, boxed: false)
data.serialize(buffer, true)
break
case .inputPaymentCredentialsApplePay(let paymentData):
if boxed {
buffer.appendInt32(178373535)
}
paymentData.serialize(buffer, true)
break
case .inputPaymentCredentialsGooglePay(let paymentToken):
if boxed {
buffer.appendInt32(-1966921727)
}
paymentToken.serialize(buffer, true)
break
case .inputPaymentCredentialsSaved(let id, let tmpPassword):
if boxed {
buffer.appendInt32(-1056001329)
}
serializeString(id, buffer: buffer, boxed: false)
serializeBytes(tmpPassword, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputPaymentCredentials(let flags, let data):
return ("inputPaymentCredentials", [("flags", flags as Any), ("data", data as Any)])
case .inputPaymentCredentialsApplePay(let paymentData):
return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData as Any)])
case .inputPaymentCredentialsGooglePay(let paymentToken):
return ("inputPaymentCredentialsGooglePay", [("paymentToken", paymentToken as Any)])
case .inputPaymentCredentialsSaved(let id, let tmpPassword):
return ("inputPaymentCredentialsSaved", [("id", id as Any), ("tmpPassword", tmpPassword as Any)])
}
}
public static func parse_inputPaymentCredentials(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.DataJSON?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputPaymentCredentials.inputPaymentCredentials(flags: _1!, data: _2!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsApplePay(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Api.DataJSON?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
if _c1 {
return Api.InputPaymentCredentials.inputPaymentCredentialsApplePay(paymentData: _1!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsGooglePay(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Api.DataJSON?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
if _c1 {
return Api.InputPaymentCredentials.inputPaymentCredentialsGooglePay(paymentToken: _1!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsSaved(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: String?
_1 = parseString(reader)
var _2: Buffer?
_2 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputPaymentCredentials.inputPaymentCredentialsSaved(id: _1!, tmpPassword: _2!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,113 @@
public extension Api {
enum InputPaymentCredentials: TypeConstructorDescription {
case inputPaymentCredentials(flags: Int32, data: Api.DataJSON)
case inputPaymentCredentialsApplePay(paymentData: Api.DataJSON)
case inputPaymentCredentialsGooglePay(paymentToken: Api.DataJSON)
case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputPaymentCredentials(let flags, let data):
if boxed {
buffer.appendInt32(873977640)
}
serializeInt32(flags, buffer: buffer, boxed: false)
data.serialize(buffer, true)
break
case .inputPaymentCredentialsApplePay(let paymentData):
if boxed {
buffer.appendInt32(178373535)
}
paymentData.serialize(buffer, true)
break
case .inputPaymentCredentialsGooglePay(let paymentToken):
if boxed {
buffer.appendInt32(-1966921727)
}
paymentToken.serialize(buffer, true)
break
case .inputPaymentCredentialsSaved(let id, let tmpPassword):
if boxed {
buffer.appendInt32(-1056001329)
}
serializeString(id, buffer: buffer, boxed: false)
serializeBytes(tmpPassword, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputPaymentCredentials(let flags, let data):
return ("inputPaymentCredentials", [("flags", flags as Any), ("data", data as Any)])
case .inputPaymentCredentialsApplePay(let paymentData):
return ("inputPaymentCredentialsApplePay", [("paymentData", paymentData as Any)])
case .inputPaymentCredentialsGooglePay(let paymentToken):
return ("inputPaymentCredentialsGooglePay", [("paymentToken", paymentToken as Any)])
case .inputPaymentCredentialsSaved(let id, let tmpPassword):
return ("inputPaymentCredentialsSaved", [("id", id as Any), ("tmpPassword", tmpPassword as Any)])
}
}
public static func parse_inputPaymentCredentials(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.DataJSON?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputPaymentCredentials.inputPaymentCredentials(flags: _1!, data: _2!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsApplePay(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Api.DataJSON?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
if _c1 {
return Api.InputPaymentCredentials.inputPaymentCredentialsApplePay(paymentData: _1!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsGooglePay(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: Api.DataJSON?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
let _c1 = _1 != nil
if _c1 {
return Api.InputPaymentCredentials.inputPaymentCredentialsGooglePay(paymentToken: _1!)
}
else {
return nil
}
}
public static func parse_inputPaymentCredentialsSaved(_ reader: BufferReader) -> InputPaymentCredentials? {
var _1: String?
_1 = parseString(reader)
var _2: Buffer?
_2 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputPaymentCredentials.inputPaymentCredentialsSaved(id: _1!, tmpPassword: _2!)
}
else {
return nil
}
}
}
}
public extension Api { public extension Api {
indirect enum InputPeer: TypeConstructorDescription { indirect enum InputPeer: TypeConstructorDescription {
case inputPeerChannel(channelId: Int64, accessHash: Int64) case inputPeerChannel(channelId: Int64, accessHash: Int64)

View File

@ -200,13 +200,13 @@ public extension Api {
} }
public extension Api { public extension Api {
enum MessageReactions: TypeConstructorDescription { enum MessageReactions: TypeConstructorDescription {
case messageReactions(flags: Int32, results: [Api.ReactionCount], recentReactions: [Api.MessagePeerReaction]?) case messageReactions(flags: Int32, results: [Api.ReactionCount], recentReactions: [Api.MessagePeerReaction]?, topReactors: [Api.MessageReactor]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .messageReactions(let flags, let results, let recentReactions): case .messageReactions(let flags, let results, let recentReactions, let topReactors):
if boxed { if boxed {
buffer.appendInt32(1328256121) buffer.appendInt32(171155211)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
@ -219,14 +219,19 @@ public extension Api {
for item in recentReactions! { for item in recentReactions! {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(topReactors!.count))
for item in topReactors! {
item.serialize(buffer, true)
}}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .messageReactions(let flags, let results, let recentReactions): case .messageReactions(let flags, let results, let recentReactions, let topReactors):
return ("messageReactions", [("flags", flags as Any), ("results", results as Any), ("recentReactions", recentReactions as Any)]) return ("messageReactions", [("flags", flags as Any), ("results", results as Any), ("recentReactions", recentReactions as Any), ("topReactors", topReactors as Any)])
} }
} }
@ -241,11 +246,62 @@ public extension Api {
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessagePeerReaction.self) _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessagePeerReaction.self)
} } } }
var _4: [Api.MessageReactor]?
if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageReactor.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.MessageReactions.messageReactions(flags: _1!, results: _2!, recentReactions: _3, topReactors: _4)
}
else {
return nil
}
}
}
}
public extension Api {
enum MessageReactor: TypeConstructorDescription {
case messageReactor(flags: Int32, peerId: Api.Peer, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageReactor(let flags, let peerId, let count):
if boxed {
buffer.appendInt32(-285158328)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peerId.serialize(buffer, true)
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageReactor(let flags, let peerId, let count):
return ("messageReactor", [("flags", flags as Any), ("peerId", peerId as Any), ("count", count as Any)])
}
}
public static func parse_messageReactor(_ reader: BufferReader) -> MessageReactor? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 { if _c1 && _c2 && _c3 {
return Api.MessageReactions.messageReactions(flags: _1!, results: _2!, recentReactions: _3) return Api.MessageReactor.messageReactor(flags: _1!, peerId: _2!, count: _3!)
} }
else { else {
return nil return nil

View File

@ -309,6 +309,7 @@ public extension Api {
case reactionCustomEmoji(documentId: Int64) case reactionCustomEmoji(documentId: Int64)
case reactionEmoji(emoticon: String) case reactionEmoji(emoticon: String)
case reactionEmpty case reactionEmpty
case reactionPaid
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -329,6 +330,12 @@ public extension Api {
buffer.appendInt32(2046153753) buffer.appendInt32(2046153753)
} }
break
case .reactionPaid:
if boxed {
buffer.appendInt32(1379771627)
}
break break
} }
} }
@ -341,6 +348,8 @@ public extension Api {
return ("reactionEmoji", [("emoticon", emoticon as Any)]) return ("reactionEmoji", [("emoticon", emoticon as Any)])
case .reactionEmpty: case .reactionEmpty:
return ("reactionEmpty", []) return ("reactionEmpty", [])
case .reactionPaid:
return ("reactionPaid", [])
} }
} }
@ -369,6 +378,9 @@ public extension Api {
public static func parse_reactionEmpty(_ reader: BufferReader) -> Reaction? { public static func parse_reactionEmpty(_ reader: BufferReader) -> Reaction? {
return Api.Reaction.reactionEmpty return Api.Reaction.reactionEmpty
} }
public static func parse_reactionPaid(_ reader: BufferReader) -> Reaction? {
return Api.Reaction.reactionPaid
}
} }
} }
@ -858,139 +870,3 @@ public extension Api {
} }
} }
public extension Api {
enum ReportReason: TypeConstructorDescription {
case inputReportReasonChildAbuse
case inputReportReasonCopyright
case inputReportReasonFake
case inputReportReasonGeoIrrelevant
case inputReportReasonIllegalDrugs
case inputReportReasonOther
case inputReportReasonPersonalDetails
case inputReportReasonPornography
case inputReportReasonSpam
case inputReportReasonViolence
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputReportReasonChildAbuse:
if boxed {
buffer.appendInt32(-1376497949)
}
break
case .inputReportReasonCopyright:
if boxed {
buffer.appendInt32(-1685456582)
}
break
case .inputReportReasonFake:
if boxed {
buffer.appendInt32(-170010905)
}
break
case .inputReportReasonGeoIrrelevant:
if boxed {
buffer.appendInt32(-606798099)
}
break
case .inputReportReasonIllegalDrugs:
if boxed {
buffer.appendInt32(177124030)
}
break
case .inputReportReasonOther:
if boxed {
buffer.appendInt32(-1041980751)
}
break
case .inputReportReasonPersonalDetails:
if boxed {
buffer.appendInt32(-1631091139)
}
break
case .inputReportReasonPornography:
if boxed {
buffer.appendInt32(777640226)
}
break
case .inputReportReasonSpam:
if boxed {
buffer.appendInt32(1490799288)
}
break
case .inputReportReasonViolence:
if boxed {
buffer.appendInt32(505595789)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputReportReasonChildAbuse:
return ("inputReportReasonChildAbuse", [])
case .inputReportReasonCopyright:
return ("inputReportReasonCopyright", [])
case .inputReportReasonFake:
return ("inputReportReasonFake", [])
case .inputReportReasonGeoIrrelevant:
return ("inputReportReasonGeoIrrelevant", [])
case .inputReportReasonIllegalDrugs:
return ("inputReportReasonIllegalDrugs", [])
case .inputReportReasonOther:
return ("inputReportReasonOther", [])
case .inputReportReasonPersonalDetails:
return ("inputReportReasonPersonalDetails", [])
case .inputReportReasonPornography:
return ("inputReportReasonPornography", [])
case .inputReportReasonSpam:
return ("inputReportReasonSpam", [])
case .inputReportReasonViolence:
return ("inputReportReasonViolence", [])
}
}
public static func parse_inputReportReasonChildAbuse(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonChildAbuse
}
public static func parse_inputReportReasonCopyright(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonCopyright
}
public static func parse_inputReportReasonFake(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonFake
}
public static func parse_inputReportReasonGeoIrrelevant(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonGeoIrrelevant
}
public static func parse_inputReportReasonIllegalDrugs(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonIllegalDrugs
}
public static func parse_inputReportReasonOther(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonOther
}
public static func parse_inputReportReasonPersonalDetails(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonPersonalDetails
}
public static func parse_inputReportReasonPornography(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonPornography
}
public static func parse_inputReportReasonSpam(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonSpam
}
public static func parse_inputReportReasonViolence(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonViolence
}
}
}

View File

@ -1,3 +1,139 @@
public extension Api {
enum ReportReason: TypeConstructorDescription {
case inputReportReasonChildAbuse
case inputReportReasonCopyright
case inputReportReasonFake
case inputReportReasonGeoIrrelevant
case inputReportReasonIllegalDrugs
case inputReportReasonOther
case inputReportReasonPersonalDetails
case inputReportReasonPornography
case inputReportReasonSpam
case inputReportReasonViolence
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputReportReasonChildAbuse:
if boxed {
buffer.appendInt32(-1376497949)
}
break
case .inputReportReasonCopyright:
if boxed {
buffer.appendInt32(-1685456582)
}
break
case .inputReportReasonFake:
if boxed {
buffer.appendInt32(-170010905)
}
break
case .inputReportReasonGeoIrrelevant:
if boxed {
buffer.appendInt32(-606798099)
}
break
case .inputReportReasonIllegalDrugs:
if boxed {
buffer.appendInt32(177124030)
}
break
case .inputReportReasonOther:
if boxed {
buffer.appendInt32(-1041980751)
}
break
case .inputReportReasonPersonalDetails:
if boxed {
buffer.appendInt32(-1631091139)
}
break
case .inputReportReasonPornography:
if boxed {
buffer.appendInt32(777640226)
}
break
case .inputReportReasonSpam:
if boxed {
buffer.appendInt32(1490799288)
}
break
case .inputReportReasonViolence:
if boxed {
buffer.appendInt32(505595789)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputReportReasonChildAbuse:
return ("inputReportReasonChildAbuse", [])
case .inputReportReasonCopyright:
return ("inputReportReasonCopyright", [])
case .inputReportReasonFake:
return ("inputReportReasonFake", [])
case .inputReportReasonGeoIrrelevant:
return ("inputReportReasonGeoIrrelevant", [])
case .inputReportReasonIllegalDrugs:
return ("inputReportReasonIllegalDrugs", [])
case .inputReportReasonOther:
return ("inputReportReasonOther", [])
case .inputReportReasonPersonalDetails:
return ("inputReportReasonPersonalDetails", [])
case .inputReportReasonPornography:
return ("inputReportReasonPornography", [])
case .inputReportReasonSpam:
return ("inputReportReasonSpam", [])
case .inputReportReasonViolence:
return ("inputReportReasonViolence", [])
}
}
public static func parse_inputReportReasonChildAbuse(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonChildAbuse
}
public static func parse_inputReportReasonCopyright(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonCopyright
}
public static func parse_inputReportReasonFake(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonFake
}
public static func parse_inputReportReasonGeoIrrelevant(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonGeoIrrelevant
}
public static func parse_inputReportReasonIllegalDrugs(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonIllegalDrugs
}
public static func parse_inputReportReasonOther(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonOther
}
public static func parse_inputReportReasonPersonalDetails(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonPersonalDetails
}
public static func parse_inputReportReasonPornography(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonPornography
}
public static func parse_inputReportReasonSpam(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonSpam
}
public static func parse_inputReportReasonViolence(_ reader: BufferReader) -> ReportReason? {
return Api.ReportReason.inputReportReasonViolence
}
}
}
public extension Api { public extension Api {
enum RequestPeerType: TypeConstructorDescription { enum RequestPeerType: TypeConstructorDescription {
case requestPeerTypeBroadcast(flags: Int32, hasUsername: Api.Bool?, userAdminRights: Api.ChatAdminRights?, botAdminRights: Api.ChatAdminRights?) case requestPeerTypeBroadcast(flags: Int32, hasUsername: Api.Bool?, userAdminRights: Api.ChatAdminRights?, botAdminRights: Api.ChatAdminRights?)
@ -688,399 +824,3 @@ public extension Api {
} }
} }
public extension Api {
enum SavedContact: TypeConstructorDescription {
case savedPhoneContact(phone: String, firstName: String, lastName: String, date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedPhoneContact(let phone, let firstName, let lastName, let date):
if boxed {
buffer.appendInt32(289586518)
}
serializeString(phone, buffer: buffer, boxed: false)
serializeString(firstName, buffer: buffer, boxed: false)
serializeString(lastName, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedPhoneContact(let phone, let firstName, let lastName, let date):
return ("savedPhoneContact", [("phone", phone as Any), ("firstName", firstName as Any), ("lastName", lastName as Any), ("date", date as Any)])
}
}
public static func parse_savedPhoneContact(_ reader: BufferReader) -> SavedContact? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
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.SavedContact.savedPhoneContact(phone: _1!, firstName: _2!, lastName: _3!, date: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SavedDialog: TypeConstructorDescription {
case savedDialog(flags: Int32, peer: Api.Peer, topMessage: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
if boxed {
buffer.appendInt32(-1115174036)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(topMessage, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
return ("savedDialog", [("flags", flags as Any), ("peer", peer as Any), ("topMessage", topMessage as Any)])
}
}
public static func parse_savedDialog(_ reader: BufferReader) -> SavedDialog? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SavedDialog.savedDialog(flags: _1!, peer: _2!, topMessage: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SavedReactionTag: TypeConstructorDescription {
case savedReactionTag(flags: Int32, reaction: Api.Reaction, title: String?, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedReactionTag(let flags, let reaction, let title, let count):
if boxed {
buffer.appendInt32(-881854424)
}
serializeInt32(flags, buffer: buffer, boxed: false)
reaction.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedReactionTag(let flags, let reaction, let title, let count):
return ("savedReactionTag", [("flags", flags as Any), ("reaction", reaction as Any), ("title", title as Any), ("count", count as Any)])
}
}
public static func parse_savedReactionTag(_ reader: BufferReader) -> SavedReactionTag? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Reaction?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Reaction
}
var _3: String?
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
var _4: Int32?
_4 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.SavedReactionTag.savedReactionTag(flags: _1!, reaction: _2!, title: _3, count: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsCalendarPeriod: TypeConstructorDescription {
case searchResultsCalendarPeriod(date: Int32, minMsgId: Int32, maxMsgId: Int32, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsCalendarPeriod(let date, let minMsgId, let maxMsgId, let count):
if boxed {
buffer.appendInt32(-911191137)
}
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(minMsgId, buffer: buffer, boxed: false)
serializeInt32(maxMsgId, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsCalendarPeriod(let date, let minMsgId, let maxMsgId, let count):
return ("searchResultsCalendarPeriod", [("date", date as Any), ("minMsgId", minMsgId as Any), ("maxMsgId", maxMsgId as Any), ("count", count as Any)])
}
}
public static func parse_searchResultsCalendarPeriod(_ reader: BufferReader) -> SearchResultsCalendarPeriod? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
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.SearchResultsCalendarPeriod.searchResultsCalendarPeriod(date: _1!, minMsgId: _2!, maxMsgId: _3!, count: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsPosition: TypeConstructorDescription {
case searchResultPosition(msgId: Int32, date: Int32, offset: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultPosition(let msgId, let date, let offset):
if boxed {
buffer.appendInt32(2137295719)
}
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(offset, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultPosition(let msgId, let date, let offset):
return ("searchResultPosition", [("msgId", msgId as Any), ("date", date as Any), ("offset", offset as Any)])
}
}
public static func parse_searchResultPosition(_ reader: BufferReader) -> SearchResultsPosition? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SearchResultsPosition.searchResultPosition(msgId: _1!, date: _2!, offset: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureCredentialsEncrypted: TypeConstructorDescription {
case secureCredentialsEncrypted(data: Buffer, hash: Buffer, secret: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureCredentialsEncrypted(let data, let hash, let secret):
if boxed {
buffer.appendInt32(871426631)
}
serializeBytes(data, buffer: buffer, boxed: false)
serializeBytes(hash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureCredentialsEncrypted(let data, let hash, let secret):
return ("secureCredentialsEncrypted", [("data", data as Any), ("hash", hash as Any), ("secret", secret as Any)])
}
}
public static func parse_secureCredentialsEncrypted(_ reader: BufferReader) -> SecureCredentialsEncrypted? {
var _1: Buffer?
_1 = parseBytes(reader)
var _2: Buffer?
_2 = parseBytes(reader)
var _3: Buffer?
_3 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SecureCredentialsEncrypted.secureCredentialsEncrypted(data: _1!, hash: _2!, secret: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureData: TypeConstructorDescription {
case secureData(data: Buffer, dataHash: Buffer, secret: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureData(let data, let dataHash, let secret):
if boxed {
buffer.appendInt32(-1964327229)
}
serializeBytes(data, buffer: buffer, boxed: false)
serializeBytes(dataHash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureData(let data, let dataHash, let secret):
return ("secureData", [("data", data as Any), ("dataHash", dataHash as Any), ("secret", secret as Any)])
}
}
public static func parse_secureData(_ reader: BufferReader) -> SecureData? {
var _1: Buffer?
_1 = parseBytes(reader)
var _2: Buffer?
_2 = parseBytes(reader)
var _3: Buffer?
_3 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SecureData.secureData(data: _1!, dataHash: _2!, secret: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureFile: TypeConstructorDescription {
case secureFile(id: Int64, accessHash: Int64, size: Int64, dcId: Int32, date: Int32, fileHash: Buffer, secret: Buffer)
case secureFileEmpty
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret):
if boxed {
buffer.appendInt32(2097791614)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeInt64(size, buffer: buffer, boxed: false)
serializeInt32(dcId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeBytes(fileHash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
case .secureFileEmpty:
if boxed {
buffer.appendInt32(1679398724)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret):
return ("secureFile", [("id", id as Any), ("accessHash", accessHash as Any), ("size", size as Any), ("dcId", dcId as Any), ("date", date as Any), ("fileHash", fileHash as Any), ("secret", secret as Any)])
case .secureFileEmpty:
return ("secureFileEmpty", [])
}
}
public static func parse_secureFile(_ reader: BufferReader) -> SecureFile? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Buffer?
_6 = parseBytes(reader)
var _7: Buffer?
_7 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.SecureFile.secureFile(id: _1!, accessHash: _2!, size: _3!, dcId: _4!, date: _5!, fileHash: _6!, secret: _7!)
}
else {
return nil
}
}
public static func parse_secureFileEmpty(_ reader: BufferReader) -> SecureFile? {
return Api.SecureFile.secureFileEmpty
}
}
}

View File

@ -1,3 +1,399 @@
public extension Api {
enum SavedContact: TypeConstructorDescription {
case savedPhoneContact(phone: String, firstName: String, lastName: String, date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedPhoneContact(let phone, let firstName, let lastName, let date):
if boxed {
buffer.appendInt32(289586518)
}
serializeString(phone, buffer: buffer, boxed: false)
serializeString(firstName, buffer: buffer, boxed: false)
serializeString(lastName, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedPhoneContact(let phone, let firstName, let lastName, let date):
return ("savedPhoneContact", [("phone", phone as Any), ("firstName", firstName as Any), ("lastName", lastName as Any), ("date", date as Any)])
}
}
public static func parse_savedPhoneContact(_ reader: BufferReader) -> SavedContact? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
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.SavedContact.savedPhoneContact(phone: _1!, firstName: _2!, lastName: _3!, date: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SavedDialog: TypeConstructorDescription {
case savedDialog(flags: Int32, peer: Api.Peer, topMessage: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
if boxed {
buffer.appendInt32(-1115174036)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(topMessage, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedDialog(let flags, let peer, let topMessage):
return ("savedDialog", [("flags", flags as Any), ("peer", peer as Any), ("topMessage", topMessage as Any)])
}
}
public static func parse_savedDialog(_ reader: BufferReader) -> SavedDialog? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SavedDialog.savedDialog(flags: _1!, peer: _2!, topMessage: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SavedReactionTag: TypeConstructorDescription {
case savedReactionTag(flags: Int32, reaction: Api.Reaction, title: String?, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedReactionTag(let flags, let reaction, let title, let count):
if boxed {
buffer.appendInt32(-881854424)
}
serializeInt32(flags, buffer: buffer, boxed: false)
reaction.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedReactionTag(let flags, let reaction, let title, let count):
return ("savedReactionTag", [("flags", flags as Any), ("reaction", reaction as Any), ("title", title as Any), ("count", count as Any)])
}
}
public static func parse_savedReactionTag(_ reader: BufferReader) -> SavedReactionTag? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Reaction?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Reaction
}
var _3: String?
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
var _4: Int32?
_4 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.SavedReactionTag.savedReactionTag(flags: _1!, reaction: _2!, title: _3, count: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsCalendarPeriod: TypeConstructorDescription {
case searchResultsCalendarPeriod(date: Int32, minMsgId: Int32, maxMsgId: Int32, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsCalendarPeriod(let date, let minMsgId, let maxMsgId, let count):
if boxed {
buffer.appendInt32(-911191137)
}
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(minMsgId, buffer: buffer, boxed: false)
serializeInt32(maxMsgId, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsCalendarPeriod(let date, let minMsgId, let maxMsgId, let count):
return ("searchResultsCalendarPeriod", [("date", date as Any), ("minMsgId", minMsgId as Any), ("maxMsgId", maxMsgId as Any), ("count", count as Any)])
}
}
public static func parse_searchResultsCalendarPeriod(_ reader: BufferReader) -> SearchResultsCalendarPeriod? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
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.SearchResultsCalendarPeriod.searchResultsCalendarPeriod(date: _1!, minMsgId: _2!, maxMsgId: _3!, count: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SearchResultsPosition: TypeConstructorDescription {
case searchResultPosition(msgId: Int32, date: Int32, offset: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultPosition(let msgId, let date, let offset):
if boxed {
buffer.appendInt32(2137295719)
}
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt32(offset, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultPosition(let msgId, let date, let offset):
return ("searchResultPosition", [("msgId", msgId as Any), ("date", date as Any), ("offset", offset as Any)])
}
}
public static func parse_searchResultPosition(_ reader: BufferReader) -> SearchResultsPosition? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SearchResultsPosition.searchResultPosition(msgId: _1!, date: _2!, offset: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureCredentialsEncrypted: TypeConstructorDescription {
case secureCredentialsEncrypted(data: Buffer, hash: Buffer, secret: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureCredentialsEncrypted(let data, let hash, let secret):
if boxed {
buffer.appendInt32(871426631)
}
serializeBytes(data, buffer: buffer, boxed: false)
serializeBytes(hash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureCredentialsEncrypted(let data, let hash, let secret):
return ("secureCredentialsEncrypted", [("data", data as Any), ("hash", hash as Any), ("secret", secret as Any)])
}
}
public static func parse_secureCredentialsEncrypted(_ reader: BufferReader) -> SecureCredentialsEncrypted? {
var _1: Buffer?
_1 = parseBytes(reader)
var _2: Buffer?
_2 = parseBytes(reader)
var _3: Buffer?
_3 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SecureCredentialsEncrypted.secureCredentialsEncrypted(data: _1!, hash: _2!, secret: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureData: TypeConstructorDescription {
case secureData(data: Buffer, dataHash: Buffer, secret: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureData(let data, let dataHash, let secret):
if boxed {
buffer.appendInt32(-1964327229)
}
serializeBytes(data, buffer: buffer, boxed: false)
serializeBytes(dataHash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureData(let data, let dataHash, let secret):
return ("secureData", [("data", data as Any), ("dataHash", dataHash as Any), ("secret", secret as Any)])
}
}
public static func parse_secureData(_ reader: BufferReader) -> SecureData? {
var _1: Buffer?
_1 = parseBytes(reader)
var _2: Buffer?
_2 = parseBytes(reader)
var _3: Buffer?
_3 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.SecureData.secureData(data: _1!, dataHash: _2!, secret: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum SecureFile: TypeConstructorDescription {
case secureFile(id: Int64, accessHash: Int64, size: Int64, dcId: Int32, date: Int32, fileHash: Buffer, secret: Buffer)
case secureFileEmpty
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret):
if boxed {
buffer.appendInt32(2097791614)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeInt64(size, buffer: buffer, boxed: false)
serializeInt32(dcId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeBytes(fileHash, buffer: buffer, boxed: false)
serializeBytes(secret, buffer: buffer, boxed: false)
break
case .secureFileEmpty:
if boxed {
buffer.appendInt32(1679398724)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .secureFile(let id, let accessHash, let size, let dcId, let date, let fileHash, let secret):
return ("secureFile", [("id", id as Any), ("accessHash", accessHash as Any), ("size", size as Any), ("dcId", dcId as Any), ("date", date as Any), ("fileHash", fileHash as Any), ("secret", secret as Any)])
case .secureFileEmpty:
return ("secureFileEmpty", [])
}
}
public static func parse_secureFile(_ reader: BufferReader) -> SecureFile? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Buffer?
_6 = parseBytes(reader)
var _7: Buffer?
_7 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.SecureFile.secureFile(id: _1!, accessHash: _2!, size: _3!, dcId: _4!, date: _5!, fileHash: _6!, secret: _7!)
}
else {
return nil
}
}
public static func parse_secureFileEmpty(_ reader: BufferReader) -> SecureFile? {
return Api.SecureFile.secureFileEmpty
}
}
}
public extension Api { public extension Api {
enum SecurePasswordKdfAlgo: TypeConstructorDescription { enum SecurePasswordKdfAlgo: TypeConstructorDescription {
case securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt: Buffer) case securePasswordKdfAlgoPBKDF2HMACSHA512iter100000(salt: Buffer)

View File

@ -670,6 +670,102 @@ public extension Api {
} }
} }
public extension Api {
enum StarsSubscription: TypeConstructorDescription {
case starsSubscription(flags: Int32, id: String, peer: Api.Peer, untilDate: Int32, pricing: Api.StarsSubscriptionPricing)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsSubscription(let flags, let id, let peer, let untilDate, let pricing):
if boxed {
buffer.appendInt32(-797707802)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(id, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(untilDate, buffer: buffer, boxed: false)
pricing.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsSubscription(let flags, let id, let peer, let untilDate, let pricing):
return ("starsSubscription", [("flags", flags as Any), ("id", id as Any), ("peer", peer as Any), ("untilDate", untilDate as Any), ("pricing", pricing as Any)])
}
}
public static func parse_starsSubscription(_ reader: BufferReader) -> StarsSubscription? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Api.Peer?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _4: Int32?
_4 = reader.readInt32()
var _5: Api.StarsSubscriptionPricing?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.StarsSubscriptionPricing
}
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.StarsSubscription.starsSubscription(flags: _1!, id: _2!, peer: _3!, untilDate: _4!, pricing: _5!)
}
else {
return nil
}
}
}
}
public extension Api {
enum StarsSubscriptionPricing: TypeConstructorDescription {
case starsSubscriptionPricing(period: Int32, amount: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsSubscriptionPricing(let period, let amount):
if boxed {
buffer.appendInt32(88173912)
}
serializeInt32(period, buffer: buffer, boxed: false)
serializeInt64(amount, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsSubscriptionPricing(let period, let amount):
return ("starsSubscriptionPricing", [("period", period as Any), ("amount", amount as Any)])
}
}
public static func parse_starsSubscriptionPricing(_ reader: BufferReader) -> StarsSubscriptionPricing? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StarsSubscriptionPricing.starsSubscriptionPricing(period: _1!, amount: _2!)
}
else {
return nil
}
}
}
}
public extension Api { public extension Api {
enum StarsTopupOption: TypeConstructorDescription { enum StarsTopupOption: TypeConstructorDescription {
case starsTopupOption(flags: Int32, stars: Int64, storeProduct: String?, currency: String, amount: Int64) case starsTopupOption(flags: Int32, stars: Int64, storeProduct: String?, currency: String, amount: Int64)
@ -724,13 +820,13 @@ public extension Api {
} }
public extension Api { public extension Api {
enum StarsTransaction: TypeConstructorDescription { enum StarsTransaction: TypeConstructorDescription {
case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?) case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?, subscriptionPeriod: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia): case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod):
if boxed { if boxed {
buffer.appendInt32(766853519) buffer.appendInt32(1127934763)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(id, buffer: buffer, boxed: false) serializeString(id, buffer: buffer, boxed: false)
@ -749,14 +845,15 @@ public extension Api {
for item in extendedMedia! { for item in extendedMedia! {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
if Int(flags) & Int(1 << 12) != 0 {serializeInt32(subscriptionPeriod!, buffer: buffer, boxed: false)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia): case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod):
return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any)]) return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any), ("subscriptionPeriod", subscriptionPeriod as Any)])
} }
} }
@ -793,6 +890,8 @@ public extension Api {
if Int(_1!) & Int(1 << 9) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 9) != 0 {if let _ = reader.readInt32() {
_13 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageMedia.self) _13 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageMedia.self)
} } } }
var _14: Int32?
if Int(_1!) & Int(1 << 12) != 0 {_14 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -806,8 +905,9 @@ public extension Api {
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 9) == 0) || _13 != nil let _c13 = (Int(_1!) & Int(1 << 9) == 0) || _13 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { let _c14 = (Int(_1!) & Int(1 << 12) == 0) || _14 != nil
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13, subscriptionPeriod: _14)
} }
else { else {
return nil return nil

View File

@ -1246,21 +1246,28 @@ public extension Api.payments {
} }
public extension Api.payments { public extension Api.payments {
enum StarsStatus: TypeConstructorDescription { enum StarsStatus: TypeConstructorDescription {
case starsStatus(flags: Int32, balance: Int64, history: [Api.StarsTransaction], nextOffset: String?, chats: [Api.Chat], users: [Api.User]) case starsStatus(flags: Int32, balance: Int64, subscriptions: [Api.StarsSubscription]?, subscriptionsNextOffset: String?, subscriptionsMissingBalance: Int64?, history: [Api.StarsTransaction]?, nextOffset: String?, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .starsStatus(let flags, let balance, let history, let nextOffset, let chats, let users): case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
if boxed { if boxed {
buffer.appendInt32(-1930105248) buffer.appendInt32(-1141231252)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(balance, buffer: buffer, boxed: false) serializeInt64(balance, buffer: buffer, boxed: false)
buffer.appendInt32(481674261) if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(history.count)) buffer.appendInt32(Int32(subscriptions!.count))
for item in history { for item in subscriptions! {
item.serialize(buffer, true) item.serialize(buffer, true)
} }}
if Int(flags) & Int(1 << 2) != 0 {serializeString(subscriptionsNextOffset!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(subscriptionsMissingBalance!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(history!.count))
for item in history! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count)) buffer.appendInt32(Int32(chats.count))
@ -1278,8 +1285,8 @@ public extension Api.payments {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .starsStatus(let flags, let balance, let history, let nextOffset, let chats, let users): case .starsStatus(let flags, let balance, let subscriptions, let subscriptionsNextOffset, let subscriptionsMissingBalance, let history, let nextOffset, let chats, let users):
return ("starsStatus", [("flags", flags as Any), ("balance", balance as Any), ("history", history as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)]) return ("starsStatus", [("flags", flags as Any), ("balance", balance as Any), ("subscriptions", subscriptions as Any), ("subscriptionsNextOffset", subscriptionsNextOffset as Any), ("subscriptionsMissingBalance", subscriptionsMissingBalance as Any), ("history", history as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
} }
} }
@ -1288,28 +1295,39 @@ public extension Api.payments {
_1 = reader.readInt32() _1 = reader.readInt32()
var _2: Int64? var _2: Int64?
_2 = reader.readInt64() _2 = reader.readInt64()
var _3: [Api.StarsTransaction]? var _3: [Api.StarsSubscription]?
if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsTransaction.self) _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsSubscription.self)
} } }
var _4: String? var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } if Int(_1!) & Int(1 << 2) != 0 {_4 = parseString(reader) }
var _5: [Api.Chat]? var _5: Int64?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt64() }
var _6: [Api.StarsTransaction]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarsTransaction.self)
} }
var _7: String?
if Int(_1!) & Int(1 << 0) != 0 {_7 = parseString(reader) }
var _8: [Api.Chat]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
} }
var _6: [Api.User]? var _9: [Api.User]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
let _c5 = _5 != nil let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = _6 != nil let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil
return Api.payments.StarsStatus.starsStatus(flags: _1!, balance: _2!, history: _3!, nextOffset: _4, chats: _5!, users: _6!) let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.payments.StarsStatus.starsStatus(flags: _1!, balance: _2!, subscriptions: _3, subscriptionsNextOffset: _4, subscriptionsMissingBalance: _5, history: _6, nextOffset: _7, chats: _8!, users: _9!)
} }
else { else {
return nil return nil

View File

@ -5439,15 +5439,16 @@ public extension Api.functions.messages {
} }
} }
public extension Api.functions.messages { public extension Api.functions.messages {
static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?, title: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) { static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?, title: String?, subscriptionPricing: Api.StarsSubscriptionPricing?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-1607670315) buffer.appendInt32(-1537876336)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeString(title!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("expireDate", String(describing: expireDate)), ("usageLimit", String(describing: usageLimit)), ("title", String(describing: title))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in if Int(flags) & Int(1 << 5) != 0 {subscriptionPricing!.serialize(buffer, true)}
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("expireDate", String(describing: expireDate)), ("usageLimit", String(describing: usageLimit)), ("title", String(describing: title)), ("subscriptionPricing", String(describing: subscriptionPricing))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite? var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -7933,6 +7934,24 @@ public extension Api.functions.messages {
}) })
} }
} }
public extension Api.functions.messages {
static func sendPaidReaction(peer: Api.InputPeer, msgId: Int32, count: Int32, randomId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(508941107)
peer.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt64(randomId, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.sendPaidReaction", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("count", String(describing: count)), ("randomId", String(describing: randomId))]), 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.messages { public extension Api.functions.messages {
static func sendQuickReplyMessages(peer: Api.InputPeer, shortcutId: Int32, id: [Int32], randomId: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) { static func sendQuickReplyMessages(peer: Api.InputPeer, shortcutId: Int32, id: [Int32], randomId: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer() let buffer = Buffer()
@ -8132,14 +8151,15 @@ public extension Api.functions.messages {
} }
} }
public extension Api.functions.messages { public extension Api.functions.messages {
static func setChatAvailableReactions(flags: Int32, peer: Api.InputPeer, availableReactions: Api.ChatReactions, reactionsLimit: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) { static func setChatAvailableReactions(flags: Int32, peer: Api.InputPeer, availableReactions: Api.ChatReactions, reactionsLimit: Int32?, paidEnabled: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1511328724) buffer.appendInt32(-2041895551)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
availableReactions.serialize(buffer, true) availableReactions.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(reactionsLimit!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeInt32(reactionsLimit!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.setChatAvailableReactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("availableReactions", String(describing: availableReactions)), ("reactionsLimit", String(describing: reactionsLimit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in if Int(flags) & Int(1 << 1) != 0 {paidEnabled!.serialize(buffer, true)}
return (FunctionDescription(name: "messages.setChatAvailableReactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("availableReactions", String(describing: availableReactions)), ("reactionsLimit", String(describing: reactionsLimit)), ("paidEnabled", String(describing: paidEnabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.Updates? var result: Api.Updates?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -8735,6 +8755,24 @@ public extension Api.functions.payments {
}) })
} }
} }
public extension Api.functions.payments {
static func changeStarsSubscription(flags: Int32, peer: Api.InputPeer, subscriptionId: String, canceled: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-948500360)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeString(subscriptionId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {canceled!.serialize(buffer, true)}
return (FunctionDescription(name: "payments.changeStarsSubscription", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("subscriptionId", String(describing: subscriptionId)), ("canceled", String(describing: canceled))]), 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.payments { public extension Api.functions.payments {
static func checkGiftCode(slug: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.CheckedGiftCode>) { static func checkGiftCode(slug: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.CheckedGiftCode>) {
let buffer = Buffer() let buffer = Buffer()
@ -8780,6 +8818,22 @@ public extension Api.functions.payments {
}) })
} }
} }
public extension Api.functions.payments {
static func fulfillStarsSubscription(peer: Api.InputPeer, subscriptionId: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-866391117)
peer.serialize(buffer, true)
serializeString(subscriptionId, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.fulfillStarsSubscription", parameters: [("peer", String(describing: peer)), ("subscriptionId", String(describing: subscriptionId))]), 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.payments { public extension Api.functions.payments {
static func getBankCardData(number: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.BankCardData>) { static func getBankCardData(number: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.BankCardData>) {
let buffer = Buffer() let buffer = Buffer()
@ -8954,6 +9008,23 @@ public extension Api.functions.payments {
}) })
} }
} }
public extension Api.functions.payments {
static func getStarsSubscriptions(flags: Int32, peer: Api.InputPeer, offset: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.StarsStatus>) {
let buffer = Buffer()
buffer.appendInt32(52761285)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeString(offset, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.getStarsSubscriptions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("offset", String(describing: offset))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in
let reader = BufferReader(buffer)
var result: Api.payments.StarsStatus?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.payments.StarsStatus
}
return result
})
}
}
public extension Api.functions.payments { public extension Api.functions.payments {
static func getStarsTopupOptions() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.StarsTopupOption]>) { static func getStarsTopupOptions() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.StarsTopupOption]>) {
let buffer = Buffer() let buffer = Buffer()
@ -8970,14 +9041,15 @@ public extension Api.functions.payments {
} }
} }
public extension Api.functions.payments { public extension Api.functions.payments {
static func getStarsTransactions(flags: Int32, peer: Api.InputPeer, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.StarsStatus>) { static func getStarsTransactions(flags: Int32, subscriptionId: String?, peer: Api.InputPeer, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.StarsStatus>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-1751937702) buffer.appendInt32(1775912279)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {serializeString(subscriptionId!, buffer: buffer, boxed: false)}
peer.serialize(buffer, true) peer.serialize(buffer, true)
serializeString(offset, buffer: buffer, boxed: false) serializeString(offset, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false) serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.getStarsTransactions", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in return (FunctionDescription(name: "payments.getStarsTransactions", parameters: [("flags", String(describing: flags)), ("subscriptionId", String(describing: subscriptionId)), ("peer", String(describing: peer)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarsStatus? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.payments.StarsStatus? var result: Api.payments.StarsStatus?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {

View File

@ -148,21 +148,23 @@ public extension Api {
} }
public extension Api { public extension Api {
enum ChannelParticipant: TypeConstructorDescription { enum ChannelParticipant: TypeConstructorDescription {
case channelParticipant(userId: Int64, date: Int32) case channelParticipant(flags: Int32, userId: Int64, date: Int32, subscriptionUntilDate: Int32?)
case channelParticipantAdmin(flags: Int32, userId: Int64, inviterId: Int64?, promotedBy: Int64, date: Int32, adminRights: Api.ChatAdminRights, rank: String?) case channelParticipantAdmin(flags: Int32, userId: Int64, inviterId: Int64?, promotedBy: Int64, date: Int32, adminRights: Api.ChatAdminRights, rank: String?)
case channelParticipantBanned(flags: Int32, peer: Api.Peer, kickedBy: Int64, date: Int32, bannedRights: Api.ChatBannedRights) case channelParticipantBanned(flags: Int32, peer: Api.Peer, kickedBy: Int64, date: Int32, bannedRights: Api.ChatBannedRights)
case channelParticipantCreator(flags: Int32, userId: Int64, adminRights: Api.ChatAdminRights, rank: String?) case channelParticipantCreator(flags: Int32, userId: Int64, adminRights: Api.ChatAdminRights, rank: String?)
case channelParticipantLeft(peer: Api.Peer) case channelParticipantLeft(peer: Api.Peer)
case channelParticipantSelf(flags: Int32, userId: Int64, inviterId: Int64, date: Int32) case channelParticipantSelf(flags: Int32, userId: Int64, inviterId: Int64, date: Int32, subscriptionUntilDate: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .channelParticipant(let userId, let date): case .channelParticipant(let flags, let userId, let date, let subscriptionUntilDate):
if boxed { if boxed {
buffer.appendInt32(-1072953408) buffer.appendInt32(-885426663)
} }
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false) serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(subscriptionUntilDate!, buffer: buffer, boxed: false)}
break break
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank): case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank):
if boxed { if boxed {
@ -201,22 +203,23 @@ public extension Api {
} }
peer.serialize(buffer, true) peer.serialize(buffer, true)
break break
case .channelParticipantSelf(let flags, let userId, let inviterId, let date): case .channelParticipantSelf(let flags, let userId, let inviterId, let date, let subscriptionUntilDate):
if boxed { if boxed {
buffer.appendInt32(900251559) buffer.appendInt32(1331723247)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false) serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt64(inviterId, buffer: buffer, boxed: false) serializeInt64(inviterId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(subscriptionUntilDate!, buffer: buffer, boxed: false)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .channelParticipant(let userId, let date): case .channelParticipant(let flags, let userId, let date, let subscriptionUntilDate):
return ("channelParticipant", [("userId", userId as Any), ("date", date as Any)]) return ("channelParticipant", [("flags", flags as Any), ("userId", userId as Any), ("date", date as Any), ("subscriptionUntilDate", subscriptionUntilDate as Any)])
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank): case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank):
return ("channelParticipantAdmin", [("flags", flags as Any), ("userId", userId as Any), ("inviterId", inviterId as Any), ("promotedBy", promotedBy as Any), ("date", date as Any), ("adminRights", adminRights as Any), ("rank", rank as Any)]) return ("channelParticipantAdmin", [("flags", flags as Any), ("userId", userId as Any), ("inviterId", inviterId as Any), ("promotedBy", promotedBy as Any), ("date", date as Any), ("adminRights", adminRights as Any), ("rank", rank as Any)])
case .channelParticipantBanned(let flags, let peer, let kickedBy, let date, let bannedRights): case .channelParticipantBanned(let flags, let peer, let kickedBy, let date, let bannedRights):
@ -225,20 +228,26 @@ public extension Api {
return ("channelParticipantCreator", [("flags", flags as Any), ("userId", userId as Any), ("adminRights", adminRights as Any), ("rank", rank as Any)]) return ("channelParticipantCreator", [("flags", flags as Any), ("userId", userId as Any), ("adminRights", adminRights as Any), ("rank", rank as Any)])
case .channelParticipantLeft(let peer): case .channelParticipantLeft(let peer):
return ("channelParticipantLeft", [("peer", peer as Any)]) return ("channelParticipantLeft", [("peer", peer as Any)])
case .channelParticipantSelf(let flags, let userId, let inviterId, let date): case .channelParticipantSelf(let flags, let userId, let inviterId, let date, let subscriptionUntilDate):
return ("channelParticipantSelf", [("flags", flags as Any), ("userId", userId as Any), ("inviterId", inviterId as Any), ("date", date as Any)]) return ("channelParticipantSelf", [("flags", flags as Any), ("userId", userId as Any), ("inviterId", inviterId as Any), ("date", date as Any), ("subscriptionUntilDate", subscriptionUntilDate as Any)])
} }
} }
public static func parse_channelParticipant(_ reader: BufferReader) -> ChannelParticipant? { public static func parse_channelParticipant(_ reader: BufferReader) -> ChannelParticipant? {
var _1: Int64? var _1: Int32?
_1 = reader.readInt64() _1 = reader.readInt32()
var _2: Int32? var _2: Int64?
_2 = reader.readInt32() _2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
if _c1 && _c2 { let _c3 = _3 != nil
return Api.ChannelParticipant.channelParticipant(userId: _1!, date: _2!) let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.ChannelParticipant.channelParticipant(flags: _1!, userId: _2!, date: _3!, subscriptionUntilDate: _4)
} }
else { else {
return nil return nil
@ -346,12 +355,15 @@ public extension Api {
_3 = reader.readInt64() _3 = reader.readInt64()
var _4: Int32? var _4: Int32?
_4 = reader.readInt32() _4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = _4 != nil let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 { let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
return Api.ChannelParticipant.channelParticipantSelf(flags: _1!, userId: _2!, inviterId: _3!, date: _4!) if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChannelParticipant.channelParticipantSelf(flags: _1!, userId: _2!, inviterId: _3!, date: _4!, subscriptionUntilDate: _5)
} }
else { else {
return nil return nil
@ -522,7 +534,7 @@ public extension Api {
} }
public extension Api { public extension Api {
indirect enum Chat: TypeConstructorDescription { indirect enum Chat: TypeConstructorDescription {
case channel(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, title: String, username: String?, photo: Api.ChatPhoto, date: Int32, restrictionReason: [Api.RestrictionReason]?, adminRights: Api.ChatAdminRights?, bannedRights: Api.ChatBannedRights?, defaultBannedRights: Api.ChatBannedRights?, participantsCount: Int32?, usernames: [Api.Username]?, storiesMaxId: Int32?, color: Api.PeerColor?, profileColor: Api.PeerColor?, emojiStatus: Api.EmojiStatus?, level: Int32?) case channel(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, title: String, username: String?, photo: Api.ChatPhoto, date: Int32, restrictionReason: [Api.RestrictionReason]?, adminRights: Api.ChatAdminRights?, bannedRights: Api.ChatBannedRights?, defaultBannedRights: Api.ChatBannedRights?, participantsCount: Int32?, usernames: [Api.Username]?, storiesMaxId: Int32?, color: Api.PeerColor?, profileColor: Api.PeerColor?, emojiStatus: Api.EmojiStatus?, level: Int32?, subscriptionUntilDate: Int32?)
case channelForbidden(flags: Int32, id: Int64, accessHash: Int64, title: String, untilDate: Int32?) case channelForbidden(flags: Int32, id: Int64, accessHash: Int64, title: String, untilDate: Int32?)
case chat(flags: Int32, id: Int64, title: String, photo: Api.ChatPhoto, participantsCount: Int32, date: Int32, version: Int32, migratedTo: Api.InputChannel?, adminRights: Api.ChatAdminRights?, defaultBannedRights: Api.ChatBannedRights?) case chat(flags: Int32, id: Int64, title: String, photo: Api.ChatPhoto, participantsCount: Int32, date: Int32, version: Int32, migratedTo: Api.InputChannel?, adminRights: Api.ChatAdminRights?, defaultBannedRights: Api.ChatBannedRights?)
case chatEmpty(id: Int64) case chatEmpty(id: Int64)
@ -530,9 +542,9 @@ public extension Api {
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level): case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level, let subscriptionUntilDate):
if boxed { if boxed {
buffer.appendInt32(179174543) buffer.appendInt32(-29067075)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(flags2, buffer: buffer, boxed: false) serializeInt32(flags2, buffer: buffer, boxed: false)
@ -561,6 +573,7 @@ public extension Api {
if Int(flags2) & Int(1 << 8) != 0 {profileColor!.serialize(buffer, true)} if Int(flags2) & Int(1 << 8) != 0 {profileColor!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 9) != 0 {emojiStatus!.serialize(buffer, true)} if Int(flags2) & Int(1 << 9) != 0 {emojiStatus!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 10) != 0 {serializeInt32(level!, buffer: buffer, boxed: false)} if Int(flags2) & Int(1 << 10) != 0 {serializeInt32(level!, buffer: buffer, boxed: false)}
if Int(flags2) & Int(1 << 11) != 0 {serializeInt32(subscriptionUntilDate!, buffer: buffer, boxed: false)}
break break
case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate): case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate):
if boxed { if boxed {
@ -605,8 +618,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level): case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level, let subscriptionUntilDate):
return ("channel", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("title", title as Any), ("username", username as Any), ("photo", photo as Any), ("date", date as Any), ("restrictionReason", restrictionReason as Any), ("adminRights", adminRights as Any), ("bannedRights", bannedRights as Any), ("defaultBannedRights", defaultBannedRights as Any), ("participantsCount", participantsCount as Any), ("usernames", usernames as Any), ("storiesMaxId", storiesMaxId as Any), ("color", color as Any), ("profileColor", profileColor as Any), ("emojiStatus", emojiStatus as Any), ("level", level as Any)]) return ("channel", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("title", title as Any), ("username", username as Any), ("photo", photo as Any), ("date", date as Any), ("restrictionReason", restrictionReason as Any), ("adminRights", adminRights as Any), ("bannedRights", bannedRights as Any), ("defaultBannedRights", defaultBannedRights as Any), ("participantsCount", participantsCount as Any), ("usernames", usernames as Any), ("storiesMaxId", storiesMaxId as Any), ("color", color as Any), ("profileColor", profileColor as Any), ("emojiStatus", emojiStatus as Any), ("level", level as Any), ("subscriptionUntilDate", subscriptionUntilDate as Any)])
case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate): case .channelForbidden(let flags, let id, let accessHash, let title, let untilDate):
return ("channelForbidden", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("title", title as Any), ("untilDate", untilDate as Any)]) return ("channelForbidden", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("title", title as Any), ("untilDate", untilDate as Any)])
case .chat(let flags, let id, let title, let photo, let participantsCount, let date, let version, let migratedTo, let adminRights, let defaultBannedRights): case .chat(let flags, let id, let title, let photo, let participantsCount, let date, let version, let migratedTo, let adminRights, let defaultBannedRights):
@ -675,6 +688,8 @@ public extension Api {
} } } }
var _19: Int32? var _19: Int32?
if Int(_2!) & Int(1 << 10) != 0 {_19 = reader.readInt32() } if Int(_2!) & Int(1 << 10) != 0 {_19 = reader.readInt32() }
var _20: Int32?
if Int(_2!) & Int(1 << 11) != 0 {_20 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -694,8 +709,9 @@ public extension Api {
let _c17 = (Int(_2!) & Int(1 << 8) == 0) || _17 != nil let _c17 = (Int(_2!) & Int(1 << 8) == 0) || _17 != nil
let _c18 = (Int(_2!) & Int(1 << 9) == 0) || _18 != nil let _c18 = (Int(_2!) & Int(1 << 9) == 0) || _18 != nil
let _c19 = (Int(_2!) & Int(1 << 10) == 0) || _19 != nil let _c19 = (Int(_2!) & Int(1 << 10) == 0) || _19 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 { let _c20 = (Int(_2!) & Int(1 << 11) == 0) || _20 != nil
return Api.Chat.channel(flags: _1!, flags2: _2!, id: _3!, accessHash: _4, title: _5!, username: _6, photo: _7!, date: _8!, restrictionReason: _9, adminRights: _10, bannedRights: _11, defaultBannedRights: _12, participantsCount: _13, usernames: _14, storiesMaxId: _15, color: _16, profileColor: _17, emojiStatus: _18, level: _19) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 {
return Api.Chat.channel(flags: _1!, flags2: _2!, id: _3!, accessHash: _4, title: _5!, username: _6, photo: _7!, date: _8!, restrictionReason: _9, adminRights: _10, bannedRights: _11, defaultBannedRights: _12, participantsCount: _13, usernames: _14, storiesMaxId: _15, color: _16, profileColor: _17, emojiStatus: _18, level: _19, subscriptionUntilDate: _20)
} }
else { else {
return nil return nil
@ -1280,15 +1296,15 @@ public extension Api {
} }
public extension Api { public extension Api {
indirect enum ChatInvite: TypeConstructorDescription { indirect enum ChatInvite: TypeConstructorDescription {
case chatInvite(flags: Int32, title: String, about: String?, photo: Api.Photo, participantsCount: Int32, participants: [Api.User]?, color: Int32) case chatInvite(flags: Int32, title: String, about: String?, photo: Api.Photo, participantsCount: Int32, participants: [Api.User]?, color: Int32, subscriptionPricing: Api.StarsSubscriptionPricing?, subscriptionFormId: Int64?)
case chatInviteAlready(chat: Api.Chat) case chatInviteAlready(chat: Api.Chat)
case chatInvitePeek(chat: Api.Chat, expires: Int32) case chatInvitePeek(chat: Api.Chat, expires: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .chatInvite(let flags, let title, let about, let photo, let participantsCount, let participants, let color): case .chatInvite(let flags, let title, let about, let photo, let participantsCount, let participants, let color, let subscriptionPricing, let subscriptionFormId):
if boxed { if boxed {
buffer.appendInt32(-840897472) buffer.appendInt32(-26920803)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false) serializeString(title, buffer: buffer, boxed: false)
@ -1301,6 +1317,8 @@ public extension Api {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
serializeInt32(color, buffer: buffer, boxed: false) serializeInt32(color, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 10) != 0 {subscriptionPricing!.serialize(buffer, true)}
if Int(flags) & Int(1 << 12) != 0 {serializeInt64(subscriptionFormId!, buffer: buffer, boxed: false)}
break break
case .chatInviteAlready(let chat): case .chatInviteAlready(let chat):
if boxed { if boxed {
@ -1320,8 +1338,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .chatInvite(let flags, let title, let about, let photo, let participantsCount, let participants, let color): case .chatInvite(let flags, let title, let about, let photo, let participantsCount, let participants, let color, let subscriptionPricing, let subscriptionFormId):
return ("chatInvite", [("flags", flags as Any), ("title", title as Any), ("about", about as Any), ("photo", photo as Any), ("participantsCount", participantsCount as Any), ("participants", participants as Any), ("color", color as Any)]) return ("chatInvite", [("flags", flags as Any), ("title", title as Any), ("about", about as Any), ("photo", photo as Any), ("participantsCount", participantsCount as Any), ("participants", participants as Any), ("color", color as Any), ("subscriptionPricing", subscriptionPricing as Any), ("subscriptionFormId", subscriptionFormId as Any)])
case .chatInviteAlready(let chat): case .chatInviteAlready(let chat):
return ("chatInviteAlready", [("chat", chat as Any)]) return ("chatInviteAlready", [("chat", chat as Any)])
case .chatInvitePeek(let chat, let expires): case .chatInvitePeek(let chat, let expires):
@ -1348,6 +1366,12 @@ public extension Api {
} } } }
var _7: Int32? var _7: Int32?
_7 = reader.readInt32() _7 = reader.readInt32()
var _8: Api.StarsSubscriptionPricing?
if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.StarsSubscriptionPricing
} }
var _9: Int64?
if Int(_1!) & Int(1 << 12) != 0 {_9 = reader.readInt64() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 5) == 0) || _3 != nil let _c3 = (Int(_1!) & Int(1 << 5) == 0) || _3 != nil
@ -1355,8 +1379,10 @@ public extension Api {
let _c5 = _5 != nil let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil
let _c7 = _7 != nil let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { let _c8 = (Int(_1!) & Int(1 << 10) == 0) || _8 != nil
return Api.ChatInvite.chatInvite(flags: _1!, title: _2!, about: _3, photo: _4!, participantsCount: _5!, participants: _6, color: _7!) let _c9 = (Int(_1!) & Int(1 << 12) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.ChatInvite.chatInvite(flags: _1!, title: _2!, about: _3, photo: _4!, participantsCount: _5!, participants: _6, color: _7!, subscriptionPricing: _8, subscriptionFormId: _9)
} }
else { else {
return nil return nil

View File

@ -1012,14 +1012,14 @@ public extension Api {
} }
public extension Api { public extension Api {
enum ExportedChatInvite: TypeConstructorDescription { enum ExportedChatInvite: TypeConstructorDescription {
case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?, title: String?) case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?, title: String?, subscriptionPricing: Api.StarsSubscriptionPricing?)
case chatInvitePublicJoinRequests case chatInvitePublicJoinRequests
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title): case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title, let subscriptionPricing):
if boxed { if boxed {
buffer.appendInt32(179611673) buffer.appendInt32(-1812799720)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(link, buffer: buffer, boxed: false) serializeString(link, buffer: buffer, boxed: false)
@ -1031,6 +1031,7 @@ public extension Api {
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {serializeString(title!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 8) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 9) != 0 {subscriptionPricing!.serialize(buffer, true)}
break break
case .chatInvitePublicJoinRequests: case .chatInvitePublicJoinRequests:
if boxed { if boxed {
@ -1043,8 +1044,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title): case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title, let subscriptionPricing):
return ("chatInviteExported", [("flags", flags as Any), ("link", link as Any), ("adminId", adminId as Any), ("date", date as Any), ("startDate", startDate as Any), ("expireDate", expireDate as Any), ("usageLimit", usageLimit as Any), ("usage", usage as Any), ("requested", requested as Any), ("title", title as Any)]) return ("chatInviteExported", [("flags", flags as Any), ("link", link as Any), ("adminId", adminId as Any), ("date", date as Any), ("startDate", startDate as Any), ("expireDate", expireDate as Any), ("usageLimit", usageLimit as Any), ("usage", usage as Any), ("requested", requested as Any), ("title", title as Any), ("subscriptionPricing", subscriptionPricing as Any)])
case .chatInvitePublicJoinRequests: case .chatInvitePublicJoinRequests:
return ("chatInvitePublicJoinRequests", []) return ("chatInvitePublicJoinRequests", [])
} }
@ -1071,6 +1072,10 @@ public extension Api {
if Int(_1!) & Int(1 << 7) != 0 {_9 = reader.readInt32() } if Int(_1!) & Int(1 << 7) != 0 {_9 = reader.readInt32() }
var _10: String? var _10: String?
if Int(_1!) & Int(1 << 8) != 0 {_10 = parseString(reader) } if Int(_1!) & Int(1 << 8) != 0 {_10 = parseString(reader) }
var _11: Api.StarsSubscriptionPricing?
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.StarsSubscriptionPricing
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -1081,8 +1086,9 @@ public extension Api {
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 8) == 0) || _10 != nil let _c10 = (Int(_1!) & Int(1 << 8) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { let _c11 = (Int(_1!) & Int(1 << 9) == 0) || _11 != nil
return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, requested: _9, title: _10) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, requested: _9, title: _10, subscriptionPricing: _11)
} }
else { else {
return nil return nil

View File

@ -478,7 +478,7 @@ struct AccountMutableState {
for chat in chats { for chat in chats {
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _):
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
self.addOperation(.UpdateCachedPeerData(chat.peerId, { current in self.addOperation(.UpdateCachedPeerData(chat.peerId, { current in
var previous: CachedChannelData var previous: CachedChannelData

View File

@ -109,6 +109,7 @@ private var declaredEncodables: Void = {
declareEncodable(ReplyThreadMessageAttribute.self, f: { ReplyThreadMessageAttribute(decoder: $0) }) declareEncodable(ReplyThreadMessageAttribute.self, f: { ReplyThreadMessageAttribute(decoder: $0) })
declareEncodable(ReactionsMessageAttribute.self, f: { ReactionsMessageAttribute(decoder: $0) }) declareEncodable(ReactionsMessageAttribute.self, f: { ReactionsMessageAttribute(decoder: $0) })
declareEncodable(PendingReactionsMessageAttribute.self, f: { PendingReactionsMessageAttribute(decoder: $0) }) declareEncodable(PendingReactionsMessageAttribute.self, f: { PendingReactionsMessageAttribute(decoder: $0) })
declareEncodable(PendingStarsReactionsMessageAttribute.self, f: { PendingStarsReactionsMessageAttribute(decoder: $0) })
declareEncodable(CloudDocumentMediaResource.self, f: { CloudDocumentMediaResource(decoder: $0) }) declareEncodable(CloudDocumentMediaResource.self, f: { CloudDocumentMediaResource(decoder: $0) })
declareEncodable(TelegramMediaWebpage.self, f: { TelegramMediaWebpage(decoder: $0) }) declareEncodable(TelegramMediaWebpage.self, f: { TelegramMediaWebpage(decoder: $0) })
declareEncodable(ViewCountMessageAttribute.self, f: { ViewCountMessageAttribute(decoder: $0) }) declareEncodable(ViewCountMessageAttribute.self, f: { ViewCountMessageAttribute(decoder: $0) })
@ -188,6 +189,7 @@ private var declaredEncodables: Void = {
declareEncodable(WasScheduledMessageAttribute.self, f: { WasScheduledMessageAttribute(decoder: $0) }) declareEncodable(WasScheduledMessageAttribute.self, f: { WasScheduledMessageAttribute(decoder: $0) })
declareEncodable(OutgoingScheduleInfoMessageAttribute.self, f: { OutgoingScheduleInfoMessageAttribute(decoder: $0) }) declareEncodable(OutgoingScheduleInfoMessageAttribute.self, f: { OutgoingScheduleInfoMessageAttribute(decoder: $0) })
declareEncodable(UpdateMessageReactionsAction.self, f: { UpdateMessageReactionsAction(decoder: $0) }) declareEncodable(UpdateMessageReactionsAction.self, f: { UpdateMessageReactionsAction(decoder: $0) })
declareEncodable(SendStarsReactionsAction.self, f: { SendStarsReactionsAction(decoder: $0) })
declareEncodable(RestrictedContentMessageAttribute.self, f: { RestrictedContentMessageAttribute(decoder: $0) }) declareEncodable(RestrictedContentMessageAttribute.self, f: { RestrictedContentMessageAttribute(decoder: $0) })
declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) }) declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) })
declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) }) declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) })

View File

@ -61,7 +61,7 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: "", photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0) return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: "", photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0)
case let .chatForbidden(id, title): case let .chatForbidden(id, title):
return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: title, photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0) return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: title, photo: [], participantCount: 0, role: .member, membership: .Removed, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0)
case let .channel(flags, flags2, id, accessHash, title, username, photo, date, restrictionReason, adminRights, bannedRights, defaultBannedRights, _, usernames, _, color, profileColor, emojiStatus, boostLevel): case let .channel(flags, flags2, id, accessHash, title, username, photo, date, restrictionReason, adminRights, bannedRights, defaultBannedRights, _, usernames, _, color, profileColor, emojiStatus, boostLevel, _):
let isMin = (flags & (1 << 12)) != 0 let isMin = (flags & (1 << 12)) != 0
let participationStatus: TelegramChannelParticipationStatus let participationStatus: TelegramChannelParticipationStatus
@ -190,7 +190,7 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? {
switch rhs { switch rhs {
case .chat, .chatEmpty, .chatForbidden, .channelForbidden: case .chat, .chatEmpty, .chatForbidden, .channelForbidden:
return parseTelegramGroupOrChannel(chat: rhs) return parseTelegramGroupOrChannel(chat: rhs)
case let .channel(flags, flags2, _, accessHash, title, username, photo, _, _, _, _, defaultBannedRights, _, usernames, _, color, profileColor, emojiStatus, boostLevel): case let .channel(flags, flags2, _, accessHash, title, username, photo, _, _, _, _, defaultBannedRights, _, usernames, _, color, profileColor, emojiStatus, boostLevel, _):
let isMin = (flags & (1 << 12)) != 0 let isMin = (flags & (1 << 12)) != 0
if accessHash != nil && !isMin { if accessHash != nil && !isMin {
return parseTelegramGroupOrChannel(chat: rhs) return parseTelegramGroupOrChannel(chat: rhs)

View File

@ -197,7 +197,7 @@ public final class CachedChannelParticipants: PostboxCoding, Equatable {
extension ChannelParticipant { extension ChannelParticipant {
init(apiParticipant: Api.ChannelParticipant) { init(apiParticipant: Api.ChannelParticipant) {
switch apiParticipant { switch apiParticipant {
case let .channelParticipant(userId, date): case let .channelParticipant(_, userId, date, _):
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil) self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil)
case let .channelParticipantCreator(_, userId, adminRights, rank): case let .channelParticipantCreator(_, userId, adminRights, rank):
self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), canBeEditedByAccountPeer: true), rank: rank) self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), canBeEditedByAccountPeer: true), rank: rank)
@ -207,7 +207,7 @@ extension ChannelParticipant {
self = .member(id: userId.peerId, invitedAt: date, adminInfo: nil, banInfo: banInfo, rank: nil) self = .member(id: userId.peerId, invitedAt: date, adminInfo: nil, banInfo: banInfo, rank: nil)
case let .channelParticipantAdmin(flags, userId, _, promotedBy, date, adminRights, rank: rank): case let .channelParticipantAdmin(flags, userId, _, promotedBy, date, adminRights, rank: rank):
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(promotedBy)), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil, rank: rank) self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(promotedBy)), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil, rank: rank)
case let .channelParticipantSelf(_, userId, _, date): case let .channelParticipantSelf(_, userId, _, date, _):
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil) self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil)
case let .channelParticipantLeft(userId): case let .channelParticipantLeft(userId):
self = .member(id: userId.peerId, invitedAt: 0, adminInfo: nil, banInfo: nil, rank: nil) self = .member(id: userId.peerId, invitedAt: 0, adminInfo: nil, banInfo: nil, rank: nil)

View File

@ -6,7 +6,7 @@ import TelegramApi
extension ExportedInvitation { extension ExportedInvitation {
init(apiExportedInvite: Api.ExportedChatInvite) { init(apiExportedInvite: Api.ExportedChatInvite) {
switch apiExportedInvite { switch apiExportedInvite {
case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title): case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title, _):
self = .link(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested) self = .link(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested)
case .chatInvitePublicJoinRequests: case .chatInvitePublicJoinRequests:
self = .publicJoinRequest self = .publicJoinRequest

View File

@ -5,7 +5,10 @@ import TelegramApi
extension ReactionsMessageAttribute { extension ReactionsMessageAttribute {
func withUpdatedResults(_ reactions: Api.MessageReactions) -> ReactionsMessageAttribute { func withUpdatedResults(_ reactions: Api.MessageReactions) -> ReactionsMessageAttribute {
switch reactions { switch reactions {
case let .messageReactions(flags, results, recentReactions): case let .messageReactions(flags, results, recentReactions, topReactors):
//TODO:release
let _ = topReactors
let min = (flags & (1 << 0)) != 0 let min = (flags & (1 << 0)) != 0
let canViewList = (flags & (1 << 2)) != 0 let canViewList = (flags & (1 << 2)) != 0
let isTags = (flags & (1 << 3)) != 0 let isTags = (flags & (1 << 3)) != 0
@ -94,26 +97,7 @@ public func mergedMessageReactionsAndPeers(accountPeerId: EnginePeer.Id, account
} }
} }
#if DEBUG
var reactions = attribute.reactions
if "".isEmpty {
if let index = reactions.firstIndex(where: {
if case .custom(MessageReaction.starsReactionId) = $0.value {
return true
} else {
return false
}
}) {
let value = reactions[index]
reactions.remove(at: index)
reactions.insert(value, at: 0)
} else {
reactions.insert(MessageReaction(value: .custom(MessageReaction.starsReactionId), count: 1000000, chosenOrder: nil), at: 0)
}
}
#else
let reactions = attribute.reactions let reactions = attribute.reactions
#endif
return (reactions, recentPeers) return (reactions, recentPeers)
} }
@ -174,14 +158,18 @@ private func mergeReactions(reactions: [MessageReaction], recentPeers: [Reaction
public func mergedMessageReactions(attributes: [MessageAttribute], isTags: Bool) -> ReactionsMessageAttribute? { public func mergedMessageReactions(attributes: [MessageAttribute], isTags: Bool) -> ReactionsMessageAttribute? {
var current: ReactionsMessageAttribute? var current: ReactionsMessageAttribute?
var pending: PendingReactionsMessageAttribute? var pending: PendingReactionsMessageAttribute?
var pendingStars: PendingStarsReactionsMessageAttribute?
for attribute in attributes { for attribute in attributes {
if let attribute = attribute as? ReactionsMessageAttribute { if let attribute = attribute as? ReactionsMessageAttribute {
current = attribute current = attribute
} else if let attribute = attribute as? PendingReactionsMessageAttribute { } else if let attribute = attribute as? PendingReactionsMessageAttribute {
pending = attribute pending = attribute
} else if let attribute = attribute as? PendingStarsReactionsMessageAttribute {
pendingStars = attribute
} }
} }
let result: ReactionsMessageAttribute?
if let pending = pending, let accountPeerId = pending.accountPeerId { if let pending = pending, let accountPeerId = pending.accountPeerId {
var reactions = current?.reactions ?? [] var reactions = current?.reactions ?? []
var recentPeers = current?.recentPeers ?? [] var recentPeers = current?.recentPeers ?? []
@ -191,21 +179,40 @@ public func mergedMessageReactions(attributes: [MessageAttribute], isTags: Bool)
recentPeers = updatedRecentPeers recentPeers = updatedRecentPeers
if !reactions.isEmpty { if !reactions.isEmpty {
return ReactionsMessageAttribute(canViewList: current?.canViewList ?? false, isTags: current?.isTags ?? isTags, reactions: reactions, recentPeers: recentPeers) result = ReactionsMessageAttribute(canViewList: current?.canViewList ?? false, isTags: current?.isTags ?? isTags, reactions: reactions, recentPeers: recentPeers)
} else { } else {
return nil result = nil
} }
} else if let current = current { } else if let current {
return current result = current
} else { } else {
return nil result = nil
}
if let pendingStars {
if let result {
var reactions = result.reactions
var updatedCount: Int32 = pendingStars.count
if let index = reactions.firstIndex(where: { $0.value == .stars }) {
updatedCount += reactions[index].count
reactions.remove(at: index)
}
reactions.insert(MessageReaction(value: .stars, count: updatedCount, chosenOrder: -1), at: 0)
return ReactionsMessageAttribute(canViewList: current?.canViewList ?? false, isTags: current?.isTags ?? isTags, reactions: reactions, recentPeers: result.recentPeers)
} else {
return ReactionsMessageAttribute(canViewList: current?.canViewList ?? false, isTags: current?.isTags ?? isTags, reactions: [MessageReaction(value: .stars, count: pendingStars.count, chosenOrder: -1)], recentPeers: [])
}
} else {
return result
} }
} }
extension ReactionsMessageAttribute { extension ReactionsMessageAttribute {
convenience init(apiReactions: Api.MessageReactions) { convenience init(apiReactions: Api.MessageReactions) {
switch apiReactions { switch apiReactions {
case let .messageReactions(flags, results, recentReactions): case let .messageReactions(flags, results, recentReactions, topReactors):
//TODO:release
let _ = topReactors
let canViewList = (flags & (1 << 2)) != 0 let canViewList = (flags & (1 << 2)) != 0
let isTags = (flags & (1 << 3)) != 0 let isTags = (flags & (1 << 3)) != 0
let parsedRecentReactions: [ReactionsMessageAttribute.RecentPeer] let parsedRecentReactions: [ReactionsMessageAttribute.RecentPeer]

View File

@ -22,6 +22,8 @@ public extension ReactionSettings {
} else { } else {
return ReactionSettings.default.quickReaction return ReactionSettings.default.quickReaction
} }
case .stars:
return self.quickReaction
} }
} }
} }

View File

@ -87,6 +87,7 @@ final class AccountTaskManager {
tasks.add(managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedSynchronizeMarkAllUnseenReactionsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedSynchronizeMarkAllUnseenReactionsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedApplyPendingMessageReactionsActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedApplyPendingMessageReactionsActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedApplyPendingMessageStarsReactionsActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network).start()) tasks.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
tasks.add(managedApplyPendingScheduledMessagesActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedApplyPendingScheduledMessagesActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedSynchronizeAvailableReactions(postbox: self.stateManager.postbox, network: self.stateManager.network).start()) tasks.add(managedSynchronizeAvailableReactions(postbox: self.stateManager.postbox, network: self.stateManager.network).start())

View File

@ -142,6 +142,8 @@ public final class AvailableReactions: Equatable, Codable {
try container.encode(value, forKey: .value) try container.encode(value, forKey: .value)
case .custom: case .custom:
break break
case .stars:
break
} }
try container.encode(self.title, forKey: .title) try container.encode(self.title, forKey: .title)
@ -172,7 +174,29 @@ public final class AvailableReactions: Equatable, Codable {
reactions: [Reaction] reactions: [Reaction]
) { ) {
self.hash = hash self.hash = hash
#if DEBUG
var reactions = reactions
reactions.removeAll(where: { if case .stars = $0.value { return true } else { return false } })
if let item = reactions.first(where: { if case .builtin("🤩") = $0.value { return true } else { return false } }) {
reactions.append(Reaction(
isEnabled: false,
isPremium: false,
value: .stars,
title: "Star",
staticIcon: item.staticIcon,
appearAnimation: item.appearAnimation,
selectAnimation: item.selectAnimation,
activateAnimation: item.activateAnimation,
effectAnimation: item.effectAnimation,
aroundAnimation: item.aroundAnimation,
centerAnimation: item.centerAnimation
))
}
self.reactions = reactions self.reactions = reactions
#else
self.reactions = reactions
#endif
} }
public static func ==(lhs: AvailableReactions, rhs: AvailableReactions) -> Bool { public static func ==(lhs: AvailableReactions, rhs: AvailableReactions) -> Bool {
@ -189,7 +213,28 @@ public final class AvailableReactions: Equatable, Codable {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
self.hash = try container.decodeIfPresent(Int32.self, forKey: .newHash) ?? 0 self.hash = try container.decodeIfPresent(Int32.self, forKey: .newHash) ?? 0
#if DEBUG
var reactions = try container.decode([Reaction].self, forKey: .reactions)
reactions.removeAll(where: { if case .stars = $0.value { return true } else { return false } })
if let item = reactions.first(where: { if case .builtin("🤩") = $0.value { return true } else { return false } }) {
reactions.append(Reaction(
isEnabled: false,
isPremium: false,
value: .stars,
title: "Star",
staticIcon: item.staticIcon,
appearAnimation: item.appearAnimation,
selectAnimation: item.selectAnimation,
activateAnimation: item.activateAnimation,
effectAnimation: item.effectAnimation,
aroundAnimation: item.aroundAnimation,
centerAnimation: item.centerAnimation
))
}
self.reactions = reactions
#else
self.reactions = try container.decode([Reaction].self, forKey: .reactions) self.reactions = try container.decode([Reaction].self, forKey: .reactions)
#endif
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {

View File

@ -656,6 +656,8 @@ func synchronizeSavedMessageTags(postbox: Postbox, network: Network, peerId: Pee
reactionId = UInt64(bitPattern: id) reactionId = UInt64(bitPattern: id)
case let .builtin(string): case let .builtin(string):
reactionId = md5StringHash(string) reactionId = md5StringHash(string)
case .stars:
reactionId = md5StringHash("star")
} }
var titleId: UInt64? var titleId: UInt64?

View File

@ -411,6 +411,8 @@ func managedRecentReactions(postbox: Postbox, network: Network) -> Signal<Void,
return 0 return 0
case let .custom(fileId): case let .custom(fileId):
return fileId.id return fileId.id
case .stars:
return 0
} }
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
return network.request(Api.functions.messages.getRecentReactions(limit: 100, hash: hash)) return network.request(Api.functions.messages.getRecentReactions(limit: 100, hash: hash))
@ -428,6 +430,8 @@ func managedRecentReactions(postbox: Postbox, network: Network) -> Signal<Void,
return nil return nil
case let .custom(fileId): case let .custom(fileId):
return fileId return fileId
case .stars:
return nil
} }
}) })
|> map { files -> [OrderedItemListEntry] in |> map { files -> [OrderedItemListEntry] in
@ -442,6 +446,8 @@ func managedRecentReactions(postbox: Postbox, network: Network) -> Signal<Void,
continue continue
} }
item = RecentReactionItem(.custom(file)) item = RecentReactionItem(.custom(file))
case .stars:
item = RecentReactionItem(.stars)
} }
if let entry = CodableEntry(item) { if let entry = CodableEntry(item) {
items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry)) items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry))
@ -462,6 +468,8 @@ func managedTopReactions(postbox: Postbox, network: Network) -> Signal<Void, NoE
return 0 return 0
case let .custom(fileId): case let .custom(fileId):
return fileId.id return fileId.id
case .stars:
return 0
} }
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
return network.request(Api.functions.messages.getTopReactions(limit: 32, hash: hash)) return network.request(Api.functions.messages.getTopReactions(limit: 32, hash: hash))
@ -479,6 +487,8 @@ func managedTopReactions(postbox: Postbox, network: Network) -> Signal<Void, NoE
return nil return nil
case let .custom(fileId): case let .custom(fileId):
return fileId return fileId
case .stars:
return nil
} }
}) })
|> map { files -> [OrderedItemListEntry] in |> map { files -> [OrderedItemListEntry] in
@ -493,6 +503,8 @@ func managedTopReactions(postbox: Postbox, network: Network) -> Signal<Void, NoE
continue continue
} }
item = RecentReactionItem(.custom(file)) item = RecentReactionItem(.custom(file))
case .stars:
item = RecentReactionItem(.stars)
} }
if let entry = CodableEntry(item) { if let entry = CodableEntry(item) {
items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry)) items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry))
@ -513,6 +525,8 @@ func managedDefaultTagReactions(postbox: Postbox, network: Network) -> Signal<Vo
return 0 return 0
case let .custom(fileId): case let .custom(fileId):
return fileId.id return fileId.id
case .stars:
return 0
} }
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
return network.request(Api.functions.messages.getDefaultTagReactions(hash: hash)) return network.request(Api.functions.messages.getDefaultTagReactions(hash: hash))
@ -530,6 +544,8 @@ func managedDefaultTagReactions(postbox: Postbox, network: Network) -> Signal<Vo
return nil return nil
case let .custom(fileId): case let .custom(fileId):
return fileId return fileId
case .stars:
return nil
} }
}) })
|> map { files -> [OrderedItemListEntry] in |> map { files -> [OrderedItemListEntry] in
@ -544,6 +560,8 @@ func managedDefaultTagReactions(postbox: Postbox, network: Network) -> Signal<Vo
continue continue
} }
item = RecentReactionItem(.custom(file)) item = RecentReactionItem(.custom(file))
case .stars:
item = RecentReactionItem(.stars)
} }
if let entry = CodableEntry(item) { if let entry = CodableEntry(item) {
items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry)) items.append(OrderedItemListEntry(id: item.id.rawValue, contents: entry))

View File

@ -7,6 +7,7 @@ import MtProtoKit
public enum UpdateMessageReaction { public enum UpdateMessageReaction {
case builtin(String) case builtin(String)
case custom(fileId: Int64, file: TelegramMediaFile?) case custom(fileId: Int64, file: TelegramMediaFile?)
case stars
public var reaction: MessageReaction.Reaction { public var reaction: MessageReaction.Reaction {
switch self { switch self {
@ -14,6 +15,8 @@ public enum UpdateMessageReaction {
return .builtin(value) return .builtin(value)
case let .custom(fileId, _): case let .custom(fileId, _):
return .custom(fileId) return .custom(fileId)
case .stars:
return .stars
} }
} }
} }
@ -83,6 +86,8 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
mappedValue = .builtin(value) mappedValue = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
mappedValue = .custom(fileId: fileId, file: nil) mappedValue = .custom(fileId: fileId, file: nil)
case .stars:
mappedValue = .stars
} }
reactions.append(mappedValue) reactions.append(mappedValue)
} }
@ -99,6 +104,8 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
} }
case let .builtin(value): case let .builtin(value):
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .builtin(value), sendAsPeerId: sendAsPeerId)) mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .builtin(value), sendAsPeerId: sendAsPeerId))
case .stars:
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .stars, sendAsPeerId: sendAsPeerId))
} }
} }
@ -132,6 +139,8 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
} else { } else {
continue continue
} }
case .stars:
recentReactionItem = RecentReactionItem(.stars)
} }
if let entry = CodableEntry(recentReactionItem) { if let entry = CodableEntry(recentReactionItem) {
@ -163,6 +172,32 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
|> ignoreValues |> ignoreValues
} }
public func sendStarsReactionsInteractively(account: Account, messageId: MessageId, count: Int) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: SendStarsReactionsAction(randomId: Int64.random(in: Int64.min ... Int64.max)))
transaction.updateMessage(messageId, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
}
var mappedCount = Int32(count)
var attributes = currentMessage.attributes
loop: for j in 0 ..< attributes.count {
if let current = attributes[j] as? PendingStarsReactionsMessageAttribute {
mappedCount += current.count
attributes.remove(at: j)
break loop
}
}
attributes.append(PendingStarsReactionsMessageAttribute(accountPeerId: account.peerId, count: mappedCount))
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
}
|> ignoreValues
}
private enum RequestUpdateMessageReactionError { private enum RequestUpdateMessageReactionError {
case generic case generic
} }
@ -250,6 +285,76 @@ private func requestUpdateMessageReaction(postbox: Postbox, network: Network, st
} }
} }
private func requestSendStarsReaction(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal<Never, RequestUpdateMessageReactionError> {
return postbox.transaction { transaction -> (Peer, Int32)? in
guard let peer = transaction.getPeer(messageId.peerId) else {
return nil
}
guard let message = transaction.getMessage(messageId) else {
return nil
}
var count: Int32 = 0
for attribute in message.attributes {
if let attribute = attribute as? PendingStarsReactionsMessageAttribute {
count += attribute.count
break
}
}
return (peer, count)
}
|> castError(RequestUpdateMessageReactionError.self)
|> mapToSignal { peerAndValue in
guard let (peer, count) = peerAndValue else {
return .fail(.generic)
}
guard let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
}
if messageId.namespace != Namespaces.Message.Cloud {
return .fail(.generic)
}
if count > 0 {
let randomPartId = UInt64(UInt32(bitPattern: Int32.random(in: Int32.min ... Int32.max)))
let timestampPart = UInt64(UInt32(bitPattern: Int32(Date().timeIntervalSince1970)))
let randomId = (timestampPart << 32) | randomPartId
let signal: Signal<Never, RequestUpdateMessageReactionError> = network.request(Api.functions.messages.sendPaidReaction(peer: inputPeer, msgId: messageId.id, count: count, randomId: Int64(bitPattern: randomId)))
|> mapError { _ -> RequestUpdateMessageReactionError in
return .generic
}
|> mapToSignal { result -> Signal<Never, RequestUpdateMessageReactionError> in
return postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: UpdateMessageReactionsAction())
transaction.updateMessage(messageId, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
}
let reactions = mergedMessageReactions(attributes: currentMessage.attributes, isTags: currentMessage.areReactionsTags(accountPeerId: stateManager.accountPeerId))
var attributes = currentMessage.attributes
for j in (0 ..< attributes.count).reversed() {
if attributes[j] is PendingStarsReactionsMessageAttribute || attributes[j] is ReactionsMessageAttribute {
attributes.remove(at: j)
}
}
if let reactions {
attributes.append(reactions)
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
stateManager.addUpdates(result)
}
|> castError(RequestUpdateMessageReactionError.self)
|> ignoreValues
}
return signal
} else {
return .complete()
}
}
}
private final class ManagedApplyPendingMessageReactionsActionsHelper { private final class ManagedApplyPendingMessageReactionsActionsHelper {
var operationDisposables: [MessageId: Disposable] = [:] var operationDisposables: [MessageId: Disposable] = [:]
@ -294,7 +399,7 @@ private final class ManagedApplyPendingMessageReactionsActionsHelper {
} }
} }
private func withTakenAction(postbox: Postbox, type: PendingMessageActionType, id: MessageId, _ f: @escaping (Transaction, PendingMessageActionsEntry?) -> Signal<Never, NoError>) -> Signal<Never, NoError> { private func withTakenReactionsAction(postbox: Postbox, type: PendingMessageActionType, id: MessageId, _ f: @escaping (Transaction, PendingMessageActionsEntry?) -> Signal<Never, NoError>) -> Signal<Never, NoError> {
return postbox.transaction { transaction -> Signal<Never, NoError> in return postbox.transaction { transaction -> Signal<Never, NoError> in
var result: PendingMessageActionsEntry? var result: PendingMessageActionsEntry?
@ -307,6 +412,19 @@ private func withTakenAction(postbox: Postbox, type: PendingMessageActionType, i
|> switchToLatest |> switchToLatest
} }
private func withTakenStarsAction(postbox: Postbox, type: PendingMessageActionType, id: MessageId, _ f: @escaping (Transaction, PendingMessageActionsEntry?) -> Signal<Never, NoError>) -> Signal<Never, NoError> {
return postbox.transaction { transaction -> Signal<Never, NoError> in
var result: PendingMessageActionsEntry?
if let action = transaction.getPendingMessageAction(type: type, id: id) as? SendStarsReactionsAction {
result = PendingMessageActionsEntry(id: id, action: action)
}
return f(transaction, result)
}
|> switchToLatest
}
func managedApplyPendingMessageReactionsActions(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal<Void, NoError> { func managedApplyPendingMessageReactionsActions(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in return Signal { _ in
let helper = Atomic<ManagedApplyPendingMessageReactionsActionsHelper>(value: ManagedApplyPendingMessageReactionsActionsHelper()) let helper = Atomic<ManagedApplyPendingMessageReactionsActionsHelper>(value: ManagedApplyPendingMessageReactionsActionsHelper())
@ -327,7 +445,7 @@ func managedApplyPendingMessageReactionsActions(postbox: Postbox, network: Netwo
} }
for (entry, disposable) in beginOperations { for (entry, disposable) in beginOperations {
let signal = withTakenAction(postbox: postbox, type: .updateReaction, id: entry.id, { transaction, entry -> Signal<Never, NoError> in let signal = withTakenReactionsAction(postbox: postbox, type: .updateReaction, id: entry.id, { transaction, entry -> Signal<Never, NoError> in
if let entry = entry { if let entry = entry {
if let _ = entry.action as? UpdateMessageReactionsAction { if let _ = entry.action as? UpdateMessageReactionsAction {
return synchronizeMessageReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id) return synchronizeMessageReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id)
@ -360,6 +478,60 @@ func managedApplyPendingMessageReactionsActions(postbox: Postbox, network: Netwo
} }
} }
func managedApplyPendingMessageStarsReactionsActions(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in
let helper = Atomic<ManagedApplyPendingMessageReactionsActionsHelper>(value: ManagedApplyPendingMessageReactionsActionsHelper())
let actionsKey = PostboxViewKey.pendingMessageActions(type: .sendStarsReaction)
let disposable = postbox.combinedView(keys: [actionsKey]).start(next: { view in
var entries: [PendingMessageActionsEntry] = []
if let v = view.views[actionsKey] as? PendingMessageActionsView {
entries = v.entries
}
let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PendingMessageActionsEntry, MetaDisposable)]) in
return helper.update(entries: entries)
}
for disposable in disposeOperations {
disposable.dispose()
}
for (entry, disposable) in beginOperations {
let signal = withTakenStarsAction(postbox: postbox, type: .sendStarsReaction, id: entry.id, { transaction, entry -> Signal<Never, NoError> in
if let entry = entry {
if let _ = entry.action as? SendStarsReactionsAction {
return synchronizeMessageStarsReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id)
|> delay(5.0, queue: .mainQueue())
} else {
assertionFailure()
}
}
return .complete()
})
|> then(
postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: entry.id, action: nil)
}
|> ignoreValues
)
disposable.set(signal.start())
}
})
return ActionDisposable {
let disposables = helper.with { helper -> [Disposable] in
return helper.reset()
}
for disposable in disposables {
disposable.dispose()
}
disposable.dispose()
}
}
}
private func synchronizeMessageReactions(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal<Never, NoError> { private func synchronizeMessageReactions(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal<Never, NoError> {
return requestUpdateMessageReaction(postbox: postbox, network: network, stateManager: stateManager, messageId: id) return requestUpdateMessageReaction(postbox: postbox, network: network, stateManager: stateManager, messageId: id)
|> `catch` { _ -> Signal<Never, NoError> in |> `catch` { _ -> Signal<Never, NoError> in
@ -384,6 +556,30 @@ private func synchronizeMessageReactions(transaction: Transaction, postbox: Post
} }
} }
private func synchronizeMessageStarsReactions(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal<Never, NoError> {
return requestSendStarsReaction(postbox: postbox, network: network, stateManager: stateManager, messageId: id)
|> `catch` { _ -> Signal<Never, NoError> in
return postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: id, action: nil)
transaction.updateMessage(id, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
}
var attributes = currentMessage.attributes
loop: for j in 0 ..< attributes.count {
if let _ = attributes[j] as? PendingStarsReactionsMessageAttribute {
attributes.remove(at: j)
break loop
}
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
}
|> ignoreValues
}
}
public extension EngineMessageReactionListContext.State { public extension EngineMessageReactionListContext.State {
init(message: EngineMessage, readStats: MessageReadStats?, reaction: MessageReaction.Reaction?) { init(message: EngineMessage, readStats: MessageReadStats?, reaction: MessageReaction.Reaction?) {
var totalCount = 0 var totalCount = 0
@ -682,7 +878,13 @@ func _internal_updatePeerReactionSettings(account: Account, peerId: PeerId, reac
reactionLimitValue = maxReactionCount reactionLimitValue = maxReactionCount
} }
return account.network.request(Api.functions.messages.setChatAvailableReactions(flags: flags, peer: inputPeer, availableReactions: mappedReactions, reactionsLimit: reactionLimitValue)) var paidEnabled: Api.Bool?
if let starsAllowed = reactionSettings.starsAllowed {
flags |= 1 << 1
paidEnabled = starsAllowed ? .boolTrue : .boolFalse
}
return account.network.request(Api.functions.messages.setChatAvailableReactions(flags: flags, peer: inputPeer, availableReactions: mappedReactions, reactionsLimit: reactionLimitValue, paidEnabled: paidEnabled))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { error -> Signal<Api.Updates?, UpdatePeerAllowedReactionsError> in |> `catch` { error -> Signal<Api.Updates?, UpdatePeerAllowedReactionsError> in
if error.errorDescription == "CHAT_NOT_MODIFIED" { if error.errorDescription == "CHAT_NOT_MODIFIED" {

View File

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

View File

@ -182,7 +182,7 @@ extension Api.Chat {
return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)) return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id))
case let .chatForbidden(id, _): case let .chatForbidden(id, _):
return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)) return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id))
case let .channel(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): case let .channel(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id)) return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id))
case let .channelForbidden(_, id, _, _, _): case let .channelForbidden(_, id, _, _, _):
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id)) return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id))

View File

@ -636,10 +636,10 @@ public final class CachedChannelData: CachedPeerData {
self.reactionSettings = .known(reactionSettings) self.reactionSettings = .known(reactionSettings)
} else if let legacyAllowedReactions = decoder.decodeOptionalStringArrayForKey("allowedReactions") { } else if let legacyAllowedReactions = decoder.decodeOptionalStringArrayForKey("allowedReactions") {
let allowedReactions: PeerAllowedReactions = .limited(legacyAllowedReactions.map(MessageReaction.Reaction.builtin)) let allowedReactions: PeerAllowedReactions = .limited(legacyAllowedReactions.map(MessageReaction.Reaction.builtin))
self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil)) self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil, starsAllowed: nil))
} else if let allowedReactions = decoder.decode(PeerAllowedReactions.self, forKey: "allowedReactionSet") { } else if let allowedReactions = decoder.decode(PeerAllowedReactions.self, forKey: "allowedReactionSet") {
let allowedReactions = allowedReactions let allowedReactions = allowedReactions
self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil)) self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil, starsAllowed: nil))
} else { } else {
self.reactionSettings = .unknown self.reactionSettings = .unknown
} }

View File

@ -100,10 +100,12 @@ extension PeerAllowedReactions {
public final class PeerReactionSettings: Equatable, Codable { public final class PeerReactionSettings: Equatable, Codable {
public let allowedReactions: PeerAllowedReactions public let allowedReactions: PeerAllowedReactions
public let maxReactionCount: Int32? public let maxReactionCount: Int32?
public let starsAllowed: Bool?
public init(allowedReactions: PeerAllowedReactions, maxReactionCount: Int32?) { public init(allowedReactions: PeerAllowedReactions, maxReactionCount: Int32?, starsAllowed: Bool?) {
self.allowedReactions = allowedReactions self.allowedReactions = allowedReactions
self.maxReactionCount = maxReactionCount self.maxReactionCount = maxReactionCount
self.starsAllowed = starsAllowed
} }
public static func ==(lhs: PeerReactionSettings, rhs: PeerReactionSettings) -> Bool { public static func ==(lhs: PeerReactionSettings, rhs: PeerReactionSettings) -> Bool {
@ -116,6 +118,9 @@ public final class PeerReactionSettings: Equatable, Codable {
if lhs.maxReactionCount != rhs.maxReactionCount { if lhs.maxReactionCount != rhs.maxReactionCount {
return false return false
} }
if lhs.starsAllowed != rhs.starsAllowed {
return false
}
return true return true
} }
} }
@ -266,10 +271,10 @@ public final class CachedGroupData: CachedPeerData {
self.reactionSettings = .known(reactionSettings) self.reactionSettings = .known(reactionSettings)
} else if let legacyAllowedReactions = decoder.decodeOptionalStringArrayForKey("allowedReactions") { } else if let legacyAllowedReactions = decoder.decodeOptionalStringArrayForKey("allowedReactions") {
let allowedReactions: PeerAllowedReactions = .limited(legacyAllowedReactions.map(MessageReaction.Reaction.builtin)) let allowedReactions: PeerAllowedReactions = .limited(legacyAllowedReactions.map(MessageReaction.Reaction.builtin))
self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil)) self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil, starsAllowed: nil))
} else if let allowedReactions = decoder.decode(PeerAllowedReactions.self, forKey: "allowedReactionSet") { } else if let allowedReactions = decoder.decode(PeerAllowedReactions.self, forKey: "allowedReactionSet") {
let allowedReactions = allowedReactions let allowedReactions = allowedReactions
self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil)) self.reactionSettings = .known(PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: nil, starsAllowed: nil))
} else { } else {
self.reactionSettings = .unknown self.reactionSettings = .unknown
} }

View File

@ -184,6 +184,7 @@ public extension PendingMessageActionType {
static let updateReaction = PendingMessageActionType(rawValue: 1) static let updateReaction = PendingMessageActionType(rawValue: 1)
static let sendScheduledMessageImmediately = PendingMessageActionType(rawValue: 2) static let sendScheduledMessageImmediately = PendingMessageActionType(rawValue: 2)
static let readReaction = PendingMessageActionType(rawValue: 3) static let readReaction = PendingMessageActionType(rawValue: 3)
static let sendStarsReaction = PendingMessageActionType(rawValue: 4)
} }
public let peerIdNamespacesWithInitialCloudMessageHoles = [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel] public let peerIdNamespacesWithInitialCloudMessageHoles = [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel]

View File

@ -12,12 +12,15 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
public enum Reaction: Hashable, Comparable, Codable, PostboxCoding { public enum Reaction: Hashable, Comparable, Codable, PostboxCoding {
case builtin(String) case builtin(String)
case custom(Int64) case custom(Int64)
case stars
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self) let container = try decoder.container(keyedBy: StringCodingKey.self)
if let value = try container.decodeIfPresent(String.self, forKey: "v") { if let value = try container.decodeIfPresent(String.self, forKey: "v") {
self = .builtin(value) self = .builtin(value)
} else if let _ = try container.decodeIfPresent(Int64.self, forKey: "star") {
self = .stars
} else { } else {
self = .custom(try container.decode(Int64.self, forKey: "cfid")) self = .custom(try container.decode(Int64.self, forKey: "cfid"))
} }
@ -26,6 +29,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
if let value = decoder.decodeOptionalStringForKey("v") { if let value = decoder.decodeOptionalStringForKey("v") {
self = .builtin(value) self = .builtin(value)
} else if let _ = decoder.decodeOptionalInt64ForKey("star") {
self = .stars
} else { } else {
self = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0)) self = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0))
} }
@ -39,6 +44,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
try container.encode(value, forKey: "v") try container.encode(value, forKey: "v")
case let .custom(fileId): case let .custom(fileId):
try container.encode(fileId, forKey: "cfid") try container.encode(fileId, forKey: "cfid")
case .stars:
try container.encode(0 as Int64, forKey: "star")
} }
} }
@ -48,6 +55,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
encoder.encodeString(value, forKey: "v") encoder.encodeString(value, forKey: "v")
case let .custom(fileId): case let .custom(fileId):
encoder.encodeInt64(fileId, forKey: "cfid") encoder.encodeInt64(fileId, forKey: "cfid")
case .stars:
encoder.encodeInt64(0, forKey: "star")
} }
} }
@ -59,6 +68,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
return lhsValue < rhsValue return lhsValue < rhsValue
case .custom: case .custom:
return true return true
case .stars:
return false
} }
case let .custom(lhsValue): case let .custom(lhsValue):
switch rhs { switch rhs {
@ -66,6 +77,17 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
return false return false
case let .custom(rhsValue): case let .custom(rhsValue):
return lhsValue < rhsValue return lhsValue < rhsValue
case .stars:
return false
}
case .stars:
switch rhs {
case .builtin:
return true
case .custom:
return true
case .stars:
return false
} }
} }
} }
@ -88,6 +110,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
if let value = decoder.decodeOptionalStringForKey("v") { if let value = decoder.decodeOptionalStringForKey("v") {
self.value = .builtin(value) self.value = .builtin(value)
} else if let _ = decoder.decodeOptionalInt64ForKey("star") {
self.value = .stars
} else { } else {
self.value = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0)) self.value = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0))
} }
@ -106,6 +130,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
if let value = try container.decodeIfPresent(String.self, forKey: "v") { if let value = try container.decodeIfPresent(String.self, forKey: "v") {
self.value = .builtin(value) self.value = .builtin(value)
} else if let _ = try container.decodeIfPresent(Int64.self, forKey: "star") {
self.value = .stars
} else { } else {
self.value = .custom(try container.decode(Int64.self, forKey: "cfid")) self.value = .custom(try container.decode(Int64.self, forKey: "cfid"))
} }
@ -125,6 +151,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
encoder.encodeString(value, forKey: "v") encoder.encodeString(value, forKey: "v")
case let .custom(fileId): case let .custom(fileId):
encoder.encodeInt64(fileId, forKey: "cfid") encoder.encodeInt64(fileId, forKey: "cfid")
case .stars:
encoder.encodeInt64(0, forKey: "star")
} }
encoder.encodeInt32(self.count, forKey: "c") encoder.encodeInt32(self.count, forKey: "c")
if let chosenOrder = self.chosenOrder { if let chosenOrder = self.chosenOrder {
@ -142,6 +170,8 @@ public struct MessageReaction: Equatable, PostboxCoding, Codable {
try container.encode(value, forKey: "v") try container.encode(value, forKey: "v")
case let .custom(fileId): case let .custom(fileId):
try container.encode(fileId, forKey: "cfid") try container.encode(fileId, forKey: "cfid")
case .stars:
try container.encode(0 as Int64, forKey: "star")
} }
try container.encode(self.count, forKey: "c") try container.encode(self.count, forKey: "c")
try container.encodeIfPresent(self.chosenOrder.flatMap(Int32.init), forKey: "cord") try container.encodeIfPresent(self.chosenOrder.flatMap(Int32.init), forKey: "cord")
@ -157,6 +187,8 @@ extension MessageReaction.Reaction {
self = .builtin(emoticon) self = .builtin(emoticon)
case let .reactionCustomEmoji(documentId): case let .reactionCustomEmoji(documentId):
self = .custom(documentId) self = .custom(documentId)
case .reactionPaid:
self = .stars
} }
} }
@ -166,6 +198,8 @@ extension MessageReaction.Reaction {
return .reactionEmoji(emoticon: value) return .reactionEmoji(emoticon: value)
case let .custom(fileId): case let .custom(fileId):
return .reactionCustomEmoji(documentId: fileId) return .reactionCustomEmoji(documentId: fileId)
case .stars:
return .reactionPaid
} }
} }
} }
@ -191,6 +225,9 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
var typeId: UInt8 = 1 var typeId: UInt8 = 1
buffer.write(&typeId, offset: 0, length: 1) buffer.write(&typeId, offset: 0, length: 1)
buffer.write(&fileId, offset: 0, length: 8) buffer.write(&fileId, offset: 0, length: 8)
case .stars:
var typeId: UInt8 = 2
buffer.write(&typeId, offset: 0, length: 1)
} }
return buffer return buffer
@ -231,6 +268,8 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
var fileId: Int64 = 0 var fileId: Int64 = 0
readBuffer.read(&fileId, offset: 0, length: 8) readBuffer.read(&fileId, offset: 0, length: 8)
return .custom(fileId) return .custom(fileId)
case 2:
return .stars
default: default:
return nil return nil
} }
@ -256,6 +295,8 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
if let value = decoder.decodeOptionalStringForKey("v") { if let value = decoder.decodeOptionalStringForKey("v") {
self.value = .builtin(value) self.value = .builtin(value)
} else if let _ = decoder.decodeOptionalInt64ForKey("star") {
self.value = .stars
} else { } else {
self.value = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0)) self.value = .custom(decoder.decodeInt64ForKey("cfid", orElse: 0))
} }
@ -272,6 +313,8 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
encoder.encodeString(value, forKey: "v") encoder.encodeString(value, forKey: "v")
case let .custom(fileId): case let .custom(fileId):
encoder.encodeInt64(fileId, forKey: "cfid") encoder.encodeInt64(fileId, forKey: "cfid")
case .stars:
encoder.encodeInt64(0, forKey: "star")
} }
encoder.encodeInt32(self.isLarge ? 1 : 0, forKey: "l") encoder.encodeInt32(self.isLarge ? 1 : 0, forKey: "l")
encoder.encodeInt32(self.isUnseen ? 1 : 0, forKey: "u") encoder.encodeInt32(self.isUnseen ? 1 : 0, forKey: "u")
@ -306,6 +349,8 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
if !result.contains(mediaId) { if !result.contains(mediaId) {
result.append(mediaId) result.append(mediaId)
} }
case .stars:
break
} }
} }
@ -430,6 +475,8 @@ public final class PendingReactionsMessageAttribute: MessageAttribute {
if !result.contains(mediaId) { if !result.contains(mediaId) {
result.append(mediaId) result.append(mediaId)
} }
case .stars:
break
} }
} }
@ -466,3 +513,35 @@ public final class PendingReactionsMessageAttribute: MessageAttribute {
encoder.encodeBool(self.isTags, forKey: "itag") encoder.encodeBool(self.isTags, forKey: "itag")
} }
} }
public final class PendingStarsReactionsMessageAttribute: MessageAttribute {
public let accountPeerId: PeerId?
public let count: Int32
public var associatedPeerIds: [PeerId] {
var peerIds: [PeerId] = []
if let accountPeerId = self.accountPeerId {
peerIds.append(accountPeerId)
}
return peerIds
}
public init(accountPeerId: PeerId?, count: Int32) {
self.accountPeerId = accountPeerId
self.count = count
}
required public init(decoder: PostboxDecoder) {
self.accountPeerId = decoder.decodeOptionalInt64ForKey("ap").flatMap(PeerId.init)
self.count = decoder.decodeInt32ForKey("cnt", orElse: 1)
}
public func encode(_ encoder: PostboxEncoder) {
if let accountPeerId = self.accountPeerId {
encoder.encodeInt64(accountPeerId.toInt64(), forKey: "ap")
} else {
encoder.encodeNil(forKey: "ap")
}
encoder.encodeInt32(self.count, forKey: "cnt")
}
}

View File

@ -154,9 +154,10 @@ public final class RecentEmojiItem: Codable, Equatable {
} }
public struct RecentReactionItemId { public struct RecentReactionItemId {
public enum Id : Hashable { public enum Id: Hashable {
case custom(MediaId) case custom(MediaId)
case builtin(String) case builtin(String)
case stars
} }
public let rawValue: MemoryBuffer public let rawValue: MemoryBuffer
@ -184,6 +185,8 @@ public struct RecentReactionItemId {
assert(rawValue.length >= 1 + 2 + Int(length)) assert(rawValue.length >= 1 + 2 + Int(length))
self.id = .builtin(String(data: Data(bytes: rawValue.memory.advanced(by: 1 + 2), count: Int(length)), encoding: .utf8) ?? ".") self.id = .builtin(String(data: Data(bytes: rawValue.memory.advanced(by: 1 + 2), count: Int(length)), encoding: .utf8) ?? ".")
} else if type == 2 {
self.id = .stars
} else { } else {
assert(false) assert(false)
self.id = .builtin(".") self.id = .builtin(".")
@ -216,12 +219,23 @@ public struct RecentReactionItemId {
let _ = memcpy(self.rawValue.memory.advanced(by: 1 + 2), bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), bytes.count) let _ = memcpy(self.rawValue.memory.advanced(by: 1 + 2), bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), bytes.count)
} }
} }
public init(_ id: Id) {
precondition(id == .stars)
self.id = id
self.rawValue = MemoryBuffer(memory: malloc(1)!, capacity: 1, length: 1, freeWhenDone: true)
var type: UInt8 = 2
memcpy(self.rawValue.memory.advanced(by: 0), &type, 1)
}
} }
public final class RecentReactionItem: Codable, Equatable { public final class RecentReactionItem: Codable, Equatable {
public enum Content: Equatable { public enum Content: Equatable {
case custom(TelegramMediaFile) case custom(TelegramMediaFile)
case builtin(String) case builtin(String)
case stars
} }
public let content: Content public let content: Content
@ -232,6 +246,8 @@ public final class RecentReactionItem: Codable, Equatable {
return RecentReactionItemId(value) return RecentReactionItemId(value)
case let .custom(file): case let .custom(file):
return RecentReactionItemId(file.fileId) return RecentReactionItemId(file.fileId)
case .stars:
return RecentReactionItemId(.stars)
} }
} }
@ -244,6 +260,8 @@ public final class RecentReactionItem: Codable, Equatable {
if let mediaData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "m") { if let mediaData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "m") {
self.content = .custom(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: mediaData.data)))) self.content = .custom(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: mediaData.data))))
} else if let _ = try container.decodeIfPresent(Int64.self, forKey: "star") {
self.content = .stars
} else { } else {
self.content = .builtin(try container.decode(String.self, forKey: "s")) self.content = .builtin(try container.decode(String.self, forKey: "s"))
} }
@ -257,6 +275,8 @@ public final class RecentReactionItem: Codable, Equatable {
try container.encode(PostboxEncoder().encodeObjectToRawData(file), forKey: "m") try container.encode(PostboxEncoder().encodeObjectToRawData(file), forKey: "m")
case let .builtin(string): case let .builtin(string):
try container.encode(string, forKey: "s") try container.encode(string, forKey: "s")
case .stars:
try container.encode(0 as Int64, forKey: "star")
} }
} }

View File

@ -18,3 +18,30 @@ public final class UpdateMessageReactionsAction: PendingMessageActionData {
} }
} }
} }
public final class SendStarsReactionsAction: PendingMessageActionData {
public let randomId: Int64
public init(randomId: Int64) {
self.randomId = randomId
}
public init(decoder: PostboxDecoder) {
self.randomId = decoder.decodeInt64ForKey("id", orElse: 0)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt64(self.randomId, forKey: "id")
}
public func isEqual(to: PendingMessageActionData) -> Bool {
if let other = to as? SendStarsReactionsAction {
if self.randomId != other.randomId {
return false
}
return true
} else {
return false
}
}
}

View File

@ -2254,7 +2254,7 @@ func _internal_groupCallDisplayAsAvailablePeers(accountPeerId: PeerId, network:
for chat in chats { for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _):
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
subscribers[groupOrChannel.id] = participantsCount subscribers[groupOrChannel.id] = participantsCount
} }

View File

@ -505,6 +505,8 @@ public final class EngineStoryViewListContext {
return nil return nil
case let .custom(fileId): case let .custom(fileId):
return transaction.getMedia(MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)) as? TelegramMediaFile return transaction.getMedia(MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)) as? TelegramMediaFile
case .stars:
return nil
} }
} }
))) )))
@ -696,6 +698,8 @@ public final class EngineStoryViewListContext {
reactionFile = nil reactionFile = nil
case let .custom(fileId): case let .custom(fileId):
reactionFile = transaction.getMedia(MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)) as? TelegramMediaFile reactionFile = transaction.getMedia(MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)) as? TelegramMediaFile
case .stars:
reactionFile = nil
} }
items.append(.view(Item.View( items.append(.view(Item.View(
peer: EnginePeer(peer), peer: EnginePeer(peer),

View File

@ -138,7 +138,7 @@ func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network,
for chat in chats { for chat in chats {
if let groupOrChannel = parsedPeers.get(chat.peerId) { if let groupOrChannel = parsedPeers.get(chat.peerId) {
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _):
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
subscribers[groupOrChannel.id] = participantsCount subscribers[groupOrChannel.id] = participantsCount
} }

View File

@ -331,7 +331,11 @@ public extension TelegramEngine {
isLarge: false, isLarge: false,
storeAsRecentlyUsed: false, storeAsRecentlyUsed: false,
add: true add: true
).start() ).startStandalone()
}
public func sendStarsReaction(id: EngineMessage.Id, count: Int) {
let _ = sendStarsReactionsInteractively(account: self.account, messageId: id, count: count).startStandalone()
} }
public func requestChatContextResults(botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> { public func requestChatContextResults(botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> {

View File

@ -176,7 +176,7 @@ private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id
default: default:
break break
} }
signal = account.network.request(Api.functions.payments.getStarsTransactions(flags: flags, peer: inputPeer, offset: offset, limit: limit)) signal = account.network.request(Api.functions.payments.getStarsTransactions(flags: flags, subscriptionId: nil, peer: inputPeer, offset: offset, limit: limit))
} else { } else {
signal = account.network.request(Api.functions.payments.getStarsStatus(peer: inputPeer)) signal = account.network.request(Api.functions.payments.getStarsStatus(peer: inputPeer))
} }
@ -187,12 +187,12 @@ private func _internal_requestStarsState(account: Account, peerId: EnginePeer.Id
|> mapToSignal { result -> Signal<InternalStarsStatus, RequestStarsStateError> in |> mapToSignal { result -> Signal<InternalStarsStatus, RequestStarsStateError> in
return account.postbox.transaction { transaction -> InternalStarsStatus in return account.postbox.transaction { transaction -> InternalStarsStatus in
switch result { switch result {
case let .starsStatus(_, balance, history, nextOffset, chats, users): case let .starsStatus(_, balance, _, _, _, history, nextOffset, chats, users):
let peers = AccumulatedPeers(chats: chats, users: users) let peers = AccumulatedPeers(chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: peers) updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: peers)
var parsedTransactions: [StarsContext.State.Transaction] = [] var parsedTransactions: [StarsContext.State.Transaction] = []
for entry in history { for entry in history ?? [] {
if let parsedTransaction = StarsContext.State.Transaction(apiTransaction: entry, peerId: peerId != account.peerId ? peerId : nil, transaction: transaction) { if let parsedTransaction = StarsContext.State.Transaction(apiTransaction: entry, peerId: peerId != account.peerId ? peerId : nil, transaction: transaction) {
parsedTransactions.append(parsedTransaction) parsedTransactions.append(parsedTransaction)
} }
@ -317,7 +317,7 @@ private final class StarsContextImpl {
private extension StarsContext.State.Transaction { private extension StarsContext.State.Transaction {
init?(apiTransaction: Api.StarsTransaction, peerId: EnginePeer.Id?, transaction: Transaction) { init?(apiTransaction: Api.StarsTransaction, peerId: EnginePeer.Id?, transaction: Transaction) {
switch apiTransaction { switch apiTransaction {
case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia): case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia, _):
let parsedPeer: StarsContext.State.Transaction.Peer let parsedPeer: StarsContext.State.Transaction.Peer
var paidMessageId: MessageId? var paidMessageId: MessageId?
switch transactionPeer { switch transactionPeer {
@ -889,7 +889,7 @@ func _internal_getStarsTransaction(accountPeerId: PeerId, postbox: Postbox, netw
} }
|> mapToSignal { result -> Signal<StarsContext.State.Transaction?, NoError> in |> mapToSignal { result -> Signal<StarsContext.State.Transaction?, NoError> in
return postbox.transaction { transaction -> StarsContext.State.Transaction? in return postbox.transaction { transaction -> StarsContext.State.Transaction? in
guard let result, case let .starsStatus(_, _, transactions, _, chats, users) = result, let matchingTransaction = transactions.first else { guard let result, case let .starsStatus(_, _, _, _, _, transactions, _, chats, users) = result, let matchingTransaction = transactions?.first else {
return nil return nil
} }
let peers = AccumulatedPeers(chats: chats, users: users) let peers = AccumulatedPeers(chats: chats, users: users)

View File

@ -558,7 +558,7 @@ func _internal_adminedPublicChannels(account: Account, scope: AdminedPublicChann
case let .chats(apiChats): case let .chats(apiChats):
chats = apiChats chats = apiChats
for chat in apiChats { for chat in apiChats {
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat {
subscriberCounts[chat.peerId] = participantsCount.flatMap(Int.init) subscriberCounts[chat.peerId] = participantsCount.flatMap(Int.init)
} }
} }
@ -630,7 +630,7 @@ func _internal_channelsForStories(account: Account) -> Signal<[Peer], NoError> {
if let peer = transaction.getPeer(chat.peerId) { if let peer = transaction.getPeer(chat.peerId) {
peers.append(peer) peers.append(peer)
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat, let participantsCount = participantsCount { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat, let participantsCount = participantsCount {
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
var current = current as? CachedChannelData ?? CachedChannelData() var current = current as? CachedChannelData ?? CachedChannelData()
var participantsSummary = current.participantsSummary var participantsSummary = current.participantsSummary

View File

@ -117,7 +117,7 @@ func _internal_requestRecommendedChannels(account: Account, peerId: EnginePeer.I
for chat in chats { for chat in chats {
if let peer = transaction.getPeer(chat.peerId) { if let peer = transaction.getPeer(chat.peerId) {
peers.append(EnginePeer(peer)) peers.append(EnginePeer(peer))
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat, let participantsCount = participantsCount { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat, let participantsCount = participantsCount {
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
var current = current as? CachedChannelData ?? CachedChannelData() var current = current as? CachedChannelData ?? CachedChannelData()
var participantsSummary = current.participantsSummary var participantsSummary = current.participantsSummary

View File

@ -280,7 +280,7 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
var memberCounts: [PeerId: Int] = [:] var memberCounts: [PeerId: Int] = [:]
for chat in chats { for chat in chats {
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat {
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
memberCounts[chat.peerId] = Int(participantsCount) memberCounts[chat.peerId] = Int(participantsCount)
} }
@ -307,7 +307,7 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
var memberCounts: [PeerId: Int] = [:] var memberCounts: [PeerId: Int] = [:]
for chat in chats { for chat in chats {
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat {
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
memberCounts[chat.peerId] = Int(participantsCount) memberCounts[chat.peerId] = Int(participantsCount)
} }
@ -621,7 +621,7 @@ func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> S
var memberCounts: [ChatListFiltersState.ChatListFilterUpdates.MemberCount] = [] var memberCounts: [ChatListFiltersState.ChatListFilterUpdates.MemberCount] = []
for chat in chats { for chat in chats {
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat {
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
memberCounts.append(ChatListFiltersState.ChatListFilterUpdates.MemberCount(id: chat.peerId, count: participantsCount)) memberCounts.append(ChatListFiltersState.ChatListFilterUpdates.MemberCount(id: chat.peerId, count: participantsCount))
} }

View File

@ -31,7 +31,7 @@ func _internal_inactiveChannelList(network: Network) -> Signal<[InactiveChannel]
var participantsCounts: [PeerId: Int32] = [:] var participantsCounts: [PeerId: Int32] = [:]
for chat in chats { for chat in chats {
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCountValue, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCountValue, _, _, _, _, _, _, _):
if let participantsCountValue = participantsCountValue { if let participantsCountValue = participantsCountValue {
participantsCounts[chat.peerId] = participantsCountValue participantsCounts[chat.peerId] = participantsCountValue
} }

View File

@ -44,7 +44,7 @@ func _internal_revokePersistentPeerExportedInvitation(account: Account, peerId:
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let flags: Int32 = (1 << 2) let flags: Int32 = (1 << 2)
if let _ = peer as? TelegramChannel { if let _ = peer as? TelegramChannel {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil, subscriptionPricing: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in return account.postbox.transaction { transaction -> ExportedInvitation? in
@ -61,7 +61,7 @@ func _internal_revokePersistentPeerExportedInvitation(account: Account, peerId:
} }
} }
} else if let _ = peer as? TelegramGroup { } else if let _ = peer as? TelegramGroup {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil, subscriptionPricing: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in return account.postbox.transaction { transaction -> ExportedInvitation? in
@ -106,7 +106,7 @@ func _internal_createPeerExportedInvitation(account: Account, peerId: PeerId, ti
if let _ = title { if let _ = title {
flags |= (1 << 4) flags |= (1 << 4)
} }
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit, title: title)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit, title: title, subscriptionPricing: nil))
|> mapError { _ in return CreatePeerExportedInvitationError.generic } |> mapError { _ in return CreatePeerExportedInvitationError.generic }
|> map { result -> ExportedInvitation? in |> map { result -> ExportedInvitation? in
return ExportedInvitation(apiExportedInvite: result) return ExportedInvitation(apiExportedInvite: result)

View File

@ -106,7 +106,7 @@ func _internal_joinLinkInformation(_ hash: String, account: Account) -> Signal<E
|> mapToSignal { result -> Signal<ExternalJoiningChatState, JoinLinkInfoError> in |> mapToSignal { result -> Signal<ExternalJoiningChatState, JoinLinkInfoError> in
if let result = result { if let result = result {
switch result { switch result {
case let .chatInvite(flags, title, about, invitePhoto, participantsCount, participants, nameColor): case let .chatInvite(flags, title, about, invitePhoto, participantsCount, participants, nameColor, _, _):
let photo = telegramMediaImageFromApiPhoto(invitePhoto).flatMap({ smallestImageRepresentation($0.representations) }) let photo = telegramMediaImageFromApiPhoto(invitePhoto).flatMap({ smallestImageRepresentation($0.representations) })
let flags: ExternalJoiningChatState.Invite.Flags = .init(isChannel: (flags & (1 << 0)) != 0, isBroadcast: (flags & (1 << 1)) != 0, isPublic: (flags & (1 << 2)) != 0, isMegagroup: (flags & (1 << 3)) != 0, requestNeeded: (flags & (1 << 6)) != 0, isVerified: (flags & (1 << 7)) != 0, isScam: (flags & (1 << 8)) != 0, isFake: (flags & (1 << 9)) != 0) let flags: ExternalJoiningChatState.Invite.Flags = .init(isChannel: (flags & (1 << 0)) != 0, isBroadcast: (flags & (1 << 1)) != 0, isPublic: (flags & (1 << 2)) != 0, isMegagroup: (flags & (1 << 3)) != 0, requestNeeded: (flags & (1 << 6)) != 0, isVerified: (flags & (1 << 7)) != 0, isScam: (flags & (1 << 8)) != 0, isFake: (flags & (1 << 9)) != 0)
return .single(.invite(ExternalJoiningChatState.Invite(flags: flags, title: title, about: about, photoRepresentation: photo, participantsCount: participantsCount, participants: participants?.map({ EnginePeer(TelegramUser(user: $0)) }), nameColor: PeerNameColor(rawValue: nameColor)))) return .single(.invite(ExternalJoiningChatState.Invite(flags: flags, title: title, about: about, photoRepresentation: photo, participantsCount: participantsCount, participants: participants?.map({ EnginePeer(TelegramUser(user: $0)) }), nameColor: PeerNameColor(rawValue: nameColor))))

View File

@ -42,7 +42,7 @@ public func _internal_searchPeers(accountPeerId: PeerId, postbox: Postbox, netwo
for chat in chats { for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _):
if let participantsCount = participantsCount { if let participantsCount = participantsCount {
subscribers[groupOrChannel.id] = participantsCount subscribers[groupOrChannel.id] = participantsCount
} }

View File

@ -367,7 +367,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
var subscriberCount: Int32? var subscriberCount: Int32?
for chat in chats { for chat in chats {
if chat.peerId == channelPeerId { if chat.peerId == channelPeerId {
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _) = chat { if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _) = chat {
subscriberCount = participantsCount subscriberCount = participantsCount
} }
} }
@ -509,7 +509,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
} else { } else {
mappedAllowedReactions = .empty mappedAllowedReactions = .empty
} }
let mappedReactionSettings = PeerReactionSettings(allowedReactions: mappedAllowedReactions, maxReactionCount: reactionsLimit)
let mappedReactionSettings = PeerReactionSettings(allowedReactions: mappedAllowedReactions, maxReactionCount: reactionsLimit, starsAllowed: nil)
return previous.withUpdatedParticipants(participants) return previous.withUpdatedParticipants(participants)
.withUpdatedExportedInvitation(exportedInvitation) .withUpdatedExportedInvitation(exportedInvitation)
@ -556,10 +557,10 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
switch result { switch result {
case let .chatFull(fullChat, chats, users): case let .chatFull(fullChat, chats, users):
switch fullChat { switch fullChat {
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .chatFull: case .chatFull:
break break
} }
switch fullChat { switch fullChat {
@ -691,7 +692,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
switch participantResult { switch participantResult {
case let .channelParticipant(participant, _, _): case let .channelParticipant(participant, _, _):
switch participant { switch participant {
case let .channelParticipantSelf(flags, _, inviterId, invitedDate): case let .channelParticipantSelf(_, _, inviterId, invitedDate, _):
invitedBy = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId)) invitedBy = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId))
if (flags & (1 << 0)) != 0 { if (flags & (1 << 0)) != 0 {
invitedOn = invitedDate invitedOn = invitedDate
@ -754,7 +755,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
} else { } else {
mappedAllowedReactions = .empty mappedAllowedReactions = .empty
} }
let mappedReactionSettings = PeerReactionSettings(allowedReactions: mappedAllowedReactions, maxReactionCount: reactionsLimit) let starsAllowed: Bool = (flags2 & (1 << 16)) != 0
let mappedReactionSettings = PeerReactionSettings(allowedReactions: mappedAllowedReactions, maxReactionCount: reactionsLimit, starsAllowed: starsAllowed)
let membersHidden = (flags2 & (1 << 2)) != 0 let membersHidden = (flags2 & (1 << 2)) != 0
let forumViewAsMessages = (flags2 & (1 << 6)) != 0 let forumViewAsMessages = (flags2 & (1 << 6)) != 0

View File

@ -180,7 +180,7 @@ func _internal_requestAccountPrivacySettings(account: Account) -> Signal<Account
if let peer = parseTelegramGroupOrChannel(chat: chat) { if let peer = parseTelegramGroupOrChannel(chat: chat) {
var participantCount: Int32? = nil var participantCount: Int32? = nil
switch chat { switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCountValue, _, _, _, _, _, _): case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCountValue, _, _, _, _, _, _, _):
participantCount = participantsCountValue participantCount = participantsCountValue
default: default:
break break

View File

@ -72,7 +72,7 @@ func updatePeers(transaction: Transaction, accountPeerId: PeerId, peers: Accumul
} }
for (_, chat) in peers.chats { for (_, chat) in peers.chats {
switch chat { switch chat {
case let .channel(flags, flags2, _, _, _, _, _, _, _, _, _, _, _, _, storiesMaxId, _, _, _, _): case let .channel(flags, flags2, _, _, _, _, _, _, _, _, _, _, _, _, storiesMaxId, _, _, _, _, _):
let isMin = (flags & (1 << 12)) != 0 let isMin = (flags & (1 << 12)) != 0
let storiesUnavailable = (flags2 & (1 << 3)) != 0 let storiesUnavailable = (flags2 & (1 << 3)) != 0

View File

@ -727,7 +727,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
var animationFileId: Int64? var animationFileId: Int64?
switch reaction.value { switch reaction.value {
case .builtin: case .builtin, .stars:
if let availableReactions = arguments.availableReactions { if let availableReactions = arguments.availableReactions {
for availableReaction in availableReactions.reactions { for availableReaction in availableReactions.reactions {
if availableReaction.value == reaction.value { if availableReaction.value == reaction.value {

View File

@ -159,6 +159,15 @@ public final class MessageReactionButtonsNode: ASDisplayNode {
} }
case let .custom(fileId): case let .custom(fileId):
animationFileId = fileId animationFileId = fileId
case .stars:
if let availableReactions = availableReactions {
for availableReaction in availableReactions.reactions {
if availableReaction.value == reaction.value {
centerAnimation = availableReaction.centerAnimation
break
}
}
}
} }
var peers: [EnginePeer] = [] var peers: [EnginePeer] = []

View File

@ -318,6 +318,8 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
return .builtin(value) return .builtin(value)
case let .custom(fileId): case let .custom(fileId):
return .custom(fileId: fileId, file: nil) return .custom(fileId: fileId, file: nil)
case .stars:
return .stars
} }
} }
if let selectionState = presentationInterfaceState.interfaceState.selectionState { if let selectionState = presentationInterfaceState.interfaceState.selectionState {

View File

@ -1636,6 +1636,8 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
reactionText = "." reactionText = "."
entities.append(MessageTextEntity(range: (text as NSString).length ..< (text as NSString).length + (reactionText as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: fileId))) entities.append(MessageTextEntity(range: (text as NSString).length ..< (text as NSString).length + (reactionText as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: fileId)))
text.append(reactionText) text.append(reactionText)
case .stars:
break
} }
} }
} }

View File

@ -94,7 +94,7 @@ private final class BalanceComponent: CombinedComponent {
animationCache: context.component.context.animationCache, animationCache: context.component.context.animationCache,
animationRenderer: context.component.context.animationRenderer, animationRenderer: context.component.context.animationRenderer,
content: .animation( content: .animation(
content: .customEmoji(fileId: MessageReaction.starsReactionId), content: .customEmoji(fileId: MessageReaction.starsReactionId), //TODO:release
size: iconSize, size: iconSize,
placeholderColor: .gray, placeholderColor: .gray,
themeColor: nil, themeColor: nil,

View File

@ -100,6 +100,13 @@ public final class ChatShareMessageTagView: UIView, UndoOverlayControllerAdditio
} }
case let .custom(_, fileValue): case let .custom(_, fileValue):
file = fileValue file = fileValue
case .stars:
for reaction in availableReactions.reactions {
if reaction.value == updateReaction.reaction {
file = reaction.centerAnimation
break
}
}
} }
guard let file else { guard let file else {

View File

@ -10,13 +10,13 @@ public enum AllowedReactions {
case all case all
} }
public func peerMessageAllowedReactions(context: AccountContext, message: Message) -> Signal<AllowedReactions?, NoError> { public func peerMessageAllowedReactions(context: AccountContext, message: Message) -> Signal<(allowedReactions: AllowedReactions?, areStarsEnabled: Bool), NoError> {
if message.id.peerId == context.account.peerId { if message.id.peerId == context.account.peerId {
return .single(.all) return .single((.all, false))
} }
if message.containsSecretMedia { if message.containsSecretMedia {
return .single(AllowedReactions.set(Set())) return .single((AllowedReactions.set(Set()), false))
} }
return combineLatest( return combineLatest(
@ -26,7 +26,7 @@ public func peerMessageAllowedReactions(context: AccountContext, message: Messag
), ),
context.engine.stickers.availableReactions() |> take(1) context.engine.stickers.availableReactions() |> take(1)
) )
|> map { data, availableReactions -> AllowedReactions? in |> map { data, availableReactions -> (allowedReactions: AllowedReactions?, areStarsEnabled: Bool) in
let (peer, reactionSettings) = data let (peer, reactionSettings) = data
let maxReactionCount: Int let maxReactionCount: Int
@ -35,35 +35,41 @@ public func peerMessageAllowedReactions(context: AccountContext, message: Messag
} else { } else {
maxReactionCount = 11 maxReactionCount = 11
} }
var areStarsEnabled: Bool = false
if let value = reactionSettings.knownValue?.starsAllowed {
areStarsEnabled = value
}
if let effectiveReactions = message.effectiveReactions(isTags: message.areReactionsTags(accountPeerId: context.account.peerId)), effectiveReactions.count >= maxReactionCount { if let effectiveReactions = message.effectiveReactions(isTags: message.areReactionsTags(accountPeerId: context.account.peerId)), effectiveReactions.count >= maxReactionCount {
return .set(Set(effectiveReactions.map(\.value))) return (.set(Set(effectiveReactions.map(\.value))), areStarsEnabled)
} }
switch reactionSettings { switch reactionSettings {
case .unknown: case .unknown:
if case let .channel(channel) = peer, case .broadcast = channel.info { if case let .channel(channel) = peer, case .broadcast = channel.info {
if let availableReactions = availableReactions { if let availableReactions = availableReactions {
return .set(Set(availableReactions.reactions.map(\.value))) return (.set(Set(availableReactions.reactions.map(\.value))), areStarsEnabled)
} else { } else {
return .set(Set()) return (.set(Set()), areStarsEnabled)
} }
} }
return .all return (.all, areStarsEnabled)
case let .known(value): case let .known(value):
switch value.allowedReactions { switch value.allowedReactions {
case .all: case .all:
if case let .channel(channel) = peer, case .broadcast = channel.info { if case let .channel(channel) = peer, case .broadcast = channel.info {
if let availableReactions = availableReactions { if let availableReactions = availableReactions {
return .set(Set(availableReactions.reactions.map(\.value))) return (.set(Set(availableReactions.reactions.map(\.value))), areStarsEnabled)
} else { } else {
return .set(Set()) return (.set(Set()), areStarsEnabled)
} }
} }
return .all return (.all, areStarsEnabled)
case let .limited(reactions): case let .limited(reactions):
return .set(Set(reactions)) return (.set(Set(reactions)), areStarsEnabled)
case .empty: case .empty:
return .set(Set()) return (.set(Set()), areStarsEnabled)
} }
} }
} }
@ -160,6 +166,8 @@ public func tagMessageReactions(context: AccountContext, subPeerId: EnginePeer.I
largeApplicationAnimation: nil, largeApplicationAnimation: nil,
isCustom: true isCustom: true
)) ))
case .stars:
continue
} }
} }
@ -212,6 +220,33 @@ public func tagMessageReactions(context: AccountContext, subPeerId: EnginePeer.I
largeApplicationAnimation: nil, largeApplicationAnimation: nil,
isCustom: true isCustom: true
)) ))
case .stars:
if let reaction = availableReactions?.reactions.first(where: { $0.value == .stars }) {
guard let centerAnimation = reaction.centerAnimation else {
continue
}
guard let aroundAnimation = reaction.aroundAnimation else {
continue
}
if existingIds.contains(reaction.value) {
continue
}
existingIds.insert(reaction.value)
result.append(ReactionItem(
reaction: ReactionItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: centerAnimation,
largeListAnimation: reaction.activateAnimation,
applicationAnimation: aroundAnimation,
largeApplicationAnimation: reaction.effectAnimation,
isCustom: false
))
} else {
continue
}
} }
} }
} }
@ -250,41 +285,28 @@ public func topMessageReactions(context: AccountContext, message: Message, subPe
} }
} }
let allowedReactionsWithFiles: Signal<(reactions: AllowedReactions, files: [Int64: TelegramMediaFile])?, NoError> = peerMessageAllowedReactions(context: context, message: message) let allowedReactionsWithFiles: Signal<(reactions: AllowedReactions, files: [Int64: TelegramMediaFile], areStarsEnabled: Bool)?, NoError> = peerMessageAllowedReactions(context: context, message: message)
|> mapToSignal { allowedReactions -> Signal<(reactions: AllowedReactions, files: [Int64: TelegramMediaFile])?, NoError> in |> mapToSignal { allowedReactions, areStarsEnabled -> Signal<(reactions: AllowedReactions, files: [Int64: TelegramMediaFile], areStarsEnabled: Bool)?, NoError> in
guard let allowedReactions = allowedReactions else { guard let allowedReactions = allowedReactions else {
return .single(nil) return .single(nil)
} }
if case let .set(reactions) = allowedReactions { if case let .set(reactions) = allowedReactions {
#if DEBUG
var reactions = reactions
if context.sharedContext.applicationBindings.appBuildType == .internal {
reactions.insert(.custom(MessageReaction.starsReactionId))
}
#endif
return context.engine.stickers.resolveInlineStickers(fileIds: reactions.compactMap { item -> Int64? in return context.engine.stickers.resolveInlineStickers(fileIds: reactions.compactMap { item -> Int64? in
switch item { switch item {
case .builtin: case .builtin:
return nil return nil
case let .custom(fileId): case let .custom(fileId):
return fileId return fileId
case .stars:
return nil
} }
}) })
|> map { files -> (reactions: AllowedReactions, files: [Int64: TelegramMediaFile]) in |> map { files -> (reactions: AllowedReactions, files: [Int64: TelegramMediaFile], areStarsEnabled: Bool) in
return (.set(reactions), files) return (.set(reactions), files, areStarsEnabled)
} }
} else { } else {
#if DEBUG return .single((allowedReactions, [:], areStarsEnabled))
if context.sharedContext.applicationBindings.appBuildType == .internal {
return context.engine.stickers.resolveInlineStickers(fileIds: [MessageReaction.starsReactionId])
|> map { files -> (reactions: AllowedReactions, files: [Int64: TelegramMediaFile]) in
return (allowedReactions, files)
}
}
#endif
return .single((allowedReactions, [:]))
} }
} }
@ -302,25 +324,6 @@ public func topMessageReactions(context: AccountContext, message: Message, subPe
var result: [ReactionItem] = [] var result: [ReactionItem] = []
var existingIds = Set<MessageReaction.Reaction>() var existingIds = Set<MessageReaction.Reaction>()
#if DEBUG
if context.sharedContext.applicationBindings.appBuildType == .internal {
if let file = allowedReactionsAndFiles.files[MessageReaction.starsReactionId] {
existingIds.insert(.custom(MessageReaction.starsReactionId))
result.append(ReactionItem(
reaction: ReactionItem.Reaction(rawValue: .custom(file.fileId.id)),
appearAnimation: file,
stillAnimation: file,
listAnimation: file,
largeListAnimation: file,
applicationAnimation: nil,
largeApplicationAnimation: nil,
isCustom: true
))
}
}
#endif
for topReaction in topReactions { for topReaction in topReactions {
switch topReaction.content { switch topReaction.content {
case let .builtin(value): case let .builtin(value):
@ -384,6 +387,8 @@ public func topMessageReactions(context: AccountContext, message: Message, subPe
largeApplicationAnimation: nil, largeApplicationAnimation: nil,
isCustom: true isCustom: true
)) ))
case .stars:
break
} }
} }
@ -447,6 +452,28 @@ public func topMessageReactions(context: AccountContext, message: Message, subPe
isCustom: true isCustom: true
)) ))
} }
case .stars:
break
}
}
}
if allowedReactionsAndFiles.areStarsEnabled {
result.removeAll(where: { $0.reaction.rawValue == .stars })
if let reaction = availableReactions.reactions.first(where: { $0.value == .stars }) {
if let centerAnimation = reaction.centerAnimation, let aroundAnimation = reaction.aroundAnimation {
existingIds.insert(reaction.value)
result.insert(ReactionItem(
reaction: ReactionItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: centerAnimation,
largeListAnimation: reaction.activateAnimation,
applicationAnimation: aroundAnimation,
largeApplicationAnimation: reaction.effectAnimation,
isCustom: false
), at: 0)
} }
} }
} }

View File

@ -793,6 +793,10 @@ public extension EmojiPagerContentComponent {
} }
case let .custom(file): case let .custom(file):
topReactionItems.append(EmojiComponentReactionItem(reaction: .custom(file.fileId.id), file: file)) topReactionItems.append(EmojiComponentReactionItem(reaction: .custom(file.fileId.id), file: file))
case .stars:
if let reaction = availableReactions?.reactions.first(where: { $0.value == .stars }) {
topReactionItems.append(EmojiComponentReactionItem(reaction: .stars, file: reaction.selectAnimation))
}
} }
} }
} }
@ -962,6 +966,22 @@ public extension EmojiPagerContentComponent {
} else { } else {
icon = .none icon = .none
} }
case .stars:
if existingIds.contains(.stars) {
continue
}
existingIds.insert(.stars)
if let availableReactions = availableReactions, let availableReaction = availableReactions.reactions.first(where: { $0.value == .stars }) {
if let centerAnimation = availableReaction.centerAnimation {
animationFile = centerAnimation
} else {
continue
}
} else {
continue
}
icon = .none
} }
var tintMode: Item.TintMode = .none var tintMode: Item.TintMode = .none
@ -1014,6 +1034,12 @@ public extension EmojiPagerContentComponent {
} }
case let .custom(file): case let .custom(file):
topReactionItems.append(EmojiComponentReactionItem(reaction: .custom(file.fileId.id), file: file)) topReactionItems.append(EmojiComponentReactionItem(reaction: .custom(file.fileId.id), file: file))
case .stars:
if let reaction = availableReactions?.reactions.first(where: { $0.value == .stars }) {
topReactionItems.append(EmojiComponentReactionItem(reaction: .stars, file: reaction.selectAnimation))
} else {
continue
}
} }
} }
} }

View File

@ -8223,6 +8223,8 @@ private func allowedStoryReactions(context: AccountContext) -> Signal<[ReactionI
largeApplicationAnimation: nil, largeApplicationAnimation: nil,
isCustom: true isCustom: true
)) ))
case .stars:
break
} }
} }

View File

@ -157,7 +157,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
allowedReactions = .empty allowedReactions = .empty
} }
let reactionSettings = PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: self.allowedReactionCount >= 11 ? nil : Int32(self.allowedReactionCount)) let reactionSettings = PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: self.allowedReactionCount >= 11 ? nil : Int32(self.allowedReactionCount), starsAllowed: self.areStarsReactionsEnabled)
if self.appliedReactionSettings != reactionSettings { if self.appliedReactionSettings != reactionSettings {
if case .empty = allowedReactions { if case .empty = allowedReactions {
@ -223,6 +223,8 @@ final class PeerAllowedReactionsScreenComponent: Component {
return true return true
case .builtin: case .builtin:
return false return false
case .stars:
return false
} }
}) })
@ -248,7 +250,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
} else { } else {
allowedReactions = .empty allowedReactions = .empty
} }
let reactionSettings = PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: self.allowedReactionCount == 11 ? nil : Int32(self.allowedReactionCount)) let reactionSettings = PeerReactionSettings(allowedReactions: allowedReactions, maxReactionCount: self.allowedReactionCount == 11 ? nil : Int32(self.allowedReactionCount), starsAllowed: self.areStarsReactionsEnabled)
let applyDisposable = (component.context.engine.peers.updatePeerReactionSettings(peerId: component.peerId, reactionSettings: reactionSettings) let applyDisposable = (component.context.engine.peers.updatePeerReactionSettings(peerId: component.peerId, reactionSettings: reactionSettings)
|> deliverOnMainQueue).start(error: { [weak self] error in |> deliverOnMainQueue).start(error: { [weak self] error in
@ -362,10 +364,16 @@ final class PeerAllowedReactionsScreenComponent: Component {
self.appliedReactionSettings = component.initialContent.reactionSettings.flatMap { reactionSettings in self.appliedReactionSettings = component.initialContent.reactionSettings.flatMap { reactionSettings in
return PeerReactionSettings( return PeerReactionSettings(
allowedReactions: reactionSettings.allowedReactions, allowedReactions: reactionSettings.allowedReactions,
maxReactionCount: reactionSettings.maxReactionCount == 11 ? nil : reactionSettings.maxReactionCount maxReactionCount: reactionSettings.maxReactionCount == 11 ? nil : reactionSettings.maxReactionCount,
starsAllowed: reactionSettings.starsAllowed
) )
} }
self.allowedReactionCount = (component.initialContent.reactionSettings?.maxReactionCount).flatMap(Int.init) ?? 11 self.allowedReactionCount = (component.initialContent.reactionSettings?.maxReactionCount).flatMap(Int.init) ?? 11
if let value = component.initialContent.reactionSettings?.starsAllowed {
self.areStarsReactionsEnabled = value
} else {
self.areStarsReactionsEnabled = component.initialContent.isStarReactionAvailable
}
} }
var caretPosition = self.caretPosition ?? enabledReactions.count var caretPosition = self.caretPosition ?? enabledReactions.count
caretPosition = max(0, min(enabledReactions.count, caretPosition)) caretPosition = max(0, min(enabledReactions.count, caretPosition))
@ -443,6 +451,8 @@ final class PeerAllowedReactionsScreenComponent: Component {
return true return true
case .builtin: case .builtin:
return false return false
case .stars:
return false
} }
}) })
@ -868,7 +878,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
} }
contentHeight += reactionCountSectionSize.height contentHeight += reactionCountSectionSize.height
if !"".isEmpty { if component.initialContent.isStarReactionAvailable {
contentHeight += 32.0 contentHeight += 32.0
let paidReactionsSection: ComponentView<Empty> let paidReactionsSection: ComponentView<Empty>
@ -926,7 +936,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListSwitchItemComponent( AnyComponentWithIdentity(id: 0, component: AnyComponent(ListSwitchItemComponent(
theme: environment.theme, theme: environment.theme,
title: "Enable Paid Reactions", title: "Enable Paid Reactions",
value: areStarsReactionsEnabled, value: self.areStarsReactionsEnabled,
valueUpdated: { [weak self] value in valueUpdated: { [weak self] value in
guard let self else { guard let self else {
return return
@ -1049,6 +1059,8 @@ final class PeerAllowedReactionsScreenComponent: Component {
return true return true
case .builtin: case .builtin:
return false return false
case .stars:
return false
} }
}).count : 0 }).count : 0
@ -1231,17 +1243,20 @@ public class PeerAllowedReactionsScreen: ViewControllerComponentContainer {
public let enabledReactions: [EmojiComponentReactionItem] public let enabledReactions: [EmojiComponentReactionItem]
public let availableReactions: AvailableReactions? public let availableReactions: AvailableReactions?
public let reactionSettings: PeerReactionSettings? public let reactionSettings: PeerReactionSettings?
public let isStarReactionAvailable: Bool
init( init(
isEnabled: Bool, isEnabled: Bool,
enabledReactions: [EmojiComponentReactionItem], enabledReactions: [EmojiComponentReactionItem],
availableReactions: AvailableReactions?, availableReactions: AvailableReactions?,
reactionSettings: PeerReactionSettings? reactionSettings: PeerReactionSettings?,
isStarReactionAvailable: Bool
) { ) {
self.isEnabled = isEnabled self.isEnabled = isEnabled
self.enabledReactions = enabledReactions self.enabledReactions = enabledReactions
self.availableReactions = availableReactions self.availableReactions = availableReactions
self.reactionSettings = reactionSettings self.reactionSettings = reactionSettings
self.isStarReactionAvailable = isStarReactionAvailable
} }
public static func ==(lhs: Content, rhs: Content) -> Bool { public static func ==(lhs: Content, rhs: Content) -> Bool {
@ -1260,6 +1275,9 @@ public class PeerAllowedReactionsScreen: ViewControllerComponentContainer {
if lhs.reactionSettings != rhs.reactionSettings { if lhs.reactionSettings != rhs.reactionSettings {
return false return false
} }
if lhs.isStarReactionAvailable != rhs.isStarReactionAvailable {
return false
}
return true return true
} }
} }
@ -1370,7 +1388,7 @@ public class PeerAllowedReactionsScreen: ViewControllerComponentContainer {
} }
} }
return Content(isEnabled: isEnabled, enabledReactions: result, availableReactions: availableReactions, reactionSettings: reactionSettings) return Content(isEnabled: isEnabled, enabledReactions: result, availableReactions: availableReactions, reactionSettings: reactionSettings, isStarReactionAvailable: cachedData.flags.contains(.paidMediaAllowed))
} }
} }
|> distinctUntilChanged |> distinctUntilChanged

View File

@ -338,6 +338,15 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
} }
case let .custom(fileId): case let .custom(fileId):
animationContent = .customEmoji(fileId: fileId) animationContent = .customEmoji(fileId: fileId)
case .stars:
if let availableReactions = item.availableReactions {
for reaction in availableReactions.reactions {
if reaction.value == item.reaction {
animationContent = .file(file: reaction.selectAnimation)
break
}
}
}
} }

View File

@ -307,6 +307,13 @@ public func quickReactionSetupController(
} }
case let .custom(fileId): case let .custom(fileId):
currentSelectedFileId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId) currentSelectedFileId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
case .stars:
if let availableReactions = availableReactions {
if let reaction = availableReactions.reactions.first(where: { $0.value == settings.quickReaction }) {
currentSelectedFileId = reaction.selectAnimation.fileId
break
}
}
} }
var selectedItems = Set<MediaId>() var selectedItems = Set<MediaId>()

View File

@ -207,6 +207,31 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
strongSelf.beginReactionAnimation(reactionItem: reactionItem) strongSelf.beginReactionAnimation(reactionItem: reactionItem)
} }
}) })
case .stars:
for reaction in availableReactions.reactions {
guard let centerAnimation = reaction.centerAnimation else {
continue
}
guard let aroundAnimation = reaction.aroundAnimation else {
continue
}
if reaction.value == updatedReaction {
let reactionItem = ReactionItem(
reaction: ReactionItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: centerAnimation,
largeListAnimation: reaction.activateAnimation,
applicationAnimation: aroundAnimation,
largeApplicationAnimation: reaction.effectAnimation,
isCustom: false
)
self.beginReactionAnimation(reactionItem: reactionItem)
break
}
}
} }
} }
} }

View File

@ -987,6 +987,9 @@ public final class PeerListItemComponent: Component {
self.file = file self.file = file
self.updateReactionLayer() self.updateReactionLayer()
}) })
case .stars:
self.file = reaction.file
self.updateReactionLayer()
} }
} else { } else {
self.file = nil self.file = nil

View File

@ -1859,6 +1859,8 @@ public func preloadStoryMedia(context: AccountContext, info: StoryPreloadInfo) -
if !customReactions.contains(fileId) { if !customReactions.contains(fileId) {
customReactions.append(fileId) customReactions.append(fileId)
} }
case .stars:
break
} }
} }
if !builtinReactions.isEmpty { if !builtinReactions.isEmpty {
@ -2090,6 +2092,8 @@ public func waitUntilStoryMediaPreloaded(context: AccountContext, peerId: Engine
if !customReactions.contains(fileId) { if !customReactions.contains(fileId) {
customReactions.append(fileId) customReactions.append(fileId)
} }
case .stars:
break
} }
} }
} }

View File

@ -2198,6 +2198,8 @@ func allowedStoryReactions(context: AccountContext) -> Signal<[ReactionItem], No
largeApplicationAnimation: nil, largeApplicationAnimation: nil,
isCustom: true isCustom: true
)) ))
case .stars:
break
} }
} }

View File

@ -98,6 +98,8 @@ public func storyPreviewWithAddedReactions(
if !customFileIds.contains(fileId) { if !customFileIds.contains(fileId) {
customFileIds.append(fileId) customFileIds.append(fileId)
} }
case .stars:
break
} }
} }
} }
@ -361,6 +363,15 @@ final class StoryItemOverlaysView: UIView {
}) })
} }
} }
case .stars:
if let availableReactions {
for reactionItem in availableReactions.reactionItems {
if reactionItem.reaction.rawValue == reaction {
file = reactionItem.stillAnimation
break
}
}
}
} }
} }

View File

@ -1745,6 +1745,15 @@ public final class StoryItemSetContainerComponent: Component {
} }
case let .custom(fileId): case let .custom(fileId):
animationFileId = fileId animationFileId = fileId
case .stars:
if let availableReactions = component.availableReactions {
for availableReaction in availableReactions.reactionItems {
if availableReaction.reaction.rawValue == value {
centerAnimation = availableReaction.listAnimation
break
}
}
}
} }
if animationFileId == nil && centerAnimation == nil { if animationFileId == nil && centerAnimation == nil {
@ -2944,6 +2953,15 @@ public final class StoryItemSetContainerComponent: Component {
} }
case let .custom(fileId): case let .custom(fileId):
animationFileId = fileId animationFileId = fileId
case .stars:
if let availableReactions = component.availableReactions {
for availableReaction in availableReactions.reactionItems {
if availableReaction.reaction.rawValue == value {
centerAnimation = availableReaction.listAnimation
break
}
}
}
} }
if animationFileId == nil && centerAnimation == nil { if animationFileId == nil && centerAnimation == nil {
@ -4564,7 +4582,7 @@ public final class StoryItemSetContainerComponent: Component {
standaloneReactionAnimation.frame = self.bounds standaloneReactionAnimation.frame = self.bounds
self.addSubview(standaloneReactionAnimation.view) self.addSubview(standaloneReactionAnimation.view)
}, completion: { [weak targetView, weak reactionContextNode] in }, onHit: nil, completion: { [weak targetView, weak reactionContextNode] in
targetView?.removeFromSuperview() targetView?.removeFromSuperview()
if let reactionContextNode { if let reactionContextNode {
reactionContextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak reactionContextNode] _ in reactionContextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak reactionContextNode] _ in
@ -4602,6 +4620,8 @@ public final class StoryItemSetContainerComponent: Component {
} }
} }
} }
case .stars:
break
} }
let message: EnqueueMessage = .message( let message: EnqueueMessage = .message(
@ -4748,7 +4768,7 @@ public final class StoryItemSetContainerComponent: Component {
standaloneReactionAnimation.frame = self.bounds standaloneReactionAnimation.frame = self.bounds
self.componentContainerView.addSubview(standaloneReactionAnimation.view) self.componentContainerView.addSubview(standaloneReactionAnimation.view)
}, completion: { [weak reactionContextNode] in }, onHit: nil, completion: { [weak reactionContextNode] in
if let reactionContextNode { if let reactionContextNode {
reactionContextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak reactionContextNode] _ in reactionContextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak reactionContextNode] _ in
reactionContextNode?.view.removeFromSuperview() reactionContextNode?.view.removeFromSuperview()

View File

@ -3577,6 +3577,15 @@ final class StoryItemSetContainerSendMessage {
animateWithReactionItem(reactionItem) animateWithReactionItem(reactionItem)
} }
}) })
case .stars:
if let availableReactions = component.availableReactions {
for reactionItem in availableReactions.reactionItems {
if reactionItem.reaction.rawValue == reaction {
animateWithReactionItem(reactionItem)
break
}
}
}
} }
} }
} }

View File

@ -569,6 +569,15 @@ final class StoryItemSetViewListComponent: Component {
if case let .view(view) = item { if case let .view(view) = item {
animationFile = view.reactionFile animationFile = view.reactionFile
} }
case .stars:
if let availableReactions = component.availableReactions {
for availableReaction in availableReactions.reactionItems {
if availableReaction.reaction.rawValue == reaction {
animationFile = availableReaction.listAnimation
break
}
}
}
} }
return PeerListItemComponent.Reaction( return PeerListItemComponent.Reaction(
reaction: reaction, reaction: reaction,

View File

@ -1627,7 +1627,7 @@ extension ChatControllerImpl {
var reactionItem: ReactionItem? var reactionItem: ReactionItem?
switch updatedReaction { switch updatedReaction {
case .builtin: case .builtin, .stars:
for reaction in availableReactions.reactions { for reaction in availableReactions.reactions {
guard let centerAnimation = reaction.centerAnimation else { guard let centerAnimation = reaction.centerAnimation else {
continue continue

View File

@ -52,15 +52,12 @@ extension ChatControllerImpl {
peerMessageSelectedReactions(context: self.context, message: topMessage), peerMessageSelectedReactions(context: self.context, message: topMessage),
topMessageReactions(context: self.context, message: topMessage, subPeerId: self.chatLocation.threadId.flatMap(EnginePeer.Id.init)), topMessageReactions(context: self.context, message: topMessage, subPeerId: self.chatLocation.threadId.flatMap(EnginePeer.Id.init)),
ApplicationSpecificNotice.getChatTextSelectionTips(accountManager: self.context.sharedContext.accountManager) ApplicationSpecificNotice.getChatTextSelectionTips(accountManager: self.context.sharedContext.accountManager)
).startStandalone(next: { [weak self] peer, actions, allowedReactions, selectedReactions, topReactions, chatTextSelectionTips in ).startStandalone(next: { [weak self] peer, actions, allowedReactionsAndStars, selectedReactions, topReactions, chatTextSelectionTips in
guard let self else { guard let self else {
return return
} }
/*var hasPremium = false var (allowedReactions, _) = allowedReactionsAndStars
if case let .user(user) = peer, user.isPremium {
hasPremium = true
}*/
var actions = actions var actions = actions
switch actions.content { switch actions.content {
@ -72,7 +69,6 @@ extension ChatControllerImpl {
break break
} }
var allowedReactions = allowedReactions
if allowedReactions != nil, case let .customChatContents(customChatContents) = self.presentationInterfaceState.subject { if allowedReactions != nil, case let .customChatContents(customChatContents) = self.presentationInterfaceState.subject {
if case let .hashTagSearch(publicPosts) = customChatContents.kind, publicPosts { if case let .hashTagSearch(publicPosts) = customChatContents.kind, publicPosts {
allowedReactions = nil allowedReactions = nil
@ -335,44 +331,13 @@ extension ChatControllerImpl {
controller?.view.endEditing(true) controller?.view.endEditing(true)
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction if case .stars = chosenUpdatedReaction.reaction {
let isFirst = !"".isEmpty
let currentReactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: self.context.account.peerId))?.reactions ?? []
var updatedReactions: [MessageReaction.Reaction] = currentReactions.filter(\.isSelected).map(\.value) self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
var removedReaction: MessageReaction.Reaction? if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {
var isFirst = false if item.message.id == message.id {
let chosenReaction: MessageReaction.Reaction = .stars
if let index = updatedReactions.firstIndex(where: { $0 == chosenReaction }) {
removedReaction = chosenReaction
updatedReactions.remove(at: index)
} else {
updatedReactions.append(chosenReaction)
isFirst = !currentReactions.contains(where: { $0.value == chosenReaction })
}
if message.areReactionsTags(accountPeerId: self.context.account.peerId) {
if removedReaction == nil, !topReactions.contains(where: { $0.reaction.rawValue == chosenReaction }) {
if !self.presentationInterfaceState.isPremium {
controller?.premiumReactionsSelected?()
return
}
}
} else {
if removedReaction == nil, case .custom = chosenReaction {
if let peer = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info {
} else {
if !self.presentationInterfaceState.isPremium {
controller?.premiumReactionsSelected?()
return
}
}
}
}
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {
if item.message.id == message.id {
if removedReaction == nil && !updatedReactions.isEmpty {
itemNode.awaitingAppliedReaction = (chosenReaction, { [weak self, weak itemNode] in itemNode.awaitingAppliedReaction = (chosenReaction, { [weak self, weak itemNode] in
guard let self, let controller = controller else { guard let self, let controller = controller else {
return return
@ -392,61 +357,139 @@ extension ChatControllerImpl {
self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation) self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
standaloneReactionAnimation.frame = self.chatDisplayNode.bounds standaloneReactionAnimation.frame = self.chatDisplayNode.bounds
self.chatDisplayNode.addSubnode(standaloneReactionAnimation) self.chatDisplayNode.addSubnode(standaloneReactionAnimation)
}, completion: { [weak self, weak itemNode, weak targetView] in }, onHit: { [weak self, weak itemNode] in
guard let self, let itemNode, let targetView else { guard let self else {
return return
} }
if let itemNode = itemNode, let targetView = itemNode.targetReactionView(value: chosenReaction) {
if self.chatLocation.peerId == self.context.account.peerId { self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view))
let _ = (ApplicationSpecificNotice.getSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager)
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak targetView, weak itemNode] value in
guard let self, let targetView, let itemNode else {
return
}
if value >= 3 {
return
}
let _ = itemNode
let rect = self.chatDisplayNode.view.convert(targetView.bounds, from: targetView).insetBy(dx: -8.0, dy: -8.0)
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.Chat_TooltipAddTagLabel), location: .point(rect, .bottom), displayDuration: .manual, shouldDismissOnTouch: { _, _ in
return .dismiss(consume: false)
})
self.present(tooltipScreen, in: .current)
let _ = ApplicationSpecificNotice.incrementSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
})
} }
}) }, completion: {})
} else { } else {
controller.dismiss() controller.dismiss()
} }
}) })
} else {
itemNode.awaitingAppliedReaction = (nil, {
controller?.dismiss()
})
} }
} }
} }
}
let _ = sendStarsReactionsInteractively(account: self.context.account, messageId: message.id, count: 1).startStandalone()
let mappedUpdatedReactions = updatedReactions.map { reaction -> UpdateMessageReaction in } else {
switch reaction { let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction
case let .builtin(value):
return .builtin(value) let currentReactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: self.context.account.peerId))?.reactions ?? []
case let .custom(fileId): var updatedReactions: [MessageReaction.Reaction] = currentReactions.filter(\.isSelected).map(\.value)
var customFile: TelegramMediaFile? var removedReaction: MessageReaction.Reaction?
if case let .custom(customFileId, file) = chosenUpdatedReaction, fileId == customFileId { var isFirst = false
customFile = file
} if let index = updatedReactions.firstIndex(where: { $0 == chosenReaction }) {
return .custom(fileId: fileId, file: customFile) removedReaction = chosenReaction
updatedReactions.remove(at: index)
} else {
updatedReactions.append(chosenReaction)
isFirst = !currentReactions.contains(where: { $0.value == chosenReaction })
} }
if message.areReactionsTags(accountPeerId: self.context.account.peerId) {
if removedReaction == nil, !topReactions.contains(where: { $0.reaction.rawValue == chosenReaction }) {
if !self.presentationInterfaceState.isPremium {
controller?.premiumReactionsSelected?()
return
}
}
} else {
if removedReaction == nil, case .custom = chosenReaction {
if let peer = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info {
} else {
if !self.presentationInterfaceState.isPremium {
controller?.premiumReactionsSelected?()
return
}
}
}
}
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {
if item.message.id == message.id {
if removedReaction == nil && !updatedReactions.isEmpty {
itemNode.awaitingAppliedReaction = (chosenReaction, { [weak self, weak itemNode] in
guard let self, let controller = controller else {
return
}
if let itemNode = itemNode, let targetView = itemNode.targetReactionView(value: chosenReaction) {
self.chatDisplayNode.messageTransitionNode.addMessageContextController(messageId: item.message.id, contextController: controller)
var hideTargetButton: UIView?
if isFirst {
hideTargetButton = targetView.superview
}
controller.dismissWithReaction(value: chosenReaction, targetView: targetView, hideNode: true, animateTargetContainer: hideTargetButton, addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in
guard let self else {
return
}
self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
standaloneReactionAnimation.frame = self.chatDisplayNode.bounds
self.chatDisplayNode.addSubnode(standaloneReactionAnimation)
}, onHit: nil, completion: { [weak self, weak itemNode, weak targetView] in
guard let self, let itemNode, let targetView else {
return
}
if self.chatLocation.peerId == self.context.account.peerId {
let _ = (ApplicationSpecificNotice.getSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager)
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak targetView, weak itemNode] value in
guard let self, let targetView, let itemNode else {
return
}
if value >= 3 {
return
}
let _ = itemNode
let rect = self.chatDisplayNode.view.convert(targetView.bounds, from: targetView).insetBy(dx: -8.0, dy: -8.0)
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.Chat_TooltipAddTagLabel), location: .point(rect, .bottom), displayDuration: .manual, shouldDismissOnTouch: { _, _ in
return .dismiss(consume: false)
})
self.present(tooltipScreen, in: .current)
let _ = ApplicationSpecificNotice.incrementSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
})
}
})
} else {
controller.dismiss()
}
})
} else {
itemNode.awaitingAppliedReaction = (nil, {
controller?.dismiss()
})
}
}
}
}
let mappedUpdatedReactions = updatedReactions.map { reaction -> UpdateMessageReaction in
switch reaction {
case let .builtin(value):
return .builtin(value)
case let .custom(fileId):
var customFile: TelegramMediaFile?
if case let .custom(customFileId, file) = chosenUpdatedReaction, fileId == customFileId {
customFile = file
}
return .custom(fileId: fileId, file: customFile)
case .stars:
return .stars
}
}
let _ = updateMessageReactionsInteractively(account: self.context.account, messageIds: [message.id], reactions: mappedUpdatedReactions, isLarge: isLarge, storeAsRecentlyUsed: true).startStandalone()
} }
let _ = updateMessageReactionsInteractively(account: self.context.account, messageIds: [message.id], reactions: mappedUpdatedReactions, isLarge: isLarge, storeAsRecentlyUsed: true).startStandalone()
} }
self.forEachController({ controller in self.forEachController({ controller in

View File

@ -19,7 +19,7 @@ func peerMessageSelectedReactions(context: AccountContext, message: Message) ->
} }
reactions.insert(reaction.value) reactions.insert(reaction.value)
switch reaction.value { switch reaction.value {
case .builtin: case .builtin, .stars:
if let availableReaction = availableReactions?.reactions.first(where: { $0.value == reaction.value }) { if let availableReaction = availableReactions?.reactions.first(where: { $0.value == reaction.value }) {
result.insert(availableReaction.selectAnimation.fileId) result.insert(availableReaction.selectAnimation.fileId)
} }

View File

@ -1510,6 +1510,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
chosenReaction = .builtin(value) chosenReaction = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
chosenReaction = .custom(fileId) chosenReaction = .custom(fileId)
case .stars:
chosenReaction = .stars
} }
case let .reaction(value): case let .reaction(value):
switch value { switch value {
@ -1517,6 +1519,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
chosenReaction = .builtin(value) chosenReaction = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
chosenReaction = .custom(fileId) chosenReaction = .custom(fileId)
case .stars:
chosenReaction = .stars
} }
} }
@ -1540,7 +1544,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
let _ = (peerMessageAllowedReactions(context: strongSelf.context, message: message) let _ = (peerMessageAllowedReactions(context: strongSelf.context, message: message)
|> deliverOnMainQueue).startStandalone(next: { allowedReactions in |> deliverOnMainQueue).startStandalone(next: { allowedReactions, _ in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -1564,6 +1568,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
chosenReaction = .builtin(value) chosenReaction = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
chosenReaction = .custom(fileId) chosenReaction = .custom(fileId)
case .stars:
chosenReaction = .stars
} }
case let .reaction(value): case let .reaction(value):
switch value { switch value {
@ -1571,6 +1577,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
chosenReaction = .builtin(value) chosenReaction = .builtin(value)
case let .custom(fileId): case let .custom(fileId):
chosenReaction = .custom(fileId) chosenReaction = .custom(fileId)
case .stars:
chosenReaction = .stars
} }
} }
@ -1578,48 +1586,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
var removedReaction: MessageReaction.Reaction? if case .stars = chosenReaction {
var messageAlreadyHasThisReaction = false
let currentReactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: context.account.peerId))?.reactions ?? []
var updatedReactions: [MessageReaction.Reaction] = currentReactions.filter(\.isSelected).map(\.value)
if let index = updatedReactions.firstIndex(where: { $0 == chosenReaction }) {
removedReaction = chosenReaction
updatedReactions.remove(at: index)
} else {
updatedReactions.append(chosenReaction)
messageAlreadyHasThisReaction = currentReactions.contains(where: { $0.value == chosenReaction })
}
if removedReaction == nil {
if !canAddMessageReactions(message: message) {
itemNode.openMessageContextMenu()
return
}
if strongSelf.context.sharedContext.immediateExperimentalUISettings.disableQuickReaction {
itemNode.openMessageContextMenu()
return
}
guard let allowedReactions = allowedReactions else {
itemNode.openMessageContextMenu()
return
}
switch allowedReactions {
case let .set(set):
if !messageAlreadyHasThisReaction && updatedReactions.contains(where: { !set.contains($0) }) {
itemNode.openMessageContextMenu()
return
}
case .all:
break
}
}
if removedReaction == nil && !updatedReactions.isEmpty {
if strongSelf.selectPollOptionFeedback == nil { if strongSelf.selectPollOptionFeedback == nil {
strongSelf.selectPollOptionFeedback = HapticFeedback() strongSelf.selectPollOptionFeedback = HapticFeedback()
} }
@ -1633,7 +1600,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var reactionItem: ReactionItem? var reactionItem: ReactionItem?
switch chosenReaction { switch chosenReaction {
case .builtin: case .builtin, .stars:
for reaction in availableReactions.reactions { for reaction in availableReactions.reactions {
guard let centerAnimation = reaction.centerAnimation else { guard let centerAnimation = reaction.centerAnimation else {
continue continue
@ -1694,6 +1661,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation) strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
}, },
onHit: { [weak itemNode] in
guard let strongSelf = self else {
return
}
if let itemNode = itemNode, let targetView = itemNode.targetReactionView(value: chosenReaction) {
strongSelf.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: strongSelf.chatDisplayNode.view))
}
},
completion: { [weak standaloneReactionAnimation] in completion: { [weak standaloneReactionAnimation] in
standaloneReactionAnimation?.removeFromSupernode() standaloneReactionAnimation?.removeFromSupernode()
} }
@ -1701,78 +1676,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
}) })
} else {
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts(itemNode: itemNode)
if let removedReaction = removedReaction, let targetView = itemNode.targetReactionView(value: removedReaction), shouldDisplayInlineDateReactions(message: message, isPremium: strongSelf.presentationInterfaceState.isPremium, forceInline: false) { let _ = sendStarsReactionsInteractively(account: strongSelf.context.account, messageId: message.id, count: 1).startStandalone()
var hideRemovedReaction: Bool = false
if let reactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: context.account.peerId)) { if !"".isEmpty {
for reaction in reactions.reactions {
if reaction.value == removedReaction {
hideRemovedReaction = reaction.count == 1
break
}
}
}
let standaloneDismissAnimation = StandaloneDismissReactionAnimation()
standaloneDismissAnimation.frame = strongSelf.chatDisplayNode.bounds
strongSelf.chatDisplayNode.addSubnode(standaloneDismissAnimation)
standaloneDismissAnimation.animateReactionDismiss(sourceView: targetView, hideNode: hideRemovedReaction, isIncoming: message.effectivelyIncoming(strongSelf.context.account.peerId), completion: { [weak standaloneDismissAnimation] in
standaloneDismissAnimation?.removeFromSupernode()
})
}
}
let mappedUpdatedReactions = updatedReactions.map { reaction -> UpdateMessageReaction in
switch reaction {
case let .builtin(value):
return .builtin(value)
case let .custom(fileId):
return .custom(fileId: fileId, file: nil)
}
}
if !strongSelf.presentationInterfaceState.isPremium && mappedUpdatedReactions.count > strongSelf.context.userLimits.maxReactionsPerMessage {
let _ = (ApplicationSpecificNotice.incrementMultipleReactionsSuggestion(accountManager: strongSelf.context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] count in
guard let self else {
return
}
if count < 1 {
let context = self.context
let controller = UndoOverlayController(
presentationData: self.presentationData,
content: .premiumPaywall(title: nil, text: self.presentationData.strings.Chat_Reactions_MultiplePremiumTooltip, customUndoText: nil, timeout: nil, linkAction: nil),
elevatedLayout: false,
action: { [weak self] action in
if case .info = action {
if let self {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .reactions, forceDark: false, dismissed: nil)
self.push(controller)
}
}
return true
}
)
self.present(controller, in: .current)
}
})
}
let _ = updateMessageReactionsInteractively(account: strongSelf.context.account, messageIds: [message.id], reactions: mappedUpdatedReactions, isLarge: false, storeAsRecentlyUsed: false).startStandalone()
#if DEBUG
if strongSelf.context.sharedContext.applicationBindings.appBuildType == .internal {
if mappedUpdatedReactions.contains(where: {
if case let .custom(fileId, _) = $0, fileId == MessageReaction.starsReactionId {
return true
} else {
return false
}
}) {
let _ = (strongSelf.context.engine.stickers.resolveInlineStickers(fileIds: [MessageReaction.starsReactionId]) let _ = (strongSelf.context.engine.stickers.resolveInlineStickers(fileIds: [MessageReaction.starsReactionId])
|> deliverOnMainQueue).start(next: { [weak strongSelf, weak itemNode] files in |> deliverOnMainQueue).start(next: { [weak strongSelf, weak itemNode] files in
guard let strongSelf, let file = files[MessageReaction.starsReactionId] else { guard let strongSelf, let file = files[MessageReaction.starsReactionId] else {
return return
} }
@ -1786,8 +1695,193 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
}) })
} }
} else {
var removedReaction: MessageReaction.Reaction?
var messageAlreadyHasThisReaction = false
let currentReactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: context.account.peerId))?.reactions ?? []
var updatedReactions: [MessageReaction.Reaction] = currentReactions.filter(\.isSelected).map(\.value)
if let index = updatedReactions.firstIndex(where: { $0 == chosenReaction }) {
removedReaction = chosenReaction
updatedReactions.remove(at: index)
} else {
updatedReactions.append(chosenReaction)
messageAlreadyHasThisReaction = currentReactions.contains(where: { $0.value == chosenReaction })
}
if removedReaction == nil {
if !canAddMessageReactions(message: message) {
itemNode.openMessageContextMenu()
return
}
if strongSelf.context.sharedContext.immediateExperimentalUISettings.disableQuickReaction {
itemNode.openMessageContextMenu()
return
}
guard let allowedReactions = allowedReactions else {
itemNode.openMessageContextMenu()
return
}
switch allowedReactions {
case let .set(set):
if !messageAlreadyHasThisReaction && updatedReactions.contains(where: { !set.contains($0) }) {
itemNode.openMessageContextMenu()
return
}
case .all:
break
}
}
if removedReaction == nil && !updatedReactions.isEmpty {
if strongSelf.selectPollOptionFeedback == nil {
strongSelf.selectPollOptionFeedback = HapticFeedback()
}
strongSelf.selectPollOptionFeedback?.tap()
itemNode.awaitingAppliedReaction = (chosenReaction, { [weak itemNode] in
guard let strongSelf = self else {
return
}
if let itemNode = itemNode, let item = itemNode.item, let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: chosenReaction) {
var reactionItem: ReactionItem?
switch chosenReaction {
case .builtin, .stars:
for reaction in availableReactions.reactions {
guard let centerAnimation = reaction.centerAnimation else {
continue
}
guard let aroundAnimation = reaction.aroundAnimation else {
continue
}
if reaction.value == chosenReaction {
reactionItem = ReactionItem(
reaction: ReactionItem.Reaction(rawValue: reaction.value),
appearAnimation: reaction.appearAnimation,
stillAnimation: reaction.selectAnimation,
listAnimation: centerAnimation,
largeListAnimation: reaction.activateAnimation,
applicationAnimation: aroundAnimation,
largeApplicationAnimation: reaction.effectAnimation,
isCustom: false
)
break
}
}
case let .custom(fileId):
if let itemFile = item.message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
reactionItem = ReactionItem(
reaction: ReactionItem.Reaction(rawValue: chosenReaction),
appearAnimation: itemFile,
stillAnimation: itemFile,
listAnimation: itemFile,
largeListAnimation: itemFile,
applicationAnimation: nil,
largeApplicationAnimation: nil,
isCustom: true
)
}
}
if let reactionItem = reactionItem {
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: strongSelf.chatDisplayNode.historyNode.takeGenericReactionEffect())
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
standaloneReactionAnimation.animateReactionSelection(
context: strongSelf.context,
theme: strongSelf.presentationData.theme,
animationCache: strongSelf.controllerInteraction!.presentationContext.animationCache,
reaction: reactionItem,
avatarPeers: [],
playHaptic: false,
isLarge: false,
targetView: targetView,
addStandaloneReactionAnimation: { standaloneReactionAnimation in
guard let strongSelf = self else {
return
}
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
},
completion: { [weak standaloneReactionAnimation] in
standaloneReactionAnimation?.removeFromSupernode()
}
)
}
}
})
} else {
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts(itemNode: itemNode)
if let removedReaction = removedReaction, let targetView = itemNode.targetReactionView(value: removedReaction), shouldDisplayInlineDateReactions(message: message, isPremium: strongSelf.presentationInterfaceState.isPremium, forceInline: false) {
var hideRemovedReaction: Bool = false
if let reactions = mergedMessageReactions(attributes: message.attributes, isTags: message.areReactionsTags(accountPeerId: context.account.peerId)) {
for reaction in reactions.reactions {
if reaction.value == removedReaction {
hideRemovedReaction = reaction.count == 1
break
}
}
}
let standaloneDismissAnimation = StandaloneDismissReactionAnimation()
standaloneDismissAnimation.frame = strongSelf.chatDisplayNode.bounds
strongSelf.chatDisplayNode.addSubnode(standaloneDismissAnimation)
standaloneDismissAnimation.animateReactionDismiss(sourceView: targetView, hideNode: hideRemovedReaction, isIncoming: message.effectivelyIncoming(strongSelf.context.account.peerId), completion: { [weak standaloneDismissAnimation] in
standaloneDismissAnimation?.removeFromSupernode()
})
}
}
let mappedUpdatedReactions = updatedReactions.map { reaction -> UpdateMessageReaction in
switch reaction {
case let .builtin(value):
return .builtin(value)
case let .custom(fileId):
return .custom(fileId: fileId, file: nil)
case .stars:
return .stars
}
}
if !strongSelf.presentationInterfaceState.isPremium && mappedUpdatedReactions.count > strongSelf.context.userLimits.maxReactionsPerMessage {
let _ = (ApplicationSpecificNotice.incrementMultipleReactionsSuggestion(accountManager: strongSelf.context.sharedContext.accountManager)
|> deliverOnMainQueue).startStandalone(next: { [weak self] count in
guard let self else {
return
}
if count < 1 {
let context = self.context
let controller = UndoOverlayController(
presentationData: self.presentationData,
content: .premiumPaywall(title: nil, text: self.presentationData.strings.Chat_Reactions_MultiplePremiumTooltip, customUndoText: nil, timeout: nil, linkAction: nil),
elevatedLayout: false,
action: { [weak self] action in
if case .info = action {
if let self {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .reactions, forceDark: false, dismissed: nil)
self.push(controller)
}
}
return true
}
)
self.present(controller, in: .current)
}
})
}
let _ = updateMessageReactionsInteractively(account: strongSelf.context.account, messageIds: [message.id], reactions: mappedUpdatedReactions, isLarge: false, storeAsRecentlyUsed: false).startStandalone()
} }
#endif
} }
}) })
}, activateMessagePinch: { [weak self] sourceNode in }, activateMessagePinch: { [weak self] sourceNode in

View File

@ -41,7 +41,7 @@ extension ChatControllerImpl {
let reactionFile: Signal<TelegramMediaFile?, NoError> let reactionFile: Signal<TelegramMediaFile?, NoError>
switch value { switch value {
case .builtin: case .builtin, .stars:
reactionFile = self.context.engine.stickers.availableReactions() reactionFile = self.context.engine.stickers.availableReactions()
|> take(1) |> take(1)
|> map { availableReactions -> TelegramMediaFile? in |> map { availableReactions -> TelegramMediaFile? in
@ -161,25 +161,21 @@ extension ChatControllerImpl {
self.window?.presentInGlobalOverlay(controller) self.window?.presentInGlobalOverlay(controller)
}) })
} else { } else {
var debug = false if case .stars = value {
#if DEBUG gesture?.cancel()
debug = true cancelParentGestures(view: sourceView)
#endif
if self.context.sharedContext.applicationBindings.appBuildType == .internal {
debug = true
}
if debug, case .custom(MessageReaction.starsReactionId) = value {
let _ = (ChatSendStarsScreen.initialData(context: self.context, peerId: message.id.peerId) let _ = (ChatSendStarsScreen.initialData(context: self.context, peerId: message.id.peerId)
|> deliverOnMainQueue).start(next: { [weak self] initialData in |> deliverOnMainQueue).start(next: { [weak self] initialData in
guard let self, let initialData else { guard let self, let initialData else {
return return
} }
self.push(ChatSendStarsScreen(context: self.context, initialData: initialData, completion: { [weak self] amount in self.push(ChatSendStarsScreen(context: self.context, initialData: initialData, completion: { [weak self] amount in
guard let self else { guard let self, amount > 0 else {
return return
} }
let _ = self.context.engine.messages.sendStarsReaction(id: message.id, count: Int(amount))
let _ = (self.context.engine.stickers.resolveInlineStickers(fileIds: [MessageReaction.starsReactionId]) let _ = (self.context.engine.stickers.resolveInlineStickers(fileIds: [MessageReaction.starsReactionId])
|> deliverOnMainQueue).start(next: { [weak self] files in |> deliverOnMainQueue).start(next: { [weak self] files in
guard let self, let file = files[MessageReaction.starsReactionId] else { guard let self, let file = files[MessageReaction.starsReactionId] else {
@ -369,7 +365,7 @@ extension ChatControllerImpl {
let reactionFile: TelegramMediaFile? let reactionFile: TelegramMediaFile?
switch value { switch value {
case .builtin: case .builtin, .stars:
reactionFile = availableReactions?.reactions.first(where: { $0.value == value })?.selectAnimation reactionFile = availableReactions?.reactions.first(where: { $0.value == value })?.selectAnimation
case let .custom(fileId): case let .custom(fileId):
reactionFile = customEmoji[fileId] reactionFile = customEmoji[fileId]

View File

@ -4031,7 +4031,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
var reactionItem: ReactionItem? var reactionItem: ReactionItem?
switch updatedReaction { switch updatedReaction {
case .builtin: case .builtin, .stars:
if let availableReactions = item.associatedData.availableReactions { if let availableReactions = item.associatedData.availableReactions {
for reaction in availableReactions.reactions { for reaction in availableReactions.reactions {
guard let centerAnimation = reaction.centerAnimation else { guard let centerAnimation = reaction.centerAnimation else {

View File

@ -484,6 +484,8 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, Chat
break break
case let .custom(fileId): case let .custom(fileId):
customFileIds.append(fileId) customFileIds.append(fileId)
case .stars:
break
} }
} }
@ -510,7 +512,7 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, Chat
let title = savedMessageTags?.tags.first(where: { $0.reaction == reaction })?.title let title = savedMessageTags?.tags.first(where: { $0.reaction == reaction })?.title
switch reaction { switch reaction {
case .builtin: case .builtin, .stars:
if let availableReactions { if let availableReactions {
inner: for availableReaction in availableReactions.reactions { inner: for availableReaction in availableReactions.reactions {
if availableReaction.value == reaction { if availableReaction.value == reaction {
@ -763,7 +765,7 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, Chat
let reactionFile: Signal<TelegramMediaFile?, NoError> let reactionFile: Signal<TelegramMediaFile?, NoError>
switch reaction { switch reaction {
case .builtin: case .builtin, .stars:
reactionFile = self.context.engine.stickers.availableReactions() reactionFile = self.context.engine.stickers.availableReactions()
|> take(1) |> take(1)
|> map { availableReactions -> TelegramMediaFile? in |> map { availableReactions -> TelegramMediaFile? in