Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin
2023-08-05 15:34:20 +02:00
24 changed files with 932 additions and 315 deletions

View File

@@ -32,6 +32,7 @@ swift_library(
"//submodules/TelegramUI/Components/EmojiSuggestionsComponent",
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
"//submodules/StickerPeekUI",
"//submodules/Components/ReactionButtonListComponent",
],
visibility = [
"//visibility:public",

View File

@@ -9,6 +9,8 @@ import TelegramPresentationData
import ChatPresentationInterfaceState
import MoreHeaderButton
import ContextUI
import ReactionButtonListComponent
import TelegramCore
private extension MessageInputActionButtonComponent.Mode {
var iconName: String? {
@@ -19,12 +21,8 @@ private extension MessageInputActionButtonComponent.Mode {
return "Chat/Input/Text/IconAttachment"
case .forward:
return "Chat/Input/Text/IconForwardSend"
case let .like(isActive):
if isActive {
return "Stories/InputLikeOn"
} else {
return "Stories/InputLikeOff"
}
case .like:
return "Stories/InputLikeOff"
default:
return nil
}
@@ -43,7 +41,7 @@ public final class MessageInputActionButtonComponent: Component {
case attach
case forward
case more
case like(isActive: Bool)
case like(reaction: MessageReaction.Reaction?, file: TelegramMediaFile?, animationFileId: Int64?)
}
public enum Action {
@@ -127,12 +125,18 @@ public final class MessageInputActionButtonComponent: Component {
public let referenceNode: ContextReferenceContentNode
public let containerNode: ContextControllerSourceNode
private let sendIconView: UIImageView
private var moreButton: MoreHeaderButton?
private var reactionIconView: ReactionIconView?
private var component: MessageInputActionButtonComponent?
private weak var componentState: EmptyComponentState?
private var acceptNextButtonPress: Bool = false
public var likeIconView: UIView? {
return self.reactionIconView
}
override init(frame: CGRect) {
self.sendIconView = UIImageView()
@@ -157,6 +161,7 @@ public final class MessageInputActionButtonComponent: Component {
guard let self, let component = self.component, let longPressAction = component.longPressAction else {
return
}
self.acceptNextButtonPress = false
longPressAction(self, gesture)
}
@@ -173,8 +178,6 @@ public final class MessageInputActionButtonComponent: Component {
self.button.addTarget(self, action: #selector(self.touchDown), forControlEvents: .touchDown)
self.button.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
// but.addTarget(self, action: #selector(self.touchDown), for: .touchDown)
// self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
@@ -182,6 +185,8 @@ public final class MessageInputActionButtonComponent: Component {
}
@objc private func touchDown() {
self.acceptNextButtonPress = true
guard let component = self.component else {
return
}
@@ -189,6 +194,10 @@ public final class MessageInputActionButtonComponent: Component {
}
@objc private func pressed() {
if !self.acceptNextButtonPress {
return
}
guard let component = self.component else {
return
}
@@ -207,6 +216,11 @@ public final class MessageInputActionButtonComponent: Component {
let themeUpdated = previousComponent?.theme !== component.theme
var transition = transition
if transition.animation.isImmediate, let previousComponent, case .like = previousComponent.mode, case .like = component.mode, previousComponent.mode != component.mode {
transition = Transition(animation: .curve(duration: 0.25, curve: .easeInOut))
}
self.containerNode.isUserInteractionEnabled = component.longPressAction != nil
if self.micButton == nil {
@@ -306,8 +320,14 @@ public final class MessageInputActionButtonComponent: Component {
switch component.mode {
case .none:
break
case .send, .apply, .attach, .delete, .forward, .like:
case .send, .apply, .attach, .delete, .forward:
sendAlpha = 1.0
case let .like(reaction, _, _):
if reaction != nil {
sendAlpha = 0.0
} else {
sendAlpha = 1.0
}
case .more:
moreAlpha = 1.0
case .videoInput, .voiceInput:
@@ -318,10 +338,7 @@ public final class MessageInputActionButtonComponent: Component {
if self.sendIconView.image == nil || previousComponent?.mode.iconName != component.mode.iconName {
if let iconName = component.mode.iconName {
var tintColor: UIColor = .white
if case .like(true) = component.mode {
tintColor = UIColor(rgb: 0xFF3B30)
}
let tintColor: UIColor = .white
self.sendIconView.image = generateTintedImage(image: UIImage(bundleImageName: iconName), color: tintColor)
} else if case .apply = component.mode {
self.sendIconView.image = generateImage(CGSize(width: 33.0, height: 33.0), contextGenerator: { size, context in
@@ -379,6 +396,44 @@ public final class MessageInputActionButtonComponent: Component {
}
}
if case let .like(reactionValue, reactionFile, animationFileId) = component.mode, let reaction = reactionValue {
let reactionIconFrame = CGRect(origin: .zero, size: CGSize(width: 32.0, height: 32.0)).insetBy(dx: 2.0, dy: 2.0)
let reactionIconView: ReactionIconView
if let current = self.reactionIconView {
reactionIconView = current
} else {
reactionIconView = ReactionIconView(frame: reactionIconFrame)
reactionIconView.isUserInteractionEnabled = false
self.reactionIconView = reactionIconView
self.addSubview(reactionIconView)
if previousComponent != nil {
reactionIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
reactionIconView.layer.animateScale(from: 0.01, to: 1.0, duration: 0.25)
}
}
transition.setFrame(view: reactionIconView, frame: reactionIconFrame)
reactionIconView.update(
size: reactionIconFrame.size,
context: component.context,
file: reactionFile,
fileId: animationFileId ?? reactionFile?.fileId.id ?? 0,
animationCache: component.context.animationCache,
animationRenderer: component.context.animationRenderer,
placeholderColor: UIColor(white: 1.0, alpha: 0.2),
animateIdle: false,
reaction: reaction,
transition: .immediate
)
} else if let reactionIconView = self.reactionIconView {
self.reactionIconView = nil
reactionIconView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak reactionIconView] _ in
reactionIconView?.removeFromSuperview()
})
reactionIconView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.25, removeOnCompletion: false)
}
transition.setFrame(view: self.button.view, frame: CGRect(origin: .zero, size: availableSize))
transition.setFrame(view: self.containerNode.view, frame: CGRect(origin: .zero, size: availableSize))
transition.setFrame(view: self.referenceNode.view, frame: CGRect(origin: .zero, size: availableSize))

View File

@@ -44,6 +44,18 @@ public final class MessageInputPanelComponent: Component {
case emoji
}
public struct MyReaction: Equatable {
public let reaction: MessageReaction.Reaction
public let file: TelegramMediaFile?
public let animationFileId: Int64?
public init(reaction: MessageReaction.Reaction, file: TelegramMediaFile?, animationFileId: Int64?) {
self.reaction = reaction
self.file = file
self.animationFileId = animationFileId
}
}
public final class ExternalState {
public fileprivate(set) var isEditing: Bool = false
public fileprivate(set) var hasText: Bool = false
@@ -79,8 +91,9 @@ public final class MessageInputPanelComponent: Component {
public let stopAndPreviewMediaRecording: (() -> Void)?
public let discardMediaRecordingPreview: (() -> Void)?
public let attachmentAction: (() -> Void)?
public let hasLike: Bool
public let myReaction: MyReaction?
public let likeAction: (() -> Void)?
public let likeOptionsAction: ((UIView, ContextGesture?) -> Void)?
public let inputModeAction: (() -> Void)?
public let timeoutAction: ((UIView) -> Void)?
public let forwardAction: (() -> Void)?
@@ -126,8 +139,9 @@ public final class MessageInputPanelComponent: Component {
stopAndPreviewMediaRecording: (() -> Void)?,
discardMediaRecordingPreview: (() -> Void)?,
attachmentAction: (() -> Void)?,
hasLike: Bool,
myReaction: MyReaction?,
likeAction: (() -> Void)?,
likeOptionsAction: ((UIView, ContextGesture?) -> Void)?,
inputModeAction: (() -> Void)?,
timeoutAction: ((UIView) -> Void)?,
forwardAction: (() -> Void)?,
@@ -172,8 +186,9 @@ public final class MessageInputPanelComponent: Component {
self.stopAndPreviewMediaRecording = stopAndPreviewMediaRecording
self.discardMediaRecordingPreview = discardMediaRecordingPreview
self.attachmentAction = attachmentAction
self.hasLike = hasLike
self.myReaction = myReaction
self.likeAction = likeAction
self.likeOptionsAction = likeOptionsAction
self.inputModeAction = inputModeAction
self.timeoutAction = timeoutAction
self.forwardAction = forwardAction
@@ -280,12 +295,15 @@ public final class MessageInputPanelComponent: Component {
if (lhs.attachmentAction == nil) != (rhs.attachmentAction == nil) {
return false
}
if lhs.hasLike != rhs.hasLike {
if lhs.myReaction != rhs.myReaction {
return false
}
if (lhs.likeAction == nil) != (rhs.likeAction == nil) {
return false
}
if (lhs.likeOptionsAction == nil) != (rhs.likeOptionsAction == nil) {
return false
}
return true
}
@@ -345,6 +363,10 @@ public final class MessageInputPanelComponent: Component {
return self.likeButton.view
}
public var likeIconView: UIView? {
return (self.likeButton.view as? MessageInputActionButtonComponent.View)?.likeIconView
}
override init(frame: CGRect) {
self.fieldBackgroundView = BlurredBackgroundView(color: UIColor(white: 0.0, alpha: 0.5), enableBlur: true)
@@ -1064,7 +1086,7 @@ public final class MessageInputPanelComponent: Component {
let likeButtonSize = self.likeButton.update(
transition: transition,
component: AnyComponent(MessageInputActionButtonComponent(
mode: .like(isActive: component.hasLike),
mode: .like(reaction: component.myReaction?.reaction, file: component.myReaction?.file, animationFileId: component.myReaction?.animationFileId),
action: { [weak self] _, action, _ in
guard let self, let component = self.component else {
return
@@ -1074,7 +1096,7 @@ public final class MessageInputPanelComponent: Component {
}
component.likeAction?()
},
longPressAction: nil,
longPressAction: component.likeOptionsAction,
switchMediaInputMode: {
},
updateMediaCancelFraction: { _ in