mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
- Story search UI
- Delete message confirmation
This commit is contained in:
@@ -12,8 +12,121 @@ import ChatControllerInteraction
|
||||
import AccountContext
|
||||
import ChatTextInputMediaRecordingButton
|
||||
import ChatSendButtonRadialStatusNode
|
||||
import ChatSendMessageActionUI
|
||||
import ComponentFlow
|
||||
|
||||
final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
private final class EffectBadgeView: UIView {
|
||||
private let context: AccountContext
|
||||
private var currentEffectId: Int64?
|
||||
|
||||
private let backgroundView: UIImageView
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
private var effect: AvailableMessageEffects.MessageEffect?
|
||||
private var effectIcon: ComponentView<Empty>?
|
||||
|
||||
private let effectDisposable = MetaDisposable()
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.backgroundView = UIImageView()
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.isUserInteractionEnabled = false
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
}
|
||||
|
||||
required init(coder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.effectDisposable.dispose()
|
||||
}
|
||||
|
||||
func update(size: CGSize, theme: PresentationTheme, effectId: Int64) {
|
||||
if self.theme !== theme {
|
||||
self.theme = theme
|
||||
self.backgroundView.image = generateFilledCircleImage(diameter: size.width, color: theme.list.plainBackgroundColor, strokeColor: nil, strokeWidth: nil, backgroundColor: nil)
|
||||
self.backgroundView.layer.shadowPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(), size: size)).cgPath
|
||||
self.backgroundView.layer.shadowColor = UIColor(white: 0.0, alpha: 1.0).cgColor
|
||||
self.backgroundView.layer.shadowOpacity = 0.14
|
||||
self.backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
|
||||
self.backgroundView.layer.shadowRadius = 1.0
|
||||
}
|
||||
|
||||
self.backgroundView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
if self.currentEffectId != effectId {
|
||||
self.currentEffectId = effectId
|
||||
|
||||
let messageEffect = self.context.engine.stickers.availableMessageEffects()
|
||||
|> take(1)
|
||||
|> map { availableMessageEffects -> AvailableMessageEffects.MessageEffect? in
|
||||
guard let availableMessageEffects else {
|
||||
return nil
|
||||
}
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if messageEffect.id == effectId || messageEffect.effectSticker.fileId.id == effectId {
|
||||
return messageEffect
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
self.effectDisposable.set((messageEffect |> deliverOnMainQueue).start(next: { [weak self] effect in
|
||||
guard let self, let effect else {
|
||||
return
|
||||
}
|
||||
self.effect = effect
|
||||
self.updateIcon()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
private func updateIcon() {
|
||||
guard let effect else {
|
||||
return
|
||||
}
|
||||
|
||||
let effectIcon: ComponentView<Empty>
|
||||
if let current = self.effectIcon {
|
||||
effectIcon = current
|
||||
} else {
|
||||
effectIcon = ComponentView()
|
||||
self.effectIcon = effectIcon
|
||||
}
|
||||
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
|
||||
if let staticIcon = effect.staticIcon {
|
||||
effectIconContent = .file(staticIcon)
|
||||
} else {
|
||||
effectIconContent = .text(effect.emoticon)
|
||||
}
|
||||
let effectIconSize = effectIcon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(ChatSendMessageScreenEffectIcon(
|
||||
context: self.context,
|
||||
content: effectIconContent
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 8.0, height: 8.0)
|
||||
)
|
||||
|
||||
let size = CGSize(width: 16.0, height: 16.0)
|
||||
if let effectIconView = effectIcon.view {
|
||||
if effectIconView.superview == nil {
|
||||
self.addSubview(effectIconView)
|
||||
}
|
||||
effectIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - effectIconSize.width) * 0.5), y: floor((size.height - effectIconSize.height) * 0.5)), size: effectIconSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessageActionSheetControllerSourceSendButtonNode {
|
||||
private let context: AccountContext
|
||||
private let presentationContext: ChatPresentationContext?
|
||||
private let strings: PresentationStrings
|
||||
|
||||
@@ -26,6 +139,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
var sendButtonHasApplyIcon = false
|
||||
var animatingSendButton = false
|
||||
let expandMediaInputButton: HighlightableButtonNode
|
||||
private var effectBadgeView: EffectBadgeView?
|
||||
|
||||
var sendButtonLongPressed: ((ASDisplayNode, ContextGesture) -> Void)?
|
||||
|
||||
@@ -42,6 +156,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
private var validLayout: CGSize?
|
||||
|
||||
init(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
|
||||
self.context = context
|
||||
self.presentationContext = presentationContext
|
||||
let theme = presentationInterfaceState.theme
|
||||
let strings = presentationInterfaceState.strings
|
||||
@@ -145,7 +260,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, isMediaInputExpanded: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
|
||||
func updateLayout(size: CGSize, isMediaInputExpanded: Bool, currentMessageEffectId: Int64?, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
|
||||
self.validLayout = size
|
||||
transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
self.micButton.layoutItems()
|
||||
@@ -154,7 +269,8 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
transition.updateFrame(node: self.sendContainerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let backgroundSize = CGSize(width: 33.0, height: 33.0)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - backgroundSize.width) / 2.0), y: floorToScreenPixels((size.height - backgroundSize.height) / 2.0)), size: backgroundSize))
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - backgroundSize.width) / 2.0), y: floorToScreenPixels((size.height - backgroundSize.height) / 2.0)), size: backgroundSize)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
self.backgroundNode.cornerRadius = backgroundSize.width / 2.0
|
||||
|
||||
transition.updateFrame(node: self.backdropNode, frame: CGRect(origin: CGPoint(x: -2.0, y: -2.0), size: CGSize(width: size.width + 12.0, height: size.height + 2.0)))
|
||||
@@ -162,42 +278,31 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
self.backdropNode.update(rect: rect, within: containerSize)
|
||||
}
|
||||
|
||||
// var isScheduledMessages = false
|
||||
// if case .scheduledMessages = interfaceState.subject {
|
||||
// isScheduledMessages = true
|
||||
// }
|
||||
//
|
||||
// if let slowmodeState = interfaceState.slowmodeState, !isScheduledMessages && interfaceState.editMessageState == nil {
|
||||
// let sendButtonRadialStatusNode: ChatSendButtonRadialStatusNode
|
||||
// if let current = self.sendButtonRadialStatusNode {
|
||||
// sendButtonRadialStatusNode = current
|
||||
// } else {
|
||||
// sendButtonRadialStatusNode = ChatSendButtonRadialStatusNode(color: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
||||
// sendButtonRadialStatusNode.alpha = self.sendContainerNode.alpha
|
||||
// self.sendButtonRadialStatusNode = sendButtonRadialStatusNode
|
||||
// self.addSubnode(sendButtonRadialStatusNode)
|
||||
// }
|
||||
//
|
||||
// transition.updateSublayerTransformScale(layer: self.sendContainerNode.layer, scale: CGPoint(x: 0.7575, y: 0.7575))
|
||||
//
|
||||
// let defaultSendButtonSize: CGFloat = 25.0
|
||||
// let defaultOriginX = floorToScreenPixels((self.sendButton.bounds.width - defaultSendButtonSize) / 2.0)
|
||||
// let defaultOriginY = floorToScreenPixels((self.sendButton.bounds.height - defaultSendButtonSize) / 2.0)
|
||||
//
|
||||
// let radialStatusFrame = CGRect(origin: CGPoint(x: defaultOriginX - 4.0, y: defaultOriginY - 4.0), size: CGSize(width: 33.0, height: 33.0))
|
||||
// sendButtonRadialStatusNode.frame = radialStatusFrame
|
||||
// sendButtonRadialStatusNode.slowmodeState = slowmodeState
|
||||
// } else {
|
||||
// if let sendButtonRadialStatusNode = self.sendButtonRadialStatusNode {
|
||||
// self.sendButtonRadialStatusNode = nil
|
||||
// sendButtonRadialStatusNode.removeFromSupernode()
|
||||
// }
|
||||
// transition.updateSublayerTransformScale(layer: self.sendContainerNode.layer, scale: CGPoint(x: 1.0, y: 1.0))
|
||||
// }
|
||||
|
||||
transition.updateFrame(node: self.expandMediaInputButton, frame: CGRect(origin: CGPoint(), size: size))
|
||||
let expanded = isMediaInputExpanded
|
||||
transition.updateSublayerTransformScale(node: self.expandMediaInputButton, scale: CGPoint(x: 1.0, y: expanded ? 1.0 : -1.0))
|
||||
|
||||
if let currentMessageEffectId {
|
||||
let effectBadgeView: EffectBadgeView
|
||||
if let current = self.effectBadgeView {
|
||||
effectBadgeView = current
|
||||
} else {
|
||||
effectBadgeView = EffectBadgeView(context: self.context)
|
||||
self.effectBadgeView = effectBadgeView
|
||||
self.sendContainerNode.view.addSubview(effectBadgeView)
|
||||
|
||||
effectBadgeView.alpha = 0.0
|
||||
transition.updateAlpha(layer: effectBadgeView.layer, alpha: 1.0)
|
||||
}
|
||||
let badgeSize = CGSize(width: 16.0, height: 16.0)
|
||||
effectBadgeView.frame = CGRect(origin: CGPoint(x: backgroundFrame.minX + backgroundSize.width + 3.0 - badgeSize.width, y: backgroundFrame.minY + backgroundSize.height + 3.0 - badgeSize.height), size: badgeSize)
|
||||
effectBadgeView.update(size: badgeSize, theme: interfaceState.theme, effectId: currentMessageEffectId)
|
||||
} else if let effectBadgeView = self.effectBadgeView {
|
||||
self.effectBadgeView = nil
|
||||
transition.updateAlpha(layer: effectBadgeView.layer, alpha: 0.0, completion: { [weak effectBadgeView] _ in
|
||||
effectBadgeView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func updateAccessibility() {
|
||||
@@ -216,4 +321,17 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
self.accessibilityHint = nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeCustomContents() -> UIView? {
|
||||
if self.sendButtonHasApplyIcon {
|
||||
let result = UIView()
|
||||
result.frame = self.bounds
|
||||
if let copyView = self.sendContainerNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
copyView.frame = self.sendContainerNode.frame
|
||||
result.addSubview(copyView)
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user