This commit is contained in:
Ali 2020-07-10 21:44:56 +04:00
commit 5bdb8a4baa
9 changed files with 141 additions and 28 deletions

View file

@ -32,7 +32,7 @@ public func presentLegacyAvatarEditor(theme: PresentationTheme, image: UIImage?,
})
}
public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, openCurrent: (() -> Void)?, completion: @escaping (UIImage) -> Void) {
public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, openCurrent: (() -> Void)?, completion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments?) -> Void = { _, _, _ in}) {
let legacyController = LegacyController(presentation: .custom, theme: theme)
legacyController.statusBar.statusBarStyle = .Ignore
@ -53,6 +53,12 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
}
completion(image)
}
mixin.didFinishWithVideo = { image, url, adjustments in
guard let image = image, let url = url else {
return
}
videoCompletion(image, url, adjustments)
}
mixin.didFinishWithView = {
openCurrent?()
}

View file

@ -269,14 +269,14 @@ private class LegacyPaintTextEntity: LegacyPaintEntity {
}
public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRenderer {
private let account: Account
private let account: Account?
private let queue = Queue()
private let entities: [LegacyPaintEntity]
private let originalSize: CGSize
private let cropRect: CGRect?
public init(account: Account, adjustments: TGMediaEditAdjustments) {
public init(account: Account?, adjustments: TGMediaEditAdjustments) {
self.account = account
self.originalSize = adjustments.originalSize
self.cropRect = adjustments.cropRect.isEmpty ? nil : adjustments.cropRect
@ -285,7 +285,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
if let paintingData = adjustments.paintingData, let paintingEntities = paintingData.entities {
for paintingEntity in paintingEntities {
if let sticker = paintingEntity as? TGPhotoPaintStickerEntity {
if let entity = LegacyPaintStickerEntity(account: account, entity: sticker) {
if let account = account, let entity = LegacyPaintStickerEntity(account: account, entity: sticker) {
entities.append(entity)
}
} else if let text = paintingEntity as? TGPhotoPaintTextEntity {

View file

@ -430,7 +430,7 @@ public enum SignUpError {
case invalidLastName
}
public func signUpWithName(accountManager: AccountManager, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?) -> Signal<Void, SignUpError> {
public func signUpWithName(accountManager: AccountManager, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?, avatarVideo: Signal<UploadedPeerPhotoData?, NoError>?, videoStartTimestamp: Double?) -> Signal<Void, SignUpError> {
return account.postbox.transaction { transaction -> Signal<Void, SignUpError> in
if let state = transaction.getState() as? UnauthorizedAccountState, case let .signUp(number, codeHash, _, _, _, syncContacts) = state.contents {
return account.network.request(Api.functions.auth.signUp(phoneNumber: number, phoneCodeHash: codeHash, firstName: firstName, lastName: lastName))
@ -470,7 +470,7 @@ public func signUpWithName(accountManager: AccountManager, account: Unauthorized
let resource = LocalFileMediaResource(fileId: arc4random64())
account.postbox.mediaBox.storeResourceData(resource.id, data: avatarData)
return updatePeerPhotoInternal(postbox: account.postbox, network: account.network, stateManager: nil, accountPeerId: user.id, peer: .single(user), photo: uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: resource), video: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { _, _ in .single([:]) })
return updatePeerPhotoInternal(postbox: account.postbox, network: account.network, stateManager: nil, accountPeerId: user.id, peer: .single(user), photo: uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: resource), video: avatarVideo, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { _, _ in .single([:]) })
|> `catch` { _ -> Signal<UpdatePeerPhotoStatus, SignUpError> in
return .complete()
}
@ -486,7 +486,7 @@ public func signUpWithName(accountManager: AccountManager, account: Unauthorized
|> then(switchedAccounts)
} else {
return appliedState
|> then(switchedAccounts)
|> then(switchedAccounts)
}
case .authorizationSignUpRequired:
return .fail(.generic)

View file

@ -47,13 +47,23 @@ public func uploadedPeerPhoto(postbox: Postbox, network: Network, resource: Medi
}
}
public func uploadedPeerVideo(postbox: Postbox, network: Network, messageMediaPreuploadManager: MessageMediaPreuploadManager, resource: MediaResource) -> Signal<UploadedPeerPhotoData, NoError> {
return messageMediaPreuploadManager.upload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false)
|> map { result -> UploadedPeerPhotoData in
return UploadedPeerPhotoData(resource: resource, content: .result(result))
}
|> `catch` { _ -> Signal<UploadedPeerPhotoData, NoError> in
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
public func uploadedPeerVideo(postbox: Postbox, network: Network, messageMediaPreuploadManager: MessageMediaPreuploadManager?, resource: MediaResource) -> Signal<UploadedPeerPhotoData, NoError> {
if let messageMediaPreuploadManager = messageMediaPreuploadManager {
return messageMediaPreuploadManager.upload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false)
|> map { result -> UploadedPeerPhotoData in
return UploadedPeerPhotoData(resource: resource, content: .result(result))
}
|> `catch` { _ -> Signal<UploadedPeerPhotoData, NoError> in
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
}
} else {
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false)
|> map { result -> UploadedPeerPhotoData in
return UploadedPeerPhotoData(resource: resource, content: .result(result))
}
|> `catch` { _ -> Signal<UploadedPeerPhotoData, NoError> in
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
}
}
}

View file

@ -15,6 +15,8 @@ import AccountContext
import CountrySelectionUI
import SettingsUI
import PhoneNumberFormat
import LegacyComponents
import LegacyMediaPickerUI
private enum InnerState: Equatable {
case state(UnauthorizedAccountStateContents)
@ -684,11 +686,70 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
}).start()
}, displayCancel: displayCancel)
controller.signUpWithName = { [weak self, weak controller] firstName, lastName, avatarData in
controller.signUpWithName = { [weak self, weak controller] firstName, lastName, avatarData, avatarUrl, avatarAdjustments in
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((signUpWithName(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, firstName: firstName, lastName: lastName, avatarData: avatarData)
var videoStartTimestamp: Double? = nil
if let adjustments = avatarAdjustments, adjustments.videoStartValue > 0.0 {
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
}
let avatarVideo: Signal<UploadedPeerPhotoData?, NoError>?
if let avatarUrl = avatarUrl {
let account = strongSelf.account
avatarVideo = Signal<TelegramMediaResource?, NoError> { subscriber in
var filteredPath = avatarUrl.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? = avatarAdjustments.flatMap { adjustments in
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
return LegacyPaintEntityRenderer(account: nil, adjustments: adjustments)
} else {
return nil
}
}
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: avatarAdjustments, watcher: nil, entityRenderer: entityRenderer)!
let signalDisposable = signal.start(next: { next in
if let result = next as? TGMediaVideoConversionResult {
var value = stat()
if stat(result.fileURL.path, &value) == 0 {
if let data = try? Data(contentsOf: result.fileURL) {
let resource = LocalFileMediaResource(fileId: arc4random64())
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()
}
}
|> mapToSignal { resource -> Signal<UploadedPeerPhotoData?, NoError> in
if let resource = resource {
return uploadedPeerVideo(postbox: account.postbox, network: account.network, messageMediaPreuploadManager: nil, resource: resource) |> map(Optional.init)
} else {
return .single(nil)
}
}
} else {
avatarVideo = nil
}
strongSelf.actionDisposable.set((signUpWithName(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, firstName: firstName, lastName: lastName, avatarData: avatarData, avatarVideo: avatarVideo, videoStartTimestamp: videoStartTimestamp)
|> deliverOnMainQueue).start(error: { error in
Queue.mainQueue().async {
if let strongSelf = self, let controller = controller {

View file

@ -22,7 +22,10 @@ final class AuthorizationSequenceSignUpController: ViewController {
var initialName: (String, String) = ("", "")
private var termsOfService: UnauthorizedAccountTermsOfService?
var signUpWithName: ((String, String, Data?) -> Void)?
var signUpWithName: ((String, String, Data?, URL?, TGVideoEditAdjustments?) -> Void)?
var avatarUrl: URL?
var avatarAdjustments: TGVideoEditAdjustments?
private let hapticFeedback = HapticFeedback()
@ -88,6 +91,12 @@ final class AuthorizationSequenceSignUpController: ViewController {
self?.present(c, in: .window(.root), with: a)
}, openCurrent: nil, completion: { image in
self?.controllerNode.currentPhoto = image
self?.avatarUrl = nil
self?.avatarAdjustments = nil
}, videoCompletion: { image, url, adjustments in
self?.controllerNode.currentPhoto = image
self?.avatarUrl = url
self?.avatarAdjustments = adjustments
})
})
self.displayNodeDidLoad()
@ -150,7 +159,7 @@ final class AuthorizationSequenceSignUpController: ViewController {
if let name = name {
self.signUpWithName?(name.0, name.1, self.controllerNode.currentPhoto.flatMap({ image in
return compressImageToJPEG(image, quality: 0.7)
}))
}), self.avatarUrl, self.avatarAdjustments)
}
}
}

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, replaceRootController: { controller, ready in
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: promise, skipInitial: true, replaceRootController: { controller, ready in
})
return .chatAvatars(galleryController, image)

View file

@ -1310,22 +1310,32 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode {
transition.updateAlpha(node: self.iconNode, alpha: iconHidden ? 0.0 : 1.0)
transition.updateAlpha(node: self.updatingAvatarOverlay, alpha: overlayHidden ? 0.0 : 1.0)
} else {
var immediately = self.currentRepresentation == nil
if isEditing {
immediately = immediately || peer.profileImageRepresentations.isEmpty
iconHidden = peer.profileImageRepresentations.isEmpty
overlayHidden = peer.profileImageRepresentations.isEmpty
} else {
iconHidden = true
overlayHidden = true
}
Queue.mainQueue().after(0.3) { [weak self] in
guard let strongSelf = self else {
return
let targetAlpha: CGFloat = overlayHidden ? 0.0 : 1.0
if self.updatingAvatarOverlay.alpha != targetAlpha {
let update = {
self.statusNode.transitionToState(.none)
self.currentRepresentation = nil
self.imageNode.setSignal(.single(nil))
transition.updateAlpha(node: self.iconNode, alpha: iconHidden ? 0.0 : 1.0)
transition.updateAlpha(node: self.updatingAvatarOverlay, alpha: overlayHidden ? 0.0 : 1.0)
}
if immediately {
update()
} else {
Queue.mainQueue().after(0.3) {
update()
}
}
strongSelf.statusNode.transitionToState(.none)
strongSelf.currentRepresentation = nil
strongSelf.imageNode.setSignal(.single(nil))
transition.updateAlpha(node: strongSelf.iconNode, alpha: iconHidden ? 0.0 : 1.0)
transition.updateAlpha(node: strongSelf.updatingAvatarOverlay, alpha: overlayHidden ? 0.0 : 1.0)
}
}
if !overlayHidden && self.updatingAvatarOverlay.image == nil {
@ -2310,6 +2320,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)?
var requestAvatarExpansion: ((Bool, [AvatarGalleryEntry], AvatarGalleryEntry?, (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?) -> Void)?
var requestOpenAvatarForEditing: ((Bool) -> Void)?
var cancelUpload: (() -> Void)?
var requestUpdateLayout: (() -> Void)?
var displayCopyContextMenu: ((ASDisplayNode, Bool, Bool) -> Void)?
@ -2358,6 +2369,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.editingContentNode.alpha = 0.0
self.avatarOverlayNode = PeerInfoEditingAvatarOverlayNode(context: context)
self.avatarOverlayNode.isUserInteractionEnabled = false
self.navigationBackgroundNode = ASDisplayNode()
self.navigationBackgroundNode.isUserInteractionEnabled = false
@ -2445,9 +2457,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if let currentEntry = self.avatarListNode.listContainerNode.currentEntry {
self.requestAvatarExpansion?(true, self.avatarListNode.listContainerNode.galleryEntries, self.avatarListNode.listContainerNode.currentEntry, self.avatarTransitionArguments(entry: currentEntry))
}
} else if let entry = self.avatarListNode.listContainerNode.galleryEntries.first{
} else if let entry = self.avatarListNode.listContainerNode.galleryEntries.first {
let _ = self.avatarListNode.avatarContainerNode.avatarNode
self.requestAvatarExpansion?(false, self.avatarListNode.listContainerNode.galleryEntries, nil, self.avatarTransitionArguments(entry: entry))
} else {
self.cancelUpload?()
}
}

View file

@ -2062,6 +2062,19 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
self?.performButtonAction(key: key)
}
self.headerNode.cancelUpload = { [weak self] in
guard let strongSelf = self else {
return
}
if strongSelf.state.updatingAvatar != nil {
strongSelf.updateAvatarDisposable.set(nil)
strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
if let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
}
}
}
self.headerNode.requestAvatarExpansion = { [weak self] gallery, entries, centralEntry, _ in
guard let strongSelf = self, let peer = strongSelf.data?.peer, peer.smallProfileImage != nil else {
return