mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-18 06:33:50 +00:00
Fix voice chat avatar expansion
This commit is contained in:
parent
86e3e2bc35
commit
822ef1b32c
@ -15,6 +15,7 @@ public final class ContextExtractedContentContainingNode: ASDisplayNode {
|
||||
public var applyAbsoluteOffsetSpring: ((CGFloat, Double, CGFloat) -> Void)?
|
||||
public var layoutUpdated: ((CGSize) -> Void)?
|
||||
public var updateDistractionFreeMode: ((Bool) -> Void)?
|
||||
public var requestDismiss: (() -> Void)?
|
||||
|
||||
public override init() {
|
||||
self.contentNode = ContextExtractedContentNode()
|
||||
|
||||
@ -24,28 +24,37 @@ public enum AvatarGalleryEntryId: Hashable {
|
||||
|
||||
public func peerInfoProfilePhotos(context: AccountContext, peerId: PeerId) -> Signal<Any, NoError> {
|
||||
return context.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
|> mapToSignal { view -> Signal<AvatarGalleryEntry?, NoError> in
|
||||
|> mapToSignal { view -> Signal<[AvatarGalleryEntry]?, NoError> in
|
||||
guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else {
|
||||
return .single(nil)
|
||||
}
|
||||
return initialAvatarGalleryEntries(account: context.account, peer: peer)
|
||||
|> map { entries in
|
||||
return entries.first
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { firstEntry -> Signal<(Bool, [AvatarGalleryEntry]), NoError> in
|
||||
if let firstEntry = firstEntry {
|
||||
return context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer -> Signal<(Bool, [AvatarGalleryEntry]), NoError>in
|
||||
return fetchedAvatarGalleryEntries(account: context.account, peer: peer, firstEntry: firstEntry)
|
||||
|> mapToSignal { entries -> Signal<(Bool, [AvatarGalleryEntry])?, NoError> in
|
||||
if let entries = entries {
|
||||
if let firstEntry = entries.first {
|
||||
return context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer -> Signal<(Bool, [AvatarGalleryEntry])?, NoError>in
|
||||
return fetchedAvatarGalleryEntries(account: context.account, peer: peer, firstEntry: firstEntry)
|
||||
|> map(Optional.init)
|
||||
}
|
||||
} else {
|
||||
return .single((true, []))
|
||||
}
|
||||
} else {
|
||||
return .single((true, []))
|
||||
return fetchAndUpdateCachedPeerData(accountPeerId: context.account.peerId, peerId: peerId, network: context.account.network, postbox: context.account.postbox)
|
||||
|> map { _ -> (Bool, [AvatarGalleryEntry])? in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|> map { items -> Any in
|
||||
return items
|
||||
if let items = items {
|
||||
return items
|
||||
} else {
|
||||
return peerInfoProfilePhotos(context: context, peerId: peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +173,7 @@ public func normalizeEntries(_ entries: [AvatarGalleryEntry]) -> [AvatarGalleryE
|
||||
return updatedEntries
|
||||
}
|
||||
|
||||
public func initialAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> {
|
||||
public func initialAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry]?, NoError> {
|
||||
var initialEntries: [AvatarGalleryEntry] = []
|
||||
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)) }), [], peer, nil, nil, nil))
|
||||
@ -189,7 +198,7 @@ public func initialAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<
|
||||
}
|
||||
return [.image(photo.imageId, photo.reference, representations, photo.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatarList(peer: peerReference, resource: $0.resource)) }), peer, nil, nil, nil, photo.immediateThumbnailData, nil)]
|
||||
} else {
|
||||
return []
|
||||
return cachedData != nil ? [] : nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -199,6 +208,9 @@ public func initialAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<
|
||||
|
||||
public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> {
|
||||
return initialAvatarGalleryEntries(account: account, peer: peer)
|
||||
|> map { entries -> [AvatarGalleryEntry] in
|
||||
return entries ?? []
|
||||
}
|
||||
|> mapToSignal { initialEntries in
|
||||
return .single(initialEntries)
|
||||
|> then(
|
||||
@ -390,7 +402,12 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
remoteEntriesSignal = fetchedAvatarGalleryEntries(account: context.account, peer: peer)
|
||||
}
|
||||
|
||||
let entriesSignal: Signal<[AvatarGalleryEntry], NoError> = skipInitial ? remoteEntriesSignal : (initialAvatarGalleryEntries(account: context.account, peer: peer) |> then(remoteEntriesSignal))
|
||||
let initialSignal = initialAvatarGalleryEntries(account: context.account, peer: peer)
|
||||
|> map { entries -> [AvatarGalleryEntry] in
|
||||
return entries ?? []
|
||||
}
|
||||
|
||||
let entriesSignal: Signal<[AvatarGalleryEntry], NoError> = skipInitial ? remoteEntriesSignal : (initialSignal |> then(remoteEntriesSignal))
|
||||
|
||||
let presentationData = self.presentationData
|
||||
|
||||
|
||||
@ -310,7 +310,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
self.isReady.set(videoNode.ready |> map { return true })
|
||||
}
|
||||
|
||||
func setup(item: PeerInfoAvatarListItem, synchronous: Bool) {
|
||||
func setup(item: PeerInfoAvatarListItem, synchronous: Bool, fullSizeOnly: Bool = false) {
|
||||
self.item = item
|
||||
|
||||
let representations: [ImageRepresentationWithReference]
|
||||
@ -336,7 +336,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
id = Int64(self.peer.id.id)
|
||||
}
|
||||
}
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: true, attemptSynchronously: synchronous), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: true, attemptSynchronously: synchronous, skipThumbnail: fullSizeOnly), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||
|
||||
if let video = videoRepresentations.last, let peerReference = PeerReference(self.peer) {
|
||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
|
||||
@ -419,6 +419,9 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
public var isCollapsing = false
|
||||
private var isExpanded = false
|
||||
|
||||
public var firstFullSizeOnly = false
|
||||
public var customCenterTapAction: (() -> Void)?
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let positionDisposable = MetaDisposable()
|
||||
private var initializedList = false
|
||||
@ -717,11 +720,16 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public var offsetLocation = false
|
||||
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
if let size = self.validLayout, case .tap = gesture {
|
||||
var location = location
|
||||
if self.offsetLocation {
|
||||
location.x += size.width / 2.0
|
||||
}
|
||||
if location.x < size.width * 1.0 / 5.0 {
|
||||
if self.currentIndex != 0 {
|
||||
let previousIndex = self.currentIndex
|
||||
@ -739,6 +747,10 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
self.updateItems(size: size, transition: .immediate, stripTransition: .animated(duration: 0.3, curve: .spring), synchronous: true)
|
||||
}
|
||||
} else {
|
||||
if let customAction = self.customCenterTapAction, location.x < size.width - size.width * 1.0 / 5.0 {
|
||||
customAction()
|
||||
return
|
||||
}
|
||||
if self.currentIndex < self.items.count - 1 {
|
||||
let previousIndex = self.currentIndex
|
||||
self.currentIndex += 1
|
||||
@ -1049,13 +1061,13 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
if let current = self.itemNodes[self.items[i].id] {
|
||||
itemNode = current
|
||||
if update {
|
||||
current.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex)
|
||||
current.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex, fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
}
|
||||
} else if let peer = self.peer {
|
||||
wasAdded = true
|
||||
let addedItemNode = PeerInfoAvatarListItemNode(context: self.context, peer: peer)
|
||||
itemNode = addedItemNode
|
||||
addedItemNode.setup(item: self.items[i], synchronous: (i == 0 && i == self.currentIndex) || (synchronous && i == self.currentIndex))
|
||||
addedItemNode.setup(item: self.items[i], synchronous: (i == 0 && i == self.currentIndex) || (synchronous && i == self.currentIndex), fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
self.itemNodes[self.items[i].id] = addedItemNode
|
||||
self.contentNode.addSubnode(addedItemNode)
|
||||
}
|
||||
|
||||
@ -2303,7 +2303,7 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR
|
||||
}
|
||||
}
|
||||
|
||||
public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false, skipThumbnail: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = avatarGalleryPhotoDatas(account: account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: autoFetchFullSize, attemptSynchronously: attemptSynchronously)
|
||||
|
||||
return signal
|
||||
@ -2352,8 +2352,8 @@ public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepr
|
||||
}
|
||||
|
||||
var blurredThumbnailImage: UIImage?
|
||||
if let thumbnailImage = thumbnailImage {
|
||||
if max(thumbnailImage.width, thumbnailImage.height) > 200 {
|
||||
if let thumbnailImage = thumbnailImage, !skipThumbnail {
|
||||
if max(thumbnailImage.width, thumbnailImage.height) > 200 {
|
||||
blurredThumbnailImage = UIImage(cgImage: thumbnailImage)
|
||||
} else {
|
||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||
|
||||
@ -1427,7 +1427,14 @@ public final class VoiceChatController: ViewController {
|
||||
return itemsForEntry(entry, muteState)
|
||||
}
|
||||
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(VoiceChatContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false, blurBackground: true)), items: items, reactionItems: [], gesture: gesture)
|
||||
|
||||
let dismissPromise = ValuePromise<Bool>(false)
|
||||
let source = VoiceChatContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false, blurBackground: true, shouldBeDismissed: dismissPromise.get())
|
||||
sourceNode.requestDismiss = {
|
||||
dismissPromise.set(true)
|
||||
}
|
||||
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(source), items: items, reactionItems: [], gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
}, setPeerIdWithRevealedOptions: { peerId, _ in
|
||||
updateState { state in
|
||||
@ -3891,11 +3898,14 @@ private final class VoiceChatContextExtractedContentSource: ContextExtractedCont
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextExtractedContentContainingNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode, keepInPlace: Bool, blurBackground: Bool) {
|
||||
var shouldBeDismissed: Signal<Bool, NoError>
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode, keepInPlace: Bool, blurBackground: Bool, shouldBeDismissed: Signal<Bool, NoError>) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
self.keepInPlace = keepInPlace
|
||||
self.blurBackground = blurBackground
|
||||
self.shouldBeDismissed = shouldBeDismissed
|
||||
}
|
||||
|
||||
func takeView() -> ContextControllerTakeViewInfo? {
|
||||
|
||||
@ -295,7 +295,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
if isExtracted {
|
||||
strongSelf.contextSourceNode.contentNode.customHitTest = { [weak self] point in
|
||||
if let strongSelf = self {
|
||||
if let avatarListContainerNode = strongSelf.avatarListContainerNode, avatarListContainerNode.frame.contains(point) {
|
||||
if let avatarListWrapperNode = strongSelf.avatarListWrapperNode, avatarListWrapperNode.frame.contains(point) {
|
||||
return strongSelf.avatarListNode?.view
|
||||
}
|
||||
}
|
||||
@ -371,7 +371,13 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updateCornerRadius(node: avatarListContainerNode, cornerRadius: 0.0)
|
||||
|
||||
let avatarListNode = PeerInfoAvatarListContainerNode(context: item.context)
|
||||
avatarListNode.backgroundColor = .clear
|
||||
avatarListNode.peer = item.peer
|
||||
avatarListNode.firstFullSizeOnly = true
|
||||
avatarListNode.offsetLocation = true
|
||||
avatarListNode.customCenterTapAction = { [weak self] in
|
||||
self?.contextSourceNode.requestDismiss?()
|
||||
}
|
||||
avatarListNode.frame = CGRect(x: targetRect.width / 2.0, y: targetRect.height / 2.0, width: targetRect.width, height: targetRect.height)
|
||||
avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.height / 2.0, width: targetRect.width, height: targetRect.height)
|
||||
avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.height / 2.0), size: CGSize())
|
||||
@ -445,7 +451,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.06, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
} else {
|
||||
strongSelf.extractedBackgroundImageNode.alpha = 0.0
|
||||
strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, delay: 0.15, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
strongSelf.extractedBackgroundImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, delay: 0.1, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
self?.extractedBackgroundImageNode.image = nil
|
||||
self?.extractedBackgroundImageNode.layer.removeAllAnimations()
|
||||
})
|
||||
@ -479,6 +485,10 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
self.raiseHandTimer?.invalidate()
|
||||
}
|
||||
|
||||
@objc private func handleTap() {
|
||||
print("tap")
|
||||
}
|
||||
|
||||
override func selected() {
|
||||
super.selected()
|
||||
self.layoutParams?.0.action?(self.contextSourceNode)
|
||||
@ -616,7 +626,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0 - titleIconsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (expandedStatusLayout, expandedStatusApply) = makeExpandedStatusLayout(TextNodeLayoutArguments(attributedString: expandedStatusAttributedString, backgroundColor: nil, maximumNumberOfLines: 4, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (expandedStatusLayout, expandedStatusApply) = makeExpandedStatusLayout(TextNodeLayoutArguments(attributedString: expandedStatusAttributedString, backgroundColor: nil, maximumNumberOfLines: 6, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let insets = UIEdgeInsets()
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, network:
|
||||
}
|
||||
}
|
||||
|
||||
func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
|
||||
public func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
|
||||
return postbox.combinedView(keys: [.basicPeer(rawPeerId)])
|
||||
|> mapToSignal { views -> Signal<Bool, NoError> in
|
||||
if accountPeerId == rawPeerId {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user