Video avatar fixes

This commit is contained in:
Ilya Laktyushin 2020-07-13 04:00:15 +03:00
parent c142520e1d
commit b4fe44ed89
9 changed files with 100 additions and 42 deletions

View File

@ -5678,8 +5678,8 @@ Any member of this group will be able to see messages in the channel.";
"ProfilePhoto.OpenInEditor" = "Open in Editor";
"Settings.EditAccount" = "Edit Account";
"Settings.EditPhoto" = "Edit Photo";
"Settings.EditVideo" = "Edit Video";
"Settings.EditPhoto" = "Edit";
"Settings.EditVideo" = "Edit";
"Settings.CancelUpload" = "Cancel Upload";
"Settings.FrequentlyAskedQuestions" = "Frequently Asked Questions";

View File

@ -206,13 +206,19 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry
}
public class AvatarGalleryController: ViewController, StandalonePresentableController {
public enum SourceCorners {
case none
case round
case roundRect(CGFloat)
}
private var galleryNode: GalleryControllerNode {
return self.displayNode as! GalleryControllerNode
}
private let context: AccountContext
private let peer: Peer
private let sourceHasRoundCorners: Bool
private let sourceCorners: SourceCorners
private var presentationData: PresentationData
@ -250,10 +256,10 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
private let editDisposable = MetaDisposable ()
public init(context: AccountContext, peer: Peer, sourceHasRoundCorners: Bool = true, 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, 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.sourceHasRoundCorners = sourceHasRoundCorners
self.sourceCorners = sourceCorners
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.replaceRootController = replaceRootController
@ -319,7 +325,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
canDelete = false
}
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ entry in PeerAvatarImageGalleryItem(context: context, peer: peer, presentationData: presentationData, entry: entry, sourceHasRoundCorners: sourceHasRoundCorners, delete: canDelete ? {
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ entry in PeerAvatarImageGalleryItem(context: context, peer: peer, presentationData: presentationData, entry: entry, sourceCorners: sourceCorners, delete: canDelete ? {
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -419,7 +425,11 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? AvatarGalleryControllerPresentationArguments {
if !self.entries.isEmpty {
if (centralItemNode.index == 0 || !self.sourceHasRoundCorners), let transitionArguments = presentationArguments.transitionArguments(self.entries[centralItemNode.index]), !forceAway {
var sourceHasRoundCorners = false
if case .round = self.sourceCorners {
sourceHasRoundCorners = true
}
if (centralItemNode.index == 0 || !sourceHasRoundCorners), let transitionArguments = presentationArguments.transitionArguments(self.entries[centralItemNode.index]), !forceAway {
animatedOutNode = false
centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: {
animatedOutNode = true
@ -457,7 +467,11 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
self.galleryNode.transitionDataForCentralItem = { [weak self] in
if let strongSelf = self {
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? AvatarGalleryControllerPresentationArguments {
if centralItemNode.index != 0 && strongSelf.sourceHasRoundCorners {
var sourceHasRoundCorners = false
if case .round = strongSelf.sourceCorners {
sourceHasRoundCorners = true
}
if centralItemNode.index != 0 && sourceHasRoundCorners {
return nil
}
if let transitionArguments = presentationArguments.transitionArguments(strongSelf.entries[centralItemNode.index]) {
@ -489,7 +503,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
}
let presentationData = self.presentationData
self.galleryNode.pager.replaceItems(self.entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: peer, presentationData: presentationData, entry: entry, sourceHasRoundCorners: self.sourceHasRoundCorners, 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: canDelete ? { [weak self] in
self?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -598,7 +612,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
if self.peer.id == self.context.account.peerId {
} else {
}
case let .image(_, reference, _, _, _, _, _, messageId, _, _):
case let .image(_, reference, _, _, _, _, _, _, _, _):
if self.peer.id == self.context.account.peerId {
if let reference = reference {
let _ = updatePeerPhotoExisting(network: self.context.account.network, reference: reference).start()
@ -633,7 +647,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
entries = normalizeEntries(entries)
self.galleryNode.pager.replaceItems(entries.map({ entry in PeerAvatarImageGalleryItem(context: self.context, peer: peer, presentationData: presentationData, entry: entry, sourceHasRoundCorners: self.sourceHasRoundCorners, delete: canDelete ? { [weak self] in
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?.deleteEntry(entry)
} : nil, setMain: { [weak self] in
self?.setMainEntry(entry)
@ -751,10 +765,10 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
}))
}
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ProfilePhoto_OpenInEditor, color: .accent, action: { [weak self] in
dismissAction()
self?.openEntryEdit(rawEntry)
}))
// items.append(ActionSheetButtonItem(title: self.presentationData.strings.ProfilePhoto_OpenInEditor, color: .accent, action: { [weak self] in
// dismissAction()
// self?.openEntryEdit(rawEntry)
// }))
items.append(ActionSheetButtonItem(title: self.presentationData.strings.GroupInfo_SetGroupPhotoDelete, color: .destructive, action: { [weak self] in
dismissAction()

View File

@ -43,6 +43,8 @@ private struct PeerAvatarImageGalleryThumbnailItem: GalleryThumbnailItem {
}
class PeerAvatarImageGalleryItem: GalleryItem {
var id: AnyHashable {
return self.entry.id
}
@ -51,24 +53,24 @@ class PeerAvatarImageGalleryItem: GalleryItem {
let peer: Peer
let presentationData: PresentationData
let entry: AvatarGalleryEntry
let sourceHasRoundCorners: Bool
let sourceCorners: AvatarGalleryController.SourceCorners
let delete: (() -> Void)?
let setMain: (() -> Void)?
let edit: (() -> Void)?
init(context: AccountContext, peer: Peer, presentationData: PresentationData, entry: AvatarGalleryEntry, sourceHasRoundCorners: Bool, delete: (() -> Void)?, setMain: (() -> Void)?, edit: (() -> Void)?) {
init(context: AccountContext, peer: Peer, presentationData: PresentationData, entry: AvatarGalleryEntry, sourceCorners: AvatarGalleryController.SourceCorners, delete: (() -> Void)?, setMain: (() -> Void)?, edit: (() -> Void)?) {
self.context = context
self.peer = peer
self.presentationData = presentationData
self.entry = entry
self.sourceHasRoundCorners = sourceHasRoundCorners
self.sourceCorners = sourceCorners
self.delete = delete
self.setMain = setMain
self.edit = edit
}
func node(synchronous: Bool) -> GalleryItemNode {
let node = PeerAvatarImageGalleryItemNode(context: self.context, presentationData: self.presentationData, peer: self.peer, sourceHasRoundCorners: self.sourceHasRoundCorners)
let node = PeerAvatarImageGalleryItemNode(context: self.context, presentationData: self.presentationData, peer: self.peer, sourceCorners: self.sourceCorners)
if let indexData = self.entry.indexData {
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0))
@ -130,7 +132,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
private let context: AccountContext
private let presentationData: PresentationData
private let peer: Peer
private let sourceHasRoundCorners: Bool
private let sourceCorners: AvatarGalleryController.SourceCorners
private var entry: AvatarGalleryEntry?
@ -155,11 +157,11 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
fileprivate var edit: (() -> Void)?
init(context: AccountContext, presentationData: PresentationData, peer: Peer, sourceHasRoundCorners: Bool) {
init(context: AccountContext, presentationData: PresentationData, peer: Peer, sourceCorners: AvatarGalleryController.SourceCorners) {
self.context = context
self.presentationData = presentationData
self.peer = peer
self.sourceHasRoundCorners = sourceHasRoundCorners
self.sourceCorners = sourceCorners
self.contentNode = PeerAvatarImageGalleryContentNode()
self.imageNode = TransformImageNode()
@ -397,7 +399,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
})
}
if self.sourceHasRoundCorners {
if case .round = self.sourceCorners {
self.view.insertSubview(copyView, belowSubview: self.scrollNode.view)
}
copyView.frame = transformedSelfFrame
@ -427,12 +429,19 @@ 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 self.sourceHasRoundCorners {
if case .round = 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
}
})
} else if case let .roundRect(cornerRadius) = self.sourceCorners {
let scale = scaledLocalImageViewBounds.width / transformedCopyViewFinalFrame.width
self.contentNode.layer.animate(from: (cornerRadius * scale) 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
}
})
}
self.statusNodeContainer.layer.animatePosition(from: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), to: self.statusNodeContainer.position, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
@ -445,6 +454,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
let transformedSuperFrame = node.0.view.convert(node.0.view.bounds, to: self.contentNode.view.superview)
let transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view)
let transformedCopyViewInitialFrame = self.contentNode.view.convert(self.contentNode.view.bounds, to: self.view)
let scaledLocalImageViewBounds = self.contentNode.view.bounds
var positionCompleted = false
var boundsCompleted = false
@ -456,13 +466,13 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
let copyView = maybeCopyView!
if self.sourceHasRoundCorners {
if case .round = self.sourceCorners {
self.view.insertSubview(copyView, belowSubview: self.scrollNode.view)
}
copyView.frame = transformedSelfFrame
let surfaceCopyView = node.2().0!
if !self.sourceHasRoundCorners {
if case .none = self.sourceCorners {
addToTransitionSurface(surfaceCopyView)
}
@ -525,8 +535,11 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
})
self.contentNode.clipsToBounds = true
if self.sourceHasRoundCorners {
if case .round = self.sourceCorners {
self.contentNode.layer.animate(from: 0.0 as NSNumber, to: (self.contentNode.frame.width / 2.0) as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.default.rawValue, duration: 0.18 * durationFactor, removeOnCompletion: false)
} else if case let .roundRect(cornerRadius) = self.sourceCorners {
let scale = scaledLocalImageViewBounds.width / transformedCopyViewInitialFrame.width
self.contentNode.layer.animate(from: 0.0 as NSNumber, to: (cornerRadius * scale) as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.default.rawValue, duration: 0.18 * durationFactor, removeOnCompletion: false)
}
self.statusNodeContainer.layer.animatePosition(from: self.statusNodeContainer.position, to: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)

View File

@ -266,16 +266,21 @@ public final class MediaBox {
}
}
public func copyResourceData(from: MediaResourceId, to: MediaResourceId) {
public func copyResourceData(from: MediaResourceId, to: MediaResourceId, synchronous: Bool = false) {
if from.isEqual(to: to) {
return
}
self.dataQueue.async {
let begin = {
let pathsFrom = self.storePathsForId(from)
let pathsTo = self.storePathsForId(to)
let _ = try? FileManager.default.copyItem(atPath: pathsFrom.partial, toPath: pathsTo.partial)
let _ = try? FileManager.default.copyItem(atPath: pathsFrom.complete, toPath: pathsTo.complete)
}
if synchronous {
begin()
} else {
self.dataQueue.async(begin)
}
}
private func maybeCopiedPreFetchedResource(completePath: String, resource: MediaResource) {

View File

@ -272,13 +272,13 @@ public func updatePeerPhotoInternal(postbox: Postbox, network: Network, stateMan
if let cachedData = cachedData as? CachedChannelData {
if let photo = cachedData.photo {
for representation in photo.videoRepresentations {
postbox.mediaBox.copyResourceData(from: videoResource.id, to: representation.resource.id)
postbox.mediaBox.copyResourceData(from: videoResource.id, to: representation.resource.id, synchronous: true)
}
}
} else if let cachedData = cachedData as? CachedGroupData {
if let photo = cachedData.photo {
for representation in photo.videoRepresentations {
postbox.mediaBox.copyResourceData(from: videoResource.id, to: representation.resource.id)
postbox.mediaBox.copyResourceData(from: videoResource.id, to: representation.resource.id, synchronous: true)
}
}
}

View File

@ -47,7 +47,7 @@ private func chatMessageGalleryControllerData(context: AccountContext, message:
case let .photoUpdated(image):
if let peer = messageMainPeer(message), let image = image {
let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.imageId, image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), image.videoRepresentations, peer, message.timestamp, nil, message.id, image.immediateThumbnailData, "action")])
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: promise, skipInitial: true, replaceRootController: { controller, ready in
let galleryController = AvatarGalleryController(context: context, peer: peer, sourceCorners: .roundRect(15.5), remoteEntries: promise, skipInitial: true, replaceRootController: { controller, ready in
})
return .chatAvatars(galleryController, image)

View File

@ -1549,7 +1549,13 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
func animateAvatarCollapse(transition: ContainedViewLayoutTransition) {
if let currentItemNode = self.listContainerNode.currentItemNode, case .animated = transition {
if let _ = self.avatarContainerNode.videoNode {
// if self.listContainerNode.currentIndex > 0 {
// transition.updateAlpha(node: currentItemNode, alpha: 0.0, completion: { _ in
// Queue.mainQueue().after(0.1, {
// currentItemNode.alpha = 1.0
// })
// })
// }
} else if let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage {
let avatarCopyView = UIImageView()
avatarCopyView.image = unroundedImage
@ -2781,6 +2787,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
controlsClippingFrame = apparentAvatarFrame
}
transition.updateFrameAdditive(node: self.avatarListNode, frame: CGRect(origin: apparentAvatarFrame.center, size: CGSize()))
transition.updateFrameAdditive(node: self.avatarOverlayNode, frame: CGRect(origin: apparentAvatarFrame.center, size: CGSize()))
let avatarListContainerFrame: CGRect
let avatarListContainerScale: CGFloat

View File

@ -2100,7 +2100,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
let entriesPromise = Promise<[AvatarGalleryEntry]>(entries)
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, sourceHasRoundCorners: !strongSelf.headerNode.isAvatarExpanded, remoteEntries: entriesPromise, skipInitial: true, centralEntryIndex: centralEntry.flatMap { entries.firstIndex(of: $0) }, replaceRootController: { controller, ready in
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
})
galleryController.openAvatarSetup = { [weak self] completion in
self?.openAvatarForEditing(hasRemove: false, completion: completion)
@ -3971,11 +3971,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}))
}
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ProfilePhoto_OpenInEditor, color: .accent, action: { [weak self] in
dismissAction()
self?.editAvatarItem(item)
}))
// items.append(ActionSheetButtonItem(title: self.presentationData.strings.ProfilePhoto_OpenInEditor, color: .accent, action: { [weak self] in
// dismissAction()
// self?.editAvatarItem(item)
// }))
let deleteTitle: String
if image.2.isEmpty {
@ -4040,6 +4039,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
}))
}
fileprivate func resetHeaderExpansion() {
if self.headerNode.isAvatarExpanded {
self.headerNode.ignoreCollapse = true
self.headerNode.updateIsAvatarExpanded(false, transition: .immediate)
self.updateNavigationExpansionPresentation(isExpanded: false, animated: true)
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
}
self.headerNode.ignoreCollapse = false
}
}
private func updateProfileVideo(_ image: UIImage, url: URL, adjustments: TGVideoEditAdjustments?) {
guard let data = image.jpegData(compressionQuality: 0.6) else {
@ -5823,7 +5834,15 @@ public final class PeerInfoScreen: ViewController {
super.displayNodeDidLoad()
}
public override func didMove(toParent viewController: UIViewController?) {
super.didMove(toParent: viewController)
if self.isSettings && viewController == nil {
self.controllerNode.resetHeaderExpansion()
}
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)

View File

@ -498,7 +498,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let rightInset: CGFloat = 16.0
var contentHeight: CGFloat = 20.0
let margin: CGFloat = 11.0
let margin: CGFloat = 12.0
let buttonTextSize = self.undoButtonTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
let buttonMinX: CGFloat
@ -508,8 +508,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
buttonMinX = layout.size.width - layout.safeInsets.left - rightInset
}
let titleSize = self.titleNode.updateLayout(CGSize(width: buttonMinX - 6.0 - leftInset - layout.safeInsets.left - margin, height: .greatestFiniteMagnitude))
let textSize = self.textNode.updateLayout(CGSize(width: buttonMinX - 6.0 - leftInset - layout.safeInsets.left - margin, height: .greatestFiniteMagnitude))
let titleSize = self.titleNode.updateLayout(CGSize(width: buttonMinX - 8.0 - leftInset - layout.safeInsets.left - margin, height: .greatestFiniteMagnitude))
let textSize = self.textNode.updateLayout(CGSize(width: buttonMinX - 8.0 - leftInset - layout.safeInsets.left - margin, height: .greatestFiniteMagnitude))
if !titleSize.width.isZero {
contentHeight += titleSize.height + 1.0