mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
26d6e52a10
@ -1958,7 +1958,7 @@ ios_application(
|
|||||||
}),
|
}),
|
||||||
watch_application = select({
|
watch_application = select({
|
||||||
":disableExtensionsSetting": None,
|
":disableExtensionsSetting": None,
|
||||||
"//conditions:default": ":TelegramWatchApp",
|
"//conditions:default": None,#":TelegramWatchApp",
|
||||||
}) if telegram_enable_watch else None,
|
}) if telegram_enable_watch else None,
|
||||||
deps = [
|
deps = [
|
||||||
":Main",
|
":Main",
|
||||||
|
@ -1537,7 +1537,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if peer.isFake {
|
} else if peer.isFake {
|
||||||
currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
|
currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
|
||||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
currentCredibilityIconContent = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
currentCredibilityIconContent = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
@ -1553,7 +1553,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if peer.isFake {
|
} else if peer.isFake {
|
||||||
currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
|
currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
|
||||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
currentCredibilityIconContent = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
currentCredibilityIconContent = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
|
@ -280,6 +280,29 @@ public struct Transition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func setBoundsSize(view: UIView, size: CGSize, completion: ((Bool) -> Void)? = nil) {
|
||||||
|
if view.bounds.size == size {
|
||||||
|
completion?(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch self.animation {
|
||||||
|
case .none:
|
||||||
|
view.bounds.size = size
|
||||||
|
view.layer.removeAnimation(forKey: "bounds.size")
|
||||||
|
completion?(true)
|
||||||
|
case .curve:
|
||||||
|
let previousBounds: CGRect
|
||||||
|
if view.layer.animation(forKey: "bounds.size") != nil, let presentation = view.layer.presentation() {
|
||||||
|
previousBounds = presentation.bounds
|
||||||
|
} else {
|
||||||
|
previousBounds = view.layer.bounds
|
||||||
|
}
|
||||||
|
view.bounds = CGRect(origin: view.bounds.origin, size: size)
|
||||||
|
|
||||||
|
self.animateBoundsSize(view: view, from: previousBounds.size, to: size, completion: completion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func setPosition(view: UIView, position: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
public func setPosition(view: UIView, position: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
||||||
if view.center == position {
|
if view.center == position {
|
||||||
completion?(true)
|
completion?(true)
|
||||||
@ -552,6 +575,10 @@ public struct Transition {
|
|||||||
self.animateBoundsOrigin(layer: view.layer, from: fromValue, to: toValue, additive: additive, completion: completion)
|
self.animateBoundsOrigin(layer: view.layer, from: fromValue, to: toValue, additive: additive, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func animateBoundsSize(view: UIView, from fromValue: CGSize, to toValue: CGSize, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
|
self.animateBoundsSize(layer: view.layer, from: fromValue, to: toValue, additive: additive, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
public func animatePosition(layer: CALayer, from fromValue: CGPoint, to toValue: CGPoint, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
public func animatePosition(layer: CALayer, from fromValue: CGPoint, to toValue: CGPoint, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
switch self.animation {
|
switch self.animation {
|
||||||
case .none:
|
case .none:
|
||||||
@ -609,6 +636,25 @@ public struct Transition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func animateBoundsSize(layer: CALayer, from fromValue: CGSize, to toValue: CGSize, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
|
switch self.animation {
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
case let .curve(duration, curve):
|
||||||
|
layer.animate(
|
||||||
|
from: NSValue(cgSize: fromValue),
|
||||||
|
to: NSValue(cgSize: toValue),
|
||||||
|
keyPath: "bounds.size",
|
||||||
|
duration: duration,
|
||||||
|
delay: 0.0,
|
||||||
|
curve: curve,
|
||||||
|
removeOnCompletion: true,
|
||||||
|
additive: additive,
|
||||||
|
completion: completion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func setCornerRadius(layer: CALayer, cornerRadius: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
public func setCornerRadius(layer: CALayer, cornerRadius: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
||||||
if layer.cornerRadius == cornerRadius {
|
if layer.cornerRadius == cornerRadius {
|
||||||
return
|
return
|
||||||
|
@ -44,13 +44,16 @@ public final class PagerComponentChildEnvironment: Equatable {
|
|||||||
|
|
||||||
public let containerInsets: UIEdgeInsets
|
public let containerInsets: UIEdgeInsets
|
||||||
public let onChildScrollingUpdate: (ContentScrollingUpdate) -> Void
|
public let onChildScrollingUpdate: (ContentScrollingUpdate) -> Void
|
||||||
|
public let onWantsExclusiveModeUpdated: (Bool) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
containerInsets: UIEdgeInsets,
|
containerInsets: UIEdgeInsets,
|
||||||
onChildScrollingUpdate: @escaping (ContentScrollingUpdate) -> Void
|
onChildScrollingUpdate: @escaping (ContentScrollingUpdate) -> Void,
|
||||||
|
onWantsExclusiveModeUpdated: @escaping (Bool) -> Void
|
||||||
) {
|
) {
|
||||||
self.containerInsets = containerInsets
|
self.containerInsets = containerInsets
|
||||||
self.onChildScrollingUpdate = onChildScrollingUpdate
|
self.onChildScrollingUpdate = onChildScrollingUpdate
|
||||||
|
self.onWantsExclusiveModeUpdated = onWantsExclusiveModeUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: PagerComponentChildEnvironment, rhs: PagerComponentChildEnvironment) -> Bool {
|
public static func ==(lhs: PagerComponentChildEnvironment, rhs: PagerComponentChildEnvironment) -> Bool {
|
||||||
@ -180,6 +183,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
public let bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?
|
public let bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?
|
||||||
public let panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?
|
public let panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?
|
||||||
public let isTopPanelExpandedUpdated: (Bool, Transition) -> Void
|
public let isTopPanelExpandedUpdated: (Bool, Transition) -> Void
|
||||||
|
public let isTopPanelHiddenUpdated: (Bool, Transition) -> Void
|
||||||
public let panelHideBehavior: PagerComponentPanelHideBehavior
|
public let panelHideBehavior: PagerComponentPanelHideBehavior
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
@ -196,6 +200,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?,
|
bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?,
|
||||||
panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?,
|
panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?,
|
||||||
isTopPanelExpandedUpdated: @escaping (Bool, Transition) -> Void,
|
isTopPanelExpandedUpdated: @escaping (Bool, Transition) -> Void,
|
||||||
|
isTopPanelHiddenUpdated: @escaping (Bool, Transition) -> Void,
|
||||||
panelHideBehavior: PagerComponentPanelHideBehavior
|
panelHideBehavior: PagerComponentPanelHideBehavior
|
||||||
) {
|
) {
|
||||||
self.contentInsets = contentInsets
|
self.contentInsets = contentInsets
|
||||||
@ -211,6 +216,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
self.bottomPanel = bottomPanel
|
self.bottomPanel = bottomPanel
|
||||||
self.panelStateUpdated = panelStateUpdated
|
self.panelStateUpdated = panelStateUpdated
|
||||||
self.isTopPanelExpandedUpdated = isTopPanelExpandedUpdated
|
self.isTopPanelExpandedUpdated = isTopPanelExpandedUpdated
|
||||||
|
self.isTopPanelHiddenUpdated = isTopPanelHiddenUpdated
|
||||||
self.panelHideBehavior = panelHideBehavior
|
self.panelHideBehavior = panelHideBehavior
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +261,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
var scrollingPanelOffsetToTopEdge: CGFloat = 0.0
|
var scrollingPanelOffsetToTopEdge: CGFloat = 0.0
|
||||||
var scrollingPanelOffsetToBottomEdge: CGFloat = .greatestFiniteMagnitude
|
var scrollingPanelOffsetToBottomEdge: CGFloat = .greatestFiniteMagnitude
|
||||||
var scrollingPanelOffsetFraction: CGFloat = 0.0
|
var scrollingPanelOffsetFraction: CGFloat = 0.0
|
||||||
|
var wantsExclusiveMode: Bool = false
|
||||||
|
|
||||||
init(view: ComponentHostView<(ChildEnvironmentType, PagerComponentChildEnvironment)>) {
|
init(view: ComponentHostView<(ChildEnvironmentType, PagerComponentChildEnvironment)>) {
|
||||||
self.view = view
|
self.view = view
|
||||||
@ -431,9 +438,12 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
|
|
||||||
var contentInsets = component.contentInsets
|
var contentInsets = component.contentInsets
|
||||||
contentInsets.bottom = 0.0
|
contentInsets.bottom = 0.0
|
||||||
|
var contentInsetTopPanelValue: CGFloat = 0.0
|
||||||
|
|
||||||
var scrollingPanelOffsetFraction: CGFloat
|
var scrollingPanelOffsetFraction: CGFloat
|
||||||
if case .show = component.panelHideBehavior {
|
if let centralId = centralId, let centralContentView = self.contentViews[centralId], centralContentView.wantsExclusiveMode {
|
||||||
|
scrollingPanelOffsetFraction = 1.0
|
||||||
|
} else if case .show = component.panelHideBehavior {
|
||||||
scrollingPanelOffsetFraction = 0.0
|
scrollingPanelOffsetFraction = 0.0
|
||||||
} else if let centralId = centralId, let centralContentView = self.contentViews[centralId] {
|
} else if let centralId = centralId, let centralContentView = self.contentViews[centralId] {
|
||||||
scrollingPanelOffsetFraction = centralContentView.scrollingPanelOffsetFraction
|
scrollingPanelOffsetFraction = centralContentView.scrollingPanelOffsetFraction
|
||||||
@ -514,6 +524,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
panelStateTransition.setFrame(view: topPanelView, frame: CGRect(origin: CGPoint(x: 0.0, y: -topPanelOffset), size: topPanelSize))
|
panelStateTransition.setFrame(view: topPanelView, frame: CGRect(origin: CGPoint(x: 0.0, y: -topPanelOffset), size: topPanelSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentInsetTopPanelValue = topPanelSize.height
|
||||||
contentInsets.top += topPanelSize.height
|
contentInsets.top += topPanelSize.height
|
||||||
} else {
|
} else {
|
||||||
if let topPanelView = self.topPanelView {
|
if let topPanelView = self.topPanelView {
|
||||||
@ -668,13 +679,25 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let childContentInsets = contentInsets
|
||||||
|
if contentView.wantsExclusiveMode {
|
||||||
|
let _ = contentInsetTopPanelValue
|
||||||
|
//childContentInsets.top -= contentInsetTopPanelValue
|
||||||
|
}
|
||||||
|
|
||||||
let pagerChildEnvironment = PagerComponentChildEnvironment(
|
let pagerChildEnvironment = PagerComponentChildEnvironment(
|
||||||
containerInsets: contentInsets,
|
containerInsets: childContentInsets,
|
||||||
onChildScrollingUpdate: { [weak self] update in
|
onChildScrollingUpdate: { [weak self] update in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.onChildScrollingUpdate(id: id, update: update)
|
strongSelf.onChildScrollingUpdate(id: id, update: update)
|
||||||
|
},
|
||||||
|
onWantsExclusiveModeUpdated: { [weak self] wantsExclusiveMode in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.onChildWantsExclusiveModeUpdated(id: id, wantsExclusiveMode: wantsExclusiveMode)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -810,6 +833,18 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func onChildWantsExclusiveModeUpdated(id: AnyHashable, wantsExclusiveMode: Bool) {
|
||||||
|
guard let contentView = self.contentViews[id] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if contentView.wantsExclusiveMode != wantsExclusiveMode {
|
||||||
|
contentView.wantsExclusiveMode = wantsExclusiveMode
|
||||||
|
//self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||||
|
self.component?.isTopPanelHiddenUpdated(wantsExclusiveMode, Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func isTopPanelExpandedUpdated(isExpanded: Bool, transition: Transition) {
|
private func isTopPanelExpandedUpdated(isExpanded: Bool, transition: Transition) {
|
||||||
if self.isTopPanelExpanded == isExpanded {
|
if self.isTopPanelExpanded == isExpanded {
|
||||||
return
|
return
|
||||||
|
@ -650,7 +650,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if case let .user(user) = peer, let emojiStatus = user.emojiStatus {
|
} else if case let .user(user) = peer, let emojiStatus = user.emojiStatus {
|
||||||
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
|
||||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
|
@ -1473,41 +1473,10 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) {
|
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) {
|
||||||
if let presentationNode = self.presentationNode {
|
if let presentationNode = self.presentationNode {
|
||||||
presentationNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, completion: completion)
|
presentationNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: completion)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let reactionContextNode = self.reactionContextNode else {
|
|
||||||
self.animateOut(result: .default, completion: completion)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var contentCompleted = false
|
|
||||||
var reactionCompleted = false
|
|
||||||
let intermediateCompletion: () -> Void = {
|
|
||||||
if contentCompleted && reactionCompleted {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.reactionContextNodeIsAnimatingOut = true
|
|
||||||
reactionContextNode.willAnimateOutToReaction(value: value)
|
|
||||||
reactionContextNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, completion: { [weak self] in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
strongSelf.reactionContextNode?.removeFromSupernode()
|
|
||||||
strongSelf.reactionContextNode = nil
|
|
||||||
reactionCompleted = true
|
|
||||||
intermediateCompletion()
|
|
||||||
})
|
|
||||||
self.animateOut(result: .default, completion: {
|
|
||||||
contentCompleted = true
|
|
||||||
intermediateCompletion()
|
|
||||||
})
|
|
||||||
|
|
||||||
self.isUserInteractionEnabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2521,6 +2490,8 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
|
|
||||||
private var animatedDidAppear = false
|
private var animatedDidAppear = false
|
||||||
private var wasDismissed = false
|
private var wasDismissed = false
|
||||||
|
private var dismissOnInputClose: (result: ContextMenuActionResult, completion: (() -> Void)?)?
|
||||||
|
private var dismissToReactionOnInputClose: (value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: (() -> Void)?)?
|
||||||
|
|
||||||
override public var overlayWantsToBeBelowKeyboard: Bool {
|
override public var overlayWantsToBeBelowKeyboard: Bool {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
@ -2669,6 +2640,20 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
self.controllerNode.updateLayout(layout: layout, transition: transition, previousActionsContainerNode: nil)
|
self.controllerNode.updateLayout(layout: layout, transition: transition, previousActionsContainerNode: nil)
|
||||||
|
|
||||||
|
if (layout.inputHeight ?? 0.0) == 0.0 {
|
||||||
|
if let dismissOnInputClose = self.dismissOnInputClose {
|
||||||
|
self.dismissOnInputClose = nil
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.dismiss(result: dismissOnInputClose.result, completion: dismissOnInputClose.completion)
|
||||||
|
}
|
||||||
|
} else if let args = self.dismissToReactionOnInputClose {
|
||||||
|
self.dismissToReactionOnInputClose = nil
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.dismissWithReactionImpl(value: args.value, targetView: args.targetView, hideNode: args.hideNode, animateTargetContainer: args.animateTargetContainer, addStandaloneReactionAnimation: args.addStandaloneReactionAnimation, reducedCurve: true, completion: args.completion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
@ -2727,8 +2712,15 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func dismiss(result: ContextMenuActionResult, completion: (() -> Void)?) {
|
private func dismiss(result: ContextMenuActionResult, completion: (() -> Void)?) {
|
||||||
|
if viewTreeContainsFirstResponder(view: self.view) {
|
||||||
|
self.dismissOnInputClose = (result, completion)
|
||||||
|
self.view.endEditing(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !self.wasDismissed {
|
if !self.wasDismissed {
|
||||||
self.wasDismissed = true
|
self.wasDismissed = true
|
||||||
|
|
||||||
self.controllerNode.animateOut(result: result, completion: { [weak self] in
|
self.controllerNode.animateOut(result: result, completion: { [weak self] in
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
completion?()
|
completion?()
|
||||||
@ -2751,9 +2743,19 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func dismissWithReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: (() -> Void)?) {
|
public func dismissWithReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: (() -> Void)?) {
|
||||||
|
self.dismissWithReactionImpl(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: false, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismissWithReactionImpl(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: (() -> Void)?) {
|
||||||
|
if viewTreeContainsFirstResponder(view: self.view) {
|
||||||
|
self.dismissToReactionOnInputClose = (value, targetView, hideNode, animateTargetContainer, addStandaloneReactionAnimation, completion)
|
||||||
|
self.view.endEditing(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !self.wasDismissed {
|
if !self.wasDismissed {
|
||||||
self.wasDismissed = true
|
self.wasDismissed = true
|
||||||
self.controllerNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, completion: { [weak self] in
|
self.controllerNode.animateOutToReaction(value: value, targetView: targetView, hideNode: hideNode, animateTargetContainer: animateTargetContainer, addStandaloneReactionAnimation: addStandaloneReactionAnimation, reducedCurve: reducedCurve, completion: { [weak self] in
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
completion?()
|
completion?()
|
||||||
})
|
})
|
||||||
|
@ -720,7 +720,15 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
reactionContextNodeTransition = .immediate
|
reactionContextNodeTransition = .immediate
|
||||||
}
|
}
|
||||||
reactionContextNodeTransition.updateFrame(node: reactionContextNode, frame: CGRect(origin: CGPoint(), size: layout.size), beginWithCurrentState: true)
|
reactionContextNodeTransition.updateFrame(node: reactionContextNode, frame: CGRect(origin: CGPoint(), size: layout.size), beginWithCurrentState: true)
|
||||||
reactionContextNode.updateLayout(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right), anchorRect: contentRect.offsetBy(dx: contentParentGlobalFrame.minX, dy: 0.0), isAnimatingOut: isAnimatingOut, transition: reactionContextNodeTransition)
|
|
||||||
|
var reactionAnchorRect = contentRect.offsetBy(dx: contentParentGlobalFrame.minX, dy: 0.0)
|
||||||
|
|
||||||
|
let bottomInset = layout.insets(options: [.input]).bottom
|
||||||
|
if reactionAnchorRect.minY > layout.size.height - bottomInset {
|
||||||
|
reactionAnchorRect.origin.y = layout.size.height - bottomInset
|
||||||
|
}
|
||||||
|
|
||||||
|
reactionContextNode.updateLayout(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right), anchorRect: reactionAnchorRect, isAnimatingOut: isAnimatingOut, transition: reactionContextNodeTransition)
|
||||||
|
|
||||||
self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - 46.0
|
self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - 46.0
|
||||||
} else {
|
} else {
|
||||||
@ -1145,7 +1153,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) {
|
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void) {
|
||||||
guard let reactionContextNode = self.reactionContextNode else {
|
guard let reactionContextNode = self.reactionContextNode else {
|
||||||
self.requestAnimateOut(.default, completion)
|
self.requestAnimateOut(.default, completion)
|
||||||
return
|
return
|
||||||
@ -1162,7 +1170,14 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
self.reactionContextNodeIsAnimatingOut = true
|
self.reactionContextNodeIsAnimatingOut = true
|
||||||
reactionContextNode.willAnimateOutToReaction(value: value)
|
reactionContextNode.willAnimateOutToReaction(value: value)
|
||||||
|
|
||||||
self.requestAnimateOut(.default, {
|
let result: ContextMenuActionResult
|
||||||
|
if reducedCurve {
|
||||||
|
result = .custom(.animated(duration: 0.5, curve: .spring))
|
||||||
|
} else {
|
||||||
|
result = .default
|
||||||
|
}
|
||||||
|
|
||||||
|
self.requestAnimateOut(result, {
|
||||||
contentCompleted = true
|
contentCompleted = true
|
||||||
intermediateCompletion()
|
intermediateCompletion()
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@ protocol ContextControllerPresentationNode: ASDisplayNode {
|
|||||||
stateTransition: ContextControllerPresentationNodeStateTransition?
|
stateTransition: ContextControllerPresentationNodeStateTransition?
|
||||||
)
|
)
|
||||||
|
|
||||||
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void)
|
func animateOutToReaction(value: MessageReaction.Reaction, targetView: UIView, hideNode: Bool, animateTargetContainer: UIView?, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, reducedCurve: Bool, completion: @escaping () -> Void)
|
||||||
func cancelReactionAnimation()
|
func cancelReactionAnimation()
|
||||||
|
|
||||||
func highlightGestureMoved(location: CGPoint, hover: Bool)
|
func highlightGestureMoved(location: CGPoint, hover: Bool)
|
||||||
|
@ -408,6 +408,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
} else {
|
} else {
|
||||||
if let statusBarHost = self.statusBarHost, let keyboardWindow = statusBarHost.keyboardWindow, let keyboardView = statusBarHost.keyboardView, !keyboardView.frame.height.isZero, isViewVisibleInHierarchy(keyboardView) {
|
if let statusBarHost = self.statusBarHost, let keyboardWindow = statusBarHost.keyboardWindow, let keyboardView = statusBarHost.keyboardView, !keyboardView.frame.height.isZero, isViewVisibleInHierarchy(keyboardView) {
|
||||||
if globalOverlayContainerParent.view.superview != keyboardWindow {
|
if globalOverlayContainerParent.view.superview != keyboardWindow {
|
||||||
|
globalOverlayContainerParent.layer.zPosition = 1000.0
|
||||||
keyboardWindow.addSubnode(globalOverlayContainerParent)
|
keyboardWindow.addSubnode(globalOverlayContainerParent)
|
||||||
}
|
}
|
||||||
} else if globalOverlayContainerParent.view.superview !== self.displayNode.view {
|
} else if globalOverlayContainerParent.view.superview !== self.displayNode.view {
|
||||||
|
@ -648,7 +648,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
} else if case let .user(user) = item.peer, let emojiStatus = user.emojiStatus {
|
} else if case let .user(user) = item.peer, let emojiStatus = user.emojiStatus {
|
||||||
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
||||||
} else if item.peer.isVerified {
|
} else if item.peer.isVerified {
|
||||||
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
|
||||||
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
|
@ -234,6 +234,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation?
|
private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation?
|
||||||
private var emojiContentDisposable: Disposable?
|
private var emojiContentDisposable: Disposable?
|
||||||
|
|
||||||
|
private let emojiSearchDisposable = MetaDisposable()
|
||||||
|
private let emojiSearchResult = Promise<(groups: [EmojiPagerContentComponent.ItemGroup], id: AnyHashable)?>(nil)
|
||||||
|
|
||||||
private var horizontalExpandRecognizer: UIPanGestureRecognizer?
|
private var horizontalExpandRecognizer: UIPanGestureRecognizer?
|
||||||
private var horizontalExpandStartLocation: CGPoint?
|
private var horizontalExpandStartLocation: CGPoint?
|
||||||
private var horizontalExpandDistance: CGFloat = 0.0
|
private var horizontalExpandDistance: CGFloat = 0.0
|
||||||
@ -249,6 +252,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private var genericReactionEffectDisposable: Disposable?
|
private var genericReactionEffectDisposable: Disposable?
|
||||||
private var genericReactionEffect: String?
|
private var genericReactionEffect: String?
|
||||||
|
|
||||||
|
private var isReactionSearchActive: Bool = false
|
||||||
|
|
||||||
public static func randomGenericReactionEffect(context: AccountContext) -> Signal<String?, NoError> {
|
public static func randomGenericReactionEffect(context: AccountContext) -> Signal<String?, NoError> {
|
||||||
return context.engine.stickers.loadedStickerPack(reference: .emojiGenericAnimations, forceActualized: false)
|
return context.engine.stickers.loadedStickerPack(reference: .emojiGenericAnimations, forceActualized: false)
|
||||||
|> map { result -> [TelegramMediaFile]? in
|
|> map { result -> [TelegramMediaFile]? in
|
||||||
@ -404,12 +409,19 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if let getEmojiContent = getEmojiContent {
|
if let getEmojiContent = getEmojiContent {
|
||||||
self.emojiContentDisposable = (getEmojiContent(self.animationCache, self.animationRenderer)
|
self.emojiContentDisposable = combineLatest(queue: .mainQueue(),
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] emojiContent in
|
getEmojiContent(self.animationCache, self.animationRenderer),
|
||||||
|
self.emojiSearchResult.get()
|
||||||
|
).start(next: { [weak self] emojiContent, emojiSearchResult in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var emojiContent = emojiContent
|
||||||
|
if let emojiSearchResult = emojiSearchResult {
|
||||||
|
emojiContent = emojiContent.withUpdatedItemGroups(itemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id)
|
||||||
|
}
|
||||||
|
|
||||||
strongSelf.emojiContent = emojiContent
|
strongSelf.emojiContent = emojiContent
|
||||||
if !strongSelf.canBeExpanded {
|
if !strongSelf.canBeExpanded {
|
||||||
strongSelf.canBeExpanded = true
|
strongSelf.canBeExpanded = true
|
||||||
@ -436,7 +448,15 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
deviceMetrics: DeviceMetrics.iPhone13,
|
deviceMetrics: DeviceMetrics.iPhone13,
|
||||||
emojiContent: emojiContent,
|
emojiContent: emojiContent,
|
||||||
backgroundColor: .clear,
|
backgroundColor: .clear,
|
||||||
separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5)
|
separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5),
|
||||||
|
hideTopPanel: strongSelf.isReactionSearchActive,
|
||||||
|
hideTopPanelUpdated: { hideTopPanel, transition in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.isReactionSearchActive = hideTopPanel
|
||||||
|
strongSelf.requestLayout(transition.containedViewLayoutTransition)
|
||||||
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: componentView.bounds.width, height: 300.0)
|
containerSize: CGSize(width: componentView.bounds.width, height: 300.0)
|
||||||
@ -456,6 +476,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.availableReactionsDisposable?.dispose()
|
self.availableReactionsDisposable?.dispose()
|
||||||
self.hasPremiumDisposable?.dispose()
|
self.hasPremiumDisposable?.dispose()
|
||||||
self.genericReactionEffectDisposable?.dispose()
|
self.genericReactionEffectDisposable?.dispose()
|
||||||
|
self.emojiSearchDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func didLoad() {
|
override public func didLoad() {
|
||||||
@ -830,7 +851,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
expandItemSize = 30.0
|
expandItemSize = 30.0
|
||||||
expandTintOffset = 0.0
|
expandTintOffset = 0.0
|
||||||
}
|
}
|
||||||
let baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0) + (self.isExpanded ? (46.0 + 54.0 - 4.0) : 0.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance))
|
let baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0) + (self.isExpanded ? (46.0) : 0.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance))
|
||||||
|
|
||||||
transition.updateFrame(view: expandItemView, frame: baseNextFrame)
|
transition.updateFrame(view: expandItemView, frame: baseNextFrame)
|
||||||
transition.updateFrame(view: expandItemView.tintView, frame: baseNextFrame.offsetBy(dx: 0.0, dy: expandTintOffset))
|
transition.updateFrame(view: expandItemView.tintView, frame: baseNextFrame.offsetBy(dx: 0.0, dy: expandTintOffset))
|
||||||
@ -931,7 +952,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
visibleItemCount: itemCount
|
visibleItemCount: itemCount
|
||||||
)
|
)
|
||||||
|
|
||||||
var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.isExpanded ? (46.0 + 54.0 - 4.0) : 0.0), size: actualBackgroundFrame.size)
|
var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.isExpanded ? (46.0) : 0.0), size: actualBackgroundFrame.size)
|
||||||
scrollFrame.origin.y += floorToScreenPixels(self.extensionDistance / 2.0)
|
scrollFrame.origin.y += floorToScreenPixels(self.extensionDistance / 2.0)
|
||||||
|
|
||||||
transition.updateFrame(node: self.contentContainer, frame: visualBackgroundFrame, beginWithCurrentState: true)
|
transition.updateFrame(node: self.contentContainer, frame: visualBackgroundFrame, beginWithCurrentState: true)
|
||||||
@ -978,7 +999,15 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
deviceMetrics: DeviceMetrics.iPhone13,
|
deviceMetrics: DeviceMetrics.iPhone13,
|
||||||
emojiContent: emojiContent,
|
emojiContent: emojiContent,
|
||||||
backgroundColor: .clear,
|
backgroundColor: .clear,
|
||||||
separatorColor: self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5)
|
separatorColor: self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5),
|
||||||
|
hideTopPanel: self.isReactionSearchActive,
|
||||||
|
hideTopPanelUpdated: { [weak self] hideTopPanel, transition in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.isReactionSearchActive = hideTopPanel
|
||||||
|
strongSelf.requestLayout(transition.containedViewLayoutTransition)
|
||||||
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: actualBackgroundFrame.width, height: 300.0)
|
containerSize: CGSize(width: actualBackgroundFrame.width, height: 300.0)
|
||||||
@ -1023,7 +1052,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
if let mirrorContentClippingView = emojiView.mirrorContentClippingView {
|
if let mirrorContentClippingView = emojiView.mirrorContentClippingView {
|
||||||
mirrorContentClippingView.clipsToBounds = false
|
mirrorContentClippingView.clipsToBounds = false
|
||||||
Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: 46.0 + 54.0 - 4.0), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in
|
Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: 46.0), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in
|
||||||
mirrorContentClippingView?.clipsToBounds = true
|
mirrorContentClippingView?.clipsToBounds = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1053,7 +1082,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
componentTransition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
componentTransition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
||||||
|
|
||||||
if animateIn {
|
if animateIn {
|
||||||
transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -(46.0 + 54.0 - 4.0) + floorToScreenPixels(self.animateFromExtensionDistance / 2.0)))
|
transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -(46.0) + floorToScreenPixels(self.animateFromExtensionDistance / 2.0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,7 +1276,116 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
strongSelf.requestUpdateOverlayWantsToBeBelowKeyboard(transition.containedViewLayoutTransition)
|
strongSelf.requestUpdateOverlayWantsToBeBelowKeyboard(transition.containedViewLayoutTransition)
|
||||||
},
|
},
|
||||||
sendSticker: nil,
|
updateSearchQuery: { [weak self] query in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.isEmpty {
|
||||||
|
strongSelf.emojiSearchDisposable.set(nil)
|
||||||
|
strongSelf.emojiSearchResult.set(.single(nil))
|
||||||
|
} else {
|
||||||
|
let context = strongSelf.context
|
||||||
|
|
||||||
|
let languageCode = "en"
|
||||||
|
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query, completeMatch: query.count < 2)
|
||||||
|
if !languageCode.lowercased().hasPrefix("en") {
|
||||||
|
signal = signal
|
||||||
|
|> mapToSignal { keywords in
|
||||||
|
return .single(keywords)
|
||||||
|
|> then(
|
||||||
|
context.engine.stickers.searchEmojiKeywords(inputLanguageCode: "en-US", query: query, completeMatch: query.count < 3)
|
||||||
|
|> map { englishKeywords in
|
||||||
|
return keywords + englishKeywords
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|
|> map { peer -> Bool in
|
||||||
|
guard case let .user(user) = peer else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return user.isPremium
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
let resultSignal = signal
|
||||||
|
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||||
|
return combineLatest(
|
||||||
|
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000),
|
||||||
|
hasPremium
|
||||||
|
)
|
||||||
|
|> map { view, hasPremium -> [EmojiPagerContentComponent.ItemGroup] in
|
||||||
|
var result: [(String, TelegramMediaFile?, String)] = []
|
||||||
|
|
||||||
|
var allEmoticons: [String: String] = [:]
|
||||||
|
for keyword in keywords {
|
||||||
|
for emoticon in keyword.emoticons {
|
||||||
|
allEmoticons[emoticon] = keyword.keyword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in view.entries {
|
||||||
|
guard let item = entry.item as? StickerPackItem else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for attribute in item.file.attributes {
|
||||||
|
switch attribute {
|
||||||
|
case let .CustomEmoji(_, alt, _):
|
||||||
|
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||||
|
if !item.file.isPremiumEmoji || hasPremium {
|
||||||
|
result.append((alt, item.file, keyword))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for keyword in keywords {
|
||||||
|
for emoticon in keyword.emoticons {
|
||||||
|
result.append((emoticon, nil, keyword.keyword))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var items: [EmojiPagerContentComponent.Item] = []
|
||||||
|
|
||||||
|
var existingIds = Set<MediaId>()
|
||||||
|
for item in result {
|
||||||
|
if let itemFile = item.1 {
|
||||||
|
if existingIds.contains(itemFile.fileId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existingIds.insert(itemFile.fileId)
|
||||||
|
let animationData = EntityKeyboardAnimationData(file: itemFile)
|
||||||
|
let item = EmojiPagerContentComponent.Item(
|
||||||
|
animationData: animationData,
|
||||||
|
content: .animation(animationData),
|
||||||
|
itemFile: itemFile, subgroupId: nil,
|
||||||
|
icon: .none,
|
||||||
|
accentTint: false
|
||||||
|
)
|
||||||
|
items.append(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [EmojiPagerContentComponent.ItemGroup(
|
||||||
|
supergroupId: "search", groupId: "search", title: nil, subtitle: nil, actionButtonTitle: nil, isFeatured: false, isPremiumLocked: false, isEmbedded: false, hasClear: false, collapsedLineCount: nil, displayPremiumBadges: false, headerItem: nil, items: items)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.emojiSearchDisposable.set((resultSignal
|
||||||
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.emojiSearchResult.set(.single((result, AnyHashable(query))))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
chatPeerId: nil,
|
chatPeerId: nil,
|
||||||
peekBehavior: nil,
|
peekBehavior: nil,
|
||||||
customLayout: emojiContentLayout,
|
customLayout: emojiContentLayout,
|
||||||
|
@ -843,7 +843,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if let user = item.peer as? TelegramUser, let emojiStatus = user.emojiStatus {
|
} else if let user = item.peer as? TelegramUser, let emojiStatus = user.emojiStatus {
|
||||||
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
credibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
||||||
} else if item.peer.isVerified {
|
} else if item.peer.isVerified {
|
||||||
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
credibilityIcon = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
|
||||||
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||||
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
credibilityIcon = .premium(color: item.presentationData.theme.list.itemAccentColor)
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,7 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M
|
|||||||
for user in apiUsers {
|
for user in apiUsers {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
if telegramUser.id == peerId, let accessHash = telegramUser.accessHash, accessHash.value != 0 {
|
if telegramUser.id == peerId, let accessHash = telegramUser.accessHash, accessHash.value != 0 {
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: [telegramUser.id: user])
|
||||||
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: [telegramUser.id: presence])
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in
|
updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in
|
||||||
return updated
|
return updated
|
||||||
|
@ -3170,7 +3170,7 @@ func replayFinalState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences)
|
updatePeerPresencesClean(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences)
|
||||||
case let .UpdateSecretChat(chat, _):
|
case let .UpdateSecretChat(chat, _):
|
||||||
updateSecretChat(encryptionProvider: encryptionProvider, accountPeerId: accountPeerId, transaction: transaction, mediaBox: mediaBox, chat: chat, requestData: nil)
|
updateSecretChat(encryptionProvider: encryptionProvider, accountPeerId: accountPeerId, transaction: transaction, mediaBox: mediaBox, chat: chat, requestData: nil)
|
||||||
case let .AddSecretMessages(messages):
|
case let .AddSecretMessages(messages):
|
||||||
|
@ -105,7 +105,7 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal<Void
|
|||||||
|
|
||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) {
|
if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -114,9 +114,7 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal<Void
|
|||||||
for apiUser in users {
|
for apiUser in users {
|
||||||
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
||||||
peers.append(user)
|
peers.append(user)
|
||||||
if let presence = TelegramUserPresence(apiUser: apiUser) {
|
peerPresences[user.id] = apiUser
|
||||||
peerPresences[user.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,16 +694,14 @@ public final class AccountViewTracker {
|
|||||||
|
|
||||||
return account.postbox.transaction { transaction -> [MessageId: ViewCountContextState] in
|
return account.postbox.transaction { transaction -> [MessageId: ViewCountContextState] in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
var resultStates: [MessageId: ViewCountContextState] = [:]
|
var resultStates: [MessageId: ViewCountContextState] = [:]
|
||||||
|
|
||||||
for apiUser in users {
|
for apiUser in users {
|
||||||
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
||||||
peers.append(user)
|
peers.append(user)
|
||||||
if let presence = TelegramUserPresence(apiUser: apiUser) {
|
peerPresences[user.id] = apiUser
|
||||||
peerPresences[user.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
@ -1086,7 +1082,7 @@ public final class AccountViewTracker {
|
|||||||
|> mapToSignal { messages, chats, users -> Signal<Void, NoError> in
|
|> mapToSignal { messages, chats, users -> Signal<Void, NoError> in
|
||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) {
|
if let groupOrChannel = mergeGroupOrChannel(lhs: transaction.getPeer(chat.peerId), rhs: chat) {
|
||||||
@ -1096,9 +1092,7 @@ public final class AccountViewTracker {
|
|||||||
for apiUser in users {
|
for apiUser in users {
|
||||||
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
if let user = TelegramUser.merge(transaction.getPeer(apiUser.peerId) as? TelegramUser, rhs: apiUser) {
|
||||||
peers.append(user)
|
peers.append(user)
|
||||||
if let presence = TelegramUserPresence(apiUser: apiUser) {
|
peerPresences[user.id] = apiUser
|
||||||
peerPresences[user.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ private func updateContactPresences(postbox: Postbox, network: Network, accountP
|
|||||||
peerPresences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))] = TelegramUserPresence(apiStatus: status)
|
peerPresences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))] = TelegramUserPresence(apiStatus: status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
updatePeerPresencesClean(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ enum FetchChatListLocation {
|
|||||||
struct ParsedDialogs {
|
struct ParsedDialogs {
|
||||||
let itemIds: [PeerId]
|
let itemIds: [PeerId]
|
||||||
let peers: [Peer]
|
let peers: [Peer]
|
||||||
let peerPresences: [PeerId: PeerPresence]
|
let peerPresences: [PeerId: Api.User]
|
||||||
|
|
||||||
let notificationSettings: [PeerId: PeerNotificationSettings]
|
let notificationSettings: [PeerId: PeerNotificationSettings]
|
||||||
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
|
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
|
||||||
@ -61,7 +61,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
var itemIds: [PeerId] = []
|
var itemIds: [PeerId] = []
|
||||||
|
|
||||||
var peers: [PeerId: Peer] = [:]
|
var peers: [PeerId: Peer] = [:]
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in apiChats {
|
for chat in apiChats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers[groupOrChannel.id] = groupOrChannel
|
peers[groupOrChannel.id] = groupOrChannel
|
||||||
@ -70,9 +70,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
for user in apiUsers {
|
for user in apiUsers {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers[telegramUser.id] = telegramUser
|
peers[telegramUser.id] = telegramUser
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for dialog in apiDialogs {
|
for dialog in apiDialogs {
|
||||||
@ -191,7 +189,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
|
|||||||
struct FetchedChatList {
|
struct FetchedChatList {
|
||||||
let chatPeerIds: [PeerId]
|
let chatPeerIds: [PeerId]
|
||||||
let peers: [Peer]
|
let peers: [Peer]
|
||||||
let peerPresences: [PeerId: PeerPresence]
|
let peerPresences: [PeerId: Api.User]
|
||||||
let notificationSettings: [PeerId: PeerNotificationSettings]
|
let notificationSettings: [PeerId: PeerNotificationSettings]
|
||||||
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
|
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
|
||||||
let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary]
|
let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary]
|
||||||
@ -297,7 +295,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
|||||||
return combineLatest(folderSignals)
|
return combineLatest(folderSignals)
|
||||||
|> mapToSignal { folders -> Signal<FetchedChatList?, NoError> in
|
|> mapToSignal { folders -> Signal<FetchedChatList?, NoError> in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
|
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
|
||||||
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
|
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
|
||||||
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
|
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
|
||||||
|
@ -566,7 +566,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -575,9 +575,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var storeMessages: [StoreMessage] = []
|
var storeMessages: [StoreMessage] = []
|
||||||
@ -838,7 +836,7 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId
|
|||||||
transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages)
|
transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages)
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -847,9 +845,7 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId
|
|||||||
for user in users {
|
for user in users {
|
||||||
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
|
|||||||
var remoteItemIds: [PinnedItemId] = []
|
var remoteItemIds: [PinnedItemId] = []
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
switch dialogs {
|
switch dialogs {
|
||||||
case let .peerDialogs(dialogs, messages, chats, users, _):
|
case let .peerDialogs(dialogs, messages, chats, users, _):
|
||||||
@ -148,9 +148,7 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loop: for dialog in dialogs {
|
loop: for dialog in dialogs {
|
||||||
|
@ -480,14 +480,12 @@ public final class EngineMessageReactionListContext {
|
|||||||
switch result {
|
switch result {
|
||||||
case let .messageReactionsList(_, count, reactions, chats, users, nextOffset):
|
case let .messageReactionsList(_, count, reactions, chats, users, nextOffset):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
|
@ -97,14 +97,12 @@ func _internal_getCurrentGroupCall(account: Account, callId: Int64, accessHash:
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
@ -383,14 +381,12 @@ func _internal_getGroupCallParticipants(account: Account, callId: Int64, accessH
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
@ -596,14 +592,12 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?,
|
|||||||
state.adminIds = Set(peerAdminIds)
|
state.adminIds = Set(peerAdminIds)
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for user in apiUsers {
|
for user in apiUsers {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let connectionMode: JoinGroupCallResult.ConnectionMode
|
let connectionMode: JoinGroupCallResult.ConnectionMode
|
||||||
|
@ -73,7 +73,7 @@ func syncContactsOnce(network: Network, postbox: Postbox, accountPeerId: PeerId)
|
|||||||
|
|
||||||
transaction.replaceRemoteContactCount(totalCount)
|
transaction.replaceRemoteContactCount(totalCount)
|
||||||
|
|
||||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
updatePeerPresencesClean(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||||
|
|
||||||
if wasEmpty {
|
if wasEmpty {
|
||||||
var insertSignal: Signal<Void, NoError> = .complete()
|
var insertSignal: Signal<Void, NoError> = .complete()
|
||||||
|
@ -400,7 +400,7 @@ private class AdMessagesHistoryContextImpl {
|
|||||||
switch result {
|
switch result {
|
||||||
case let .sponsoredMessages(messages, chats, users):
|
case let .sponsoredMessages(messages, chats, users):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
@ -410,9 +410,7 @@ private class AdMessagesHistoryContextImpl {
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
@ -13,7 +13,7 @@ func _internal_clearCloudDraftsInteractively(postbox: Postbox, network: Network,
|
|||||||
switch updates {
|
switch updates {
|
||||||
case let .updates(updates, users, chats, _, _):
|
case let .updates(updates, users, chats, _, _):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -22,9 +22,7 @@ func _internal_clearCloudDraftsInteractively(postbox: Postbox, network: Network,
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for update in updates {
|
for update in updates {
|
||||||
switch update {
|
switch update {
|
||||||
|
@ -94,7 +94,7 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -103,9 +103,7 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
@ -171,7 +171,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
@ -181,9 +181,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = transaction.addMessages(parsedMessages, location: .Random)
|
let _ = transaction.addMessages(parsedMessages, location: .Random)
|
||||||
@ -608,7 +606,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
@ -618,9 +616,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = transaction.addMessages(parsedMessages, location: .Random)
|
let _ = transaction.addMessages(parsedMessages, location: .Random)
|
||||||
|
@ -925,7 +925,7 @@ public final class SparseMessageCalendar {
|
|||||||
case let .searchResultsCalendar(_, _, minDate, minMsgId, _, periods, messages, chats, users):
|
case let .searchResultsCalendar(_, _, minDate, minMsgId, _, periods, messages, chats, users):
|
||||||
var parsedMessages: [StoreMessage] = []
|
var parsedMessages: [StoreMessage] = []
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
@ -935,9 +935,7 @@ public final class SparseMessageCalendar {
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for message in messages {
|
for message in messages {
|
||||||
|
@ -91,13 +91,11 @@ func _internal_channelMembers(postbox: Postbox, network: Network, accountPeerId:
|
|||||||
switch result {
|
switch result {
|
||||||
case let .channelParticipants(_, participants, chats, users):
|
case let .channelParticipants(_, participants, chats, users):
|
||||||
var peers: [PeerId: Peer] = [:]
|
var peers: [PeerId: Peer] = [:]
|
||||||
var presences: [PeerId: PeerPresence] = [:]
|
var presences: [PeerId: Api.User] = [:]
|
||||||
for user in users {
|
for user in users {
|
||||||
let peer = TelegramUser(user: user)
|
let peer = TelegramUser(user: user)
|
||||||
peers[peer.id] = peer
|
peers[peer.id] = peer
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
presences[peer.id] = user
|
||||||
presences[peer.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
@ -111,7 +109,11 @@ func _internal_channelMembers(postbox: Postbox, network: Network, accountPeerId:
|
|||||||
|
|
||||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||||
if let peer = peers[participant.peerId] {
|
if let peer = peers[participant.peerId] {
|
||||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences))
|
var renderedPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
if let presence = transaction.getPeerPresence(peerId: participant.peerId) {
|
||||||
|
renderedPresences[participant.peerId] = presence
|
||||||
|
}
|
||||||
|
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: renderedPresences))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .channelParticipantsNotModified:
|
case .channelParticipantsNotModified:
|
||||||
|
@ -633,7 +633,7 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
|
|||||||
|
|
||||||
return postbox.transaction { transaction -> Void in
|
return postbox.transaction { transaction -> Void in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
|
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
|
||||||
var channelStates: [PeerId: Int32] = [:]
|
var channelStates: [PeerId: Int32] = [:]
|
||||||
|
|
||||||
@ -647,9 +647,7 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var topMessageIds = Set<MessageId>()
|
var topMessageIds = Set<MessageId>()
|
||||||
|
@ -66,13 +66,11 @@ func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox
|
|||||||
switch result {
|
switch result {
|
||||||
case let .topPeers(_, _, users):
|
case let .topPeers(_, _, users):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updatePeers(transaction: transaction, peers: peers, update: { return $1 })
|
updatePeers(transaction: transaction, peers: peers, update: { return $1 })
|
||||||
|
|
||||||
@ -158,19 +156,17 @@ func _internal_updateRecentPeersEnabled(postbox: Postbox, network: Network, enab
|
|||||||
func _internal_managedRecentlyUsedInlineBots(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal<Void, NoError> {
|
func _internal_managedRecentlyUsedInlineBots(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal<Void, NoError> {
|
||||||
let remotePeers = network.request(Api.functions.contacts.getTopPeers(flags: 1 << 2, offset: 0, limit: 16, hash: 0))
|
let remotePeers = network.request(Api.functions.contacts.getTopPeers(flags: 1 << 2, offset: 0, limit: 16, hash: 0))
|
||||||
|> retryRequest
|
|> retryRequest
|
||||||
|> map { result -> ([Peer], [PeerId: PeerPresence], [(PeerId, Double)])? in
|
|> map { result -> ([Peer], [PeerId: Api.User], [(PeerId, Double)])? in
|
||||||
switch result {
|
switch result {
|
||||||
case .topPeersDisabled:
|
case .topPeersDisabled:
|
||||||
break
|
break
|
||||||
case let .topPeers(categories, _, users):
|
case let .topPeers(categories, _, users):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var peersWithRating: [(PeerId, Double)] = []
|
var peersWithRating: [(PeerId, Double)] = []
|
||||||
for category in categories {
|
for category in categories {
|
||||||
|
@ -79,7 +79,7 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountP
|
|||||||
|> retryRequest
|
|> retryRequest
|
||||||
|> mapToSignal { peerSettings -> Signal<Bool, NoError> in
|
|> mapToSignal { peerSettings -> Signal<Bool, NoError> in
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
let peerStatusSettings: PeerStatusSettings
|
let peerStatusSettings: PeerStatusSettings
|
||||||
switch peerSettings {
|
switch peerSettings {
|
||||||
@ -93,9 +93,7 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountP
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +196,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
case let .userFull(fullUser, chats, users):
|
case let .userFull(fullUser, chats, users):
|
||||||
var accountUser: Api.User?
|
var accountUser: Api.User?
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(peer)
|
peers.append(peer)
|
||||||
@ -207,9 +205,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
for user in users {
|
for user in users {
|
||||||
let telegramUser = TelegramUser(user: user)
|
let telegramUser = TelegramUser(user: user)
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
if telegramUser.id == accountPeerId {
|
if telegramUser.id == accountPeerId {
|
||||||
accountUser = user
|
accountUser = user
|
||||||
}
|
}
|
||||||
@ -327,7 +323,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
let pinnedMessageId = chatFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
let pinnedMessageId = chatFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -336,9 +332,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
for user in users {
|
for user in users {
|
||||||
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +509,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
}
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
peers.append(groupOrChannel)
|
peers.append(groupOrChannel)
|
||||||
@ -524,9 +518,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
for user in users {
|
for user in users {
|
||||||
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,9 +528,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||||||
for user in users {
|
for user in users {
|
||||||
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
||||||
peers.append(telegramUser)
|
peers.append(telegramUser)
|
||||||
if let presence = TelegramUserPresence(apiUser: user) {
|
peerPresences[telegramUser.id] = user
|
||||||
peerPresences[telegramUser.id] = presence
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for chat in chats {
|
for chat in chats {
|
||||||
|
@ -106,7 +106,40 @@ public func updatePeers(transaction: Transaction, peers: [Peer], update: (Peer?,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePeerPresences(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: PeerPresence]) {
|
func updatePeerPresences(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: Api.User]) {
|
||||||
|
var parsedPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
for (peerId, user) in peerPresences {
|
||||||
|
guard let presence = TelegramUserPresence(apiUser: user) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch presence.status {
|
||||||
|
case .present:
|
||||||
|
parsedPresences[peerId] = presence
|
||||||
|
default:
|
||||||
|
switch user {
|
||||||
|
case let .user(flags, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
|
let isMin = (flags & (1 << 20)) != 0
|
||||||
|
if isMin, let _ = transaction.getPeerPresence(peerId: peerId) {
|
||||||
|
} else {
|
||||||
|
parsedPresences[peerId] = presence
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedPresences.removeValue(forKey: accountPeerId)
|
||||||
|
|
||||||
|
transaction.updatePeerPresencesInternal(presences: parsedPresences, merge: { previous, updated in
|
||||||
|
if let previous = previous as? TelegramUserPresence, let updated = updated as? TelegramUserPresence, previous.lastActivity != updated.lastActivity {
|
||||||
|
return TelegramUserPresence(status: updated.status, lastActivity: max(previous.lastActivity, updated.lastActivity))
|
||||||
|
}
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func updatePeerPresencesClean(transaction: Transaction, accountPeerId: PeerId, peerPresences: [PeerId: PeerPresence]) {
|
||||||
var peerPresences = peerPresences
|
var peerPresences = peerPresences
|
||||||
if peerPresences[accountPeerId] != nil {
|
if peerPresences[accountPeerId] != nil {
|
||||||
peerPresences.removeValue(forKey: accountPeerId)
|
peerPresences.removeValue(forKey: accountPeerId)
|
||||||
|
@ -37,10 +37,15 @@ public final class EmojiStatusComponent: Component {
|
|||||||
case count(Int)
|
case count(Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SizeType {
|
||||||
|
case compact
|
||||||
|
case large
|
||||||
|
}
|
||||||
|
|
||||||
public enum Content: Equatable {
|
public enum Content: Equatable {
|
||||||
case none
|
case none
|
||||||
case premium(color: UIColor)
|
case premium(color: UIColor)
|
||||||
case verified(fillColor: UIColor, foregroundColor: UIColor)
|
case verified(fillColor: UIColor, foregroundColor: UIColor, sizeType: SizeType)
|
||||||
case text(color: UIColor, string: String)
|
case text(color: UIColor, string: String)
|
||||||
case animation(content: AnimationContent, size: CGSize, placeholderColor: UIColor, themeColor: UIColor?, loopMode: LoopMode)
|
case animation(content: AnimationContent, size: CGSize, placeholderColor: UIColor, themeColor: UIColor?, loopMode: LoopMode)
|
||||||
}
|
}
|
||||||
@ -217,8 +222,16 @@ public final class EmojiStatusComponent: Component {
|
|||||||
} else {
|
} else {
|
||||||
iconImage = nil
|
iconImage = nil
|
||||||
}
|
}
|
||||||
case let .verified(fillColor, foregroundColor):
|
case let .verified(fillColor, foregroundColor, sizeType):
|
||||||
if let backgroundImage = UIImage(bundleImageName: "Peer Info/VerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Peer Info/VerifiedIconForeground") {
|
let imageNamePrefix: String
|
||||||
|
switch sizeType {
|
||||||
|
case .compact:
|
||||||
|
imageNamePrefix = "Chat List/PeerVerifiedIcon"
|
||||||
|
case .large:
|
||||||
|
imageNamePrefix = "Peer Info/VerifiedIcon"
|
||||||
|
}
|
||||||
|
|
||||||
|
if let backgroundImage = UIImage(bundleImageName: "\(imageNamePrefix)Background"), let foregroundImage = UIImage(bundleImageName: "\(imageNamePrefix)Foreground") {
|
||||||
iconImage = generateImage(backgroundImage.size, contextGenerator: { size, context in
|
iconImage = generateImage(backgroundImage.size, contextGenerator: { size, context in
|
||||||
if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage {
|
if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage {
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
@ -342,7 +355,16 @@ public final class EmojiStatusComponent: Component {
|
|||||||
}
|
}
|
||||||
iconView.image = iconImage
|
iconView.image = iconImage
|
||||||
|
|
||||||
if case .text = component.content {
|
var useFit = false
|
||||||
|
switch component.content {
|
||||||
|
case .text:
|
||||||
|
useFit = true
|
||||||
|
case .verified(_, _, sizeType: .compact):
|
||||||
|
useFit = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if useFit {
|
||||||
size = CGSize(width: iconImage.size.width, height: availableSize.height)
|
size = CGSize(width: iconImage.size.width, height: availableSize.height)
|
||||||
iconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconImage.size.width) / 2.0), y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
|
iconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconImage.size.width) / 2.0), y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,6 +64,8 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
public let emojiContent: EmojiPagerContentComponent
|
public let emojiContent: EmojiPagerContentComponent
|
||||||
public let backgroundColor: UIColor
|
public let backgroundColor: UIColor
|
||||||
public let separatorColor: UIColor
|
public let separatorColor: UIColor
|
||||||
|
public let hideTopPanel: Bool
|
||||||
|
public let hideTopPanelUpdated: (Bool, Transition) -> Void
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
@ -71,7 +73,9 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
deviceMetrics: DeviceMetrics,
|
deviceMetrics: DeviceMetrics,
|
||||||
emojiContent: EmojiPagerContentComponent,
|
emojiContent: EmojiPagerContentComponent,
|
||||||
backgroundColor: UIColor,
|
backgroundColor: UIColor,
|
||||||
separatorColor: UIColor
|
separatorColor: UIColor,
|
||||||
|
hideTopPanel: Bool,
|
||||||
|
hideTopPanelUpdated: @escaping (Bool, Transition) -> Void
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
@ -79,6 +83,8 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
self.emojiContent = emojiContent
|
self.emojiContent = emojiContent
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.separatorColor = separatorColor
|
self.separatorColor = separatorColor
|
||||||
|
self.hideTopPanel = hideTopPanel
|
||||||
|
self.hideTopPanelUpdated = hideTopPanelUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: EmojiStatusSelectionComponent, rhs: EmojiStatusSelectionComponent) -> Bool {
|
public static func ==(lhs: EmojiStatusSelectionComponent, rhs: EmojiStatusSelectionComponent) -> Bool {
|
||||||
@ -100,6 +106,9 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
if lhs.separatorColor != rhs.separatorColor {
|
if lhs.separatorColor != rhs.separatorColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.hideTopPanel != rhs.hideTopPanel {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +120,7 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
private let panelSeparatorView: UIView
|
private let panelSeparatorView: UIView
|
||||||
|
|
||||||
private var component: EmojiStatusSelectionComponent?
|
private var component: EmojiStatusSelectionComponent?
|
||||||
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.keyboardView = ComponentView<Empty>()
|
self.keyboardView = ComponentView<Empty>()
|
||||||
@ -131,6 +141,9 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
}
|
||||||
|
|
||||||
func update(component: EmojiStatusSelectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
func update(component: EmojiStatusSelectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||||
self.backgroundColor = component.backgroundColor
|
self.backgroundColor = component.backgroundColor
|
||||||
let panelBackgroundColor = component.backgroundColor.withMultipliedAlpha(0.85)
|
let panelBackgroundColor = component.backgroundColor.withMultipliedAlpha(0.85)
|
||||||
@ -138,8 +151,9 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
self.panelSeparatorView.backgroundColor = component.separatorColor
|
self.panelSeparatorView.backgroundColor = component.separatorColor
|
||||||
|
|
||||||
self.component = component
|
self.component = component
|
||||||
|
self.state = state
|
||||||
|
|
||||||
let topPanelHeight: CGFloat = 42.0
|
let topPanelHeight: CGFloat = component.hideTopPanel ? 0.0 : 42.0
|
||||||
|
|
||||||
let keyboardSize = self.keyboardView.update(
|
let keyboardSize = self.keyboardView.update(
|
||||||
transition: transition.withUserData(EmojiPagerContentComponent.SynchronousLoadBehavior(isDisabled: true)),
|
transition: transition.withUserData(EmojiPagerContentComponent.SynchronousLoadBehavior(isDisabled: true)),
|
||||||
@ -158,6 +172,12 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
externalTopPanelContainer: self.panelHostView,
|
externalTopPanelContainer: self.panelHostView,
|
||||||
topPanelExtensionUpdated: { _, _ in },
|
topPanelExtensionUpdated: { _, _ in },
|
||||||
hideInputUpdated: { _, _, _ in },
|
hideInputUpdated: { _, _, _ in },
|
||||||
|
hideTopPanelUpdated: { [weak self] hideTopPanel, transition in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.component?.hideTopPanelUpdated(hideTopPanel, transition)
|
||||||
|
},
|
||||||
switchToTextInput: {},
|
switchToTextInput: {},
|
||||||
switchToGifSubject: { _ in },
|
switchToGifSubject: { _ in },
|
||||||
reorderItems: { _, _ in },
|
reorderItems: { _, _ in },
|
||||||
@ -189,7 +209,7 @@ public final class EmojiStatusSelectionComponent: Component {
|
|||||||
transition.setFrame(view: self.panelBackgroundView, frame: CGRect(origin: CGPoint(), size: CGSize(width: keyboardSize.width, height: topPanelHeight)))
|
transition.setFrame(view: self.panelBackgroundView, frame: CGRect(origin: CGPoint(), size: CGSize(width: keyboardSize.width, height: topPanelHeight)))
|
||||||
self.panelBackgroundView.update(size: self.panelBackgroundView.bounds.size, transition: transition.containedViewLayoutTransition)
|
self.panelBackgroundView.update(size: self.panelBackgroundView.bounds.size, transition: transition.containedViewLayoutTransition)
|
||||||
|
|
||||||
transition.setFrame(view: self.panelSeparatorView, frame: CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight), size: CGSize(width: keyboardSize.width, height: UIScreenPixel)))
|
transition.setFrame(view: self.panelSeparatorView, frame: CGRect(origin: CGPoint(x: 0.0, y: component.hideTopPanel ? -UIScreenPixel : topPanelHeight), size: CGSize(width: keyboardSize.width, height: UIScreenPixel)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
@ -343,7 +363,8 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
},
|
},
|
||||||
requestUpdate: { _ in
|
requestUpdate: { _ in
|
||||||
},
|
},
|
||||||
sendSticker: nil,
|
updateSearchQuery: { _ in
|
||||||
|
},
|
||||||
chatPeerId: nil,
|
chatPeerId: nil,
|
||||||
peekBehavior: nil,
|
peekBehavior: nil,
|
||||||
customLayout: nil,
|
customLayout: nil,
|
||||||
@ -639,7 +660,9 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
deviceMetrics: layout.deviceMetrics,
|
deviceMetrics: layout.deviceMetrics,
|
||||||
emojiContent: emojiContent,
|
emojiContent: emojiContent,
|
||||||
backgroundColor: listBackgroundColor,
|
backgroundColor: listBackgroundColor,
|
||||||
separatorColor: separatorColor
|
separatorColor: separatorColor,
|
||||||
|
hideTopPanel: false,
|
||||||
|
hideTopPanelUpdated: { _, _ in }
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: componentWidth, height: min(308.0, layout.size.height))
|
containerSize: CGSize(width: componentWidth, height: min(308.0, layout.size.height))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -99,6 +99,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
public let externalTopPanelContainer: PagerExternalTopPanelContainer?
|
public let externalTopPanelContainer: PagerExternalTopPanelContainer?
|
||||||
public let topPanelExtensionUpdated: (CGFloat, Transition) -> Void
|
public let topPanelExtensionUpdated: (CGFloat, Transition) -> Void
|
||||||
public let hideInputUpdated: (Bool, Bool, Transition) -> Void
|
public let hideInputUpdated: (Bool, Bool, Transition) -> Void
|
||||||
|
public let hideTopPanelUpdated: (Bool, Transition) -> Void
|
||||||
public let switchToTextInput: () -> Void
|
public let switchToTextInput: () -> Void
|
||||||
public let switchToGifSubject: (GifPagerContentComponent.Subject) -> Void
|
public let switchToGifSubject: (GifPagerContentComponent.Subject) -> Void
|
||||||
public let reorderItems: (ReorderCategory, [EntityKeyboardTopPanelComponent.Item]) -> Void
|
public let reorderItems: (ReorderCategory, [EntityKeyboardTopPanelComponent.Item]) -> Void
|
||||||
@ -123,6 +124,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
externalTopPanelContainer: PagerExternalTopPanelContainer?,
|
externalTopPanelContainer: PagerExternalTopPanelContainer?,
|
||||||
topPanelExtensionUpdated: @escaping (CGFloat, Transition) -> Void,
|
topPanelExtensionUpdated: @escaping (CGFloat, Transition) -> Void,
|
||||||
hideInputUpdated: @escaping (Bool, Bool, Transition) -> Void,
|
hideInputUpdated: @escaping (Bool, Bool, Transition) -> Void,
|
||||||
|
hideTopPanelUpdated: @escaping (Bool, Transition) -> Void,
|
||||||
switchToTextInput: @escaping () -> Void,
|
switchToTextInput: @escaping () -> Void,
|
||||||
switchToGifSubject: @escaping (GifPagerContentComponent.Subject) -> Void,
|
switchToGifSubject: @escaping (GifPagerContentComponent.Subject) -> Void,
|
||||||
reorderItems: @escaping (ReorderCategory, [EntityKeyboardTopPanelComponent.Item]) -> Void,
|
reorderItems: @escaping (ReorderCategory, [EntityKeyboardTopPanelComponent.Item]) -> Void,
|
||||||
@ -146,6 +148,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
self.externalTopPanelContainer = externalTopPanelContainer
|
self.externalTopPanelContainer = externalTopPanelContainer
|
||||||
self.topPanelExtensionUpdated = topPanelExtensionUpdated
|
self.topPanelExtensionUpdated = topPanelExtensionUpdated
|
||||||
self.hideInputUpdated = hideInputUpdated
|
self.hideInputUpdated = hideInputUpdated
|
||||||
|
self.hideTopPanelUpdated = hideTopPanelUpdated
|
||||||
self.switchToTextInput = switchToTextInput
|
self.switchToTextInput = switchToTextInput
|
||||||
self.switchToGifSubject = switchToGifSubject
|
self.switchToGifSubject = switchToGifSubject
|
||||||
self.reorderItems = reorderItems
|
self.reorderItems = reorderItems
|
||||||
@ -222,6 +225,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
|
|
||||||
private var topPanelExtension: CGFloat?
|
private var topPanelExtension: CGFloat?
|
||||||
private var isTopPanelExpanded: Bool = false
|
private var isTopPanelExpanded: Bool = false
|
||||||
|
private var isTopPanelHidden: Bool = false
|
||||||
|
|
||||||
public var centralId: AnyHashable? {
|
public var centralId: AnyHashable? {
|
||||||
if let pagerView = self.pagerView.findTaggedView(tag: PagerComponentViewTag()) as? PagerComponent<EntityKeyboardChildEnvironment, EntityKeyboardTopContainerPanelEnvironment>.View {
|
if let pagerView = self.pagerView.findTaggedView(tag: PagerComponentViewTag()) as? PagerComponent<EntityKeyboardChildEnvironment, EntityKeyboardTopContainerPanelEnvironment>.View {
|
||||||
@ -626,6 +630,12 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
}
|
}
|
||||||
strongSelf.isTopPanelExpandedUpdated(isExpanded: isExpanded, transition: transition)
|
strongSelf.isTopPanelExpandedUpdated(isExpanded: isExpanded, transition: transition)
|
||||||
},
|
},
|
||||||
|
isTopPanelHiddenUpdated: { [weak self] isTopPanelHidden, transition in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.isTopPanelHiddenUpdated(isTopPanelHidden: isTopPanelHidden, transition: transition)
|
||||||
|
},
|
||||||
panelHideBehavior: panelHideBehavior
|
panelHideBehavior: panelHideBehavior
|
||||||
)),
|
)),
|
||||||
environment: {
|
environment: {
|
||||||
@ -727,6 +737,18 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
component.hideInputUpdated(self.isTopPanelExpanded, false, transition)
|
component.hideInputUpdated(self.isTopPanelExpanded, false, transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func isTopPanelHiddenUpdated(isTopPanelHidden: Bool, transition: Transition) {
|
||||||
|
if self.isTopPanelHidden != isTopPanelHidden {
|
||||||
|
self.isTopPanelHidden = isTopPanelHidden
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
component.hideTopPanelUpdated(self.isTopPanelHidden, transition)
|
||||||
|
}
|
||||||
|
|
||||||
private func openSearch() {
|
private func openSearch() {
|
||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
|
@ -110,6 +110,10 @@ private class ApplicationStatusBarHost: StatusBarHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var keyboardWindow: UIWindow? {
|
var keyboardWindow: UIWindow? {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
return UIApplication.shared.internalGetKeyboard()
|
||||||
|
}
|
||||||
|
|
||||||
for window in UIApplication.shared.windows {
|
for window in UIApplication.shared.windows {
|
||||||
if isKeyboardWindow(window: window) {
|
if isKeyboardWindow(window: window) {
|
||||||
return window
|
return window
|
||||||
|
@ -1237,6 +1237,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controller?.view.endEditing(true)
|
||||||
|
|
||||||
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction
|
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction
|
||||||
|
|
||||||
let currentReactions = mergedMessageReactions(attributes: message.attributes)?.reactions ?? []
|
let currentReactions = mergedMessageReactions(attributes: message.attributes)?.reactions ?? []
|
||||||
|
@ -535,6 +535,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
itemLayoutType: .detailed,
|
itemLayoutType: .detailed,
|
||||||
|
itemContentUniqueId: nil,
|
||||||
warpContentsOnEdges: false,
|
warpContentsOnEdges: false,
|
||||||
displaySearch: false,
|
displaySearch: false,
|
||||||
enableLongPress: false,
|
enableLongPress: false,
|
||||||
@ -1120,13 +1121,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
return controllerInteraction?.navigationController()
|
return controllerInteraction?.navigationController()
|
||||||
},
|
},
|
||||||
requestUpdate: { _ in
|
requestUpdate: { _ in
|
||||||
|
|
||||||
},
|
},
|
||||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets in
|
updateSearchQuery: { _ in
|
||||||
guard let controllerInteraction = controllerInteraction else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets)
|
|
||||||
},
|
},
|
||||||
chatPeerId: chatPeerId,
|
chatPeerId: chatPeerId,
|
||||||
peekBehavior: nil,
|
peekBehavior: nil,
|
||||||
@ -1329,13 +1325,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
return controllerInteraction?.navigationController()
|
return controllerInteraction?.navigationController()
|
||||||
},
|
},
|
||||||
requestUpdate: { _ in
|
requestUpdate: { _ in
|
||||||
|
|
||||||
},
|
},
|
||||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets in
|
updateSearchQuery: { _ in
|
||||||
guard let controllerInteraction = controllerInteraction else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer, bubbleUpEmojiOrStickersets)
|
|
||||||
},
|
},
|
||||||
chatPeerId: chatPeerId,
|
chatPeerId: chatPeerId,
|
||||||
peekBehavior: stickerPeekBehavior,
|
peekBehavior: stickerPeekBehavior,
|
||||||
@ -1592,6 +1583,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
strongSelf.hideInputUpdated?(transition.containedViewLayoutTransition)
|
strongSelf.hideInputUpdated?(transition.containedViewLayoutTransition)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
hideTopPanelUpdated: { _, _ in
|
||||||
|
},
|
||||||
switchToTextInput: { [weak self] in
|
switchToTextInput: { [weak self] in
|
||||||
self?.switchToTextInput?()
|
self?.switchToTextInput?()
|
||||||
},
|
},
|
||||||
@ -1721,9 +1714,9 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
|
|
||||||
private func processInputData(inputData: InputData) -> InputData {
|
private func processInputData(inputData: InputData) -> InputData {
|
||||||
return InputData(
|
return InputData(
|
||||||
emoji: inputData.emoji.withUpdatedItemGroups(self.processStableItemGroupList(category: .emoji, itemGroups: inputData.emoji.itemGroups)),
|
emoji: inputData.emoji.withUpdatedItemGroups(itemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: inputData.emoji.itemGroups), itemContentUniqueId: nil),
|
||||||
stickers: inputData.stickers.flatMap { stickers in
|
stickers: inputData.stickers.flatMap { stickers in
|
||||||
return stickers.withUpdatedItemGroups(self.processStableItemGroupList(category: .stickers, itemGroups: stickers.itemGroups))
|
return stickers.withUpdatedItemGroups(itemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.itemGroups), itemContentUniqueId: nil)
|
||||||
},
|
},
|
||||||
gifs: inputData.gifs,
|
gifs: inputData.gifs,
|
||||||
availableGifSearchEmojies: inputData.availableGifSearchEmojies
|
availableGifSearchEmojies: inputData.availableGifSearchEmojies
|
||||||
@ -2057,10 +2050,10 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
navigationController: {
|
navigationController: {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
requestUpdate: { _ in
|
requestUpdate: { _ in
|
||||||
|
},
|
||||||
|
updateSearchQuery: { _ in
|
||||||
},
|
},
|
||||||
sendSticker: nil,
|
|
||||||
chatPeerId: nil,
|
chatPeerId: nil,
|
||||||
peekBehavior: nil,
|
peekBehavior: nil,
|
||||||
customLayout: nil,
|
customLayout: nil,
|
||||||
|
@ -673,7 +673,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
case .premium:
|
case .premium:
|
||||||
titleCredibilityContent = .premium(color: self.theme.list.itemAccentColor)
|
titleCredibilityContent = .premium(color: self.theme.list.itemAccentColor)
|
||||||
case .verified:
|
case .verified:
|
||||||
titleCredibilityContent = .verified(fillColor: self.theme.list.itemCheckColors.fillColor, foregroundColor: self.theme.list.itemCheckColors.foregroundColor)
|
titleCredibilityContent = .verified(fillColor: self.theme.list.itemCheckColors.fillColor, foregroundColor: self.theme.list.itemCheckColors.foregroundColor, sizeType: .large)
|
||||||
case .fake:
|
case .fake:
|
||||||
titleCredibilityContent = .text(color: self.theme.chat.message.incoming.scamColor, string: self.strings.Message_FakeAccount.uppercased())
|
titleCredibilityContent = .text(color: self.theme.chat.message.incoming.scamColor, string: self.strings.Message_FakeAccount.uppercased())
|
||||||
case .scam:
|
case .scam:
|
||||||
|
@ -2343,8 +2343,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
emojiRegularStatusContent = .premium(color: presentationData.theme.list.itemAccentColor)
|
emojiRegularStatusContent = .premium(color: presentationData.theme.list.itemAccentColor)
|
||||||
emojiExpandedStatusContent = .premium(color: UIColor(rgb: 0xffffff, alpha: 0.75))
|
emojiExpandedStatusContent = .premium(color: UIColor(rgb: 0xffffff, alpha: 0.75))
|
||||||
case .verified:
|
case .verified:
|
||||||
emojiRegularStatusContent = .verified(fillColor: presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: presentationData.theme.list.itemCheckColors.foregroundColor)
|
emojiRegularStatusContent = .verified(fillColor: presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .large)
|
||||||
emojiExpandedStatusContent = .verified(fillColor: UIColor(rgb: 0xffffff, alpha: 0.75), foregroundColor: .clear)
|
emojiExpandedStatusContent = .verified(fillColor: UIColor(rgb: 0xffffff, alpha: 0.75), foregroundColor: .clear, sizeType: .large)
|
||||||
case .fake:
|
case .fake:
|
||||||
emojiRegularStatusContent = .text(color: presentationData.theme.chat.message.incoming.scamColor, string: presentationData.strings.Message_FakeAccount.uppercased())
|
emojiRegularStatusContent = .text(color: presentationData.theme.chat.message.incoming.scamColor, string: presentationData.strings.Message_FakeAccount.uppercased())
|
||||||
emojiExpandedStatusContent = emojiRegularStatusContent
|
emojiExpandedStatusContent = emojiRegularStatusContent
|
||||||
|
@ -22,6 +22,7 @@ typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) {
|
|||||||
|
|
||||||
- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated;
|
- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated;
|
||||||
- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation;
|
- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation;
|
||||||
|
- (UIWindow * _Nullable)internalGetKeyboard;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -139,6 +139,12 @@ static bool notyfyingShiftState = false;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@protocol UIRemoteKeyboardWindowProtocol
|
||||||
|
|
||||||
|
+ (UIWindow * _Nullable)remoteKeyboardWindowForScreen:(UIScreen * _Nullable)screen create:(BOOL)create;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation UIViewController (Navigation)
|
@implementation UIViewController (Navigation)
|
||||||
|
|
||||||
+ (void)load
|
+ (void)load
|
||||||
@ -155,6 +161,8 @@ static bool notyfyingShiftState = false;
|
|||||||
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(presentViewController:animated:completion:) newSelector:@selector(_65087dc8_presentViewController:animated:completion:)];
|
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(presentViewController:animated:completion:) newSelector:@selector(_65087dc8_presentViewController:animated:completion:)];
|
||||||
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(setNeedsStatusBarAppearanceUpdate) newSelector:@selector(_65087dc8_setNeedsStatusBarAppearanceUpdate)];
|
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(setNeedsStatusBarAppearanceUpdate) newSelector:@selector(_65087dc8_setNeedsStatusBarAppearanceUpdate)];
|
||||||
|
|
||||||
|
[RuntimeUtils swizzleClassMethodOfClass:NSClassFromString(@"UIRemoteKeyboardWindow") currentSelector:NSSelectorFromString(@"remoteKeyboardWindowForScreen:create:") newSelector:NSSelectorFromString(@"_65087dc8_remoteKeyboardWindowForScreen:create:")];
|
||||||
|
|
||||||
if (@available(iOS 15.0, *)) {
|
if (@available(iOS 15.0, *)) {
|
||||||
[RuntimeUtils swizzleInstanceMethodOfClass:[CADisplayLink class] currentSelector:@selector(setPreferredFrameRateRange:) newSelector:@selector(_65087dc8_setPreferredFrameRateRange:)];
|
[RuntimeUtils swizzleInstanceMethodOfClass:[CADisplayLink class] currentSelector:@selector(setPreferredFrameRateRange:) newSelector:@selector(_65087dc8_setPreferredFrameRateRange:)];
|
||||||
}
|
}
|
||||||
@ -291,6 +299,14 @@ static bool notyfyingShiftState = false;
|
|||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (UIWindow * _Nullable)internalGetKeyboard {
|
||||||
|
Class windowClass = NSClassFromString(@"UIRemoteKeyboardWindow");
|
||||||
|
if (!windowClass) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return [(id<UIRemoteKeyboardWindowProtocol>)windowClass remoteKeyboardWindowForScreen:[UIScreen mainScreen] create:false];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation UIView (Navigation)
|
@implementation UIView (Navigation)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user