mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Stories
This commit is contained in:
parent
12d9f973f3
commit
8e49f105e5
@ -97,6 +97,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
|||||||
private var effectView: UIVisualEffectView?
|
private var effectView: UIVisualEffectView?
|
||||||
private let contentView: ComponentHostView<ChildEnvironmentType>
|
private let contentView: ComponentHostView<ChildEnvironmentType>
|
||||||
|
|
||||||
|
private var isAnimatingOut: Bool = false
|
||||||
private var previousIsDisplaying: Bool = false
|
private var previousIsDisplaying: Bool = false
|
||||||
private var dismiss: ((Bool) -> Void)?
|
private var dismiss: ((Bool) -> Void)?
|
||||||
|
|
||||||
@ -218,6 +219,12 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func animateOut(initialVelocity: CGFloat? = nil, completion: @escaping () -> Void) {
|
private func animateOut(initialVelocity: CGFloat? = nil, completion: @escaping () -> Void) {
|
||||||
|
if self.isAnimatingOut {
|
||||||
|
completion()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isAnimatingOut = true
|
||||||
|
|
||||||
self.isUserInteractionEnabled = false
|
self.isUserInteractionEnabled = false
|
||||||
self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||||
|
|
||||||
|
@ -2143,9 +2143,10 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let rect = likeButtonView.convert(likeButtonView.bounds, to: nil)
|
|
||||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
|
|
||||||
|
/*let rect = likeButtonView.convert(likeButtonView.bounds, to: nil)
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let text = "Long tap for more reactions"
|
let text = "Long tap for more reactions"
|
||||||
let controller = TooltipController(content: .text(text), baseFontSize: presentationData.listsFontSize.baseDisplaySize, padding: 2.0)
|
let controller = TooltipController(content: .text(text), baseFontSize: presentationData.listsFontSize.baseDisplaySize, padding: 2.0)
|
||||||
controller.dismissed = { [weak self] _ in
|
controller.dismissed = { [weak self] _ in
|
||||||
@ -2161,10 +2162,10 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
self.voiceMessagesRestrictedTooltipController = controller
|
self.voiceMessagesRestrictedTooltipController = controller
|
||||||
self.updateIsProgressPaused()
|
self.updateIsProgressPaused()*/
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
/*let tooltipScreen = TooltipScreen(
|
let tooltipScreen = TooltipScreen(
|
||||||
account: component.context.account,
|
account: component.context.account,
|
||||||
sharedContext: component.context.sharedContext,
|
sharedContext: component.context.sharedContext,
|
||||||
text: .markdown(text: "Long tap for more reactions"),
|
text: .markdown(text: "Long tap for more reactions"),
|
||||||
@ -2184,7 +2185,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
self.sendMessageContext.tooltipScreen?.dismiss()
|
self.sendMessageContext.tooltipScreen?.dismiss()
|
||||||
self.sendMessageContext.tooltipScreen = tooltipScreen
|
self.sendMessageContext.tooltipScreen = tooltipScreen
|
||||||
self.updateIsProgressPaused()
|
self.updateIsProgressPaused()
|
||||||
component.controller()?.present(tooltipScreen, in: .current)*/
|
component.controller()?.present(tooltipScreen, in: .current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(component: StoryItemSetContainerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: StoryItemSetContainerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
@ -3717,7 +3718,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
effectiveDisplayReactions = false
|
effectiveDisplayReactions = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if let reactionContextNode = self.reactionContextNode, reactionContextNode.isReactionSearchActive {
|
if let reactionContextNode = self.reactionContextNode, (reactionContextNode.isReactionSearchActive && !reactionContextNode.isAnimatingOutToReaction && !reactionContextNode.isAnimatingOut) {
|
||||||
effectiveDisplayReactions = true
|
effectiveDisplayReactions = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3794,22 +3795,43 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
self.displayLikeReactions = false
|
self.displayLikeReactions = false
|
||||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
||||||
} else {
|
} else {
|
||||||
|
if hasFirstResponder(self) {
|
||||||
|
self.sendMessageContext.currentInputMode = .text
|
||||||
|
self.endEditing(true)
|
||||||
|
}
|
||||||
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
||||||
|
|
||||||
self.waitingForReactionAnimateOutToLike = updateReaction.reaction
|
self.waitingForReactionAnimateOutToLike = updateReaction.reaction
|
||||||
let _ = component.context.engine.messages.setStoryReaction(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id, reaction: updateReaction.reaction).start()
|
let _ = component.context.engine.messages.setStoryReaction(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id, reaction: updateReaction.reaction).start()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let _ = (component.context.engine.stickers.availableReactions()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self, weak reactionContextNode] availableReactions in
|
||||||
|
guard let self, let component = self.component, let availableReactions else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var animation: TelegramMediaFile?
|
||||||
|
for reaction in availableReactions.reactions {
|
||||||
|
if reaction.value == updateReaction.reaction {
|
||||||
|
animation = reaction.centerAnimation
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let targetView = UIView(frame: CGRect(origin: CGPoint(x: floor((self.bounds.width - 100.0) * 0.5), y: floor((self.bounds.height - 100.0) * 0.5)), size: CGSize(width: 100.0, height: 100.0)))
|
let targetView = UIView(frame: CGRect(origin: CGPoint(x: floor((self.bounds.width - 100.0) * 0.5), y: floor((self.bounds.height - 100.0) * 0.5)), size: CGSize(width: 100.0, height: 100.0)))
|
||||||
targetView.isUserInteractionEnabled = false
|
targetView.isUserInteractionEnabled = false
|
||||||
self.componentContainerView.addSubview(targetView)
|
self.addSubview(targetView)
|
||||||
|
|
||||||
if let reactionContextNode = self.reactionContextNode {
|
if let reactionContextNode {
|
||||||
reactionContextNode.willAnimateOutToReaction(value: updateReaction.reaction)
|
reactionContextNode.willAnimateOutToReaction(value: updateReaction.reaction)
|
||||||
reactionContextNode.animateOutToReaction(value: updateReaction.reaction, targetView: targetView, hideNode: false, animateTargetContainer: nil, addStandaloneReactionAnimation: "".isEmpty ? nil : { [weak self] standaloneReactionAnimation in
|
reactionContextNode.animateOutToReaction(value: updateReaction.reaction, targetView: targetView, hideNode: false, animateTargetContainer: nil, addStandaloneReactionAnimation: "".isEmpty ? nil : { [weak self] standaloneReactionAnimation in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
standaloneReactionAnimation.frame = self.bounds
|
standaloneReactionAnimation.frame = self.bounds
|
||||||
self.componentContainerView.addSubview(standaloneReactionAnimation.view)
|
self.addSubview(standaloneReactionAnimation.view)
|
||||||
}, completion: { [weak targetView, weak reactionContextNode] in
|
}, completion: { [weak targetView, weak reactionContextNode] in
|
||||||
targetView?.removeFromSuperview()
|
targetView?.removeFromSuperview()
|
||||||
if let reactionContextNode {
|
if let reactionContextNode {
|
||||||
@ -3827,7 +3849,72 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
||||||
|
|
||||||
let _ = component.context.engine.messages.setStoryReaction(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id, reaction: updateReaction.reaction).start()
|
var text = ""
|
||||||
|
var messageAttributes: [MessageAttribute] = []
|
||||||
|
var inlineStickers: [MediaId : Media] = [:]
|
||||||
|
switch updateReaction {
|
||||||
|
case let .builtin(textValue):
|
||||||
|
text = textValue
|
||||||
|
case let .custom(fileId, file):
|
||||||
|
if let file {
|
||||||
|
animation = file
|
||||||
|
loop: for attribute in file.attributes {
|
||||||
|
switch attribute {
|
||||||
|
case let .CustomEmoji(_, _, displayText, _):
|
||||||
|
text = displayText
|
||||||
|
let length = (text as NSString).length
|
||||||
|
messageAttributes = [TextEntitiesMessageAttribute(entities: [MessageTextEntity(range: 0 ..< length, type: .CustomEmoji(stickerPack: nil, fileId: fileId))])]
|
||||||
|
inlineStickers = [file.fileId: file]
|
||||||
|
break loop
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let message: EnqueueMessage = .message(
|
||||||
|
text: text,
|
||||||
|
attributes: messageAttributes,
|
||||||
|
inlineStickers: inlineStickers,
|
||||||
|
mediaReference: nil,
|
||||||
|
replyToMessageId: nil,
|
||||||
|
replyToStoryId: StoryId(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id),
|
||||||
|
localGroupingKey: nil,
|
||||||
|
correlationId: nil,
|
||||||
|
bubbleUpEmojiOrStickersets: []
|
||||||
|
)
|
||||||
|
|
||||||
|
let context = component.context
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme)
|
||||||
|
let presentController = component.presentController
|
||||||
|
let peer = component.slice.peer
|
||||||
|
|
||||||
|
let _ = (enqueueMessages(account: context.account, peerId: peer.id, messages: [message])
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
|
||||||
|
if let animation, let self, let component = self.component {
|
||||||
|
let controller = UndoOverlayController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
content: .sticker(context: context, file: animation, loop: false, title: nil, text: component.strings.Story_ToastReactionSent, undoText: component.strings.Story_ToastViewInChat, customAction: { [weak self] in
|
||||||
|
if let messageId = messageIds.first, let self {
|
||||||
|
self.navigateToPeer(peer: peer, chat: true, subject: messageId.flatMap { .message(id: .id($0), highlight: false, timecode: nil) })
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
elevatedLayout: false,
|
||||||
|
animateInAsReplacement: false,
|
||||||
|
action: { [weak self] _ in
|
||||||
|
self?.sendMessageContext.tooltipScreen = nil
|
||||||
|
self?.updateIsProgressPaused()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.sendMessageContext.tooltipScreen?.dismiss()
|
||||||
|
self.sendMessageContext.tooltipScreen = controller
|
||||||
|
self.updateIsProgressPaused()
|
||||||
|
presentController(controller, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4544,10 +4631,54 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentSaveUpgradeScreen() {
|
||||||
|
guard let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme)
|
||||||
|
let animationBackgroundColor = presentationData.theme.rootController.tabBar.backgroundColor
|
||||||
|
component.presentController(UndoOverlayController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
content: .universal(
|
||||||
|
animation: "anim_infotip",
|
||||||
|
scale: 1.0,
|
||||||
|
colors: [
|
||||||
|
"info1.info1.stroke": animationBackgroundColor,
|
||||||
|
"info2.info2.Fill": animationBackgroundColor
|
||||||
|
],
|
||||||
|
title: nil,
|
||||||
|
text: "Subscribe to [Telegram Premium]() to save other people's unprotected stories to your Gallery.",
|
||||||
|
customUndoText: nil,
|
||||||
|
timeout: nil
|
||||||
|
),
|
||||||
|
elevatedLayout: false,
|
||||||
|
animateInAsReplacement: false,
|
||||||
|
blurred: true,
|
||||||
|
action: { [weak self] action in
|
||||||
|
guard let self else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch action {
|
||||||
|
case .info:
|
||||||
|
self.presentStoriesUpgradeScreen()
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
), nil)
|
||||||
|
}
|
||||||
|
|
||||||
private func presentStoriesUpgradeScreen() {
|
private func presentStoriesUpgradeScreen() {
|
||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = component.context
|
let context = component.context
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
@ -4703,6 +4834,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func performLikeOptionsAction(sourceView: UIView) {
|
private func performLikeOptionsAction(sourceView: UIView) {
|
||||||
|
HapticFeedback().tap()
|
||||||
|
|
||||||
self.displayLikeReactions = true
|
self.displayLikeReactions = true
|
||||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
|
||||||
self.updateIsProgressPaused()
|
self.updateIsProgressPaused()
|
||||||
@ -5177,7 +5310,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
if accountUser.isPremium {
|
if accountUser.isPremium {
|
||||||
self.requestSave()
|
self.requestSave()
|
||||||
} else {
|
} else {
|
||||||
self.presentStoriesUpgradeScreen()
|
self.presentSaveUpgradeScreen()
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user