mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stories
This commit is contained in:
parent
9d8777443f
commit
a6d7f6d45d
@ -20,6 +20,8 @@ swift_library(
|
|||||||
"//submodules/Emoji:Emoji",
|
"//submodules/Emoji:Emoji",
|
||||||
"//submodules/TinyThumbnail:TinyThumbnail",
|
"//submodules/TinyThumbnail:TinyThumbnail",
|
||||||
"//submodules/FastBlur:FastBlur",
|
"//submodules/FastBlur:FastBlur",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -327,6 +327,8 @@ final class MutableMessageHistoryView {
|
|||||||
|
|
||||||
private var userId: Int64?
|
private var userId: Int64?
|
||||||
|
|
||||||
|
fileprivate var peerStoryStats: [PeerId: PeerStoryStats] = [:]
|
||||||
|
|
||||||
init(
|
init(
|
||||||
postbox: PostboxImpl,
|
postbox: PostboxImpl,
|
||||||
orderStatistics: MessageHistoryViewOrderStatistics,
|
orderStatistics: MessageHistoryViewOrderStatistics,
|
||||||
@ -388,6 +390,7 @@ final class MutableMessageHistoryView {
|
|||||||
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
|
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
|
||||||
|
|
||||||
self.render(postbox: postbox)
|
self.render(postbox: postbox)
|
||||||
|
let _ = self.updateStoryStats(postbox: postbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reset(postbox: PostboxImpl) {
|
private func reset(postbox: PostboxImpl) {
|
||||||
@ -411,6 +414,8 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
|
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
|
||||||
|
|
||||||
|
let _ = self.updateStoryStats(postbox: postbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
|
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
|
||||||
@ -907,6 +912,11 @@ final class MutableMessageHistoryView {
|
|||||||
if hasChanges {
|
if hasChanges {
|
||||||
self.render(postbox: postbox)
|
self.render(postbox: postbox)
|
||||||
}
|
}
|
||||||
|
if hasChanges || !transaction.currentStoryTopItemEvents.isEmpty || !transaction.storyPeerStatesEvents.isEmpty {
|
||||||
|
if self.updateStoryStats(postbox: postbox) {
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return hasChanges
|
return hasChanges
|
||||||
}
|
}
|
||||||
@ -920,6 +930,26 @@ final class MutableMessageHistoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateStoryStats(postbox: PostboxImpl) -> Bool {
|
||||||
|
//TODO:optimize refresh
|
||||||
|
var peerStoryStats: [PeerId: PeerStoryStats] = [:]
|
||||||
|
if case let .loaded(state) = self.sampledState {
|
||||||
|
for entry in state.entries {
|
||||||
|
if let author = entry.message.author {
|
||||||
|
if let value = fetchPeerStoryStats(postbox: postbox, peerId: author.id) {
|
||||||
|
peerStoryStats[author.id] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.peerStoryStats != peerStoryStats {
|
||||||
|
self.peerStoryStats = peerStoryStats
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func firstHole() -> (MessageHistoryViewHole, MessageHistoryViewRelativeHoleDirection, Int, Int64?)? {
|
func firstHole() -> (MessageHistoryViewHole, MessageHistoryViewRelativeHoleDirection, Int, Int64?)? {
|
||||||
switch self.sampledState {
|
switch self.sampledState {
|
||||||
case let .loading(loadingSample):
|
case let .loading(loadingSample):
|
||||||
@ -965,6 +995,7 @@ public final class MessageHistoryView {
|
|||||||
public let isLoading: Bool
|
public let isLoading: Bool
|
||||||
public let isLoadingEarlier: Bool
|
public let isLoadingEarlier: Bool
|
||||||
public let isAddedToChatList: Bool
|
public let isAddedToChatList: Bool
|
||||||
|
public let peerStoryStats: [PeerId: PeerStoryStats]
|
||||||
|
|
||||||
public init(tagMask: MessageTags?, namespaces: MessageIdNamespaces, entries: [MessageHistoryEntry], holeEarlier: Bool, holeLater: Bool, isLoading: Bool) {
|
public init(tagMask: MessageTags?, namespaces: MessageIdNamespaces, entries: [MessageHistoryEntry], holeEarlier: Bool, holeLater: Bool, isLoading: Bool) {
|
||||||
self.tagMask = tagMask
|
self.tagMask = tagMask
|
||||||
@ -983,6 +1014,7 @@ public final class MessageHistoryView {
|
|||||||
self.isLoading = isLoading
|
self.isLoading = isLoading
|
||||||
self.isLoadingEarlier = true
|
self.isLoadingEarlier = true
|
||||||
self.isAddedToChatList = false
|
self.isAddedToChatList = false
|
||||||
|
self.peerStoryStats = [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_ mutableView: MutableMessageHistoryView) {
|
init(_ mutableView: MutableMessageHistoryView) {
|
||||||
@ -1207,6 +1239,7 @@ public final class MessageHistoryView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
|
self.peerStoryStats = mutableView.peerStoryStats
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(base: MessageHistoryView, fixed combinedReadStates: MessageHistoryViewReadState?, transient transientReadStates: MessageHistoryViewReadState?) {
|
public init(base: MessageHistoryView, fixed combinedReadStates: MessageHistoryViewReadState?, transient transientReadStates: MessageHistoryViewReadState?) {
|
||||||
@ -1225,6 +1258,7 @@ public final class MessageHistoryView {
|
|||||||
self.isLoading = base.isLoading
|
self.isLoading = base.isLoading
|
||||||
self.isLoadingEarlier = base.isLoadingEarlier
|
self.isLoadingEarlier = base.isLoadingEarlier
|
||||||
self.isAddedToChatList = base.isAddedToChatList
|
self.isAddedToChatList = base.isAddedToChatList
|
||||||
|
self.peerStoryStats = base.peerStoryStats
|
||||||
|
|
||||||
if let combinedReadStates = combinedReadStates {
|
if let combinedReadStates = combinedReadStates {
|
||||||
switch combinedReadStates {
|
switch combinedReadStates {
|
||||||
|
@ -50,11 +50,10 @@ final class StoryTopItemsTable: Table {
|
|||||||
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let sharedKey = ValueBoxKey(length: 8 + 4)
|
|
||||||
|
|
||||||
private func key(_ key: Key) -> ValueBoxKey {
|
private func key(_ key: Key) -> ValueBoxKey {
|
||||||
self.sharedKey.setInt64(0, value: key.peerId.toInt64())
|
let keyValue = ValueBoxKey(length: 8)
|
||||||
return self.sharedKey
|
keyValue.setInt64(0, value: key.peerId.toInt64())
|
||||||
|
return keyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
public func get(peerId: PeerId) -> Entry? {
|
public func get(peerId: PeerId) -> Entry? {
|
||||||
@ -115,12 +114,11 @@ final class StoryItemsTable: Table {
|
|||||||
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let sharedKey = ValueBoxKey(length: 8 + 4)
|
|
||||||
|
|
||||||
private func key(_ key: Key) -> ValueBoxKey {
|
private func key(_ key: Key) -> ValueBoxKey {
|
||||||
self.sharedKey.setInt64(0, value: key.peerId.toInt64())
|
let keyValue = ValueBoxKey(length: 8 + 4)
|
||||||
self.sharedKey.setInt32(8, value: key.id)
|
keyValue.setInt64(0, value: key.peerId.toInt64())
|
||||||
return self.sharedKey
|
keyValue.setInt32(8, value: key.id)
|
||||||
|
return keyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private func lowerBound(peerId: PeerId) -> ValueBoxKey {
|
private func lowerBound(peerId: PeerId) -> ValueBoxKey {
|
||||||
@ -159,6 +157,8 @@ final class StoryItemsTable: Table {
|
|||||||
self.valueBox.range(self.table, start: self.lowerBound(peerId: peerId), end: self.upperBound(peerId: peerId), values: { key, value in
|
self.valueBox.range(self.table, start: self.lowerBound(peerId: peerId), end: self.upperBound(peerId: peerId), values: { key, value in
|
||||||
let id = key.getInt32(8)
|
let id = key.getInt32(8)
|
||||||
|
|
||||||
|
assert(peerId.toInt64() == key.getInt64(0))
|
||||||
|
|
||||||
let entry: CodableEntry
|
let entry: CodableEntry
|
||||||
var expirationTimestamp: Int32?
|
var expirationTimestamp: Int32?
|
||||||
|
|
||||||
|
@ -1127,7 +1127,7 @@ func _internal_markStoryAsSeen(account: Account, peerId: PeerId, id: Int32, asPi
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG && true
|
#if DEBUG && false
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@ -1156,7 +1156,7 @@ func _internal_markStoryAsSeen(account: Account, peerId: PeerId, id: Int32, asPi
|
|||||||
|
|
||||||
account.stateManager.injectStoryUpdates(updates: [.read(peerId: peerId, maxId: id)])
|
account.stateManager.injectStoryUpdates(updates: [.read(peerId: peerId, maxId: id)])
|
||||||
|
|
||||||
#if DEBUG && false
|
#if DEBUG && true
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ public final class ChatControllerInteraction {
|
|||||||
public enum OpenPeerSource {
|
public enum OpenPeerSource {
|
||||||
case `default`
|
case `default`
|
||||||
case reaction
|
case reaction
|
||||||
case groupParticipant
|
case groupParticipant(storyStats: PeerStoryStats?, avatarHeaderNode: ASDisplayNode?)
|
||||||
}
|
}
|
||||||
|
|
||||||
public let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool
|
public let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool
|
||||||
|
@ -1426,7 +1426,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
transitionViewImpl.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
transitionViewImpl.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
leftInfoView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
contentContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||||
|
self.controlsContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||||
|
|
||||||
for transitionViewImpl in transitionViewsImpl {
|
for transitionViewImpl in transitionViewsImpl {
|
||||||
transition.setFrame(view: transitionViewImpl, frame: sourceLocalFrame)
|
transition.setFrame(view: transitionViewImpl, frame: sourceLocalFrame)
|
||||||
|
@ -56,7 +56,7 @@ private func calculateCircleIntersection(center: CGPoint, otherCenter: CGPoint,
|
|||||||
return (point1Angle, point2Angle)
|
return (point1Angle, point2Angle)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func calculateMergingCircleShape(center: CGPoint, leftCenter: CGPoint?, rightCenter: CGPoint?, radius: CGFloat, totalCount: Int, unseenCount: Int, isSeen: Bool) -> CGPath {
|
private func calculateMergingCircleShape(center: CGPoint, leftCenter: CGPoint?, rightCenter: CGPoint?, radius: CGFloat, totalCount: Int, unseenCount: Int, isSeen: Bool, segmentFraction: CGFloat) -> CGPath {
|
||||||
let leftAngles = leftCenter.flatMap { calculateCircleIntersection(center: center, otherCenter: $0, radius: radius) }
|
let leftAngles = leftCenter.flatMap { calculateCircleIntersection(center: center, otherCenter: $0, radius: radius) }
|
||||||
let rightAngles = rightCenter.flatMap { calculateCircleIntersection(center: center, otherCenter: $0, radius: radius) }
|
let rightAngles = rightCenter.flatMap { calculateCircleIntersection(center: center, otherCenter: $0, radius: radius) }
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ private func calculateMergingCircleShape(center: CGPoint, leftCenter: CGPoint?,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let segmentSpacing: CGFloat = 4.0
|
let segmentSpacing: CGFloat = 4.0 * segmentFraction
|
||||||
let segmentSpacingAngle: CGFloat = segmentSpacing / radius
|
let segmentSpacingAngle: CGFloat = segmentSpacing / radius
|
||||||
let segmentAngle = (2.0 * CGFloat.pi - segmentSpacingAngle * CGFloat(segmentCount)) / CGFloat(segmentCount)
|
let segmentAngle = (2.0 * CGFloat.pi - segmentSpacingAngle * CGFloat(segmentCount)) / CGFloat(segmentCount)
|
||||||
for i in 0 ..< segmentCount {
|
for i in 0 ..< segmentCount {
|
||||||
@ -111,7 +111,9 @@ private func calculateMergingCircleShape(center: CGPoint, leftCenter: CGPoint?,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let startAngle = segmentSpacingAngle * 0.5 - CGFloat.pi * 0.5 + CGFloat(i) * (segmentSpacingAngle + segmentAngle)
|
var startAngle = segmentSpacingAngle * 0.5 - CGFloat.pi * 0.5 + CGFloat(i) * (segmentSpacingAngle + segmentAngle)
|
||||||
|
startAngle += (1.0 - segmentFraction) * CGFloat.pi * 2.0 * 0.25
|
||||||
|
|
||||||
let endAngle = startAngle + segmentAngle
|
let endAngle = startAngle + segmentAngle
|
||||||
path.move(to: CGPoint(x: center.x + cos(startAngle) * radius, y: center.y + sin(startAngle) * radius))
|
path.move(to: CGPoint(x: center.x + cos(startAngle) * radius, y: center.y + sin(startAngle) * radius))
|
||||||
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
|
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
|
||||||
@ -765,8 +767,8 @@ public final class StoryPeerListItemComponent: Component {
|
|||||||
}
|
}
|
||||||
Transition.immediate.setShapeLayerPath(layer: self.avatarShapeLayer, path: avatarPath)
|
Transition.immediate.setShapeLayerPath(layer: self.avatarShapeLayer, path: avatarPath)
|
||||||
|
|
||||||
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeSeenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: true))
|
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeSeenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: true, segmentFraction: component.expandedAlphaFraction))
|
||||||
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeUnseenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: false))
|
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeUnseenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: false, segmentFraction: component.expandedAlphaFraction))
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
let titleString: String
|
let titleString: String
|
||||||
@ -810,7 +812,7 @@ public final class StoryPeerListItemComponent: Component {
|
|||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(string: titleString, font: Font.regular(11.0), textColor: component.theme.list.itemPrimaryTextColor)),
|
text: .plain(NSAttributedString(string: titleString, font: Font.regular(11.0), textColor: (component.unseenCount != 0 || component.peer.id == component.context.account.peerId) ? component.theme.list.itemPrimaryTextColor : component.theme.list.itemPrimaryTextColor.withMultipliedAlpha(0.5))),
|
||||||
maximumNumberOfLines: 1
|
maximumNumberOfLines: 1
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -840,7 +842,7 @@ public final class StoryPeerListItemComponent: Component {
|
|||||||
self.progressLayer = progressLayer
|
self.progressLayer = progressLayer
|
||||||
self.indicatorMaskUnseenLayer.addSublayer(progressLayer)
|
self.indicatorMaskUnseenLayer.addSublayer(progressLayer)
|
||||||
}
|
}
|
||||||
let progressFrame = CGRect(origin: CGPoint(), size: indicatorFrame.size).insetBy(dx: 2.0, dy: 2.0)
|
let progressFrame = CGRect(origin: CGPoint(), size: indicatorFrame.size).insetBy(dx: 4.0, dy: 4.0)
|
||||||
progressTransition.setFrame(layer: progressLayer, frame: progressFrame)
|
progressTransition.setFrame(layer: progressLayer, frame: progressFrame)
|
||||||
|
|
||||||
switch ringAnimation {
|
switch ringAnimation {
|
||||||
@ -851,9 +853,9 @@ public final class StoryPeerListItemComponent: Component {
|
|||||||
} else {
|
} else {
|
||||||
progressTransition = .easeInOut(duration: 0.3)
|
progressTransition = .easeInOut(duration: 0.3)
|
||||||
}
|
}
|
||||||
progressLayer.update(size: progressFrame.size, lineWidth: 4.0, value: .progress(progress), transition: progressTransition)
|
progressLayer.update(size: progressFrame.size, lineWidth: indicatorLineUnseenWidth, value: .progress(progress), transition: progressTransition)
|
||||||
case .loading:
|
case .loading:
|
||||||
progressLayer.update(size: progressFrame.size, lineWidth: 4.0, value: .indefinite, transition: transition)
|
progressLayer.update(size: progressFrame.size, lineWidth: indicatorLineUnseenWidth, value: .indefinite, transition: transition)
|
||||||
}
|
}
|
||||||
self.indicatorShapeSeenLayer.opacity = 0.0
|
self.indicatorShapeSeenLayer.opacity = 0.0
|
||||||
self.indicatorShapeUnseenLayer.opacity = 0.0
|
self.indicatorShapeUnseenLayer.opacity = 0.0
|
||||||
|
@ -1162,7 +1162,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
}, openPeer: { [weak self] peer, navigation, fromMessage, source in
|
}, openPeer: { [weak self] peer, navigation, fromMessage, source in
|
||||||
self?.openPeer(peer: peer, navigation: navigation, fromMessage: fromMessage, fromReactionMessageId: source == .reaction ? fromMessage?.id : nil, expandAvatar: source == .groupParticipant)
|
var expandAvatar = false
|
||||||
|
if case let .groupParticipant(storyStats, avatarHeaderNode) = source {
|
||||||
|
if let storyStats, storyStats.totalCount != 0, let avatarHeaderNode = avatarHeaderNode as? ChatMessageAvatarHeaderNode {
|
||||||
|
self?.openStories(peerId: peer.id, avatarHeaderNode: avatarHeaderNode)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
expandAvatar = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fromReactionMessageId: MessageId?
|
||||||
|
if case .reaction = source {
|
||||||
|
fromReactionMessageId = fromMessage?.id
|
||||||
|
}
|
||||||
|
self?.openPeer(peer: peer, navigation: navigation, fromMessage: fromMessage, fromReactionMessageId: fromReactionMessageId, expandAvatar: expandAvatar)
|
||||||
}, openPeerMention: { [weak self] name in
|
}, openPeerMention: { [weak self] name in
|
||||||
self?.openPeerMention(name)
|
self?.openPeerMention(name)
|
||||||
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, anyRecognizer, location in
|
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, anyRecognizer, location in
|
||||||
@ -16998,6 +17011,72 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func openStories(peerId: EnginePeer.Id, avatarHeaderNode: ChatMessageAvatarHeaderNode) {
|
||||||
|
let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: peerId, singlePeer: true)
|
||||||
|
let _ = (storyContent.state
|
||||||
|
|> filter { $0.slice != nil }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self, weak avatarHeaderNode] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var transitionIn: StoryContainerScreen.TransitionIn?
|
||||||
|
if let avatarHeaderNode {
|
||||||
|
transitionIn = StoryContainerScreen.TransitionIn(
|
||||||
|
sourceView: avatarHeaderNode.avatarNode.view,
|
||||||
|
sourceRect: avatarHeaderNode.avatarNode.view.bounds,
|
||||||
|
sourceCornerRadius: avatarHeaderNode.avatarNode.view.bounds.width * 0.5,
|
||||||
|
sourceIsAvatar: false
|
||||||
|
)
|
||||||
|
avatarHeaderNode.avatarNode.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let storyContainerScreen = StoryContainerScreen(
|
||||||
|
context: self.context,
|
||||||
|
content: storyContent,
|
||||||
|
transitionIn: transitionIn,
|
||||||
|
transitionOut: { peerId, _ in
|
||||||
|
guard let avatarHeaderNode else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let destinationView = avatarHeaderNode.avatarNode.view
|
||||||
|
return StoryContainerScreen.TransitionOut(
|
||||||
|
destinationView: destinationView,
|
||||||
|
transitionView: StoryContainerScreen.TransitionView(
|
||||||
|
makeView: { [weak destinationView] in
|
||||||
|
let parentView = UIView()
|
||||||
|
if let copyView = destinationView?.snapshotContentTree(unhide: true) {
|
||||||
|
parentView.addSubview(copyView)
|
||||||
|
}
|
||||||
|
return parentView
|
||||||
|
},
|
||||||
|
updateView: { copyView, state, transition in
|
||||||
|
guard let view = copyView.subviews.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let size = state.sourceSize.interpolate(to: state.destinationSize, amount: state.progress)
|
||||||
|
transition.setPosition(view: view, position: CGPoint(x: size.width * 0.5, y: size.height * 0.5))
|
||||||
|
transition.setScale(view: view, scale: size.width / state.destinationSize.width)
|
||||||
|
},
|
||||||
|
insertCloneTransitionView: nil
|
||||||
|
),
|
||||||
|
destinationRect: destinationView.bounds,
|
||||||
|
destinationCornerRadius: destinationView.bounds.width * 0.5,
|
||||||
|
destinationIsAvatar: false,
|
||||||
|
completed: { [weak avatarHeaderNode] in
|
||||||
|
guard let avatarHeaderNode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
avatarHeaderNode.avatarNode.isHidden = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.push(storyContainerScreen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private func openPeerMention(_ name: String, navigation: ChatControllerInteractionNavigateToPeer = .default, sourceMessageId: MessageId? = nil) {
|
private func openPeerMention(_ name: String, navigation: ChatControllerInteractionNavigateToPeer = .default, sourceMessageId: MessageId? = nil) {
|
||||||
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||||
let disposable: MetaDisposable
|
let disposable: MetaDisposable
|
||||||
|
@ -101,7 +101,7 @@ func chatHistoryEntriesForView(
|
|||||||
|
|
||||||
if let maybeJoinMessage = joinMessage {
|
if let maybeJoinMessage = joinMessage {
|
||||||
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
||||||
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil)))
|
||||||
joinMessage = nil
|
joinMessage = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false), entry.location))
|
groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }), entry.location))
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
if let selectedMessages = selectedMessages {
|
if let selectedMessages = selectedMessages {
|
||||||
@ -190,7 +190,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false)))
|
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] })))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
@ -199,7 +199,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false)))
|
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] })))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ func chatHistoryEntriesForView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let maybeJoinMessage = joinMessage, !view.holeLater {
|
if let maybeJoinMessage = joinMessage, !view.holeLater {
|
||||||
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil)))
|
||||||
joinMessage = nil
|
joinMessage = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,12 +283,12 @@ func chatHistoryEntriesForView(
|
|||||||
if messages.count > 1, let groupInfo = messages[0].groupInfo {
|
if messages.count > 1, let groupInfo = messages[0].groupInfo {
|
||||||
var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
|
var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
|
||||||
for message in messages {
|
for message in messages {
|
||||||
groupMessages.append((message, false, .none, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false), nil))
|
groupMessages.append((message, false, .none, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false, authorStoryStats: message.author.flatMap { view.peerStoryStats[$0.id] }), nil))
|
||||||
}
|
}
|
||||||
entries.insert(.MessageGroupEntry(groupInfo, groupMessages, presentationData), at: 0)
|
entries.insert(.MessageGroupEntry(groupInfo, groupMessages, presentationData), at: 0)
|
||||||
} else {
|
} else {
|
||||||
if !hasTopicCreated {
|
if !hasTopicCreated {
|
||||||
entries.insert(.MessageEntry(messages[0], presentationData, false, nil, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[messages[0].id], isPlaying: false, isCentered: false)), at: 0)
|
entries.insert(.MessageEntry(messages[0], presentationData, false, nil, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[messages[0].id], isPlaying: false, isCentered: false, authorStoryStats: messages[0].author.flatMap { view.peerStoryStats[$0.id] })), at: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +362,7 @@ func chatHistoryEntriesForView(
|
|||||||
if !dynamicAdMessages.isEmpty {
|
if !dynamicAdMessages.isEmpty {
|
||||||
assert(entries.sorted() == entries)
|
assert(entries.sorted() == entries)
|
||||||
for message in dynamicAdMessages {
|
for message in dynamicAdMessages {
|
||||||
entries.append(.MessageEntry(message, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
entries.append(.MessageEntry(message, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil)))
|
||||||
}
|
}
|
||||||
entries.sort()
|
entries.sort()
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@ func chatHistoryEntriesForView(
|
|||||||
associatedStories: message.associatedStories
|
associatedStories: message.associatedStories
|
||||||
)
|
)
|
||||||
nextAdMessageId += 1
|
nextAdMessageId += 1
|
||||||
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if includeSearchEntry {
|
} else if includeSearchEntry {
|
||||||
|
@ -18,14 +18,16 @@ public struct ChatMessageEntryAttributes: Equatable {
|
|||||||
var updatingMedia: ChatUpdatingMessageMedia?
|
var updatingMedia: ChatUpdatingMessageMedia?
|
||||||
var isPlaying: Bool
|
var isPlaying: Bool
|
||||||
var isCentered: Bool
|
var isCentered: Bool
|
||||||
|
var authorStoryStats: PeerStoryStats?
|
||||||
|
|
||||||
init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool, isCentered: Bool) {
|
init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool, isCentered: Bool, authorStoryStats: PeerStoryStats?) {
|
||||||
self.rank = rank
|
self.rank = rank
|
||||||
self.isContact = isContact
|
self.isContact = isContact
|
||||||
self.contentTypeHint = contentTypeHint
|
self.contentTypeHint = contentTypeHint
|
||||||
self.updatingMedia = updatingMedia
|
self.updatingMedia = updatingMedia
|
||||||
self.isPlaying = isPlaying
|
self.isPlaying = isPlaying
|
||||||
self.isCentered = isCentered
|
self.isCentered = isCentered
|
||||||
|
self.authorStoryStats = authorStoryStats
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
@ -35,6 +37,7 @@ public struct ChatMessageEntryAttributes: Equatable {
|
|||||||
self.updatingMedia = nil
|
self.updatingMedia = nil
|
||||||
self.isPlaying = false
|
self.isPlaying = false
|
||||||
self.isCentered = false
|
self.isCentered = false
|
||||||
|
self.authorStoryStats = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,8 +374,9 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
|||||||
let presentationData: ChatPresentationData
|
let presentationData: ChatPresentationData
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let controllerInteraction: ChatControllerInteraction
|
let controllerInteraction: ChatControllerInteraction
|
||||||
|
let storyStats: PeerStoryStats?
|
||||||
|
|
||||||
init(timestamp: Int32, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, message: Message, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction) {
|
init(timestamp: Int32, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, message: Message, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, storyStats: PeerStoryStats?) {
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.messageReference = messageReference
|
self.messageReference = messageReference
|
||||||
@ -395,6 +396,7 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
self.id = ListViewItemNode.HeaderId(space: 1, id: Id(peerId: peerId, timestampId: dateHeaderTimestampId(timestamp: timestamp)))
|
self.id = ListViewItemNode.HeaderId(space: 1, id: Id(peerId: peerId, timestampId: dateHeaderTimestampId(timestamp: timestamp)))
|
||||||
|
self.storyStats = storyStats
|
||||||
}
|
}
|
||||||
|
|
||||||
let stickDirection: ListViewItemHeaderStickDirection = .top
|
let stickDirection: ListViewItemHeaderStickDirection = .top
|
||||||
@ -414,14 +416,15 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
|
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
|
||||||
return ChatMessageAvatarHeaderNode(peerId: self.peerId, peer: self.peer, messageReference: self.messageReference, adMessageId: self.adMessageId, presentationData: self.presentationData, context: self.context, controllerInteraction: self.controllerInteraction, synchronousLoad: synchronousLoad)
|
return ChatMessageAvatarHeaderNode(peerId: self.peerId, peer: self.peer, messageReference: self.messageReference, adMessageId: self.adMessageId, presentationData: self.presentationData, context: self.context, controllerInteraction: self.controllerInteraction, storyStats: self.storyStats, synchronousLoad: synchronousLoad)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) {
|
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) {
|
||||||
guard let node = node as? ChatMessageAvatarHeaderNode, let next = next as? ChatMessageAvatarHeader else {
|
guard let node = node as? ChatMessageAvatarHeaderNode else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node.updatePresentationData(next.presentationData, context: next.context)
|
node.updatePresentationData(self.presentationData, context: self.context)
|
||||||
|
node.updateStoryStats(storyStats: self.storyStats, theme: self.presentationData.theme.theme, force: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +436,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var presentationData: ChatPresentationData
|
private var presentationData: ChatPresentationData
|
||||||
private let controllerInteraction: ChatControllerInteraction
|
private let controllerInteraction: ChatControllerInteraction
|
||||||
|
private var storyStats: PeerStoryStats?
|
||||||
|
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
private let messageReference: MessageReference?
|
private let messageReference: MessageReference?
|
||||||
@ -440,7 +444,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
private let adMessageId: EngineMessage.Id?
|
private let adMessageId: EngineMessage.Id?
|
||||||
|
|
||||||
private let containerNode: ContextControllerSourceNode
|
private let containerNode: ContextControllerSourceNode
|
||||||
private let avatarNode: AvatarNode
|
let avatarNode: AvatarNode
|
||||||
private var avatarVideoNode: AvatarVideoNode?
|
private var avatarVideoNode: AvatarVideoNode?
|
||||||
|
|
||||||
private var cachedDataDisposable = MetaDisposable()
|
private var cachedDataDisposable = MetaDisposable()
|
||||||
@ -459,7 +463,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(peerId: PeerId, peer: Peer?, messageReference: MessageReference?, adMessageId: EngineMessage.Id?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, synchronousLoad: Bool) {
|
init(peerId: PeerId, peer: Peer?, messageReference: MessageReference?, adMessageId: EngineMessage.Id?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, storyStats: PeerStoryStats?, synchronousLoad: Bool) {
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.messageReference = messageReference
|
self.messageReference = messageReference
|
||||||
@ -467,6 +471,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.context = context
|
self.context = context
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
|
self.storyStats = storyStats
|
||||||
|
|
||||||
self.containerNode = ContextControllerSourceNode()
|
self.containerNode = ContextControllerSourceNode()
|
||||||
|
|
||||||
@ -482,6 +487,10 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
self.setPeer(context: context, theme: presentationData.theme.theme, synchronousLoad: synchronousLoad, peer: peer, authorOfMessage: messageReference, emptyColor: .black)
|
self.setPeer(context: context, theme: presentationData.theme.theme, synchronousLoad: synchronousLoad, peer: peer, authorOfMessage: messageReference, emptyColor: .black)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let storyStats {
|
||||||
|
self.updateStoryStats(storyStats: storyStats, theme: presentationData.theme.theme, force: true)
|
||||||
|
}
|
||||||
|
|
||||||
self.containerNode.activated = { [weak self] gesture, _ in
|
self.containerNode.activated = { [weak self] gesture, _ in
|
||||||
guard let strongSelf = self, let peer = strongSelf.peer else {
|
guard let strongSelf = self, let peer = strongSelf.peer else {
|
||||||
@ -595,6 +604,18 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
self.hierarchyTrackingLayer = nil
|
self.hierarchyTrackingLayer = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateStoryStats(storyStats: PeerStoryStats?, theme: PresentationTheme, force: Bool) {
|
||||||
|
if self.storyStats != storyStats || self.presentationData.theme.theme !== theme || force {
|
||||||
|
self.avatarNode.setStoryStats(storyStats: storyStats.flatMap { storyStats in
|
||||||
|
return AvatarNode.StoryStats(
|
||||||
|
totalCount: storyStats.totalCount,
|
||||||
|
unseenCount: storyStats.unseenCount,
|
||||||
|
hasUnseenCloseFriendsItems: false
|
||||||
|
)
|
||||||
|
}, theme: theme, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
@ -603,9 +624,10 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: ChatPresentationData, context: AccountContext) {
|
func updatePresentationData(_ presentationData: ChatPresentationData, context: AccountContext) {
|
||||||
self.presentationData = presentationData
|
if self.presentationData !== presentationData {
|
||||||
|
self.presentationData = presentationData
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||||
@ -663,7 +685,7 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||||
self.controllerInteraction.openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: nil, peekData: nil), self.messageReference, .default)
|
self.controllerInteraction.openPeer(EnginePeer(peer), .chat(textInputState: nil, subject: nil, peekData: nil), self.messageReference, .default)
|
||||||
} else {
|
} else {
|
||||||
self.controllerInteraction.openPeer(EnginePeer(peer), .info, self.messageReference, .groupParticipant)
|
self.controllerInteraction.openPeer(EnginePeer(peer), .info, self.messageReference, .groupParticipant(storyStats: self.storyStats, avatarHeaderNode: self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,7 +406,15 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
|
|
||||||
if hasAvatar {
|
if hasAvatar {
|
||||||
if let effectiveAuthor = effectiveAuthor {
|
if let effectiveAuthor = effectiveAuthor {
|
||||||
avatarHeader = ChatMessageAvatarHeader(timestamp: content.index.timestamp, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), message: message, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction)
|
let storyStats: PeerStoryStats?
|
||||||
|
switch content {
|
||||||
|
case let .message(_, _, _, attributes, _):
|
||||||
|
storyStats = attributes.authorStoryStats
|
||||||
|
case let .group(messages):
|
||||||
|
storyStats = messages.first?.3.authorStoryStats
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarHeader = ChatMessageAvatarHeader(timestamp: content.index.timestamp, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), message: message, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction, storyStats: storyStats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user