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
|
@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;
|
+ (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 "TGMediaPickerGalleryVideoItemView.h"
|
||||||
|
|
||||||
|
#import "LegacyComponentsInternal.h"
|
||||||
|
|
||||||
@implementation TGPhotoVideoEditor
|
@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];
|
id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager];
|
||||||
|
|
||||||
@ -18,52 +20,85 @@
|
|||||||
if (image != nil) {
|
if (image != nil) {
|
||||||
editableItem = image;
|
editableItem = image;
|
||||||
} else if (video != nil) {
|
} 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];
|
editableItem = [[TGCameraCapturedVideo alloc] initWithURL:video];
|
||||||
}
|
}
|
||||||
|
|
||||||
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.skipInitialTransition = true;
|
|
||||||
controller.dontHideStatusBar = true;
|
|
||||||
controller.didFinishEditing = ^(__unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges)
|
|
||||||
{
|
|
||||||
if (didFinishWithImage != nil)
|
|
||||||
didFinishWithImage(resultImage);
|
|
||||||
};
|
|
||||||
controller.didFinishEditingVideo = ^(NSURL *url, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
|
||||||
if (didFinishWithVideo != nil)
|
|
||||||
didFinishWithVideo(resultImage, url, adjustments);
|
|
||||||
};
|
|
||||||
controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
|
|
||||||
{
|
|
||||||
return [editableItem thumbnailImageSignal];
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.requestOriginalScreenSizeImage = ^(id<TGMediaEditableItem> editableItem, NSTimeInterval position)
|
|
||||||
{
|
void (^present)(UIImage *) = ^(UIImage *screenImage) {
|
||||||
return [editableItem screenImageSignal:position];
|
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.requestOriginalFullSizeImage = ^(id<TGMediaEditableItem> editableItem, NSTimeInterval position)
|
controller.skipInitialTransition = true;
|
||||||
{
|
controller.dontHideStatusBar = true;
|
||||||
if (editableItem.isVideo) {
|
controller.didFinishEditing = ^(__unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges)
|
||||||
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
{
|
||||||
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
if (didFinishWithImage != nil)
|
||||||
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
didFinishWithImage(resultImage);
|
||||||
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
};
|
||||||
|
controller.didFinishEditingVideo = ^(NSURL *url, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||||
|
if (didFinishWithVideo != nil)
|
||||||
|
didFinishWithVideo(resultImage, url, adjustments);
|
||||||
|
};
|
||||||
|
controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
|
||||||
|
{
|
||||||
|
return [editableItem thumbnailImageSignal];
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.requestOriginalScreenSizeImage = ^(id<TGMediaEditableItem> editableItem, NSTimeInterval position)
|
||||||
|
{
|
||||||
|
return [editableItem screenImageSignal:position];
|
||||||
|
};
|
||||||
|
controller.requestOriginalFullSizeImage = ^(id<TGMediaEditableItem> editableItem, NSTimeInterval position)
|
||||||
|
{
|
||||||
|
if (editableItem.isVideo) {
|
||||||
|
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
|
||||||
|
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem allowNetworkAccess:true];
|
||||||
|
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||||
|
return ((TGCameraCapturedVideo *)editableItem).avAsset;
|
||||||
|
} else {
|
||||||
|
return [editableItem originalImageSignal:position];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return [editableItem originalImageSignal:position];
|
return [editableItem originalImageSignal:position];
|
||||||
}
|
}
|
||||||
} else {
|
};
|
||||||
return [editableItem originalImageSignal:position];
|
controller.onDismiss = ^{
|
||||||
}
|
dismissed();
|
||||||
};
|
};
|
||||||
controller.onDismiss = ^{
|
|
||||||
dismissed();
|
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:controller];
|
||||||
|
controllerWindow.hidden = false;
|
||||||
|
controller.view.clipsToBounds = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:controller];
|
if (image != nil) {
|
||||||
controllerWindow.hidden = false;
|
present(image);
|
||||||
controller.view.clipsToBounds = true;
|
} 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
|
+ (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 TelegramPresentationData
|
||||||
import LegacyUI
|
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)
|
let legacyController = LegacyController(presentation: .custom, theme: theme)
|
||||||
legacyController.statusBar.statusBarStyle = .Ignore
|
legacyController.statusBar.statusBarStyle = .Ignore
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ public func presentLegacyAvatarEditor(theme: PresentationTheme, screenImage: UII
|
|||||||
|
|
||||||
present(legacyController, nil)
|
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 {
|
if let image = image {
|
||||||
imageCompletion(image)
|
imageCompletion(image)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ static_library(
|
|||||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||||
"//submodules/ShareController:ShareController",
|
"//submodules/ShareController:ShareController",
|
||||||
"//submodules/AppBundle:AppBundle",
|
"//submodules/AppBundle:AppBundle",
|
||||||
|
"//submodules/LegacyComponents:LegacyComponents",
|
||||||
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
||||||
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
||||||
],
|
],
|
||||||
|
@ -22,6 +22,7 @@ swift_library(
|
|||||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||||
"//submodules/ShareController:ShareController",
|
"//submodules/ShareController:ShareController",
|
||||||
"//submodules/AppBundle:AppBundle",
|
"//submodules/AppBundle:AppBundle",
|
||||||
|
"//submodules/LegacyComponents:LegacyComponents",
|
||||||
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
"//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI",
|
||||||
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
"//submodules/SaveToCameraRoll:SaveToCameraRoll",
|
||||||
],
|
],
|
||||||
|
@ -10,6 +10,7 @@ import SyncCore
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import GalleryUI
|
import GalleryUI
|
||||||
|
import LegacyComponents
|
||||||
import LegacyMediaPickerUI
|
import LegacyMediaPickerUI
|
||||||
import SaveToCameraRoll
|
import SaveToCameraRoll
|
||||||
|
|
||||||
@ -187,6 +188,9 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>()
|
private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>()
|
||||||
private let centralItemAttributesDisposable = DisposableSet();
|
private let centralItemAttributesDisposable = DisposableSet();
|
||||||
|
|
||||||
|
public var avatarPhotoEditCompletion: ((UIImage) -> Void)?
|
||||||
|
public var avatarVideoEditCompletion: ((UIImage, URL, TGVideoEditAdjustments?) -> Void)?
|
||||||
|
|
||||||
private let _hiddenMedia = Promise<AvatarGalleryEntry?>(nil)
|
private let _hiddenMedia = Promise<AvatarGalleryEntry?>(nil)
|
||||||
public var hiddenMedia: Signal<AvatarGalleryEntry?, NoError> {
|
public var hiddenMedia: Signal<AvatarGalleryEntry?, NoError> {
|
||||||
return self._hiddenMedia.get()
|
return self._hiddenMedia.get()
|
||||||
@ -635,7 +639,6 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
case let .progress(value):
|
case let .progress(value):
|
||||||
break
|
break
|
||||||
case let .data(data):
|
case let .data(data):
|
||||||
let screenImage: UIImage?
|
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
let video: URL?
|
let video: URL?
|
||||||
if isImage {
|
if isImage {
|
||||||
@ -644,22 +647,28 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
|
|||||||
} else {
|
} else {
|
||||||
image = nil
|
image = nil
|
||||||
}
|
}
|
||||||
screenImage = image
|
|
||||||
video = nil
|
video = nil
|
||||||
} else {
|
} else {
|
||||||
image = nil
|
image = nil
|
||||||
video = URL(fileURLWithPath: data.path)
|
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 {
|
if let strongSelf = self {
|
||||||
strongSelf.present(c, in: .window(.root), with: a, blockInteraction: true)
|
strongSelf.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||||
}
|
}
|
||||||
}, imageCompletion: { [weak self] image in
|
}, imageCompletion: { image in
|
||||||
|
avatarPhotoEditCompletion?(image)
|
||||||
}, videoCompletion: { [weak self] image, url, adjustments in
|
}, 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
|
hasPhotos = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let completedPhotoImpl: (UIImage) -> Void = { image in
|
let completedProfilePhotoImpl: (UIImage) -> Void = { image in
|
||||||
if let data = image.jpegData(compressionQuality: 0.6) {
|
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
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) {
|
if let data = image.jpegData(compressionQuality: 0.6) {
|
||||||
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
||||||
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||||
@ -675,18 +675,18 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
|||||||
mixin.requestSearchController = { assetsController in
|
mixin.requestSearchController = { assetsController in
|
||||||
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
||||||
assetsController?.dismiss()
|
assetsController?.dismiss()
|
||||||
completedPhotoImpl(result)
|
completedProfilePhotoImpl(result)
|
||||||
}))
|
}))
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
mixin.didFinishWithImage = { image in
|
mixin.didFinishWithImage = { image in
|
||||||
if let image = image {
|
if let image = image {
|
||||||
completedPhotoImpl(image)
|
completedProfilePhotoImpl(image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixin.didFinishWithVideo = { image, url, adjustments in
|
mixin.didFinishWithVideo = { image, url, adjustments in
|
||||||
if let image = image, let url = url {
|
if let image = image, let url = url {
|
||||||
completedVideoImpl(image, url, adjustments)
|
completedProfileVideoImpl(image, url, adjustments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixin.didFinishWithDelete = {
|
mixin.didFinishWithDelete = {
|
||||||
@ -727,6 +727,12 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
|||||||
if peer.smallProfileImage != nil {
|
if peer.smallProfileImage != nil {
|
||||||
let galleryController = AvatarGalleryController(context: context, peer: peer, remoteEntries: cachedAvatarEntries.with { $0 }, replaceRootController: { controller, ready in
|
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
|
presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
@ -994,6 +994,119 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
|||||||
let blockedPeers = Promise<BlockedPeersContext?>(nil)
|
let blockedPeers = Promise<BlockedPeersContext?>(nil)
|
||||||
let hasTwoStepAuthPromise = Promise<Bool?>(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: {
|
let arguments = SettingsItemArguments(sharedContext: context.sharedContext, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
|
||||||
var updating = false
|
var updating = false
|
||||||
updateState {
|
updateState {
|
||||||
@ -1013,6 +1126,12 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
|||||||
let galleryController = AvatarGalleryController(context: context, peer: peer, replaceRootController: { controller, ready in
|
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
|
hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in
|
||||||
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.last?.representation
|
avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.last?.representation
|
||||||
updateHiddenAvatarImpl?()
|
updateHiddenAvatarImpl?()
|
||||||
@ -1284,137 +1403,24 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
|||||||
if let peer = peer, !peer.profileImageRepresentations.isEmpty {
|
if let peer = peer, !peer.profileImageRepresentations.isEmpty {
|
||||||
hasPhotos = true
|
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 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)
|
let _ = currentAvatarMixin.swap(mixin)
|
||||||
mixin.requestSearchController = { assetsController in
|
mixin.requestSearchController = { assetsController in
|
||||||
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
let controller = WebSearchController(context: context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: nil, completion: { result in
|
||||||
assetsController?.dismiss()
|
assetsController?.dismiss()
|
||||||
completedImpl(result)
|
completedProfilePhotoImpl(result)
|
||||||
}))
|
}))
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
mixin.didFinishWithImage = { image in
|
mixin.didFinishWithImage = { image in
|
||||||
if let image = image {
|
if let image = image {
|
||||||
completedImpl(image)
|
completedProfilePhotoImpl(image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixin.didFinishWithVideo = { image, url, adjustments in
|
mixin.didFinishWithVideo = { image, url, adjustments in
|
||||||
if let image = image, let url = url {
|
if let image = image, let url = url {
|
||||||
completedVideoImpl(image, url, adjustments)
|
completedProfileVideoImpl(image, url, adjustments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixin.didFinishWithDelete = {
|
mixin.didFinishWithDelete = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user