mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Video avatar fixes
This commit is contained in:
@@ -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)
|
let legacyController = LegacyController(presentation: .custom, theme: theme)
|
||||||
legacyController.statusBar.statusBarStyle = .Ignore
|
legacyController.statusBar.statusBarStyle = .Ignore
|
||||||
|
|
||||||
|
|||||||
@@ -269,14 +269,14 @@ private class LegacyPaintTextEntity: LegacyPaintEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRenderer {
|
public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRenderer {
|
||||||
private let account: Account
|
private let account: Account?
|
||||||
private let queue = Queue()
|
private let queue = Queue()
|
||||||
|
|
||||||
private let entities: [LegacyPaintEntity]
|
private let entities: [LegacyPaintEntity]
|
||||||
private let originalSize: CGSize
|
private let originalSize: CGSize
|
||||||
private let cropRect: CGRect?
|
private let cropRect: CGRect?
|
||||||
|
|
||||||
public init(account: Account, adjustments: TGMediaEditAdjustments) {
|
public init(account: Account?, adjustments: TGMediaEditAdjustments) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.originalSize = adjustments.originalSize
|
self.originalSize = adjustments.originalSize
|
||||||
self.cropRect = adjustments.cropRect.isEmpty ? nil : adjustments.cropRect
|
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 {
|
if let paintingData = adjustments.paintingData, let paintingEntities = paintingData.entities {
|
||||||
for paintingEntity in paintingEntities {
|
for paintingEntity in paintingEntities {
|
||||||
if let sticker = paintingEntity as? TGPhotoPaintStickerEntity {
|
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)
|
entities.append(entity)
|
||||||
}
|
}
|
||||||
} else if let text = paintingEntity as? TGPhotoPaintTextEntity {
|
} else if let text = paintingEntity as? TGPhotoPaintTextEntity {
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ public enum SignUpError {
|
|||||||
case invalidLastName
|
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
|
return account.postbox.transaction { transaction -> Signal<Void, SignUpError> in
|
||||||
if let state = transaction.getState() as? UnauthorizedAccountState, case let .signUp(number, codeHash, _, _, _, syncContacts) = state.contents {
|
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))
|
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())
|
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||||
account.postbox.mediaBox.storeResourceData(resource.id, data: avatarData)
|
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
|
|> `catch` { _ -> Signal<UpdatePeerPhotoStatus, SignUpError> in
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@@ -486,7 +486,7 @@ public func signUpWithName(accountManager: AccountManager, account: Unauthorized
|
|||||||
|> then(switchedAccounts)
|
|> then(switchedAccounts)
|
||||||
} else {
|
} else {
|
||||||
return appliedState
|
return appliedState
|
||||||
|> then(switchedAccounts)
|
|> then(switchedAccounts)
|
||||||
}
|
}
|
||||||
case .authorizationSignUpRequired:
|
case .authorizationSignUpRequired:
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
|
|||||||
@@ -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> {
|
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)
|
if let messageMediaPreuploadManager = messageMediaPreuploadManager {
|
||||||
|> map { result -> UploadedPeerPhotoData in
|
return messageMediaPreuploadManager.upload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .video), hintFileSize: nil, hintFileIsLarge: false)
|
||||||
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
|> map { result -> UploadedPeerPhotoData in
|
||||||
}
|
return UploadedPeerPhotoData(resource: resource, content: .result(result))
|
||||||
|> `catch` { _ -> Signal<UploadedPeerPhotoData, NoError> in
|
}
|
||||||
return .single(UploadedPeerPhotoData(resource: resource, content: .error))
|
|> `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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import AccountContext
|
|||||||
import CountrySelectionUI
|
import CountrySelectionUI
|
||||||
import SettingsUI
|
import SettingsUI
|
||||||
import PhoneNumberFormat
|
import PhoneNumberFormat
|
||||||
|
import LegacyComponents
|
||||||
|
import LegacyMediaPickerUI
|
||||||
|
|
||||||
private enum InnerState: Equatable {
|
private enum InnerState: Equatable {
|
||||||
case state(UnauthorizedAccountStateContents)
|
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: "")))
|
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||||
}).start()
|
}).start()
|
||||||
}, displayCancel: displayCancel)
|
}, 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 {
|
if let strongSelf = self {
|
||||||
controller?.inProgress = true
|
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
|
|> deliverOnMainQueue).start(error: { error in
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let strongSelf = self, let controller = controller {
|
if let strongSelf = self, let controller = controller {
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||||||
var initialName: (String, String) = ("", "")
|
var initialName: (String, String) = ("", "")
|
||||||
private var termsOfService: UnauthorizedAccountTermsOfService?
|
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()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
@@ -88,6 +91,12 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||||||
self?.present(c, in: .window(.root), with: a)
|
self?.present(c, in: .window(.root), with: a)
|
||||||
}, openCurrent: nil, completion: { image in
|
}, openCurrent: nil, completion: { image in
|
||||||
self?.controllerNode.currentPhoto = image
|
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()
|
self.displayNodeDidLoad()
|
||||||
@@ -150,7 +159,7 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||||||
if let name = name {
|
if let name = name {
|
||||||
self.signUpWithName?(name.0, name.1, self.controllerNode.currentPhoto.flatMap({ image in
|
self.signUpWithName?(name.0, name.1, self.controllerNode.currentPhoto.flatMap({ image in
|
||||||
return compressImageToJPEG(image, quality: 0.7)
|
return compressImageToJPEG(image, quality: 0.7)
|
||||||
}))
|
}), self.avatarUrl, self.avatarAdjustments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user