- Story search UI

- Delete message confirmation
This commit is contained in:
Isaac
2024-06-04 19:18:41 +04:00
parent 6ccc9ed693
commit d7bb7d55b4
46 changed files with 1534 additions and 951 deletions

View File

@@ -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
}
}