Merge commit '187e2603747bd07e4429443ff4e85a8e99242ccd' into beta

This commit is contained in:
Ilya Laktyushin 2020-07-15 19:18:16 +03:00
commit 16d63eadf6
4 changed files with 80 additions and 73 deletions

View File

@ -217,7 +217,7 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry
public class AvatarGalleryController: ViewController, StandalonePresentableController {
public enum SourceCorners {
case none
case round
case round(Bool)
case roundRect(CGFloat)
}
@ -256,6 +256,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
public var avatarPhotoEditCompletion: ((UIImage) -> Void)?
public var avatarVideoEditCompletion: ((UIImage, URL, TGVideoEditAdjustments?) -> Void)?
public var removedEntry: ((AvatarGalleryEntry) -> Void)?
private let _hiddenMedia = Promise<AvatarGalleryEntry?>(nil)
public var hiddenMedia: Signal<AvatarGalleryEntry?, NoError> {
return self._hiddenMedia.get()
@ -265,7 +267,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
private let editDisposable = MetaDisposable ()
public init(context: AccountContext, peer: Peer, sourceCorners: SourceCorners = .round, remoteEntries: Promise<[AvatarGalleryEntry]>? = nil, skipInitial: Bool = false, centralEntryIndex: Int? = nil, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, synchronousLoad: Bool = false) {
public init(context: AccountContext, peer: Peer, sourceCorners: SourceCorners = .round(true), remoteEntries: Promise<[AvatarGalleryEntry]>? = nil, skipInitial: Bool = false, centralEntryIndex: Int? = nil, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, synchronousLoad: Bool = false) {
self.context = context
self.peer = peer
self.sourceCorners = sourceCorners
@ -318,23 +320,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
strongSelf.centralEntryIndex = 0
}
if strongSelf.isViewLoaded {
let canDelete: Bool
if strongSelf.peer.id == strongSelf.context.account.peerId {
canDelete = true
} else if let group = strongSelf.peer as? TelegramGroup {
switch group.role {
case .creator, .admin:
canDelete = true
case .member:
canDelete = false
}
} else if let channel = strongSelf.peer as? TelegramChannel {
canDelete = channel.hasPermission(.changeInfo)
} else {
canDelete = false
}
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ entry in PeerAvatarImageGalleryItem(context: context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: sourceCorners, delete: canDelete ? {
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ entry in PeerAvatarImageGalleryItem(context: context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: sourceCorners, delete: strongSelf.canDelete ? {
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -495,24 +481,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
let canDelete: Bool
if self.peer.id == self.context.account.peerId {
canDelete = true
} else if let group = self.peer as? TelegramGroup {
switch group.role {
case .creator, .admin:
canDelete = true
case .member:
canDelete = false
}
} else if let channel = self.peer as? TelegramChannel {
canDelete = channel.hasPermission(.changeInfo)
} else {
canDelete = false
}
let presentationData = self.presentationData
self.galleryNode.pager.replaceItems(self.entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: self.sourceCorners, delete: canDelete ? { [weak self] in
self.galleryNode.pager.replaceItems(self.entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: self.sourceCorners, delete: self.canDelete ? { [weak self] in
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -610,6 +580,25 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
}
}
private var canDelete: Bool {
let canDelete: Bool
if self.peer.id == self.context.account.peerId {
canDelete = true
} else if let group = self.peer as? TelegramGroup {
switch group.role {
case .creator, .admin:
canDelete = true
case .member:
canDelete = false
}
} else if let channel = self.peer as? TelegramChannel {
canDelete = channel.hasPermission(.changeInfo)
} else {
canDelete = false
}
return canDelete
}
private func setMainEntry(_ rawEntry: AvatarGalleryEntry) {
var entry = rawEntry
if case .topImage = entry, !self.entries.isEmpty {
@ -638,25 +627,10 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
entries.insert(previousFirstEntry, at: index)
}
let canDelete: Bool
if self.peer.id == self.context.account.peerId {
canDelete = true
} else if let group = self.peer as? TelegramGroup {
switch group.role {
case .creator, .admin:
canDelete = true
case .member:
canDelete = false
}
} else if let channel = self.peer as? TelegramChannel {
canDelete = channel.hasPermission(.changeInfo)
} else {
canDelete = false
}
entries = normalizeEntries(entries)
self.galleryNode.pager.replaceItems(entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: self.sourceCorners, delete: canDelete ? { [weak self] in
self.galleryNode.pager.replaceItems(entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: self.peer, presentationData: presentationData, entry: entry, sourceCorners: self.sourceCorners, delete: self.canDelete ? { [weak self] in
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -798,12 +772,19 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
}
private func deleteEntry(_ rawEntry: AvatarGalleryEntry) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let proceed = {
var entry = rawEntry
if case .topImage = entry, !self.entries.isEmpty {
entry = self.entries[0]
}
self.removedEntry?(rawEntry)
var focusOnItem: Int?
var updatedEntries = self.entries
var replaceItems = false
switch entry {
case .topImage:
if self.peer.id == self.context.account.peerId {
@ -827,8 +808,9 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
self.dismiss(forceAway: true)
} else {
if let index = self.entries.firstIndex(of: entry) {
self.entries.remove(at: index)
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
replaceItems = true
updatedEntries.remove(at: index)
focusOnItem = index - 1
}
}
} else {
@ -841,14 +823,26 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
self.dismiss(forceAway: true)
} else {
if let index = self.entries.firstIndex(of: entry) {
self.entries.remove(at: index)
self.galleryNode.pager.transaction(GalleryPagerTransaction(deleteItems: [index], insertItems: [], updateItems: [], focusOnItem: index - 1, synchronous: false))
replaceItems = true
updatedEntries.remove(at: index)
focusOnItem = index - 1
}
}
}
}
if replaceItems {
updatedEntries = normalizeEntries(updatedEntries)
self.galleryNode.pager.replaceItems(updatedEntries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: self.peer, presentationData: presentationData, entry: entry, sourceCorners: self.sourceCorners, delete: self.canDelete ? { [weak self] in
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
}, edit: { [weak self] in
self?.editEntry(entry)
}) }), centralItemIndex: focusOnItem, synchronous: true)
self.entries = updatedEntries
}
}
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationData: presentationData)
let items: [ActionSheetItem] = [
ActionSheetButtonItem(title: presentationData.strings.Common_Delete, color: .destructive, action: { [weak actionSheet] in

View File

@ -266,7 +266,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
let mediaManager = self.context.sharedContext.mediaManager
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: entry.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id, category), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .overlay)
videoNode.isUserInteractionEnabled = false
videoNode.isHidden = true
self.videoStartTimestamp = video.representation.startTimestamp
@ -429,7 +429,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
self.contentNode.layer.animate(from: NSValue(caTransform3D: transform), to: NSValue(caTransform3D: self.contentNode.layer.transform), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25)
self.contentNode.clipsToBounds = true
if case .round = self.sourceCorners {
if case .round(true) = self.sourceCorners {
self.contentNode.layer.animate(from: (self.contentNode.frame.width / 2.0) as NSNumber, to: 0.0 as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.default.rawValue, duration: 0.18, removeOnCompletion: false, completion: { [weak self] value in
if value {
self?.contentNode.clipsToBounds = false
@ -443,6 +443,8 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
self?.contentNode.clipsToBounds = false
}
})
} else {
self.contentNode.clipsToBounds = false
}
self.statusNodeContainer.layer.animatePosition(from: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), to: self.statusNodeContainer.position, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)

View File

@ -180,6 +180,15 @@ enum PeerInfoAvatarListItem: Equatable {
return videoRepresentations
}
}
init(entry: AvatarGalleryEntry) {
switch entry {
case let .topImage(representations, videoRepresentations, _, _, immediateThumbnailData, _):
self = .topImage(representations, videoRepresentations, immediateThumbnailData)
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _):
self = .image(reference, representations, videoRepresentations, immediateThumbnailData)
}
}
}
final class PeerInfoAvatarListItemNode: ASDisplayNode {
@ -972,12 +981,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
var items: [PeerInfoAvatarListItem] = []
for entry in entries {
switch entry {
case let .topImage(representations, videoRepresentations, _, _, immediateThumbnailData, _):
items.append(.topImage(representations, videoRepresentations, immediateThumbnailData))
case let .image(_, reference, representations, videoRepresentations, _, _, _, _, immediateThumbnailData, _):
items.append(.image(reference, representations, videoRepresentations, immediateThumbnailData))
}
items.append(PeerInfoAvatarListItem(entry: entry))
}
strongSelf.galleryEntries = entries
strongSelf.items = items
@ -1532,7 +1536,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode {
let videoContent = NativeVideoContent(id: .profileVideo(id, nil), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.representation.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, autoFetchFullSizeThumbnail: true, startTimestamp: video.representation.startTimestamp, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
if videoContent.id != self.videoContent?.id {
let mediaManager = self.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .overlay)
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .gallery)
videoNode.isUserInteractionEnabled = false
self.videoStartTimestamp = video.representation.startTimestamp
self.videoContent = videoContent
@ -2536,10 +2540,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.addSubnode(self.separatorNode)
self.avatarListNode.avatarContainerNode.tapped = { [weak self] in
self?.initiateAvatarExpansion(gallery: false)
self?.initiateAvatarExpansion(gallery: false, first: false)
}
self.editingContentNode.avatarNode.tapped = { [weak self] confirm in
self?.initiateAvatarExpansion(gallery: true)
self?.initiateAvatarExpansion(gallery: true, first: true)
}
self.editingContentNode.requestEditing = { [weak self] in
self?.requestOpenAvatarForEditing?(true)
@ -2575,10 +2579,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
}
}
func initiateAvatarExpansion(gallery: Bool) {
func initiateAvatarExpansion(gallery: Bool, first: Bool) {
if self.isAvatarExpanded || gallery {
if let currentEntry = self.avatarListNode.listContainerNode.currentEntry, let firstEntry = self.avatarListNode.listContainerNode.galleryEntries.first {
let entry = gallery ? firstEntry : currentEntry
let entry = first ? firstEntry : currentEntry
self.requestAvatarExpansion?(true, self.avatarListNode.listContainerNode.galleryEntries, entry, self.avatarTransitionArguments(entry: currentEntry))
}
} else if let entry = self.avatarListNode.listContainerNode.galleryEntries.first {

View File

@ -2105,7 +2105,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
let entriesPromise = Promise<[AvatarGalleryEntry]>(entries)
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, sourceCorners: !strongSelf.headerNode.isAvatarExpanded ? .round : .none, remoteEntries: entriesPromise, skipInitial: true, centralEntryIndex: centralEntry.flatMap { entries.firstIndex(of: $0) }, replaceRootController: { controller, ready in
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, sourceCorners: .round(!strongSelf.headerNode.isAvatarExpanded), remoteEntries: entriesPromise, skipInitial: true, centralEntryIndex: centralEntry.flatMap { entries.firstIndex(of: $0) }, replaceRootController: { controller, ready in
})
galleryController.openAvatarSetup = { [weak self] completion in
self?.openAvatarForEditing(hasRemove: false, completion: completion)
@ -2116,6 +2116,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
galleryController.avatarVideoEditCompletion = { [weak self] image, url, adjustments in
self?.updateProfileVideo(image, url: url, adjustments: adjustments)
}
galleryController.removedEntry = { [weak self] entry in
self?.headerNode.avatarListNode.listContainerNode.deleteItem(PeerInfoAvatarListItem(entry: entry))
}
strongSelf.hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
self?.headerNode.updateAvatarIsHidden(entry: entry)
}))
@ -2129,6 +2132,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
return nil
}
}))
Queue.mainQueue().after(0.4) {
strongSelf.resetHeaderExpansion()
}
}
self.headerNode.requestOpenAvatarForEditing = { [weak self] confirm in
@ -5401,7 +5408,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
self.canOpenAvatarByDragging = false
let contentOffset = scrollView.contentOffset.y
scrollView.panGestureRecognizer.isEnabled = false
self.headerNode.initiateAvatarExpansion(gallery: true)
self.headerNode.initiateAvatarExpansion(gallery: true, first: false)
scrollView.panGestureRecognizer.isEnabled = true
scrollView.contentOffset = CGPoint(x: 0.0, y: contentOffset)
UIView.animate(withDuration: 0.1) {