mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Reaction improvements
This commit is contained in:
parent
53690ab199
commit
3b76a3cbfa
@ -89,7 +89,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void) -> ListViewItem {
|
func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .topPeers(peers, theme, strings):
|
case let .topPeers(peers, theme, strings):
|
||||||
return ChatListRecentPeersListItem(theme: theme, strings: strings, context: context, peers: peers, peerSelected: { peer in
|
return ChatListRecentPeersListItem(theme: theme, strings: strings, context: context, peers: peers, peerSelected: { peer in
|
||||||
@ -195,25 +195,45 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
|||||||
badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active)
|
badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: {
|
return ContactsPeerItem(
|
||||||
clearRecentlySearchedPeers()
|
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
|
||||||
}), action: { _ in
|
sortOrder: nameSortOrder,
|
||||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
displayOrder: nameDisplayOrder,
|
||||||
peerSelected(EnginePeer(chatPeer))
|
context: context,
|
||||||
}
|
peerMode: .generalSearch,
|
||||||
}, disabledAction: { _ in
|
peer: .peer(peer: primaryPeer, chatPeer: chatPeer),
|
||||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
status: status,
|
||||||
disabledPeerSelected(EnginePeer(chatPeer))
|
badge: badge,
|
||||||
}
|
enabled: enabled,
|
||||||
}, deletePeer: deletePeer, contextAction: peerContextAction.flatMap { peerContextAction in
|
selection: .none,
|
||||||
return { node, gesture, location in
|
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||||
|
index: nil,
|
||||||
|
header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: {
|
||||||
|
clearRecentlySearchedPeers()
|
||||||
|
}),
|
||||||
|
action: { _ in
|
||||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||||
peerContextAction(EnginePeer(chatPeer), .recentSearch, node, gesture, location)
|
peerSelected(EnginePeer(chatPeer))
|
||||||
} else {
|
|
||||||
gesture?.cancel()
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
disabledAction: { _ in
|
||||||
|
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||||
|
disabledPeerSelected(EnginePeer(chatPeer))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deletePeer: deletePeer,
|
||||||
|
contextAction: peerContextAction.flatMap { peerContextAction in
|
||||||
|
return { node, gesture, location in
|
||||||
|
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||||
|
peerContextAction(EnginePeer(chatPeer), .recentSearch, node, gesture, location)
|
||||||
|
} else {
|
||||||
|
gesture?.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animationCache: animationCache,
|
||||||
|
animationRenderer: animationRenderer
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,7 +517,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, arrowAction: nil)
|
}, arrowAction: nil, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer)
|
||||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
||||||
let primaryPeer: EnginePeer
|
let primaryPeer: EnginePeer
|
||||||
var chatPeer: EnginePeer?
|
var chatPeer: EnginePeer?
|
||||||
@ -584,7 +604,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, arrowAction: nil)
|
}, arrowAction: nil, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer)
|
||||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
||||||
var enabled = true
|
var enabled = true
|
||||||
if filter.contains(.onlyWriteable) {
|
if filter.contains(.onlyWriteable) {
|
||||||
@ -643,7 +663,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
return { node, gesture, location in
|
return { node, gesture, location in
|
||||||
peerContextAction(EnginePeer(peer.peer), .search(nil), node, gesture, location)
|
peerContextAction(EnginePeer(peer.peer), .search(nil), node, gesture, location)
|
||||||
}
|
}
|
||||||
})
|
}, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer)
|
||||||
case let .message(message, peer, readState, presentationData, _, selected, displayCustomHeader, orderingKey, _, _, allPaused):
|
case let .message(message, peer, readState, presentationData, _, selected, displayCustomHeader, orderingKey, _, _, allPaused):
|
||||||
let header: ChatListSearchItemHeader
|
let header: ChatListSearchItemHeader
|
||||||
switch orderingKey {
|
switch orderingKey {
|
||||||
@ -712,12 +732,12 @@ public struct ChatListSearchContainerTransition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void) -> ChatListSearchContainerRecentTransition {
|
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> ChatListSearchContainerRecentTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer), directionHint: nil) }
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer), directionHint: nil) }
|
||||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer), directionHint: nil) }
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, filter: filter, peerSelected: peerSelected, disabledPeerSelected: disabledPeerSelected, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, deletePeer: deletePeer, animationCache: animationCache, animationRenderer: animationRenderer), directionHint: nil) }
|
||||||
|
|
||||||
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||||
}
|
}
|
||||||
@ -2058,7 +2078,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
interaction.clearRecentSearch()
|
interaction.clearRecentSearch()
|
||||||
}, deletePeer: { peerId in
|
}, deletePeer: { peerId in
|
||||||
let _ = context.engine.peers.removeRecentlySearchedPeer(peerId: peerId).start()
|
let _ = context.engine.peers.removeRecentlySearchedPeer(peerId: peerId).start()
|
||||||
})
|
}, animationCache: strongSelf.animationCache, animationRenderer: strongSelf.animationRenderer)
|
||||||
strongSelf.enqueueRecentTransition(transition, firstTime: firstTime)
|
strongSelf.enqueueRecentTransition(transition, firstTime: firstTime)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -435,6 +435,14 @@ final class ChatListTitleView: UIView, NavigationBarTitleView, NavigationBarTitl
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
if let titleCredibilityIconView = self.titleCredibilityIconView, !titleCredibilityIconView.isHidden, titleCredibilityIconView.alpha != 0.0 {
|
||||||
|
if titleCredibilityIconView.bounds.insetBy(dx: -8.0, dy: -8.0).contains(self.convert(point, to: titleCredibilityIconView)) {
|
||||||
|
if let result = titleCredibilityIconView.hitTest(titleCredibilityIconView.bounds.center, with: event) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !self.proxyButton.isHidden {
|
if !self.proxyButton.isHidden {
|
||||||
if let result = self.proxyButton.hitTest(point.offsetBy(dx: -self.proxyButton.frame.minX, dy: -self.proxyButton.frame.minY), with: event) {
|
if let result = self.proxyButton.hitTest(point.offsetBy(dx: -self.proxyButton.frame.minX, dy: -self.proxyButton.frame.minY), with: event) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -393,7 +393,9 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
if let chatPeer = chatPeer {
|
if let chatPeer = chatPeer {
|
||||||
nodeInteraction.disabledPeerSelected(chatPeer)
|
nodeInteraction.disabledPeerSelected(chatPeer)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
animationCache: nodeInteraction.animationCache,
|
||||||
|
animationRenderer: nodeInteraction.animationRenderer
|
||||||
), directionHint: entry.directionHint)
|
), directionHint: entry.directionHint)
|
||||||
}
|
}
|
||||||
case let .HoleEntry(_, theme):
|
case let .HoleEntry(_, theme):
|
||||||
@ -533,7 +535,9 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
if let chatPeer = chatPeer {
|
if let chatPeer = chatPeer {
|
||||||
nodeInteraction.disabledPeerSelected(chatPeer)
|
nodeInteraction.disabledPeerSelected(chatPeer)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
animationCache: nodeInteraction.animationCache,
|
||||||
|
animationRenderer: nodeInteraction.animationRenderer
|
||||||
), directionHint: entry.directionHint)
|
), directionHint: entry.directionHint)
|
||||||
}
|
}
|
||||||
case let .HoleEntry(_, theme):
|
case let .HoleEntry(_, theme):
|
||||||
|
@ -390,7 +390,11 @@ public struct Transition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func setScale(view: UIView, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
public func setScale(view: UIView, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
||||||
let t = view.layer.presentation()?.transform ?? view.layer.transform
|
self.setScale(layer: view.layer, scale: scale, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setScale(layer: CALayer, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
||||||
|
let t = layer.presentation()?.transform ?? layer.transform
|
||||||
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
|
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
|
||||||
if currentScale == scale {
|
if currentScale == scale {
|
||||||
completion?(true)
|
completion?(true)
|
||||||
@ -398,12 +402,12 @@ public struct Transition {
|
|||||||
}
|
}
|
||||||
switch self.animation {
|
switch self.animation {
|
||||||
case .none:
|
case .none:
|
||||||
view.layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
completion?(true)
|
completion?(true)
|
||||||
case let .curve(duration, curve):
|
case let .curve(duration, curve):
|
||||||
let previousScale = currentScale
|
let previousScale = currentScale
|
||||||
view.layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
view.layer.animate(
|
layer.animate(
|
||||||
from: previousScale as NSNumber,
|
from: previousScale as NSNumber,
|
||||||
to: scale as NSNumber,
|
to: scale as NSNumber,
|
||||||
keyPath: "transform.scale",
|
keyPath: "transform.scale",
|
||||||
|
@ -746,7 +746,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
|
|||||||
fileId: fileId,
|
fileId: fileId,
|
||||||
animationCache: arguments.animationCache,
|
animationCache: arguments.animationCache,
|
||||||
animationRenderer: arguments.animationRenderer,
|
animationRenderer: arguments.animationRenderer,
|
||||||
placeholderColor: .gray,
|
placeholderColor: layout.spec.component.chosenOrder != nil ? UIColor(argb: layout.spec.component.colors.selectedForeground).withMultipliedAlpha(0.1) : UIColor(argb: layout.spec.component.colors.deselectedForeground).withMultipliedAlpha(0.1),
|
||||||
animateIdle: animateIdle,
|
animateIdle: animateIdle,
|
||||||
reaction: layout.spec.component.reaction.value,
|
reaction: layout.spec.component.reaction.value,
|
||||||
transition: animation.transition
|
transition: animation.transition
|
||||||
|
@ -26,6 +26,10 @@ swift_library(
|
|||||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||||
"//submodules/ContextUI:ContextUI",
|
"//submodules/ContextUI:ContextUI",
|
||||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/TelegramUI/Components/AnimationCache",
|
||||||
|
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
|
||||||
|
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -16,6 +16,10 @@ import PeerPresenceStatusManager
|
|||||||
import ItemListPeerItem
|
import ItemListPeerItem
|
||||||
import ContextUI
|
import ContextUI
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ComponentFlow
|
||||||
|
import AnimationCache
|
||||||
|
import MultiAnimationRenderer
|
||||||
|
import EmojiStatusComponent
|
||||||
|
|
||||||
public final class ContactItemHighlighting {
|
public final class ContactItemHighlighting {
|
||||||
public var chatLocation: ChatLocation?
|
public var chatLocation: ChatLocation?
|
||||||
@ -150,6 +154,8 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
|
|||||||
let itemHighlighting: ContactItemHighlighting?
|
let itemHighlighting: ContactItemHighlighting?
|
||||||
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||||
let arrowAction: (() -> Void)?
|
let arrowAction: (() -> Void)?
|
||||||
|
let animationCache: AnimationCache?
|
||||||
|
let animationRenderer: MultiAnimationRenderer?
|
||||||
|
|
||||||
public let selectable: Bool
|
public let selectable: Bool
|
||||||
|
|
||||||
@ -157,7 +163,35 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
|
|||||||
|
|
||||||
public let header: ListViewItemHeader?
|
public let header: ListViewItemHeader?
|
||||||
|
|
||||||
public init(presentationData: ItemListPresentationData, style: ItemListStyle = .plain, sectionId: ItemListSectionId = 0, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, context: AccountContext, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, selectionPosition: ContactsPeerItemSelectionPosition = .right, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], additionalActions: [ContactsPeerItemAction] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: SortIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil, setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? = nil, deletePeer: ((EnginePeer.Id) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil, contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil, arrowAction: (() -> Void)? = nil) {
|
public init(
|
||||||
|
presentationData: ItemListPresentationData,
|
||||||
|
style: ItemListStyle = .plain,
|
||||||
|
sectionId: ItemListSectionId = 0,
|
||||||
|
sortOrder: PresentationPersonNameOrder,
|
||||||
|
displayOrder: PresentationPersonNameOrder,
|
||||||
|
context: AccountContext,
|
||||||
|
peerMode: ContactsPeerItemPeerMode,
|
||||||
|
peer: ContactsPeerItemPeer,
|
||||||
|
status: ContactsPeerItemStatus,
|
||||||
|
badge: ContactsPeerItemBadge? = nil,
|
||||||
|
enabled: Bool,
|
||||||
|
selection: ContactsPeerItemSelection,
|
||||||
|
selectionPosition: ContactsPeerItemSelectionPosition = .right,
|
||||||
|
editing: ContactsPeerItemEditing,
|
||||||
|
options: [ItemListPeerItemRevealOption] = [],
|
||||||
|
additionalActions: [ContactsPeerItemAction] = [],
|
||||||
|
actionIcon: ContactsPeerItemActionIcon = .none,
|
||||||
|
index: SortIndex?,
|
||||||
|
header: ListViewItemHeader?,
|
||||||
|
action: @escaping (ContactsPeerItemPeer) -> Void,
|
||||||
|
disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil,
|
||||||
|
setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? = nil,
|
||||||
|
deletePeer: ((EnginePeer.Id) -> Void)? = nil,
|
||||||
|
itemHighlighting: ContactItemHighlighting? = nil,
|
||||||
|
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil, arrowAction: (() -> Void)? = nil,
|
||||||
|
animationCache: AnimationCache? = nil,
|
||||||
|
animationRenderer: MultiAnimationRenderer? = nil
|
||||||
|
) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.style = style
|
self.style = style
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
@ -184,6 +218,8 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader {
|
|||||||
self.selectable = enabled || disabledAction != nil
|
self.selectable = enabled || disabledAction != nil
|
||||||
self.contextAction = contextAction
|
self.contextAction = contextAction
|
||||||
self.arrowAction = arrowAction
|
self.arrowAction = arrowAction
|
||||||
|
self.animationCache = animationCache
|
||||||
|
self.animationRenderer = animationRenderer
|
||||||
|
|
||||||
if let index = index {
|
if let index = index {
|
||||||
var letter: String = "#"
|
var letter: String = "#"
|
||||||
@ -333,7 +369,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
private let avatarNode: AvatarNode
|
private let avatarNode: AvatarNode
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private var credibilityIconNode: ASImageNode?
|
private var credibilityIconView: ComponentHostView<Empty>?
|
||||||
private let statusNode: TextNode
|
private let statusNode: TextNode
|
||||||
private var badgeBackgroundNode: ASImageNode?
|
private var badgeBackgroundNode: ASImageNode?
|
||||||
private var badgeTextNode: TextNode?
|
private var badgeTextNode: TextNode?
|
||||||
@ -571,18 +607,20 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||||
|
|
||||||
var currentCredibilityIconImage: UIImage?
|
var credibilityIcon: EmojiStatusComponent.Content?
|
||||||
switch item.peer {
|
switch item.peer {
|
||||||
case let .peer(peer, _):
|
case let .peer(peer, _):
|
||||||
if let peer = peer, peer.id != item.context.account.peerId {
|
if let peer = peer, peer.id != item.context.account.peerId {
|
||||||
if peer.isScam {
|
if peer.isScam {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
credibilityIcon = .scam(color: item.presentationData.theme.chat.message.incoming.scamColor)
|
||||||
} else if peer.isFake {
|
} else if peer.isFake {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
credibilityIcon = .fake(color: item.presentationData.theme.chat.message.incoming.scamColor)
|
||||||
|
} else if case let .user(user) = peer, let emojiStatus = user.emojiStatus {
|
||||||
|
credibilityIcon = .emojiStatus(status: emojiStatus, size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor)
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .deviceContact:
|
case .deviceContact:
|
||||||
@ -743,8 +781,14 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var additionalTitleInset: CGFloat = 0.0
|
var additionalTitleInset: CGFloat = 0.0
|
||||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
if let credibilityIcon = credibilityIcon {
|
||||||
additionalTitleInset += 3.0 + currentCredibilityIconImage.size.width
|
additionalTitleInset += 3.0
|
||||||
|
switch credibilityIcon {
|
||||||
|
case .scam, .fake:
|
||||||
|
additionalTitleInset += 30.0
|
||||||
|
default:
|
||||||
|
additionalTitleInset += 16.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let actionButtons = actionButtons {
|
if let actionButtons = actionButtons {
|
||||||
additionalTitleInset += 3.0
|
additionalTitleInset += 3.0
|
||||||
@ -930,23 +974,35 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
strongSelf.statusNode.frame = statusFrame
|
strongSelf.statusNode.frame = statusFrame
|
||||||
transition.animatePositionAdditive(node: strongSelf.statusNode, offset: CGPoint(x: previousStatusFrame.minX - statusFrame.minX, y: 0))
|
transition.animatePositionAdditive(node: strongSelf.statusNode, offset: CGPoint(x: previousStatusFrame.minX - statusFrame.minX, y: 0))
|
||||||
|
|
||||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
if let credibilityIcon = credibilityIcon, let animationCache = item.animationCache, let animationRenderer = item.animationRenderer {
|
||||||
let iconNode: ASImageNode
|
let credibilityIconView: ComponentHostView<Empty>
|
||||||
if let current = strongSelf.credibilityIconNode {
|
if let current = strongSelf.credibilityIconView {
|
||||||
iconNode = current
|
credibilityIconView = current
|
||||||
} else {
|
} else {
|
||||||
iconNode = ASImageNode()
|
credibilityIconView = ComponentHostView<Empty>()
|
||||||
iconNode.isLayerBacked = true
|
strongSelf.offsetContainerNode.view.addSubview(credibilityIconView)
|
||||||
iconNode.displaysAsynchronously = false
|
strongSelf.credibilityIconView = credibilityIconView
|
||||||
iconNode.displayWithoutProcessing = true
|
|
||||||
strongSelf.offsetContainerNode.addSubnode(iconNode)
|
|
||||||
strongSelf.credibilityIconNode = iconNode
|
|
||||||
}
|
}
|
||||||
iconNode.image = currentCredibilityIconImage
|
|
||||||
transition.updateFrame(node: iconNode, frame: CGRect(origin: CGPoint(x: titleFrame.maxX + 4.0, y: floorToScreenPixels(titleFrame.midY - currentCredibilityIconImage.size.height / 2.0) - UIScreenPixel), size: currentCredibilityIconImage.size))
|
let iconSize = credibilityIconView.update(
|
||||||
} else if let credibilityIconNode = strongSelf.credibilityIconNode {
|
transition: .immediate,
|
||||||
strongSelf.credibilityIconNode = nil
|
component: AnyComponent(EmojiStatusComponent(
|
||||||
credibilityIconNode.removeFromSupernode()
|
context: item.context,
|
||||||
|
animationCache: animationCache,
|
||||||
|
animationRenderer: animationRenderer,
|
||||||
|
content: credibilityIcon,
|
||||||
|
action: nil,
|
||||||
|
longTapAction: nil,
|
||||||
|
emojiFileUpdated: nil
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 20.0, height: 20.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
transition.updateFrame(view: credibilityIconView, frame: CGRect(origin: CGPoint(x: titleFrame.maxX + 4.0, y: floorToScreenPixels(titleFrame.midY - iconSize.height / 2.0)), size: iconSize))
|
||||||
|
} else if let credibilityIconView = strongSelf.credibilityIconView {
|
||||||
|
strongSelf.credibilityIconView = nil
|
||||||
|
credibilityIconView.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let actionButtons = actionButtons {
|
if let actionButtons = actionButtons {
|
||||||
@ -1146,10 +1202,10 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
self.statusNode.frame = statusFrame
|
self.statusNode.frame = statusFrame
|
||||||
transition.animatePositionAdditive(node: self.statusNode, offset: CGPoint(x: previousStatusFrame.minX - statusFrame.minX, y: 0))
|
transition.animatePositionAdditive(node: self.statusNode, offset: CGPoint(x: previousStatusFrame.minX - statusFrame.minX, y: 0))
|
||||||
|
|
||||||
if let credibilityIconNode = self.credibilityIconNode {
|
if let credibilityIconView = self.credibilityIconView {
|
||||||
var iconFrame = credibilityIconNode.frame
|
var iconFrame = credibilityIconView.frame
|
||||||
iconFrame.origin.x = titleFrame.maxX + 4.0
|
iconFrame.origin.x = titleFrame.maxX + 4.0
|
||||||
transition.updateFrame(node: credibilityIconNode, frame: iconFrame)
|
transition.updateFrame(view: credibilityIconView, frame: iconFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let badgeBackgroundNode = self.badgeBackgroundNode, let badgeTextNode = self.badgeTextNode {
|
if let badgeBackgroundNode = self.badgeBackgroundNode, let badgeTextNode = self.badgeTextNode {
|
||||||
|
@ -215,7 +215,7 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) {
|
func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) {
|
||||||
let springDuration: Double = 0.3
|
let springDuration: Double = 0.5
|
||||||
let springDamping: CGFloat = 104.0
|
let springDamping: CGFloat = 104.0
|
||||||
let springDelay: Double = 0.05
|
let springDelay: Double = 0.05
|
||||||
let shadowInset: CGFloat = 15.0
|
let shadowInset: CGFloat = 15.0
|
||||||
|
@ -114,7 +114,7 @@ private final class ExpandItemView: UIView {
|
|||||||
transition.updateCornerRadius(layer: self.tintView.layer, cornerRadius: size.width / 2.0)
|
transition.updateCornerRadius(layer: self.tintView.layer, cornerRadius: size.width / 2.0)
|
||||||
|
|
||||||
if let image = self.arrowView.image {
|
if let image = self.arrowView.image {
|
||||||
transition.updateFrame(view: self.arrowView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - image.size.width) / 2.0), y: floorToScreenPixels(size.height - size.width + (size.width - image.size.height) / 2.0)), size: image.size))
|
transition.updateFrame(view: self.arrowView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - image.size.width) / 2.0), y: floorToScreenPixels(size.height - size.width + (size.width - image.size.height) / 2.0 + 1.0)), size: image.size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -874,7 +874,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let animateInFromAnchorRect = animateInFromAnchorRect {
|
if let animateInFromAnchorRect = animateInFromAnchorRect {
|
||||||
let springDuration: Double = 0.3
|
let springDuration: Double = 0.5
|
||||||
let springDamping: CGFloat = 104.0
|
let springDamping: CGFloat = 104.0
|
||||||
let springDelay: Double = 0.05
|
let springDelay: Double = 0.05
|
||||||
|
|
||||||
@ -902,11 +902,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { [weak self] groupId, item, sourceView, sourceRect, sourceLayer in
|
performItemAction: { [weak self] groupId, item, sourceView, sourceRect, sourceLayer, isLongPress in
|
||||||
guard let strongSelf = self, let itemFile = item.itemFile else {
|
guard let strongSelf = self, let itemFile = item.itemFile else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.didTriggerExpandedReaction = isLongPress
|
||||||
|
|
||||||
var found = false
|
var found = false
|
||||||
if let groupId = groupId.base as? String, groupId == "recent" {
|
if let groupId = groupId.base as? String, groupId == "recent" {
|
||||||
for reactionItem in strongSelf.items {
|
for reactionItem in strongSelf.items {
|
||||||
@ -915,7 +917,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
found = true
|
found = true
|
||||||
|
|
||||||
strongSelf.customReactionSource = (sourceView, sourceRect, sourceLayer, reactionItem)
|
strongSelf.customReactionSource = (sourceView, sourceRect, sourceLayer, reactionItem)
|
||||||
strongSelf.reactionSelected?(reactionItem.updateMessageReaction, false)
|
strongSelf.reactionSelected?(reactionItem.updateMessageReaction, isLongPress)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -934,7 +936,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
isCustom: true
|
isCustom: true
|
||||||
)
|
)
|
||||||
strongSelf.customReactionSource = (sourceView, sourceRect, sourceLayer, reactionItem)
|
strongSelf.customReactionSource = (sourceView, sourceRect, sourceLayer, reactionItem)
|
||||||
strongSelf.reactionSelected?(reactionItem.updateMessageReaction, false)
|
strongSelf.reactionSelected?(reactionItem.updateMessageReaction, isLongPress)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteBackwards: {
|
deleteBackwards: {
|
||||||
@ -1157,10 +1159,10 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
case .builtin:
|
case .builtin:
|
||||||
switchToInlineImmediately = false
|
switchToInlineImmediately = false
|
||||||
case .custom:
|
case .custom:
|
||||||
switchToInlineImmediately = true
|
switchToInlineImmediately = !self.didTriggerExpandedReaction
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switchToInlineImmediately = true
|
switchToInlineImmediately = !self.didTriggerExpandedReaction
|
||||||
}
|
}
|
||||||
|
|
||||||
self.animationTargetView = targetView
|
self.animationTargetView = targetView
|
||||||
@ -1192,7 +1194,11 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
var expandedSize: CGSize = selfTargetRect.size
|
var expandedSize: CGSize = selfTargetRect.size
|
||||||
if self.didTriggerExpandedReaction {
|
if self.didTriggerExpandedReaction {
|
||||||
expandedSize = CGSize(width: 120.0, height: 120.0)
|
if itemNode.item.listAnimation.isVideoEmoji || itemNode.item.listAnimation.isVideoSticker {
|
||||||
|
expandedSize = CGSize(width: 80.0, height: 80.0)
|
||||||
|
} else {
|
||||||
|
expandedSize = CGSize(width: 120.0, height: 120.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
||||||
@ -1200,7 +1206,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let effectFrame: CGRect
|
let effectFrame: CGRect
|
||||||
let incomingMessage: Bool = expandedFrame.midX < self.bounds.width / 2.0
|
let incomingMessage: Bool = expandedFrame.midX < self.bounds.width / 2.0
|
||||||
if self.didTriggerExpandedReaction {
|
if self.didTriggerExpandedReaction {
|
||||||
effectFrame = expandedFrame.insetBy(dx: -expandedFrame.width * 0.5, dy: -expandedFrame.height * 0.5).offsetBy(dx: incomingMessage ? (expandedFrame.width - 50.0) : (-expandedFrame.width + 50.0), dy: 0.0)
|
let expandFactor: CGFloat = 0.5
|
||||||
|
effectFrame = expandedFrame.insetBy(dx: -expandedFrame.width * expandFactor, dy: -expandedFrame.height * expandFactor).offsetBy(dx: incomingMessage ? (expandedFrame.width - 50.0) : (-expandedFrame.width + 50.0), dy: 0.0)
|
||||||
} else {
|
} else {
|
||||||
effectFrame = expandedFrame.insetBy(dx: -expandedSize.width, dy: -expandedSize.height)
|
effectFrame = expandedFrame.insetBy(dx: -expandedSize.width, dy: -expandedSize.height)
|
||||||
}
|
}
|
||||||
@ -1265,7 +1272,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
cache: animationCache,
|
cache: animationCache,
|
||||||
renderer: animationRenderer,
|
renderer: animationRenderer,
|
||||||
placeholderColor: UIColor(white: 0.0, alpha: 0.0),
|
placeholderColor: UIColor(white: 0.0, alpha: 0.0),
|
||||||
pointSize: CGSize(width: 32.0, height: 32.0)
|
pointSize: CGSize(width: self.didTriggerExpandedReaction ? 64.0 : 32.0, height: self.didTriggerExpandedReaction ? 64.0 : 32.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
if let sublayers = animationLayer.sublayers {
|
if let sublayers = animationLayer.sublayers {
|
||||||
@ -1484,6 +1491,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let expandItemView = self.expandItemView, expandItemView.bounds.contains(self.view.convert(point, to: self.expandItemView)) {
|
if let expandItemView = self.expandItemView, expandItemView.bounds.contains(self.view.convert(point, to: self.expandItemView)) {
|
||||||
self.currentContentHeight = 300.0
|
self.currentContentHeight = 300.0
|
||||||
self.isExpanded = true
|
self.isExpanded = true
|
||||||
|
self.longPressRecognizer?.isEnabled = false
|
||||||
self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring))
|
self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring))
|
||||||
} else if let reaction = self.reaction(at: point) {
|
} else if let reaction = self.reaction(at: point) {
|
||||||
switch reaction {
|
switch reaction {
|
||||||
@ -1504,6 +1512,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
self.hapticFeedback?.tap()
|
self.hapticFeedback?.tap()
|
||||||
|
|
||||||
|
self.longPressRecognizer?.isEnabled = false
|
||||||
|
|
||||||
self.animateFromExtensionDistance = self.extensionDistance
|
self.animateFromExtensionDistance = self.extensionDistance
|
||||||
self.extensionDistance = 0.0
|
self.extensionDistance = 0.0
|
||||||
self.visibleExtensionDistance = 0.0
|
self.visibleExtensionDistance = 0.0
|
||||||
|
@ -235,7 +235,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
strongSelf.emojiContent = emojiContent
|
strongSelf.emojiContent = emojiContent
|
||||||
|
|
||||||
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { _, item, _, _, _ in
|
performItemAction: { _, item, _, _, _, _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -416,16 +416,14 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
transition.setFrame(layer: self.cloudShadowLayer1, frame: cloudFrame1)
|
transition.setFrame(layer: self.cloudShadowLayer1, frame: cloudFrame1)
|
||||||
transition.setCornerRadius(layer: self.cloudLayer1, cornerRadius: cloudFrame1.width / 2.0)
|
transition.setCornerRadius(layer: self.cloudLayer1, cornerRadius: cloudFrame1.width / 2.0)
|
||||||
|
|
||||||
//transition.setFrame(view: componentView, frame: componentFrame)
|
|
||||||
transition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
transition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
||||||
|
|
||||||
if animateIn {
|
if animateIn {
|
||||||
//self.allowsGroupOpacity = true
|
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, completion: { [weak self] _ in
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, completion: { [weak self] _ in
|
||||||
self?.allowsGroupOpacity = false
|
self?.allowsGroupOpacity = false
|
||||||
})
|
})
|
||||||
|
|
||||||
let contentDuration: Double = 0.5
|
let contentDuration: Double = 0.3
|
||||||
let contentDelay: Double = 0.14
|
let contentDelay: Double = 0.14
|
||||||
let initialContentFrame = CGRect(origin: CGPoint(x: cloudFrame0.midX - 24.0, y: componentFrame.minY), size: CGSize(width: 24.0 * 2.0, height: 24.0 * 2.0))
|
let initialContentFrame = CGRect(origin: CGPoint(x: cloudFrame0.midX - 24.0, y: componentFrame.minY), size: CGSize(width: 24.0 * 2.0, height: 24.0 * 2.0))
|
||||||
|
|
||||||
@ -439,16 +437,9 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
componentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: contentDelay)
|
componentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: contentDelay)
|
||||||
self.componentShadowLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: contentDelay)
|
self.componentShadowLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: contentDelay)
|
||||||
|
|
||||||
//componentView.layer.animateScale(from: 0.5, to: 1.0, duration: contentDuration, delay: contentDelay, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
//self.componentShadowLayer.animateScale(from: 0.5, to: 1.0, duration: contentDuration, delay: contentDelay, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
|
|
||||||
let initialComponentShadowPath = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: initialContentFrame.size), cornerRadius: 24.0).cgPath
|
let initialComponentShadowPath = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: initialContentFrame.size), cornerRadius: 24.0).cgPath
|
||||||
self.componentShadowLayer.animate(from: initialComponentShadowPath, to: self.componentShadowLayer.shadowPath!, keyPath: "shadowPath", timingFunction: kCAMediaTimingFunctionSpring, duration: contentDuration, delay: contentDelay)
|
self.componentShadowLayer.animate(from: initialComponentShadowPath, to: self.componentShadowLayer.shadowPath!, keyPath: "shadowPath", timingFunction: kCAMediaTimingFunctionSpring, duration: contentDuration, delay: contentDelay)
|
||||||
|
|
||||||
//componentView.layer.animateScale(from: (componentView.bounds.width - 10.0) / componentView.bounds.width, to: 1.0, duration: 0.4, delay: 0.1, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
//componentView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: contentDelay)
|
|
||||||
//self.componentShadowLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: contentDelay)
|
|
||||||
|
|
||||||
self.cloudLayer0.animateScale(from: 0.01, to: 1.0, duration: 0.4, delay: 0.05, timingFunction: kCAMediaTimingFunctionSpring)
|
self.cloudLayer0.animateScale(from: 0.01, to: 1.0, duration: 0.4, delay: 0.05, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
self.cloudShadowLayer0.animateScale(from: 0.01, to: 1.0, duration: 0.4, delay: 0.05, timingFunction: kCAMediaTimingFunctionSpring)
|
self.cloudShadowLayer0.animateScale(from: 0.01, to: 1.0, duration: 0.4, delay: 0.05, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
|
|
||||||
|
@ -1543,7 +1543,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class InputInteraction {
|
public final class InputInteraction {
|
||||||
public let performItemAction: (AnyHashable, Item, UIView, CGRect, CALayer) -> Void
|
public let performItemAction: (AnyHashable, Item, UIView, CGRect, CALayer, Bool) -> Void
|
||||||
public let deleteBackwards: () -> Void
|
public let deleteBackwards: () -> Void
|
||||||
public let openStickerSettings: () -> Void
|
public let openStickerSettings: () -> Void
|
||||||
public let openFeatured: () -> Void
|
public let openFeatured: () -> Void
|
||||||
@ -1560,7 +1560,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
public let externalBackground: ExternalBackground?
|
public let externalBackground: ExternalBackground?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
performItemAction: @escaping (AnyHashable, Item, UIView, CGRect, CALayer) -> Void,
|
performItemAction: @escaping (AnyHashable, Item, UIView, CGRect, CALayer, Bool) -> Void,
|
||||||
deleteBackwards: @escaping () -> Void,
|
deleteBackwards: @escaping () -> Void,
|
||||||
openStickerSettings: @escaping () -> Void,
|
openStickerSettings: @escaping () -> Void,
|
||||||
openFeatured: @escaping () -> Void,
|
openFeatured: @escaping () -> Void,
|
||||||
@ -1777,6 +1777,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
public let itemGroups: [ItemGroup]
|
public let itemGroups: [ItemGroup]
|
||||||
public let itemLayoutType: ItemLayoutType
|
public let itemLayoutType: ItemLayoutType
|
||||||
public let warpContentsOnEdges: Bool
|
public let warpContentsOnEdges: Bool
|
||||||
|
public let enableLongPress: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
id: AnyHashable,
|
id: AnyHashable,
|
||||||
@ -1787,7 +1788,8 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
inputInteractionHolder: InputInteractionHolder,
|
inputInteractionHolder: InputInteractionHolder,
|
||||||
itemGroups: [ItemGroup],
|
itemGroups: [ItemGroup],
|
||||||
itemLayoutType: ItemLayoutType,
|
itemLayoutType: ItemLayoutType,
|
||||||
warpContentsOnEdges: Bool
|
warpContentsOnEdges: Bool,
|
||||||
|
enableLongPress: Bool
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -1798,6 +1800,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.itemGroups = itemGroups
|
self.itemGroups = itemGroups
|
||||||
self.itemLayoutType = itemLayoutType
|
self.itemLayoutType = itemLayoutType
|
||||||
self.warpContentsOnEdges = warpContentsOnEdges
|
self.warpContentsOnEdges = warpContentsOnEdges
|
||||||
|
self.enableLongPress = enableLongPress
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: EmojiPagerContentComponent, rhs: EmojiPagerContentComponent) -> Bool {
|
public static func ==(lhs: EmojiPagerContentComponent, rhs: EmojiPagerContentComponent) -> Bool {
|
||||||
@ -1831,6 +1834,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
if lhs.warpContentsOnEdges != rhs.warpContentsOnEdges {
|
if lhs.warpContentsOnEdges != rhs.warpContentsOnEdges {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.enableLongPress != rhs.enableLongPress {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -2556,6 +2562,8 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
private var activeItemUpdated: ActionSlot<(AnyHashable, AnyHashable?, Transition)>?
|
private var activeItemUpdated: ActionSlot<(AnyHashable, AnyHashable?, Transition)>?
|
||||||
private var itemLayout: ItemLayout?
|
private var itemLayout: ItemLayout?
|
||||||
|
|
||||||
|
private var longTapRecognizer: UILongPressGestureRecognizer?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.backgroundView = BlurredBackgroundView(color: nil)
|
self.backgroundView = BlurredBackgroundView(color: nil)
|
||||||
|
|
||||||
@ -2607,6 +2615,12 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.scrollView.addSubview(self.placeholdersContainerView)
|
self.scrollView.addSubview(self.placeholdersContainerView)
|
||||||
|
|
||||||
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||||
|
|
||||||
|
let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:)))
|
||||||
|
longTapRecognizer.minimumPressDuration = 0.2
|
||||||
|
self.longTapRecognizer = longTapRecognizer
|
||||||
|
self.addGestureRecognizer(longTapRecognizer)
|
||||||
|
longTapRecognizer.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -2665,7 +2679,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
let distance = sqrt(distanceVector.x * distanceVector.x + distanceVector.y * distanceVector.y)
|
let distance = sqrt(distanceVector.x * distanceVector.x + distanceVector.y * distanceVector.y)
|
||||||
|
|
||||||
let distanceNorm = min(1.0, max(0.0, distance / self.bounds.width))
|
let distanceNorm = min(1.0, max(0.0, distance / self.bounds.width))
|
||||||
let delay = 0.05 + (distanceNorm) * 0.4
|
let delay = 0.05 + (distanceNorm) * 0.3
|
||||||
itemLayer.animateScale(from: 0.01, to: 1.0, duration: 0.18, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
|
itemLayer.animateScale(from: 0.01, to: 1.0, duration: 0.18, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2692,7 +2706,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
let clippedDistance = max(0.0, min(distance, maxDistance))
|
let clippedDistance = max(0.0, min(distance, maxDistance))
|
||||||
let distanceNorm = clippedDistance / maxDistance
|
let distanceNorm = clippedDistance / maxDistance
|
||||||
|
|
||||||
let delay = listViewAnimationCurveSystem(distanceNorm) * 0.16
|
let delay = listViewAnimationCurveSystem(distanceNorm) * 0.1
|
||||||
|
|
||||||
itemLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
|
itemLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
|
||||||
itemLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, delay: delay)
|
itemLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, delay: delay)
|
||||||
@ -3196,7 +3210,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
foundExactItem = true
|
foundExactItem = true
|
||||||
foundItem = true
|
foundItem = true
|
||||||
if !itemLayer.displayPlaceholder {
|
if !itemLayer.displayPlaceholder {
|
||||||
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer)
|
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3204,7 +3218,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
if let (item, itemKey) = self.item(atPoint: recognizer.location(in: self), extendedHitRange: true), let itemLayer = self.visibleItemLayers[itemKey] {
|
if let (item, itemKey) = self.item(atPoint: recognizer.location(in: self), extendedHitRange: true), let itemLayer = self.visibleItemLayers[itemKey] {
|
||||||
foundItem = true
|
foundItem = true
|
||||||
if !itemLayer.displayPlaceholder {
|
if !itemLayer.displayPlaceholder {
|
||||||
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer)
|
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3213,6 +3227,87 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let longPressDuration: Double = 0.5
|
||||||
|
private var longPressItem: EmojiPagerContentComponent.View.ItemLayer.Key?
|
||||||
|
private var hapticFeedback: HapticFeedback?
|
||||||
|
private var continuousHaptic: AnyObject?
|
||||||
|
private var longPressTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
|
@objc private func longPressGesture(_ recognizer: UILongPressGestureRecognizer) {
|
||||||
|
switch recognizer.state {
|
||||||
|
case .began:
|
||||||
|
let point = recognizer.location(in: self)
|
||||||
|
|
||||||
|
guard let item = self.item(atPoint: point), let itemLayer = self.visibleItemLayers[item.1] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch item.0.content {
|
||||||
|
case .animation:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.longPressItem = item.1
|
||||||
|
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
self.continuousHaptic = try? ContinuousHaptic(duration: longPressDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.hapticFeedback == nil {
|
||||||
|
self.hapticFeedback = HapticFeedback()
|
||||||
|
}
|
||||||
|
|
||||||
|
let transition = Transition(animation: .curve(duration: longPressDuration, curve: .easeInOut))
|
||||||
|
transition.setScale(layer: itemLayer, scale: 1.3)
|
||||||
|
|
||||||
|
self.longPressTimer?.invalidate()
|
||||||
|
self.longPressTimer = SwiftSignalKit.Timer(timeout: longPressDuration, repeat: false, completion: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.longTapRecognizer?.state = .ended
|
||||||
|
}, queue: .mainQueue())
|
||||||
|
self.longPressTimer?.start()
|
||||||
|
case .changed:
|
||||||
|
let point = recognizer.location(in: self)
|
||||||
|
|
||||||
|
if let longPressItem = self.longPressItem, let item = self.item(atPoint: point), longPressItem == item.1 {
|
||||||
|
} else {
|
||||||
|
self.longTapRecognizer?.state = .cancelled
|
||||||
|
}
|
||||||
|
case .cancelled:
|
||||||
|
self.longPressTimer?.invalidate()
|
||||||
|
self.continuousHaptic = nil
|
||||||
|
|
||||||
|
if let itemKey = self.longPressItem {
|
||||||
|
self.longPressItem = nil
|
||||||
|
|
||||||
|
if let itemLayer = self.visibleItemLayers[itemKey] {
|
||||||
|
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||||
|
transition.setScale(layer: itemLayer, scale: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .ended:
|
||||||
|
self.longPressTimer?.invalidate()
|
||||||
|
self.continuousHaptic = nil
|
||||||
|
|
||||||
|
if let itemKey = self.longPressItem {
|
||||||
|
self.longPressItem = nil
|
||||||
|
|
||||||
|
if let component = self.component, let itemLayer = self.visibleItemLayers[itemKey] {
|
||||||
|
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, itemLayer.item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer, true)
|
||||||
|
} else {
|
||||||
|
if let itemLayer = self.visibleItemLayers[itemKey] {
|
||||||
|
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||||
|
transition.setScale(layer: itemLayer, scale: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func item(atPoint point: CGPoint, extendedHitRange: Bool = false) -> (Item, ItemLayer.Key)? {
|
private func item(atPoint point: CGPoint, extendedHitRange: Bool = false) -> (Item, ItemLayer.Key)? {
|
||||||
let localPoint = self.convert(point, to: self.scrollView)
|
let localPoint = self.convert(point, to: self.scrollView)
|
||||||
|
|
||||||
@ -3411,7 +3506,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
guard let strongSelf = self, let component = strongSelf.component else {
|
guard let strongSelf = self, let component = strongSelf.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.inputInteractionHolder.inputInteraction?.performItemAction(groupId, item, view, rect, layer)
|
component.inputInteractionHolder.inputInteraction?.performItemAction(groupId, item, view, rect, layer, false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.visibleGroupHeaders[itemGroup.groupId] = groupHeaderView
|
self.visibleGroupHeaders[itemGroup.groupId] = groupHeaderView
|
||||||
@ -4133,6 +4228,10 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
self.updateIsWarpEnabled(isEnabled: component.warpContentsOnEdges)
|
self.updateIsWarpEnabled(isEnabled: component.warpContentsOnEdges)
|
||||||
|
|
||||||
|
if let longTapRecognizer = self.longTapRecognizer {
|
||||||
|
longTapRecognizer.isEnabled = component.enableLongPress
|
||||||
|
}
|
||||||
|
|
||||||
if let shimmerHostView = self.shimmerHostView {
|
if let shimmerHostView = self.shimmerHostView {
|
||||||
transition.setFrame(view: shimmerHostView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
transition.setFrame(view: shimmerHostView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||||
}
|
}
|
||||||
@ -4892,7 +4991,8 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
itemLayoutType: .compact,
|
itemLayoutType: .compact,
|
||||||
warpContentsOnEdges: isReactionSelection || isStatusSelection
|
warpContentsOnEdges: isReactionSelection || isStatusSelection,
|
||||||
|
enableLongPress: isReactionSelection
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return emojiItems
|
return emojiItems
|
||||||
|
@ -505,7 +505,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
itemLayoutType: .detailed,
|
itemLayoutType: .detailed,
|
||||||
warpContentsOnEdges: false
|
warpContentsOnEdges: false,
|
||||||
|
enableLongPress: false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,7 +903,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
|
|
||||||
var premiumToastCounter = 0
|
var premiumToastCounter = 0
|
||||||
self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { [weak self, weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _ in
|
performItemAction: { [weak self, weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _, _ in
|
||||||
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: true) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: true) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||||
guard let strongSelf = self, let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
guard let strongSelf = self, let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||||
return
|
return
|
||||||
@ -1099,7 +1100,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
self.stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
self.stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { [weak controllerInteraction, weak interfaceInteraction] groupId, item, view, rect, layer in
|
performItemAction: { [weak controllerInteraction, weak interfaceInteraction] groupId, item, view, rect, layer, _ in
|
||||||
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: false) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: false) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||||
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||||
return
|
return
|
||||||
@ -1918,7 +1919,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
|
|
||||||
let inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
let inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { [weak self] _, item, _, _, _ in
|
performItemAction: { [weak self] _, item, _, _, _, _ in
|
||||||
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: nil, premiumIfSavedMessages: false) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
let _ = (ChatEntityKeyboardInputNode.hasPremium(context: context, chatPeerId: nil, premiumIfSavedMessages: false) |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -143,6 +143,22 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
animateIdle = false
|
animateIdle = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let placeholderColor: UIColor
|
||||||
|
switch type {
|
||||||
|
case .BubbleIncoming:
|
||||||
|
placeholderColor = theme.chat.message.incoming.mediaPlaceholderColor
|
||||||
|
case .BubbleOutgoing:
|
||||||
|
placeholderColor = theme.chat.message.incoming.mediaPlaceholderColor
|
||||||
|
case .ImageIncoming:
|
||||||
|
placeholderColor = UIColor(white: 1.0, alpha: 0.1)
|
||||||
|
case .ImageOutgoing:
|
||||||
|
placeholderColor = UIColor(white: 1.0, alpha: 0.1)
|
||||||
|
case .FreeIncoming:
|
||||||
|
placeholderColor = UIColor(white: 0.0, alpha: 0.1)
|
||||||
|
case .FreeOutgoing:
|
||||||
|
placeholderColor = UIColor(white: 0.0, alpha: 0.1)
|
||||||
|
}
|
||||||
|
|
||||||
self.iconView.update(
|
self.iconView.update(
|
||||||
size: boundingImageSize,
|
size: boundingImageSize,
|
||||||
context: context,
|
context: context,
|
||||||
@ -150,7 +166,7 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
fileId: fileId,
|
fileId: fileId,
|
||||||
animationCache: animationCache,
|
animationCache: animationCache,
|
||||||
animationRenderer: animationRenderer,
|
animationRenderer: animationRenderer,
|
||||||
placeholderColor: .gray,
|
placeholderColor: placeholderColor,
|
||||||
animateIdle: animateIdle,
|
animateIdle: animateIdle,
|
||||||
reaction: value,
|
reaction: value,
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
|
Loading…
x
Reference in New Issue
Block a user