mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Video avatar fixes
This commit is contained in:
parent
f659d08c78
commit
94ef5b9acf
@ -2,7 +2,7 @@
|
||||
|
||||
@interface TGPhotoVideoEditor : NSObject
|
||||
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController screenImage:(UIImage *)screenImage image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed;
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed;
|
||||
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
|
||||
|
||||
|
@ -8,9 +8,11 @@
|
||||
|
||||
#import "TGMediaPickerGalleryVideoItemView.h"
|
||||
|
||||
#import "LegacyComponentsInternal.h"
|
||||
|
||||
@implementation TGPhotoVideoEditor
|
||||
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController screenImage:(UIImage *)screenImage image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed
|
||||
{
|
||||
id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager];
|
||||
|
||||
@ -18,11 +20,24 @@
|
||||
if (image != nil) {
|
||||
editableItem = image;
|
||||
} else if (video != nil) {
|
||||
if (![video.path.lowercaseString hasSuffix:@".mp4"]) {
|
||||
NSString *tmpPath = NSTemporaryDirectory();
|
||||
int64_t fileId = 0;
|
||||
arc4random_buf(&fileId, sizeof(fileId));
|
||||
NSString *videoMp4FilePath = [tmpPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%" PRId64 ".mp4", fileId]];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:videoMp4FilePath error:nil];
|
||||
[[NSFileManager defaultManager] createSymbolicLinkAtPath:videoMp4FilePath withDestinationPath:video.path error:nil];
|
||||
video = [NSURL fileURLWithPath:videoMp4FilePath];
|
||||
}
|
||||
|
||||
editableItem = [[TGCameraCapturedVideo alloc] initWithURL:video];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void (^present)(UIImage *) = ^(UIImage *screenImage) {
|
||||
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:editableItem intent:TGPhotoEditorControllerAvatarIntent adjustments:nil caption:nil screenImage:screenImage availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
||||
// controller.stickersContext = _stickersContext;
|
||||
// controller.stickersContext = _stickersContext;
|
||||
controller.skipInitialTransition = true;
|
||||
controller.dontHideStatusBar = true;
|
||||
controller.didFinishEditing = ^(__unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges)
|
||||
@ -64,6 +79,26 @@
|
||||
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:controller];
|
||||
controllerWindow.hidden = false;
|
||||
controller.view.clipsToBounds = true;
|
||||
};
|
||||
|
||||
if (image != nil) {
|
||||
present(image);
|
||||
} else if (video != nil) {
|
||||
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:[AVURLAsset assetWithURL:video]];
|
||||
imageGenerator.appliesPreferredTrackTransform = true;
|
||||
imageGenerator.maximumSize = CGSizeMake(1280, 1280);
|
||||
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
|
||||
imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
|
||||
|
||||
[imageGenerator generateCGImagesAsynchronouslyForTimes:@[ [NSValue valueWithCMTime:kCMTimeZero] ] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
|
||||
if (result == AVAssetImageGeneratorSucceeded) {
|
||||
UIImage *screenImage = [UIImage imageWithCGImage:image];
|
||||
TGDispatchOnMainThread(^{
|
||||
present(screenImage);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed
|
||||
|
@ -6,7 +6,7 @@ import LegacyComponents
|
||||
import TelegramPresentationData
|
||||
import LegacyUI
|
||||
|
||||
public func presentLegacyAvatarEditor(theme: PresentationTheme, screenImage: UIImage?, image: UIImage?, video: URL?, present: (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments?) -> Void) {
|
||||
public func presentLegacyAvatarEditor(theme: PresentationTheme, image: UIImage?, video: URL?, present: (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments?) -> Void) {
|
||||
let legacyController = LegacyController(presentation: .custom, theme: theme)
|
||||
legacyController.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
@ -19,7 +19,7 @@ public func presentLegacyAvatarEditor(theme: PresentationTheme, screenImage: UII
|
||||
|
||||
present(legacyController, nil)
|
||||
|
||||
TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, screenImage: screenImage, image: image, video: video, didFinishWithImage: { image in
|
||||
TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image, video: video, didFinishWithImage: { image in
|
||||
if let image = image {
|
||||
imageCompletion(image)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ static_library(
|
||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||
"//submodules/ShareController:ShareController",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
||||
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
||||
],
|
||||
|
@ -22,6 +22,7 @@ swift_library(
|
||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||
"//submodules/ShareController:ShareController",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
||||
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
||||
],
|
||||
|
@ -10,6 +10,7 @@ import SyncCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import GalleryUI
|
||||
import LegacyComponents
|
||||
import LegacyMediaPickerUI
|
||||
import SaveToCameraRoll
|
||||
|
||||
@ -187,6 +188,9 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>()
|
||||
private let centralItemAttributesDisposable = DisposableSet();
|
||||
|
||||
public var avatarPhotoEditCompletion: ((UIImage) -> Void)?
|
||||
public var avatarVideoEditCompletion: ((UIImage, URL, TGVideoEditAdjustments?) -> Void)?
|
||||
|
||||
private let _hiddenMedia = Promise<AvatarGalleryEntry?>(nil)
|
||||
public var hiddenMedia: Signal<AvatarGalleryEntry?, NoError> {
|
||||
return self._hiddenMedia.get()
|
||||
@ -635,7 +639,6 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
case let .progress(value):
|
||||
break
|
||||
case let .data(data):
|
||||
let screenImage: UIImage?
|
||||
let image: UIImage?
|
||||
let video: URL?
|
||||
if isImage {
|
||||
@ -644,22 +647,28 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
||||
} else {
|
||||
image = nil
|
||||
}
|
||||
screenImage = image
|
||||
video = nil
|
||||
} else {
|
||||
image = nil
|
||||
video = URL(fileURLWithPath: data.path)
|
||||
screenImage = nil
|
||||
}
|
||||
presentLegacyAvatarEditor(theme: strongSelf.presentationData.theme, screenImage: screenImage, image: image, video: video, present: { [weak self] c, a in
|
||||
|
||||
let avatarPhotoEditCompletion = strongSelf.avatarPhotoEditCompletion
|
||||
let avatarVideoEditCompletion = strongSelf.avatarVideoEditCompletion
|
||||
|
||||
presentLegacyAvatarEditor(theme: strongSelf.presentationData.theme, image: image, video: video, present: { [weak self] c, a in
|
||||
if let strongSelf = self {
|
||||
strongSelf.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
}
|
||||
}, imageCompletion: { [weak self] image in
|
||||
|
||||
}, videoCompletion: { [weak self] image, url, adjustments in
|
||||
|
||||
}, imageCompletion: { image in
|
||||
avatarPhotoEditCompletion?(image)
|
||||
}, videoCompletion: { image, url, adjustments in
|
||||
avatarVideoEditCompletion?(image, url, adjustments)
|
||||
})
|
||||
|
||||
Queue.mainQueue().after(0.4) {
|
||||
strongSelf.dismiss(forceAway: true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
@ -549,7 +549,7 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
hasPhotos = true
|
||||
}
|
||||
|
||||
let completedPhotoImpl: (UIImage) -> Void = { image in
|
||||
let completedProfilePhotoImpl: (UIImage) -> Void = { image in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
@ -580,7 +580,7 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
}
|
||||
}
|
||||
|
||||
let completedVideoImpl: (UIImage, URL, TGVideoEditAdjustments?) -> Void = { image, url, adjustments in
|
||||
let completedProfileVideoImpl: (UIImage, URL, TGVideoEditAdjustments?) -> Void = { image, url, adjustments in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
@ -675,18 +675,18 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
mixin.requestSearchController = { assetsController in
|
||||
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
||||
assetsController?.dismiss()
|
||||
completedPhotoImpl(result)
|
||||
completedProfilePhotoImpl(result)
|
||||
}))
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
mixin.didFinishWithImage = { image in
|
||||
if let image = image {
|
||||
completedPhotoImpl(image)
|
||||
completedProfilePhotoImpl(image)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithVideo = { image, url, adjustments in
|
||||
if let image = image, let url = url {
|
||||
completedVideoImpl(image, url, adjustments)
|
||||
completedProfileVideoImpl(image, url, adjustments)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithDelete = {
|
||||
@ -727,6 +727,12 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
if peer.smallProfileImage != nil {
|
||||
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: cachedAvatarEntries.with { $0 }, replaceRootController: { controller, ready in
|
||||
})
|
||||
galleryController.avatarPhotoEditCompletion = { image in
|
||||
completedProfilePhotoImpl(image)
|
||||
}
|
||||
galleryController.avatarVideoEditCompletion = { image, url, adjustments in
|
||||
completedProfileVideoImpl(image, url, adjustments)
|
||||
}
|
||||
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||
return nil
|
||||
}))
|
||||
|
@ -994,6 +994,119 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
let blockedPeers = Promise<BlockedPeersContext?>(nil)
|
||||
let hasTwoStepAuthPromise = Promise<Bool?>(nil)
|
||||
|
||||
let completedProfilePhotoImpl: (UIImage) -> Void = { image in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource)
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = .image(representation, true)
|
||||
return state
|
||||
}
|
||||
updateAvatarDisposable.set((updateAccountPhoto(account: context.account, resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
}) |> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .complete:
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = nil
|
||||
return state
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
let completedProfileVideoImpl: (UIImage, URL, TGVideoEditAdjustments?) -> Void = { image, url, adjustments in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource)
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = .image(representation, true)
|
||||
return state
|
||||
}
|
||||
|
||||
var videoStartTimestamp: Double? = nil
|
||||
if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
|
||||
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
|
||||
}
|
||||
|
||||
let signal = Signal<TelegramMediaResource, UploadPeerPhotoError> { subscriber in
|
||||
var filteredPath = url.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? = adjustments.flatMap { adjustments in
|
||||
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
||||
return LegacyPaintEntityRenderer(account: context.account, adjustments: adjustments)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(account: context.account)
|
||||
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
|
||||
let signalDisposable = signal.start(next: { next in
|
||||
if let result = next as? TGMediaVideoConversionResult {
|
||||
if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
|
||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
}
|
||||
|
||||
var value = stat()
|
||||
if stat(result.fileURL.path, &value) == 0 {
|
||||
if let data = try? Data(contentsOf: result.fileURL) {
|
||||
let resource: TelegramMediaResource
|
||||
if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
|
||||
resource = LocalFileMediaResource(fileId: liveUploadData.id)
|
||||
} else {
|
||||
resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
}
|
||||
context.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()
|
||||
}
|
||||
}
|
||||
|
||||
updateAvatarDisposable.set((signal
|
||||
|> mapToSignal { videoResource in
|
||||
return updateAccountPhoto(account: context.account, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} |> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .complete:
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = nil
|
||||
return state
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
let arguments = SettingsItemArguments(sharedContext: context.sharedContext, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
|
||||
var updating = false
|
||||
updateState {
|
||||
@ -1013,6 +1126,12 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
let galleryController = AvatarGalleryController(context: context, peer: peer, replaceRootController: { controller, ready in
|
||||
|
||||
})
|
||||
galleryController.avatarPhotoEditCompletion = { image in
|
||||
completedProfilePhotoImpl(image)
|
||||
}
|
||||
galleryController.avatarVideoEditCompletion = { image, url, adjustments in
|
||||
completedProfileVideoImpl(image, url, adjustments)
|
||||
}
|
||||
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.last?.representation
|
||||
updateHiddenAvatarImpl?()
|
||||
@ -1285,136 +1404,23 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
hasPhotos = true
|
||||
}
|
||||
|
||||
let completedImpl: (UIImage) -> Void = { image in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource)
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = .image(representation, true)
|
||||
return state
|
||||
}
|
||||
updateAvatarDisposable.set((updateAccountPhoto(account: context.account, resource: resource, videoResource: nil, videoStartTimestamp: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
}) |> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .complete:
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = nil
|
||||
return state
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
let completedVideoImpl: (UIImage, URL, TGVideoEditAdjustments?) -> Void = { image, url, adjustments in
|
||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource)
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = .image(representation, true)
|
||||
return state
|
||||
}
|
||||
|
||||
var videoStartTimestamp: Double? = nil
|
||||
if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
|
||||
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
|
||||
}
|
||||
|
||||
let signal = Signal<TelegramMediaResource, UploadPeerPhotoError> { subscriber in
|
||||
var filteredPath = url.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? = adjustments.flatMap { adjustments in
|
||||
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
||||
return LegacyPaintEntityRenderer(account: context.account, adjustments: adjustments)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(account: context.account)
|
||||
let signal = TGMediaVideoConverter.convert(avAsset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
|
||||
let signalDisposable = signal.start(next: { next in
|
||||
if let result = next as? TGMediaVideoConversionResult {
|
||||
if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
|
||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
}
|
||||
|
||||
var value = stat()
|
||||
if stat(result.fileURL.path, &value) == 0 {
|
||||
if let data = try? Data(contentsOf: result.fileURL) {
|
||||
let resource: TelegramMediaResource
|
||||
if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
|
||||
resource = LocalFileMediaResource(fileId: liveUploadData.id)
|
||||
} else {
|
||||
resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
}
|
||||
context.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()
|
||||
}
|
||||
}
|
||||
|
||||
updateAvatarDisposable.set((signal
|
||||
|> mapToSignal { videoResource in
|
||||
return updateAccountPhoto(account: context.account, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} |> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .complete:
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.updatingAvatar = nil
|
||||
return state
|
||||
}
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos, hasViewButton: false, personalPhoto: true, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false)!
|
||||
let _ = currentAvatarMixin.swap(mixin)
|
||||
mixin.requestSearchController = { assetsController in
|
||||
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
||||
assetsController?.dismiss()
|
||||
completedImpl(result)
|
||||
completedProfilePhotoImpl(result)
|
||||
}))
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
mixin.didFinishWithImage = { image in
|
||||
if let image = image {
|
||||
completedImpl(image)
|
||||
completedProfilePhotoImpl(image)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithVideo = { image, url, adjustments in
|
||||
if let image = image, let url = url {
|
||||
completedVideoImpl(image, url, adjustments)
|
||||
completedProfileVideoImpl(image, url, adjustments)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithDelete = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user