mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
fc8d25851a
@ -1435,7 +1435,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
transition.updateAlpha(node: self.setByYouNode, alpha: 0.7)
|
transition.updateAlpha(node: self.setByYouNode, alpha: 0.7)
|
||||||
self.setByYouNode.attributedText = NSAttributedString(string: photoTitle, font: Font.regular(12.0), textColor: UIColor.white)
|
self.setByYouNode.attributedText = NSAttributedString(string: photoTitle, font: Font.regular(12.0), textColor: UIColor.white)
|
||||||
let setByYouSize = self.setByYouNode.updateLayout(size)
|
let setByYouSize = self.setByYouNode.updateLayout(size)
|
||||||
self.setByYouNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - setByYouSize.width) / 2.0), y: 17.0), size: setByYouSize)
|
self.setByYouNode.frame = CGRect(origin: CGPoint(x: size.width - setByYouSize.width - 14.0, y: size.height - setByYouSize.height - 58.0), size: setByYouSize)
|
||||||
self.setByYouNode.isUserInteractionEnabled = hasLink
|
self.setByYouNode.isUserInteractionEnabled = hasLink
|
||||||
} else {
|
} else {
|
||||||
transition.updateAlpha(node: self.setByYouNode, alpha: 0.0)
|
transition.updateAlpha(node: self.setByYouNode, alpha: 0.0)
|
||||||
@ -1445,7 +1445,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
|||||||
if let fallbackImageSignal = fallbackImageSignal {
|
if let fallbackImageSignal = fallbackImageSignal {
|
||||||
self.setByYouImageNode.setSignal(fallbackImageSignal)
|
self.setByYouImageNode.setSignal(fallbackImageSignal)
|
||||||
transition.updateAlpha(node: self.setByYouImageNode, alpha: 1.0)
|
transition.updateAlpha(node: self.setByYouImageNode, alpha: 1.0)
|
||||||
self.setByYouImageNode.frame = CGRect(origin: CGPoint(x: self.setByYouNode.frame.minX - 32.0, y: 11.0), size: CGSize(width: 28.0, height: 28.0))
|
self.setByYouImageNode.frame = CGRect(origin: CGPoint(x: self.setByYouNode.frame.minX - 32.0, y: self.setByYouNode.frame.minY - 7.0), size: CGSize(width: 28.0, height: 28.0))
|
||||||
} else {
|
} else {
|
||||||
transition.updateAlpha(node: self.setByYouImageNode, alpha: 0.0)
|
transition.updateAlpha(node: self.setByYouImageNode, alpha: 0.0)
|
||||||
}
|
}
|
||||||
|
@ -376,6 +376,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
"//submodules/TelegramUI/Components/Stories/StorySetIndicatorComponent",
|
"//submodules/TelegramUI/Components/Stories/StorySetIndicatorComponent",
|
||||||
"//submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode",
|
"//submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode",
|
||||||
|
"//submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode",
|
||||||
"//submodules/Utils/VolumeButtons",
|
"//submodules/Utils/VolumeButtons",
|
||||||
"//submodules/ChatContextQuery",
|
"//submodules/ChatContextQuery",
|
||||||
] + select({
|
] + select({
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "ChatAvatarNavigationNode",
|
||||||
|
module_name = "ChatAvatarNavigationNode",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/AsyncDisplayKit",
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
|
"//submodules/Postbox",
|
||||||
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/AvatarNode",
|
||||||
|
"//submodules/ContextUI",
|
||||||
|
"//submodules/TelegramPresentationData",
|
||||||
|
"//submodules/TelegramUniversalVideoContent",
|
||||||
|
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
||||||
|
"//submodules/GalleryUI",
|
||||||
|
"//submodules/Components/HierarchyTrackingLayer",
|
||||||
|
"//submodules/AccountContext",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||||
|
"//submodules/AvatarVideoNode",
|
||||||
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -16,18 +16,23 @@ import AccountContext
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
import AvatarVideoNode
|
import AvatarVideoNode
|
||||||
|
import AvatarStoryIndicatorComponent
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
|
||||||
private let normalFont = avatarPlaceholderFont(size: 16.0)
|
private let normalFont = avatarPlaceholderFont(size: 16.0)
|
||||||
private let smallFont = avatarPlaceholderFont(size: 12.0)
|
private let smallFont = avatarPlaceholderFont(size: 12.0)
|
||||||
|
|
||||||
final class ChatAvatarNavigationNode: ASDisplayNode {
|
public final class ChatAvatarNavigationNode: ASDisplayNode {
|
||||||
private var context: AccountContext?
|
private var context: AccountContext?
|
||||||
|
|
||||||
private let containerNode: ContextControllerSourceNode
|
private let containerNode: ContextControllerSourceNode
|
||||||
let avatarNode: AvatarNode
|
public let avatarNode: AvatarNode
|
||||||
private var avatarVideoNode: AvatarVideoNode?
|
private var avatarVideoNode: AvatarVideoNode?
|
||||||
|
|
||||||
let statusView: ComponentView<Empty>
|
public private(set) var avatarStoryView: ComponentView<Empty>?
|
||||||
|
public var hasUnseenStories: Bool?
|
||||||
|
|
||||||
|
public let statusView: ComponentView<Empty>
|
||||||
|
|
||||||
private var cachedDataDisposable = MetaDisposable()
|
private var cachedDataDisposable = MetaDisposable()
|
||||||
private var hierarchyTrackingLayer: HierarchyTrackingLayer?
|
private var hierarchyTrackingLayer: HierarchyTrackingLayer?
|
||||||
@ -42,8 +47,8 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
public var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
var contextActionIsEnabled: Bool = false {
|
public var contextActionIsEnabled: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if self.contextActionIsEnabled != oldValue {
|
if self.contextActionIsEnabled != oldValue {
|
||||||
self.containerNode.isGestureEnabled = self.contextActionIsEnabled
|
self.containerNode.isGestureEnabled = self.contextActionIsEnabled
|
||||||
@ -51,7 +56,7 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override init() {
|
override public init() {
|
||||||
self.containerNode = ContextControllerSourceNode()
|
self.containerNode = ContextControllerSourceNode()
|
||||||
self.containerNode.isGestureEnabled = false
|
self.containerNode.isGestureEnabled = false
|
||||||
self.avatarNode = AvatarNode(font: normalFont)
|
self.avatarNode = AvatarNode(font: normalFont)
|
||||||
@ -71,13 +76,17 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)).offsetBy(dx: 10.0, dy: 1.0)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)).offsetBy(dx: 10.0, dy: 1.0)
|
||||||
self.avatarNode.frame = self.containerNode.bounds
|
self.avatarNode.frame = self.containerNode.bounds
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
self.hasUnseenStories = true
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.cachedDataDisposable.dispose()
|
self.cachedDataDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
self.view.isOpaque = false
|
self.view.isOpaque = false
|
||||||
}
|
}
|
||||||
@ -190,14 +199,49 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
public func updateStoryView(transition: ContainedViewLayoutTransition, theme: PresentationTheme) {
|
||||||
|
if let hasUnseenStories = self.hasUnseenStories {
|
||||||
|
let avatarStoryView: ComponentView<Empty>
|
||||||
|
if let current = self.avatarStoryView {
|
||||||
|
avatarStoryView = current
|
||||||
|
} else {
|
||||||
|
avatarStoryView = ComponentView()
|
||||||
|
self.avatarStoryView = avatarStoryView
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = avatarStoryView.update(
|
||||||
|
transition: Transition(transition),
|
||||||
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
|
hasUnseen: hasUnseenStories,
|
||||||
|
isDarkTheme: theme.overallDarkAppearance,
|
||||||
|
activeLineWidth: 1.0,
|
||||||
|
inactiveLineWidth: 1.0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: self.avatarNode.bounds.insetBy(dx: 2.0, dy: 2.0).size
|
||||||
|
)
|
||||||
|
if let avatarStoryComponentView = avatarStoryView.view {
|
||||||
|
if avatarStoryComponentView.superview == nil {
|
||||||
|
self.containerNode.view.insertSubview(avatarStoryComponentView, at: 0)
|
||||||
|
}
|
||||||
|
avatarStoryComponentView.frame = self.avatarNode.frame
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let avatarStoryView = self.avatarStoryView {
|
||||||
|
self.avatarStoryView = nil
|
||||||
|
avatarStoryView.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
return CGSize(width: 37.0, height: 37.0)
|
return CGSize(width: 37.0, height: 37.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func onLayout() {
|
public func onLayout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SnapshotState {
|
public final class SnapshotState {
|
||||||
fileprivate let snapshotView: UIView?
|
fileprivate let snapshotView: UIView?
|
||||||
|
|
||||||
fileprivate init(snapshotView: UIView?) {
|
fileprivate init(snapshotView: UIView?) {
|
||||||
@ -205,14 +249,14 @@ final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareSnapshotState() -> SnapshotState {
|
public func prepareSnapshotState() -> SnapshotState {
|
||||||
let snapshotView = self.avatarNode.view.snapshotView(afterScreenUpdates: false)
|
let snapshotView = self.avatarNode.view.snapshotView(afterScreenUpdates: false)
|
||||||
return SnapshotState(
|
return SnapshotState(
|
||||||
snapshotView: snapshotView
|
snapshotView: snapshotView
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateFromSnapshot(_ snapshotState: SnapshotState) {
|
public func animateFromSnapshot(_ snapshotState: SnapshotState) {
|
||||||
self.avatarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
self.avatarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
self.avatarNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: true)
|
self.avatarNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: true)
|
||||||
|
|
@ -11,11 +11,20 @@ swift_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//submodules/AsyncDisplayKit",
|
"//submodules/AsyncDisplayKit",
|
||||||
"//submodules/Display",
|
|
||||||
"//submodules/Postbox",
|
"//submodules/Postbox",
|
||||||
|
"//submodules/Display",
|
||||||
"//submodules/TelegramCore",
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
"//submodules/TelegramPresentationData",
|
"//submodules/TelegramPresentationData",
|
||||||
|
"//submodules/AccountContext",
|
||||||
"//submodules/LocalizedPeerData",
|
"//submodules/LocalizedPeerData",
|
||||||
|
"//submodules/PhotoResources",
|
||||||
|
"//submodules/TelegramStringFormatting",
|
||||||
|
"//submodules/TextFormat",
|
||||||
|
"//submodules/InvisibleInkDustNode",
|
||||||
|
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||||
|
"//submodules/TelegramUI/Components/AnimationCache",
|
||||||
|
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -429,7 +429,10 @@ public final class ChatListNavigationBar: Component {
|
|||||||
tabsFrame.origin.y -= 46.0
|
tabsFrame.origin.y -= 46.0
|
||||||
}
|
}
|
||||||
|
|
||||||
let accessoryPanelContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height - component.accessoryPanelContainerHeight), size: CGSize(width: visibleSize.width, height: component.accessoryPanelContainerHeight))
|
var accessoryPanelContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height), size: CGSize(width: visibleSize.width, height: component.accessoryPanelContainerHeight))
|
||||||
|
if !component.isSearchActive {
|
||||||
|
accessoryPanelContainerFrame.origin.y -= component.accessoryPanelContainerHeight
|
||||||
|
}
|
||||||
|
|
||||||
if let disappearingTabsView = self.disappearingTabsView {
|
if let disappearingTabsView = self.disappearingTabsView {
|
||||||
disappearingTabsView.layer.anchorPoint = CGPoint()
|
disappearingTabsView.layer.anchorPoint = CGPoint()
|
||||||
@ -466,6 +469,7 @@ public final class ChatListNavigationBar: Component {
|
|||||||
var tabsNodeTransition = transition
|
var tabsNodeTransition = transition
|
||||||
if accessoryPanelContainer.view.superview !== self {
|
if accessoryPanelContainer.view.superview !== self {
|
||||||
accessoryPanelContainer.view.layer.anchorPoint = CGPoint()
|
accessoryPanelContainer.view.layer.anchorPoint = CGPoint()
|
||||||
|
accessoryPanelContainer.clipsToBounds = true
|
||||||
tabsNodeTransition = .immediate
|
tabsNodeTransition = .immediate
|
||||||
accessoryPanelContainer.view.alpha = 1.0
|
accessoryPanelContainer.view.alpha = 1.0
|
||||||
self.addSubview(accessoryPanelContainer.view)
|
self.addSubview(accessoryPanelContainer.view)
|
||||||
|
@ -1038,7 +1038,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.view.insertSubview(view, aboveSubview: self.itemGrid.view)
|
self.addToTransitionSurface(view: view)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
destinationRect: self.itemGrid.view.convert(itemRect, to: self.view),
|
destinationRect: self.itemGrid.view.convert(itemRect, to: self.view),
|
||||||
|
@ -552,6 +552,10 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
focusedItemPromise.set(.single(nil))
|
focusedItemPromise.set(.single(nil))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let transitionOut = component.transitionOut(slice.peer.id, slice.item.id) {
|
||||||
|
transitionOut.completed()
|
||||||
|
}
|
||||||
|
|
||||||
let transition: Transition
|
let transition: Transition
|
||||||
if self.dismissWithoutTransitionOut {
|
if self.dismissWithoutTransitionOut {
|
||||||
transition = Transition(animation: .curve(duration: 0.5, curve: .spring))
|
transition = Transition(animation: .curve(duration: 0.5, curve: .spring))
|
||||||
|
@ -537,6 +537,9 @@ public final class StoryContentContextImpl: StoryContentContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sortedItems: [EngineStorySubscriptions.Item] = []
|
var sortedItems: [EngineStorySubscriptions.Item] = []
|
||||||
|
if !startedWithUnseen, let accountItem = storySubscriptions.accountItem, accountItem.storyCount != 0 {
|
||||||
|
sortedItems.append(accountItem)
|
||||||
|
}
|
||||||
for peerId in self.fixedSubscriptionOrder {
|
for peerId in self.fixedSubscriptionOrder {
|
||||||
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
if let index = storySubscriptions.items.firstIndex(where: { $0.peer.id == peerId }) {
|
||||||
sortedItems.append(storySubscriptions.items[index])
|
sortedItems.append(storySubscriptions.items[index])
|
||||||
@ -607,13 +610,48 @@ public final class StoryContentContextImpl: StoryContentContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (focusedPeerId, _) = self.focusedItem, focusedPeerId == self.context.account.peerId {
|
var centralIndex: Int?
|
||||||
let centralPeerContext = PeerContext(context: self.context, peerId: self.context.account.peerId, focusedId: nil, loadIds: loadIds)
|
if let (focusedPeerId, _) = self.focusedItem {
|
||||||
|
if let index = subscriptionItems.firstIndex(where: { $0.peer.id == focusedPeerId }) {
|
||||||
|
centralIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if centralIndex == nil {
|
||||||
|
if !subscriptionItems.isEmpty {
|
||||||
|
centralIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let centralIndex {
|
||||||
|
let centralPeerContext: PeerContext
|
||||||
|
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex].peer.id) {
|
||||||
|
centralPeerContext = existingContext
|
||||||
|
} else {
|
||||||
|
centralPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex].peer.id, focusedId: nil, loadIds: loadIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
var previousPeerContext: PeerContext?
|
||||||
|
if centralIndex != 0 {
|
||||||
|
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex - 1].peer.id) {
|
||||||
|
previousPeerContext = existingContext
|
||||||
|
} else {
|
||||||
|
previousPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex - 1].peer.id, focusedId: nil, loadIds: loadIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextPeerContext: PeerContext?
|
||||||
|
if centralIndex != subscriptionItems.count - 1 {
|
||||||
|
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex + 1].peer.id) {
|
||||||
|
nextPeerContext = existingContext
|
||||||
|
} else {
|
||||||
|
nextPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex + 1].peer.id, focusedId: nil, loadIds: loadIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let pendingState = StateContext(
|
let pendingState = StateContext(
|
||||||
centralPeerContext: centralPeerContext,
|
centralPeerContext: centralPeerContext,
|
||||||
previousPeerContext: nil,
|
previousPeerContext: previousPeerContext,
|
||||||
nextPeerContext: nil
|
nextPeerContext: nextPeerContext
|
||||||
)
|
)
|
||||||
self.pendingState = pendingState
|
self.pendingState = pendingState
|
||||||
self.pendingStateReadyDisposable = (pendingState.updated.get()
|
self.pendingStateReadyDisposable = (pendingState.updated.get()
|
||||||
@ -638,74 +676,6 @@ public final class StoryContentContextImpl: StoryContentContext {
|
|||||||
self.updateState()
|
self.updateState()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
var centralIndex: Int?
|
|
||||||
if let (focusedPeerId, _) = self.focusedItem {
|
|
||||||
if let index = subscriptionItems.firstIndex(where: { $0.peer.id == focusedPeerId }) {
|
|
||||||
centralIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if centralIndex == nil {
|
|
||||||
if !subscriptionItems.isEmpty {
|
|
||||||
centralIndex = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let centralIndex {
|
|
||||||
let centralPeerContext: PeerContext
|
|
||||||
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex].peer.id) {
|
|
||||||
centralPeerContext = existingContext
|
|
||||||
} else {
|
|
||||||
centralPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex].peer.id, focusedId: nil, loadIds: loadIds)
|
|
||||||
}
|
|
||||||
|
|
||||||
var previousPeerContext: PeerContext?
|
|
||||||
if centralIndex != 0 {
|
|
||||||
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex - 1].peer.id) {
|
|
||||||
previousPeerContext = existingContext
|
|
||||||
} else {
|
|
||||||
previousPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex - 1].peer.id, focusedId: nil, loadIds: loadIds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextPeerContext: PeerContext?
|
|
||||||
if centralIndex != subscriptionItems.count - 1 {
|
|
||||||
if let currentState = self.currentState, let existingContext = currentState.findPeerContext(id: subscriptionItems[centralIndex + 1].peer.id) {
|
|
||||||
nextPeerContext = existingContext
|
|
||||||
} else {
|
|
||||||
nextPeerContext = PeerContext(context: self.context, peerId: subscriptionItems[centralIndex + 1].peer.id, focusedId: nil, loadIds: loadIds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let pendingState = StateContext(
|
|
||||||
centralPeerContext: centralPeerContext,
|
|
||||||
previousPeerContext: previousPeerContext,
|
|
||||||
nextPeerContext: nextPeerContext
|
|
||||||
)
|
|
||||||
self.pendingState = pendingState
|
|
||||||
self.pendingStateReadyDisposable = (pendingState.updated.get()
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self, weak pendingState] _ in
|
|
||||||
guard let self, let pendingState, self.pendingState === pendingState, pendingState.isReady else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.pendingState = nil
|
|
||||||
self.pendingStateReadyDisposable?.dispose()
|
|
||||||
self.pendingStateReadyDisposable = nil
|
|
||||||
|
|
||||||
self.currentState = pendingState
|
|
||||||
|
|
||||||
self.updateState()
|
|
||||||
|
|
||||||
self.currentStateUpdatedDisposable?.dispose()
|
|
||||||
self.currentStateUpdatedDisposable = (pendingState.updated.get()
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self, weak pendingState] _ in
|
|
||||||
guard let self, let pendingState, self.currentState === pendingState else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.updateState()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ import StoryContainerScreen
|
|||||||
import StoryContentComponent
|
import StoryContentComponent
|
||||||
import MoreHeaderButton
|
import MoreHeaderButton
|
||||||
import VolumeButtons
|
import VolumeButtons
|
||||||
|
import ChatAvatarNavigationNode
|
||||||
import ChatContextQuery
|
import ChatContextQuery
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -562,6 +563,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
private var powerSavingMonitoringDisposable: Disposable?
|
private var powerSavingMonitoringDisposable: Disposable?
|
||||||
|
|
||||||
|
private var avatarNode: ChatAvatarNavigationNode?
|
||||||
|
|
||||||
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = []) {
|
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = []) {
|
||||||
let _ = ChatControllerCount.modify { value in
|
let _ = ChatControllerCount.modify { value in
|
||||||
return value + 1
|
return value + 1
|
||||||
@ -4688,7 +4691,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
}
|
}
|
||||||
|
|
||||||
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
||||||
|
self.avatarNode = avatarNode
|
||||||
|
|
||||||
|
avatarNode.updateStoryView(transition: .immediate, theme: self.presentationData.theme)
|
||||||
case .feed:
|
case .feed:
|
||||||
chatInfoButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
chatInfoButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import ChatTitleView
|
|||||||
import ChatInputNode
|
import ChatInputNode
|
||||||
import ChatEntityKeyboardInputNode
|
import ChatEntityKeyboardInputNode
|
||||||
import ChatControllerInteraction
|
import ChatControllerInteraction
|
||||||
|
import ChatAvatarNavigationNode
|
||||||
|
|
||||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||||
let itemNode: OverlayMediaItemNode
|
let itemNode: OverlayMediaItemNode
|
||||||
|
@ -16,26 +16,26 @@ import TextNodeWithEntities
|
|||||||
import AnimationCache
|
import AnimationCache
|
||||||
import MultiAnimationRenderer
|
import MultiAnimationRenderer
|
||||||
|
|
||||||
enum ChatMessageReplyInfoType {
|
public enum ChatMessageReplyInfoType {
|
||||||
case bubble(incoming: Bool)
|
case bubble(incoming: Bool)
|
||||||
case standalone
|
case standalone
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatMessageReplyInfoNode: ASDisplayNode {
|
public class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||||
class Arguments {
|
public class Arguments {
|
||||||
let presentationData: ChatPresentationData
|
public let presentationData: ChatPresentationData
|
||||||
let strings: PresentationStrings
|
public let strings: PresentationStrings
|
||||||
let context: AccountContext
|
public let context: AccountContext
|
||||||
let type: ChatMessageReplyInfoType
|
public let type: ChatMessageReplyInfoType
|
||||||
let message: Message?
|
public let message: Message?
|
||||||
let story: StoryId?
|
public let story: StoryId?
|
||||||
let parentMessage: Message
|
public let parentMessage: Message
|
||||||
let constrainedSize: CGSize
|
public let constrainedSize: CGSize
|
||||||
let animationCache: AnimationCache?
|
public let animationCache: AnimationCache?
|
||||||
let animationRenderer: MultiAnimationRenderer?
|
public let animationRenderer: MultiAnimationRenderer?
|
||||||
let associatedData: ChatMessageItemAssociatedData
|
public let associatedData: ChatMessageItemAssociatedData
|
||||||
|
|
||||||
init(
|
public init(
|
||||||
presentationData: ChatPresentationData,
|
presentationData: ChatPresentationData,
|
||||||
strings: PresentationStrings,
|
strings: PresentationStrings,
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -62,7 +62,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibility: Bool = false {
|
public var visibility: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if self.visibility != oldValue {
|
if self.visibility != oldValue {
|
||||||
self.textNode?.visibilityRect = self.visibility ? CGRect.infinite : nil
|
self.textNode?.visibilityRect = self.visibility ? CGRect.infinite : nil
|
||||||
@ -79,7 +79,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
private var previousMediaReference: AnyMediaReference?
|
private var previousMediaReference: AnyMediaReference?
|
||||||
private var expiredStoryIconView: UIImageView?
|
private var expiredStoryIconView: UIImageView?
|
||||||
|
|
||||||
override init() {
|
override public init() {
|
||||||
self.contentNode = ASDisplayNode()
|
self.contentNode = ASDisplayNode()
|
||||||
self.contentNode.isUserInteractionEnabled = false
|
self.contentNode.isUserInteractionEnabled = false
|
||||||
self.contentNode.displaysAsynchronously = false
|
self.contentNode.displaysAsynchronously = false
|
||||||
@ -97,7 +97,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
self.contentNode.addSubnode(self.lineNode)
|
self.contentNode.addSubnode(self.lineNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
class func asyncLayout(_ maybeNode: ChatMessageReplyInfoNode?) -> (_ arguments: Arguments) -> (CGSize, (Bool) -> ChatMessageReplyInfoNode) {
|
public static func asyncLayout(_ maybeNode: ChatMessageReplyInfoNode?) -> (_ arguments: Arguments) -> (CGSize, (Bool) -> ChatMessageReplyInfoNode) {
|
||||||
let titleNodeLayout = TextNode.asyncLayout(maybeNode?.titleNode)
|
let titleNodeLayout = TextNode.asyncLayout(maybeNode?.titleNode)
|
||||||
let textNodeLayout = TextNodeWithEntities.asyncLayout(maybeNode?.textNode)
|
let textNodeLayout = TextNodeWithEntities.asyncLayout(maybeNode?.textNode)
|
||||||
let imageNodeLayout = TransformImageNode.asyncLayout(maybeNode?.imageNode)
|
let imageNodeLayout = TransformImageNode.asyncLayout(maybeNode?.imageNode)
|
||||||
@ -583,7 +583,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mediaTransitionView() -> UIView? {
|
public func mediaTransitionView() -> UIView? {
|
||||||
if let imageNode = self.imageNode {
|
if let imageNode = self.imageNode {
|
||||||
return imageNode.view
|
return imageNode.view
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import AvatarVideoNode
|
|||||||
import PeerInfoVisualMediaPaneNode
|
import PeerInfoVisualMediaPaneNode
|
||||||
import AvatarStoryIndicatorComponent
|
import AvatarStoryIndicatorComponent
|
||||||
import ComponentDisplayAdapters
|
import ComponentDisplayAdapters
|
||||||
|
import ChatAvatarNavigationNode
|
||||||
|
|
||||||
enum PeerInfoHeaderButtonKey: Hashable {
|
enum PeerInfoHeaderButtonKey: Hashable {
|
||||||
case message
|
case message
|
||||||
|
@ -90,6 +90,7 @@ import PeerInfoVisualMediaPaneNode
|
|||||||
import PeerInfoStoryGridScreen
|
import PeerInfoStoryGridScreen
|
||||||
import StoryContainerScreen
|
import StoryContainerScreen
|
||||||
import StoryContentComponent
|
import StoryContentComponent
|
||||||
|
import ChatAvatarNavigationNode
|
||||||
|
|
||||||
enum PeerInfoAvatarEditingMode {
|
enum PeerInfoAvatarEditingMode {
|
||||||
case generic
|
case generic
|
||||||
|
Loading…
x
Reference in New Issue
Block a user