Video avatar fixes

This commit is contained in:
Ilya Laktyushin 2020-07-10 05:31:32 +03:00
parent eebcab90b9
commit aaff05021d
14 changed files with 320 additions and 88 deletions

View File

@ -928,8 +928,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let transformedCopyViewFinalFrame = videoNode.view.convert(videoNode.view.bounds, to: self.view) let transformedCopyViewFinalFrame = videoNode.view.convert(videoNode.view.bounds, to: self.view)
let (maybeSurfaceCopyView, _) = node.2() let (maybeSurfaceCopyView, _) = node.2()
let (maybeCopyView, copyViewBackgrond) = node.2() let (maybeCopyView, copyViewBackground) = node.2()
copyViewBackgrond?.alpha = 0.0 copyViewBackground?.alpha = 0.0
let surfaceCopyView = maybeSurfaceCopyView! let surfaceCopyView = maybeSurfaceCopyView!
let copyView = maybeCopyView! let copyView = maybeCopyView!
@ -1032,8 +1032,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var copyCompleted = false var copyCompleted = false
let (maybeSurfaceCopyView, _) = node.2() let (maybeSurfaceCopyView, _) = node.2()
let (maybeCopyView, copyViewBackgrond) = node.2() let (maybeCopyView, copyViewBackground) = node.2()
copyViewBackgrond?.alpha = 0.0 copyViewBackground?.alpha = 0.0
let surfaceCopyView = maybeSurfaceCopyView! let surfaceCopyView = maybeSurfaceCopyView!
let copyView = maybeCopyView! let copyView = maybeCopyView!

View File

@ -1716,7 +1716,7 @@
CGFloat duration = self.view.frame.size.height / velocity; CGFloat duration = self.view.frame.size.height / velocity;
CGRect targetFrame = CGRectOffset(self.view.frame, 0, self.view.frame.size.height); CGRect targetFrame = CGRectOffset(self.view.frame, 0, self.view.frame.size.height);
[UIView animateWithDuration:duration animations:^ [UIView animateWithDuration:duration delay:0.4 options:kNilOptions animations:^
{ {
self.view.frame = targetFrame; self.view.frame = targetFrame;
} completion:^(__unused BOOL finished) } completion:^(__unused BOOL finished)

View File

@ -112,39 +112,53 @@ public func normalizeEntries(_ entries: [AvatarGalleryEntry]) -> [AvatarGalleryE
return updatedEntries return updatedEntries
} }
public func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry] { public func initialAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> {
var initialEntries: [AvatarGalleryEntry] = [] var initialEntries: [AvatarGalleryEntry] = []
if !peer.profileImageRepresentations.isEmpty, let peerReference = PeerReference(peer) { if !peer.profileImageRepresentations.isEmpty, let peerReference = PeerReference(peer) {
initialEntries.append(.topImage(peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), nil, nil, nil)) initialEntries.append(.topImage(peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), nil, nil, nil))
} }
return initialEntries
if let peer = peer as? TelegramChannel {
return account.postbox.transaction { transaction in
return transaction.getPeerCachedData(peerId: peer.id)
} |> map { cachedData in
if let cachedData = cachedData as? CachedChannelData, let photo = cachedData.photo {
return [.image(photo.imageId, photo.reference, photo.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.videoRepresentations, peer, 0, nil, nil, photo.immediateThumbnailData, nil)]
} else {
return initialEntries
}
}
} else {
return .single(initialEntries)
}
} }
public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> { public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> {
let initialEntries = initialAvatarGalleryEntries(peer: peer) return initialAvatarGalleryEntries(account: account, peer: peer)
return Signal<[AvatarGalleryEntry], NoError>.single(initialEntries) |> mapToSignal { initialEntries in
|> then( return .single(initialEntries)
requestPeerPhotos(account: account, peerId: peer.id) |> then(
|> map { photos -> [AvatarGalleryEntry] in requestPeerPhotos(account: account, peerId: peer.id)
var result: [AvatarGalleryEntry] = [] |> map { photos -> [AvatarGalleryEntry] in
let initialEntries = initialAvatarGalleryEntries(peer: peer) var result: [AvatarGalleryEntry] = []
if photos.isEmpty { if photos.isEmpty {
result = initialEntries result = initialEntries
} else { } else {
var index: Int32 = 0 var index: Int32 = 0
for photo in photos { for photo in photos {
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
if result.isEmpty, let first = initialEntries.first { if result.isEmpty, let first = initialEntries.first {
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil)) result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
} else { } else {
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil)) result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData, nil))
}
index += 1
} }
index += 1
} }
return result
} }
return result )
} }
)
} }
public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry: AvatarGalleryEntry) -> Signal<[AvatarGalleryEntry], NoError> { public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry: AvatarGalleryEntry) -> Signal<[AvatarGalleryEntry], NoError> {
@ -242,7 +256,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
remoteEntriesSignal = fetchedAvatarGalleryEntries(account: context.account, peer: peer) remoteEntriesSignal = fetchedAvatarGalleryEntries(account: context.account, peer: peer)
} }
let entriesSignal: Signal<[AvatarGalleryEntry], NoError> = .single(initialAvatarGalleryEntries(peer: peer)) |> then(remoteEntriesSignal) let entriesSignal: Signal<[AvatarGalleryEntry], NoError> = initialAvatarGalleryEntries(account: context.account, peer: peer) |> then(remoteEntriesSignal)
let presentationData = self.presentationData let presentationData = self.presentationData

View File

@ -449,7 +449,10 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
var copyCompleted = false var copyCompleted = false
var surfaceCopyCompleted = false var surfaceCopyCompleted = false
let copyView = node.2().0! let (maybeCopyView, copyViewBackground) = node.2()
copyViewBackground?.alpha = 1.0
let copyView = maybeCopyView!
if self.sourceHasRoundCorners { if self.sourceHasRoundCorners {
self.view.insertSubview(copyView, belowSubview: self.scrollNode.view) self.view.insertSubview(copyView, belowSubview: self.scrollNode.view)

View File

@ -168,6 +168,7 @@ public final class CachedChannelData: CachedPeerData {
public let hasScheduledMessages: Bool public let hasScheduledMessages: Bool
public let statsDatacenterId: Int32 public let statsDatacenterId: Int32
public let invitedBy: PeerId? public let invitedBy: PeerId?
public let photo: TelegramMediaImage?
public let peerIds: Set<PeerId> public let peerIds: Set<PeerId>
public let messageIds: Set<MessageId> public let messageIds: Set<MessageId>
@ -196,9 +197,10 @@ public final class CachedChannelData: CachedPeerData {
self.hasScheduledMessages = false self.hasScheduledMessages = false
self.statsDatacenterId = 0 self.statsDatacenterId = 0
self.invitedBy = nil self.invitedBy = nil
self.photo = nil
} }
public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32, invitedBy: PeerId?) { public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32, invitedBy: PeerId?, photo: TelegramMediaImage?) {
self.isNotAccessible = isNotAccessible self.isNotAccessible = isNotAccessible
self.flags = flags self.flags = flags
self.about = about self.about = about
@ -217,6 +219,7 @@ public final class CachedChannelData: CachedPeerData {
self.hasScheduledMessages = hasScheduledMessages self.hasScheduledMessages = hasScheduledMessages
self.statsDatacenterId = statsDatacenterId self.statsDatacenterId = statsDatacenterId
self.invitedBy = invitedBy self.invitedBy = invitedBy
self.photo = photo
var peerIds = Set<PeerId>() var peerIds = Set<PeerId>()
for botInfo in botInfos { for botInfo in botInfos {
@ -242,75 +245,79 @@ public final class CachedChannelData: CachedPeerData {
} }
public func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { public func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData {
return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { public func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedAbout(_ about: String?) -> CachedChannelData { public func withUpdatedAbout(_ about: String?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { public func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { public func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { public func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { public func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> CachedChannelData { public func withUpdatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedSlowModeTimeout(_ slowModeTimeout: Int32?) -> CachedChannelData { public func withUpdatedSlowModeTimeout(_ slowModeTimeout: Int32?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedSlowModeValidUntilTimestamp(_ slowModeValidUntilTimestamp: Int32?) -> CachedChannelData { public func withUpdatedSlowModeValidUntilTimestamp(_ slowModeValidUntilTimestamp: Int32?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedChannelData { public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedStatsDatacenterId(_ statsDatacenterId: Int32) -> CachedChannelData { public func withUpdatedStatsDatacenterId(_ statsDatacenterId: Int32) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId, invitedBy: self.invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedChannelData { public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: invitedBy) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: invitedBy, photo: self.photo)
}
public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: photo)
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -372,6 +379,12 @@ public final class CachedChannelData: CachedPeerData {
self.invitedBy = decoder.decodeOptionalInt64ForKey("invBy").flatMap(PeerId.init) self.invitedBy = decoder.decodeOptionalInt64ForKey("invBy").flatMap(PeerId.init)
if let photo = decoder.decodeObjectForKey("ph", decoder: { TelegramMediaImage(decoder: $0) }) as? TelegramMediaImage {
self.photo = photo
} else {
self.photo = nil
}
if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { if let linkedDiscussionPeerId = self.linkedDiscussionPeerId {
peerIds.insert(linkedDiscussionPeerId) peerIds.insert(linkedDiscussionPeerId)
} }
@ -462,6 +475,12 @@ public final class CachedChannelData: CachedPeerData {
} else { } else {
encoder.encodeNil(forKey: "invBy") encoder.encodeNil(forKey: "invBy")
} }
if let photo = self.photo {
encoder.encodeObject(photo, forKey: "ph")
} else {
encoder.encodeNil(forKey: "ph")
}
} }
public func isEqual(to: CachedPeerData) -> Bool { public func isEqual(to: CachedPeerData) -> Bool {
@ -541,6 +560,10 @@ public final class CachedChannelData: CachedPeerData {
return false return false
} }
if other.photo != self.photo {
return false
}
return true return true
} }
} }

View File

@ -36,7 +36,7 @@ public enum AdminLogEventAction {
case changeTitle(prev: String, new: String) case changeTitle(prev: String, new: String)
case changeAbout(prev: String, new: String) case changeAbout(prev: String, new: String)
case changeUsername(prev: String, new: String) case changeUsername(prev: String, new: String)
case changePhoto(prev: [TelegramMediaImageRepresentation], new: [TelegramMediaImageRepresentation]) case changePhoto(prev: ([TelegramMediaImageRepresentation], [TelegramMediaImage.VideoRepresentation]), new: ([TelegramMediaImageRepresentation], [TelegramMediaImage.VideoRepresentation]))
case toggleInvites(Bool) case toggleInvites(Bool)
case toggleSignatures(Bool) case toggleSignatures(Bool)
case updatePinned(Message?) case updatePinned(Message?)
@ -149,7 +149,9 @@ public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: Pe
case let .channelAdminLogEventActionChangeUsername(prev, new): case let .channelAdminLogEventActionChangeUsername(prev, new):
action = .changeUsername(prev: prev, new: new) action = .changeUsername(prev: prev, new: new)
case let .channelAdminLogEventActionChangePhoto(prev, new): case let .channelAdminLogEventActionChangePhoto(prev, new):
action = .changePhoto(prev: telegramMediaImageFromApiPhoto(prev)?.representations ?? [], new: telegramMediaImageFromApiPhoto(new)?.representations ?? []) let previousImage = telegramMediaImageFromApiPhoto(prev)
let newImage = telegramMediaImageFromApiPhoto(new)
action = .changePhoto(prev: (previousImage?.representations ?? [], previousImage?.videoRepresentations ?? []) , new: (newImage?.representations ?? [], newImage?.videoRepresentations ?? []))
case let .channelAdminLogEventActionToggleInvites(new): case let .channelAdminLogEventActionToggleInvites(new):
action = .toggleInvites(boolFromApiValue(new)) action = .toggleInvites(boolFromApiValue(new))
case let .channelAdminLogEventActionToggleSignatures(new): case let .channelAdminLogEventActionToggleSignatures(new):

View File

@ -337,7 +337,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
} }
switch fullChat { switch fullChat {
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts): case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts):
var channelFlags = CachedChannelFlags() var channelFlags = CachedChannelFlags()
if (flags & (1 << 3)) != 0 { if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants) channelFlags.insert(.canDisplayParticipants)
@ -467,6 +467,8 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
} }
} }
let photo = telegramMediaImageFromApiPhoto(chatPhoto)
var minAvailableMessageIdUpdated = false var minAvailableMessageIdUpdated = false
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
var previous: CachedChannelData var previous: CachedChannelData
@ -496,6 +498,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
.withUpdatedHasScheduledMessages(hasScheduledMessages) .withUpdatedHasScheduledMessages(hasScheduledMessages)
.withUpdatedStatsDatacenterId(statsDc ?? 0) .withUpdatedStatsDatacenterId(statsDc ?? 0)
.withUpdatedInvitedBy(invitedBy) .withUpdatedInvitedBy(invitedBy)
.withUpdatedPhoto(photo)
}) })
if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated { if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated {

View File

@ -65,9 +65,28 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
override func transitionNode(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { override func transitionNode(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
if let imageNode = self.imageNode, self.item?.message.id == messageId { if let imageNode = self.imageNode, self.item?.message.id == messageId {
return (imageNode, imageNode.bounds, { [weak imageNode] in return (imageNode, imageNode.bounds, { [weak self] in
let snapshot = imageNode?.view.snapshotContentTree(unhide: true) guard let strongSelf = self, let imageNode = strongSelf.imageNode else {
return (snapshot, nil) return (nil, nil)
}
let resultView = imageNode.view.snapshotContentTree(unhide: true)
if let resultView = resultView, strongSelf.mediaBackgroundNode.supernode != nil, let backgroundView = strongSelf.mediaBackgroundNode.view.snapshotContentTree(unhide: true) {
let backgroundContainer = UIView()
backgroundContainer.addSubview(backgroundView)
let backgroundFrame = strongSelf.mediaBackgroundNode.layer.convert(strongSelf.mediaBackgroundNode.bounds, to: resultView.layer)
backgroundContainer.frame = CGRect(origin: CGPoint(x: -2.0, y: -2.0), size: CGSize(width: resultView.frame.width + 4.0, height: resultView.frame.height + 4.0))
backgroundView.frame = backgroundContainer.bounds
let viewWithBackground = UIView()
viewWithBackground.addSubview(backgroundContainer)
viewWithBackground.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: resultView.frame.size)
resultView.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: resultView.frame.size)
viewWithBackground.addSubview(resultView)
return (viewWithBackground, backgroundContainer)
}
return (resultView, nil)
}) })
} else { } else {
return nil return nil
@ -100,6 +119,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
} }
self.imageNode?.isHidden = mediaHidden self.imageNode?.isHidden = mediaHidden
self.mediaBackgroundNode.isHidden = mediaHidden
return mediaHidden return mediaHidden
} }

View File

@ -44,6 +44,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
private var controllerInteraction: ChatControllerInteraction! private var controllerInteraction: ChatControllerInteraction!
private let galleryHiddenMesageAndMediaDisposable = MetaDisposable() private let galleryHiddenMesageAndMediaDisposable = MetaDisposable()
private let temporaryHiddenGalleryMediaDisposable = MetaDisposable()
private var chatPresentationDataPromise: Promise<ChatPresentationData> private var chatPresentationDataPromise: Promise<ChatPresentationData>
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
@ -183,7 +184,27 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, callPeer: { peerId, isVideo in }, callPeer: { peerId, isVideo in
self?.controllerInteraction?.callPeer(peerId, isVideo) self?.controllerInteraction?.callPeer(peerId, isVideo)
}, enqueueMessage: { _ in }, enqueueMessage: { _ in
}, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in })) }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { signal, media in
if let strongSelf = self {
strongSelf.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).start(next: { messageId in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
var messageIdAndMedia: [MessageId: [Media]] = [:]
if let messageId = messageId {
messageIdAndMedia[messageId] = [media]
}
controllerInteraction.hiddenMedia = messageIdAndMedia
strongSelf.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView {
itemNode.updateHiddenMedia()
}
}
}
}))
}
}))
} }
return false return false
}, openPeer: { [weak self] peerId, _, message in }, openPeer: { [weak self] peerId, _, message in
@ -516,6 +537,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.historyDisposable?.dispose() self.historyDisposable?.dispose()
self.navigationActionDisposable.dispose() self.navigationActionDisposable.dispose()
self.galleryHiddenMesageAndMediaDisposable.dispose() self.galleryHiddenMesageAndMediaDisposable.dispose()
self.temporaryHiddenGalleryMediaDisposable.dispose()
self.resolvePeerByNameDisposable.dispose() self.resolvePeerByNameDisposable.dispose()
self.adminsDisposable?.dispose() self.adminsDisposable?.dispose()
self.banDisposables.dispose() self.banDisposables.dispose()

View File

@ -219,8 +219,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
peers[peer.id] = peer peers[peer.id] = peer
var photo: TelegramMediaImage? var photo: TelegramMediaImage?
if !new.isEmpty { let (newPhoto, newVideo) = new
photo = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: new, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []) if !newPhoto.isEmpty || !newVideo.isEmpty {
photo = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: newPhoto, videoRepresentations: newVideo, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
} }
let action = TelegramMediaActionType.photoUpdated(image: photo) let action = TelegramMediaActionType.photoUpdated(image: photo)

View File

@ -26,6 +26,7 @@ import PeerInfoUI
import MapResourceToAvatarSizes import MapResourceToAvatarSizes
import ItemListAddressItem import ItemListAddressItem
import ItemListVenueItem import ItemListVenueItem
import LegacyMediaPickerUI
private struct CreateGroupArguments { private struct CreateGroupArguments {
let context: AccountContext let context: AccountContext
@ -383,6 +384,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
let currentAvatarMixin = Atomic<TGMediaAvatarMenuMixin?>(value: nil) let currentAvatarMixin = Atomic<TGMediaAvatarMenuMixin?>(value: nil)
let uploadedAvatar = Promise<UploadedPeerPhotoData>() let uploadedAvatar = Promise<UploadedPeerPhotoData>()
var uploadedVideoAvatar: Promise<UploadedPeerPhotoData?>? = nil
let addressPromise = Promise<String?>(nil) let addressPromise = Promise<String?>(nil)
let venuesPromise = Promise<[TelegramMediaMap]?>(nil) let venuesPromise = Promise<[TelegramMediaMap]?>(nil)
@ -480,7 +482,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
return $0.avatar return $0.avatar
} }
if let _ = updatingAvatar { if let _ = updatingAvatar {
return updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerId, photo: uploadedAvatar.get(), mapResourceToAvatarSizes: { resource, representations in return updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.get(), mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations) return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
}) })
|> ignoreValues |> ignoreValues
@ -569,12 +571,13 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
endEditingImpl?() endEditingImpl?()
presentControllerImpl?(legacyController, nil) presentControllerImpl?(legacyController, nil)
let completedImpl: (UIImage) -> Void = { image in let completedGroupPhotoImpl: (UIImage) -> Void = { image in
if let data = image.jpegData(compressionQuality: 0.6) { if let data = image.jpegData(compressionQuality: 0.6) {
let resource = LocalFileMediaResource(fileId: arc4random64()) let resource = LocalFileMediaResource(fileId: arc4random64())
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource) let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource)
uploadedAvatar.set(uploadedPeerPhoto(postbox: context.account.postbox, network: context.account.network, resource: resource)) uploadedAvatar.set(uploadedPeerPhoto(postbox: context.account.postbox, network: context.account.network, resource: resource))
uploadedVideoAvatar = nil
updateState { current in updateState { current in
var current = current var current = current
current.avatar = .image(representation, false) current.avatar = .image(representation, false)
@ -583,19 +586,99 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
} }
} }
let completedGroupVideoImpl: (UIImage, URL, TGVideoEditAdjustments?) -> Void = { image, url, adjustments in
if let data = image.jpegData(compressionQuality: 0.6) {
let photoResource = LocalFileMediaResource(fileId: arc4random64())
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource)
updateState { state in
var state = state
state.avatar = .image(representation, true)
return state
}
var videoStartTimestamp: Double? = nil
if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
}
let signal = Signal<TelegramMediaResource, UploadPeerPhotoError> { subscriber in
var filteredPath = url.path
if filteredPath.hasPrefix("file://") {
filteredPath = String(filteredPath[filteredPath.index(filteredPath.startIndex, offsetBy: "file://".count)])
}
let avAsset = AVURLAsset(url: URL(fileURLWithPath: filteredPath))
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
return LegacyPaintEntityRenderer(account: context.account, adjustments: adjustments)
} else {
return nil
}
}
let uploadInterface = LegacyLiveUploadInterface(account: context.account)
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
let signalDisposable = signal.start(next: { next in
if let result = next as? TGMediaVideoConversionResult {
if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
}
var value = stat()
if stat(result.fileURL.path, &value) == 0 {
if let data = try? Data(contentsOf: result.fileURL) {
let resource: TelegramMediaResource
if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
resource = LocalFileMediaResource(fileId: liveUploadData.id)
} else {
resource = LocalFileMediaResource(fileId: arc4random64())
}
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
subscriber.putNext(resource)
}
}
subscriber.putCompletion()
}
}, error: { _ in
}, completed: nil)
let disposable = ActionDisposable {
signalDisposable?.dispose()
}
return ActionDisposable {
disposable.dispose()
}
}
// let promise = Promise<UploadedPeerPhotoData?>()
// promise.set(signal |> mapToSignal { resource in
// return uploadedPeerVideo(postbox: context.account.postbox, network: context.account.network, messageMediaPreuploadManager: context.account.messageMediaPreuploadManager, resource: resource) |> map(Optional.init)
// |> `catch` { _ -> Signal<UploadedPeerPhotoData?, NoError> in
// return .single(nil)
// }
// })
// uploadedVideoAvatar = promise
}
}
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false)!
let _ = currentAvatarMixin.swap(mixin) let _ = currentAvatarMixin.swap(mixin)
mixin.requestSearchController = { assetsController in mixin.requestSearchController = { assetsController in
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in
assetsController?.dismiss() assetsController?.dismiss()
completedImpl(result) completedGroupPhotoImpl(result)
})) }))
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} }
mixin.didFinishWithImage = { image in mixin.didFinishWithImage = { image in
if let image = image { if let image = image {
completedImpl(image) completedGroupPhotoImpl(image)
} }
}
mixin.didFinishWithVideo = { _, _, _ in
} }
if stateValue.with({ $0.avatar }) != nil { if stateValue.with({ $0.avatar }) != nil {
mixin.didFinishWithDelete = { mixin.didFinishWithDelete = {

View File

@ -318,11 +318,14 @@ private func peerInfoScreenInputData(context: AccountContext, peerId: PeerId, is
private func peerInfoProfilePhotos(context: AccountContext, peerId: PeerId) -> Signal<Any, NoError> { private func peerInfoProfilePhotos(context: AccountContext, peerId: PeerId) -> Signal<Any, NoError> {
return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) return context.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|> map { view -> AvatarGalleryEntry? in |> mapToSignal { view -> Signal<AvatarGalleryEntry?, NoError> in
guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else {
return nil return .single(nil)
}
return initialAvatarGalleryEntries(account: context.account, peer: peer)
|> map { entries in
return entries.first
} }
return initialAvatarGalleryEntries(peer: peer).first
} }
|> distinctUntilChanged |> distinctUntilChanged
|> mapToSignal { firstEntry -> Signal<[AvatarGalleryEntry], NoError> in |> mapToSignal { firstEntry -> Signal<[AvatarGalleryEntry], NoError> in

View File

@ -273,7 +273,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
videoNode.isUserInteractionEnabled = false videoNode.isUserInteractionEnabled = false
videoNode.isHidden = true videoNode.isHidden = true
if let _ = video.startTimestamp { if let startTimestamp = video.startTimestamp {
self.playbackStatusDisposable.set((videoNode.status self.playbackStatusDisposable.set((videoNode.status
|> map { status -> Bool in |> map { status -> Bool in
if let status = status, case .playing = status.status { if let status = status, case .playing = status.status {
@ -288,20 +288,17 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|> take(1) |> take(1)
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
Queue.mainQueue().after(0.1) { Queue.mainQueue().after(0.15) {
strongSelf.videoNode?.isHidden = false strongSelf.videoNode?.isHidden = false
} }
} }
})) }))
videoNode.seek(startTimestamp)
} else { } else {
self.playbackStatusDisposable.set(nil) self.playbackStatusDisposable.set(nil)
videoNode.isHidden = false videoNode.isHidden = false
} }
if let startTimestamp = video.startTimestamp {
videoNode.seek(startTimestamp)
}
self.videoContent = videoContent self.videoContent = videoContent
self.videoNode = videoNode self.videoNode = videoNode
self.statusPromise.set(videoNode.status |> map { ($0, video.startTimestamp) }) self.statusPromise.set(videoNode.status |> map { ($0, video.startTimestamp) })
@ -1035,6 +1032,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
var tapped: (() -> Void)? var tapped: (() -> Void)?
private var isFirstAvatarLoading = true private var isFirstAvatarLoading = true
var item: PeerInfoAvatarListItem?
private let playbackStatusDisposable = MetaDisposable() private let playbackStatusDisposable = MetaDisposable()
@ -1090,11 +1088,22 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
} }
} }
var removedPhotoResourceIds = Set<String>()
func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) { func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) {
if let peer = peer { if let peer = peer {
let previousItem = self.item
self.item = item
var overrideImage: AvatarNodeImageOverride? var overrideImage: AvatarNodeImageOverride?
if peer.isDeleted { if peer.isDeleted {
overrideImage = .deletedIcon overrideImage = .deletedIcon
} else if let previousItem = previousItem, item == nil {
if case let .image(image) = previousItem, let rep = image.1.last {
self.removedPhotoResourceIds.insert(rep.representation.resource.id.uniqueId)
}
overrideImage = AvatarNodeImageOverride.none
} else if let rep = peer.profileImageRepresentations.last, self.removedPhotoResourceIds.contains(rep.resource.id.uniqueId) {
overrideImage = AvatarNodeImageOverride.none
} }
self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true) self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
self.isFirstAvatarLoading = false self.isFirstAvatarLoading = false
@ -1128,7 +1137,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|> take(1) |> take(1)
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
Queue.mainQueue().after(0.1) { Queue.mainQueue().after(0.15) {
strongSelf.videoNode?.isHidden = false strongSelf.videoNode?.isHidden = false
} }
} }
@ -1213,6 +1222,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
self.iconNode = ASImageNode() self.iconNode = ASImageNode()
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: .white) self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: .white)
self.iconNode.isHidden = true
super.init() super.init()
@ -1248,7 +1258,7 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
overlayHidden = false overlayHidden = false
iconHidden = true iconHidden = true
self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: uploadProgress ?? 0.0, cancelEnabled: true)) self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: max(0.027, uploadProgress ?? 0.0), cancelEnabled: true))
if case let .image(representation) = updatingAvatar { if case let .image(representation) = updatingAvatar {
if representation != self.currentRepresentation { if representation != self.currentRepresentation {
@ -1262,12 +1272,13 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
self.updatingAvatarOverlay.isHidden = overlayHidden self.updatingAvatarOverlay.isHidden = overlayHidden
} else { } else {
if isEditing { if isEditing {
iconHidden = false iconHidden = peer.profileImageRepresentations.isEmpty
overlayHidden = peer.profileImageRepresentations.isEmpty
} else { } else {
iconHidden = true iconHidden = true
overlayHidden = true overlayHidden = true
} }
Queue.mainQueue().after(0.1) { [weak self] in Queue.mainQueue().after(0.15) { [weak self] in
self?.statusNode.transitionToState(.none) self?.statusNode.transitionToState(.none)
self?.currentRepresentation = nil self?.currentRepresentation = nil
self?.imageNode.setSignal(.single(nil)) self?.imageNode.setSignal(.single(nil))
@ -1283,7 +1294,6 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
self.iconNode.isHidden = true self.iconNode.isHidden = true
self.updatingAvatarOverlay.isHidden = true self.updatingAvatarOverlay.isHidden = true
self.currentRepresentation = nil self.currentRepresentation = nil
} }
} }
} }
@ -1296,7 +1306,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
private var videoStartTimestamp: Double? private var videoStartTimestamp: Double?
var tapped: ((Bool) -> Void)? var tapped: ((Bool) -> Void)?
var canAttachVideo: Bool = true var canAttachVideo: Bool = true
init(context: AccountContext) { init(context: AccountContext) {
@ -1322,7 +1332,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
guard let peer = peer else { guard let peer = peer else {
return return
} }
let overrideImage: AvatarNodeImageOverride? let overrideImage: AvatarNodeImageOverride?
if canEditPeerInfo(context: self.context, peer: peer), peer.profileImageRepresentations.isEmpty { if canEditPeerInfo(context: self.context, peer: peer), peer.profileImageRepresentations.isEmpty {
overrideImage = .editAvatarIcon overrideImage = .editAvatarIcon
@ -1393,6 +1403,8 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
var arguments: (Peer?, PresentationTheme, CGFloat, Bool)? var arguments: (Peer?, PresentationTheme, CGFloat, Bool)?
var item: PeerInfoAvatarListItem? var item: PeerInfoAvatarListItem?
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
init(context: AccountContext, readyWhenGalleryLoads: Bool) { init(context: AccountContext, readyWhenGalleryLoads: Bool) {
self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context) self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context)
self.listContainerTransformNode = ASDisplayNode() self.listContainerTransformNode = ASDisplayNode()
@ -1440,6 +1452,7 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
self.listContainerNode.itemsUpdated = { [weak self] items in self.listContainerNode.itemsUpdated = { [weak self] items in
if let strongSelf = self { if let strongSelf = self {
strongSelf.item = items.first strongSelf.item = items.first
strongSelf.itemsUpdated?(items)
if let (peer, theme, avatarSize, isExpanded) = strongSelf.arguments { if let (peer, theme, avatarSize, isExpanded) = strongSelf.arguments {
strongSelf.avatarContainerNode.update(peer: peer, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded) strongSelf.avatarContainerNode.update(peer: peer, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded)
} }
@ -2190,6 +2203,9 @@ private let TitleNodeStateExpanded = 1
final class PeerInfoHeaderNode: ASDisplayNode { final class PeerInfoHeaderNode: ASDisplayNode {
private var context: AccountContext private var context: AccountContext
private var presentationData: PresentationData? private var presentationData: PresentationData?
private var state: PeerInfoState?
private var peer: Peer?
private var avatarSize: CGFloat?
private let isOpenedFromChat: Bool private let isOpenedFromChat: Bool
private let isSettings: Bool private let isSettings: Bool
@ -2218,6 +2234,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let expandedBackgroundNode: ASDisplayNode private let expandedBackgroundNode: ASDisplayNode
let separatorNode: ASDisplayNode let separatorNode: ASDisplayNode
let navigationBackgroundNode: ASDisplayNode
var navigationTitle: String?
let navigationTitleNode: ImmediateTextNode
let navigationSeparatorNode: ASDisplayNode
let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode
var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)?
@ -2272,6 +2292,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.avatarOverlayNode = PeerInfoEditingAvatarOverlayNode(context: context) self.avatarOverlayNode = PeerInfoEditingAvatarOverlayNode(context: context)
self.navigationBackgroundNode = ASDisplayNode()
self.navigationBackgroundNode.isUserInteractionEnabled = false
self.navigationTitleNode = ImmediateTextNode()
self.navigationSeparatorNode = ASDisplayNode()
self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode() self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode()
self.backgroundNode = ASDisplayNode() self.backgroundNode = ASDisplayNode()
@ -2303,6 +2330,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.addSubnode(self.regularContentNode) self.addSubnode(self.regularContentNode)
self.addSubnode(self.editingContentNode) self.addSubnode(self.editingContentNode)
self.addSubnode(self.avatarOverlayNode) self.addSubnode(self.avatarOverlayNode)
self.addSubnode(self.navigationBackgroundNode)
self.navigationBackgroundNode.addSubnode(self.navigationTitleNode)
self.navigationBackgroundNode.addSubnode(self.navigationSeparatorNode)
self.addSubnode(self.navigationButtonContainer) self.addSubnode(self.navigationButtonContainer)
self.addSubnode(self.separatorNode) self.addSubnode(self.separatorNode)
@ -2310,10 +2340,14 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self?.initiateAvatarExpansion() self?.initiateAvatarExpansion()
} }
self.editingContentNode.avatarNode.tapped = { [weak self] confirm in self.editingContentNode.avatarNode.tapped = { [weak self] confirm in
guard let strongSelf = self else { self?.requestOpenAvatarForEditing?(confirm)
}
self.avatarListNode.itemsUpdated = { [weak self] items in
guard let strongSelf = self, let state = strongSelf.state, let peer = strongSelf.peer, let presentationData = strongSelf.presentationData, let avatarSize = strongSelf.avatarSize else {
return return
} }
strongSelf.requestOpenAvatarForEditing?(confirm) strongSelf.editingContentNode.avatarNode.update(peer: peer, item: strongSelf.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
} }
} }
@ -2387,6 +2421,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
} }
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
self.state = state
self.peer = peer
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
self.avatarSize = avatarSize
var contentOffset = contentOffset var contentOffset = contentOffset
if isMediaOnly { if isMediaOnly {
@ -2446,7 +2486,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.avatarListNode.animateAvatarCollapse(transition: transition) self.avatarListNode.animateAvatarCollapse(transition: transition)
} }
} else { } else {
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (112.0 + avatarSize))) let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (112.0 + avatarSize)))
transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction) transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction)
} }
@ -2454,6 +2493,18 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.avatarListNode.avatarContainerNode.updateTransitionFraction(transitionFraction, transition: transition) self.avatarListNode.avatarContainerNode.updateTransitionFraction(transitionFraction, transition: transition)
self.avatarListNode.listContainerNode.currentItemNode?.updateTransitionFraction(transitionFraction, transition: transition) self.avatarListNode.listContainerNode.currentItemNode?.updateTransitionFraction(transitionFraction, transition: transition)
if self.navigationTitle != presentationData.strings.EditProfile_Title || themeUpdated {
self.navigationTitleNode.attributedText = NSAttributedString(string: presentationData.strings.EditProfile_Title, font: Font.bold(17.0), textColor: presentationData.theme.rootController.navigationBar.primaryTextColor)
}
let navigationTitleSize = self.navigationTitleNode.updateLayout(CGSize(width: width, height: navigationHeight))
self.navigationTitleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - navigationTitleSize.width) / 2.0), y: navigationHeight - 44.0 + floorToScreenPixels((44.0 - navigationTitleSize.height) / 2.0)), size: navigationTitleSize)
self.navigationBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: navigationHeight))
self.navigationSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: navigationHeight), size: CGSize(width: width, height: UIScreenPixel))
self.navigationBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor
self.navigationSeparatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
transition.updateAlpha(node: self.navigationBackgroundNode, alpha: state.isEditing && self.isSettings ? min(1.0, contentOffset / (navigationHeight * 0.5)) : 0.0)
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
let defaultButtonSize: CGFloat = 40.0 let defaultButtonSize: CGFloat = 40.0
@ -2521,7 +2572,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
TitleNodeStateExpanded: MultiScaleTextState(attributedText: usernameString, constrainedSize: CGSize(width: width - titleNodeLayout[TitleNodeStateExpanded]!.size.width - 8.0, height: titleConstrainedSize.height)) TitleNodeStateExpanded: MultiScaleTextState(attributedText: usernameString, constrainedSize: CGSize(width: width - titleNodeLayout[TitleNodeStateExpanded]!.size.width - 8.0, height: titleConstrainedSize.height))
], mainState: TitleNodeStateRegular) ], mainState: TitleNodeStateRegular)
let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize))
let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY)

View File

@ -5415,11 +5415,19 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
guard let (_, navigationHeight) = self.validLayout else { guard let (_, navigationHeight) = self.validLayout else {
return return
} }
var height: CGFloat = self.isSettings ? 140.0 : 212.0 if self.state.isEditing && self.isSettings {
if self.headerNode.twoLineInfo { if targetContentOffset.pointee.y < navigationHeight {
height += 17.0 if targetContentOffset.pointee.y < navigationHeight / 2.0 {
} targetContentOffset.pointee.y = 0.0
if !self.state.isEditing { } else {
targetContentOffset.pointee.y = navigationHeight
}
}
} else {
var height: CGFloat = self.isSettings ? 140.0 : 212.0
if self.headerNode.twoLineInfo {
height += 17.0
}
if targetContentOffset.pointee.y < height { if targetContentOffset.pointee.y < height {
if targetContentOffset.pointee.y < height / 2.0 { if targetContentOffset.pointee.y < height / 2.0 {
targetContentOffset.pointee.y = 0.0 targetContentOffset.pointee.y = 0.0