diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index d5c8ff0984..c87abff163 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -312,6 +312,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest } } + public var updateOnReplacement = false public func replaceItems(_ items: [GalleryItem], centralItemIndex: Int?, synchronous: Bool = false) { var updateItems: [GalleryPagerUpdateItem] = [] var deleteItems: [Int] = [] @@ -326,14 +327,20 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest } } - for i in 0 ..< items.count { - if i == previousIndexById[items[i].id] { - updateItems.append(GalleryPagerUpdateItem(index: i, previousIndex: i, item: items[i])) - } else { + if self.updateOnReplacement { + for i in 0 ..< items.count { + if (previousIndexById[items[i].id] == nil) { + insertItems.append(GalleryPagerInsertItem(index: i, item: items[i], previousIndex: previousIndexById[items[i].id])) + } else { + updateItems.append(GalleryPagerUpdateItem(index: i, previousIndex: i, item: items[i])) + } + } + } else { + for i in 0 ..< items.count { insertItems.append(GalleryPagerInsertItem(index: i, item: items[i], previousIndex: previousIndexById[items[i].id])) } } - + self.transaction(GalleryPagerTransaction(deleteItems: deleteItems, insertItems: insertItems, updateItems: updateItems, focusOnItem: centralItemIndex, synchronous: synchronous)) } @@ -404,7 +411,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest self.ignoreCentralItemIndexUpdate = true self.centralItemIndex = focusOnItem self.ignoreCentralItemIndexUpdate = false - self.updateItemNodes(transition: .immediate, forceOffsetReset: true) + self.updateItemNodes(transition: .immediate, forceOffsetReset: true, synchronous: transaction.synchronous) } } diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h index b9db557041..98f4b11d96 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoAvatarCropView.h @@ -39,6 +39,8 @@ - (void)closeCurtains; - (void)openCurtains; +- (void)flash:(void (^)(void))completion; + - (void)invalidateCropRect; - (UIImage *)currentImage; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorTabController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorTabController.h index d62573d6e4..7ee9d2b520 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorTabController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorTabController.h @@ -44,6 +44,7 @@ - (void)prepareTransitionOutSaving:(bool)saving; - (void)prepareForCustomTransitionOut; +- (void)finishCustomTransitionOut; - (void)animateTransitionIn; - (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h index d71f9344cf..9c75611f85 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h @@ -2,6 +2,8 @@ @interface TGPhotoVideoEditor : NSObject ++ (void)presentWithContext:(id)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo; + + (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; @end diff --git a/submodules/LegacyComponents/Sources/PGPhotoEditor.m b/submodules/LegacyComponents/Sources/PGPhotoEditor.m index 52adf9807e..43b7bddd9e 100644 --- a/submodules/LegacyComponents/Sources/PGPhotoEditor.m +++ b/submodules/LegacyComponents/Sources/PGPhotoEditor.m @@ -484,7 +484,6 @@ [_finalFilter addTarget:self.previewOutput.imageView]; } } - if (_histogramGenerator != nil && !self.standalone) { [_finalFilter addTarget:_histogramGenerator]; diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m index fa6bb67318..7a2e3403c7 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryPhotoItemView.m @@ -23,8 +23,12 @@ #import +#import "TGPaintFaceDetector.h" + @interface TGMediaPickerGalleryPhotoItemView () { + SMetaDisposable *_facesDisposable; + UILabel *_fileInfoLabel; TGMessageImageViewOverlayView *_progressView; @@ -57,6 +61,8 @@ self = [super initWithFrame:frame]; if (self != nil) { + _facesDisposable = [[SMetaDisposable alloc] init]; + __weak TGMediaPickerGalleryPhotoItemView *weakSelf = self; _imageView = [[TGModernGalleryImageItemImageView alloc] init]; _imageView.clipsToBounds = true; @@ -101,6 +107,7 @@ { [_adjustmentsDisposable dispose]; [_attributesDisposable dispose]; + [_facesDisposable dispose]; } - (void)setHiddenAsBeingEdited:(bool)hidden @@ -226,8 +233,11 @@ }]]; - if (!item.asFile) + if (!item.asFile) { + [_facesDisposable setDisposable:[[TGPaintFaceDetector detectFacesInItem:item.editableMediaItem editingContext:item.editingContext] startWithNext:nil]]; + return; + } _fileInfoLabel.text = nil; diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m index e221f89126..7f8e0c90a0 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryVideoItemView.m @@ -41,6 +41,7 @@ #import #import "PGPhotoEditor.h" +#import "TGPaintFaceDetector.h" @interface TGMediaPickerGalleryVideoItemView() { @@ -96,6 +97,7 @@ SMetaDisposable *_adjustmentsDisposable; SMetaDisposable *_attributesDisposable; SMetaDisposable *_downloadDisposable; + SMetaDisposable *_facesDisposable; SMetaDisposable *_currentAudioSession; SVariable *_editableItemVariable; @@ -131,6 +133,7 @@ _currentAudioSession = [[SMetaDisposable alloc] init]; _playerItemDisposable = [[SMetaDisposable alloc] init]; + _facesDisposable = [[SMetaDisposable alloc] init]; _videoDurationVar = [[SVariable alloc] init]; _videoDurationDisposable = [[SMetaDisposable alloc] init]; @@ -251,6 +254,7 @@ [_thumbnailsDisposable dispose]; [_attributesDisposable dispose]; [_downloadDisposable dispose]; + [_facesDisposable dispose]; [self stopPlayer]; [self releaseVolumeOverlay]; @@ -385,8 +389,13 @@ [super setItem:item synchronously:synchronously]; - if (itemChanged) + if (itemChanged) { [self _playerCleanup]; + + if (!item.asFile) { + [_facesDisposable setDisposable:[[TGPaintFaceDetector detectFacesInItem:item.editableMediaItem editingContext:item.editingContext] startWithNext:nil]]; + } + } _scrubberView.allowsTrimming = false; _videoDimensions = item.dimensions; diff --git a/submodules/LegacyComponents/Sources/TGPaintFaceDetector.h b/submodules/LegacyComponents/Sources/TGPaintFaceDetector.h index c12151e06d..c08915ac85 100644 --- a/submodules/LegacyComponents/Sources/TGPaintFaceDetector.h +++ b/submodules/LegacyComponents/Sources/TGPaintFaceDetector.h @@ -1,6 +1,9 @@ #import #import +@protocol TGMediaEditableItem; +@class TGMediaEditingContext; + @interface TGPaintFaceFeature : NSObject { CGPoint _position; @@ -49,6 +52,8 @@ + (SSignal *)detectFacesInImage:(UIImage *)image originalSize:(CGSize)originalSize; ++ (SSignal *)detectFacesInItem:(id)item editingContext:(TGMediaEditingContext *)editingContext; + @end diff --git a/submodules/LegacyComponents/Sources/TGPaintFaceDetector.m b/submodules/LegacyComponents/Sources/TGPaintFaceDetector.m index 05646d1490..67833111d2 100644 --- a/submodules/LegacyComponents/Sources/TGPaintFaceDetector.m +++ b/submodules/LegacyComponents/Sources/TGPaintFaceDetector.m @@ -3,6 +3,9 @@ #import #import +#import "TGMediaEditingContext.h" +#import "UIImage+TG.h" + @interface TGPaintFace () + (instancetype)faceWithBounds:(CGRect)bounds angle:(CGFloat)angle leftEye:(TGPaintFaceEye *)leftEye rightEye:(TGPaintFaceEye *)rightEye mouth:(TGPaintFaceMouth *)mouth; @@ -26,6 +29,41 @@ @implementation TGPaintFaceDetector ++ (SSignal *)detectFacesInItem:(id)item editingContext:(TGMediaEditingContext *)editingContext +{ + CGSize originalSize = item.originalSize; + + SSignal *cachedFaces = [editingContext facesForItem:item]; + SSignal *cachedSignal = [cachedFaces mapToSignal:^SSignal *(id result) + { + if (result == nil) + return [SSignal fail:nil]; + return [SSignal single:result]; + }]; + + SSignal *imageSignal = [item screenImageSignal:0]; + SSignal *detectSignal = [[[imageSignal filter:^bool(UIImage *image) + { + if (![image isKindOfClass:[UIImage class]]) + return false; + + if (image.degraded) + return false; + + return true; + }] take:1] mapToSignal:^SSignal *(UIImage *image) { + return [[TGPaintFaceDetector detectFacesInImage:image originalSize:originalSize] startOn:[SQueue concurrentDefaultQueue]]; + }]; + + return [[[cachedSignal catch:^SSignal *(__unused id error) + { + return detectSignal; + }] deliverOn:[SQueue mainQueue]] onNext:^(NSArray *next) + { + [editingContext setFaces:next forItem:item]; + }]; +} + + (SSignal *)detectFacesInImage:(UIImage *)image originalSize:(CGSize)originalSize { return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) diff --git a/submodules/LegacyComponents/Sources/TGPhotoAvatarCropView.m b/submodules/LegacyComponents/Sources/TGPhotoAvatarCropView.m index 91f48f0f33..7666ec7bb6 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoAvatarCropView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoAvatarCropView.m @@ -26,6 +26,8 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; UIView *_snapshotView; CGSize _snapshotSize; + UIView *_flashView; + UIView *_topOverlayView; UIView *_leftOverlayView; UIView *_rightOverlayView; @@ -39,7 +41,7 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; CGFloat _currentDiameter; - PGPhotoEditorView *_fullPreviewView; + __weak PGPhotoEditorView *_fullPreviewView; } @end @@ -82,6 +84,12 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; _fullPreviewView.userInteractionEnabled = false; [_wrapperView addSubview:_fullPreviewView]; + _flashView = [[UIView alloc] init]; + _flashView.alpha = 0.0; + _flashView.backgroundColor = [UIColor whiteColor]; + _flashView.userInteractionEnabled = false; + [self addSubview:_flashView]; + _topCurtainView = [[UIView alloc] initWithFrame:CGRectZero]; _topCurtainView.backgroundColor = [UIColor blackColor]; [self addSubview:_topCurtainView]; @@ -122,6 +130,11 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; return self; } +- (void)dealloc +{ + _scrollView.delegate = nil; +} + - (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer { if (self.tapped != nil) self.tapped(); @@ -611,6 +624,8 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; { [self _layoutOverlayViews]; + _flashView.frame = self.bounds; + if (_scrollView.superview == nil) { _scrollView.frame = self.bounds; @@ -647,4 +662,16 @@ const CGFloat TGPhotoAvatarCropViewCurtainMargin = 200; return CGSizeMake(20, 20); } +- (void)flash:(void (^)(void))completion { + [UIView animateWithDuration:0.12 animations:^{ + _flashView.alpha = 1.0f; + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.2 animations:^{ + _flashView.alpha = 0.0f; + } completion:^(BOOL finished) { + completion(); + }]; + }]; +} + @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.h b/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.h index e761cbba71..ca98f9a308 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.h +++ b/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.h @@ -15,7 +15,12 @@ @property (nonatomic, copy) void (^croppingChanged)(void); @property (nonatomic, copy) void (^togglePlayback)(void); -- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView dotImageView:(UIView *)dotImageView fullPreviewView:(PGPhotoEditorView *)fullPreviewView; +@property (nonatomic, weak) UIView *dotImageView; +@property (nonatomic, weak) UIView *dotMarkerView; +@property (nonatomic, weak) PGPhotoEditorView *fullPreviewView; +@property (nonatomic, weak) TGMediaPickerGalleryVideoScrubber *scrubberView; + +- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView; - (void)setImage:(UIImage *)image; - (void)setSnapshotImage:(UIImage *)snapshotImage; diff --git a/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.m b/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.m index 1836cb7e2b..c83846c005 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoAvatarPreviewController.m @@ -32,18 +32,13 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel UIView *_wrapperView; - TGPhotoAvatarCropView *_cropView; - PGPhotoEditorView *_fullPreviewView; + __weak TGPhotoAvatarCropView *_cropView; UIView *_portraitToolsWrapperView; UIView *_landscapeToolsWrapperView; UIView *_portraitWrapperBackgroundView; UIView *_landscapeWrapperBackgroundView; - - TGMediaPickerGalleryVideoScrubber *_scrubberView; - UIView *_dotImageView; - UIView *_videoAreaView; - UIView *_flashView; + UIView *_portraitToolControlView; UIView *_landscapeToolControlView; UILabel *_coverLabel; @@ -58,21 +53,20 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel @implementation TGPhotoAvatarPreviewController -- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView dotImageView:(UIView *)dotImageView fullPreviewView:(PGPhotoEditorView *)fullPreviewView -{ +- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView { self = [super initWithContext:context]; if (self != nil) { self.photoEditor = photoEditor; self.previewView = previewView; - _fullPreviewView = fullPreviewView; - _scrubberView = scrubberView; - - _dotImageView = dotImageView; } return self; } +- (void)dealloc { + NSLog(@""); +} + - (void)loadView { [super loadView]; @@ -90,7 +84,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel if (strongSelf == nil) return; - self.controlVideoPlayback(false); + strongSelf.controlVideoPlayback(false); }; void(^interactionEnded)(void) = ^ { @@ -101,11 +95,12 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel if ([strongSelf shouldAutorotate]) [TGViewController attemptAutorotation]; - self.controlVideoPlayback(true); + strongSelf.controlVideoPlayback(true); }; PGPhotoEditor *photoEditor = self.photoEditor; - _cropView = [[TGPhotoAvatarCropView alloc] initWithOriginalSize:photoEditor.originalSize screenSize:[self referenceViewSize] fullPreviewView:_fullPreviewView]; + TGPhotoAvatarCropView *cropView = [[TGPhotoAvatarCropView alloc] initWithOriginalSize:photoEditor.originalSize screenSize:[self referenceViewSize] fullPreviewView:_fullPreviewView]; + _cropView = cropView; [_cropView setCropRect:photoEditor.cropRect]; [_cropView setCropOrientation:photoEditor.cropOrientation]; [_cropView setCropMirrored:photoEditor.cropMirrored]; @@ -142,7 +137,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel } _cropView.interactionBegan = interactionBegan; _cropView.interactionEnded = interactionEnded; - [_wrapperView addSubview:_cropView]; + [_wrapperView addSubview:cropView]; _portraitToolsWrapperView = [[UIView alloc] initWithFrame:CGRectZero]; [_wrapperView addSubview:_portraitToolsWrapperView]; @@ -162,18 +157,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel _landscapeWrapperBackgroundView.backgroundColor = [TGPhotoEditorInterfaceAssets toolbarTransparentBackgroundColor]; _landscapeWrapperBackgroundView.userInteractionEnabled = false; [_landscapeToolsWrapperView addSubview:_landscapeWrapperBackgroundView]; - - _videoAreaView = [[UIView alloc] init]; - [self.view insertSubview:_videoAreaView belowSubview:_wrapperView]; - + [_portraitToolsWrapperView addSubview:_scrubberView]; - _flashView = [[UIView alloc] init]; - _flashView.alpha = 0.0; - _flashView.backgroundColor = [UIColor whiteColor]; - _flashView.userInteractionEnabled = false; - [_videoAreaView addSubview:_flashView]; - _coverLabel = [[UILabel alloc] init]; _coverLabel.alpha = 0.7f; _coverLabel.backgroundColor = [UIColor clearColor]; @@ -183,7 +169,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel [_coverLabel sizeToFit]; [_portraitToolsWrapperView addSubview:_coverLabel]; - _dotImageView.alpha = 1.0f; [_wrapperView addSubview:_dotImageView]; } } @@ -263,7 +248,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel - (void)prepareTransitionInWithReferenceView:(UIView *)referenceView referenceFrame:(CGRect)referenceFrame parentView:(UIView *)parentView noTransitionView:(bool)noTransitionView { [super prepareTransitionInWithReferenceView:referenceView referenceFrame:referenceFrame parentView:parentView noTransitionView:noTransitionView]; - [self.view insertSubview:_transitionView belowSubview:_wrapperView]; + + if (self.initialAppearance && self.fromCamera) + [self.view insertSubview:_transitionView belowSubview:_wrapperView]; } - (void)transitionIn @@ -282,6 +269,8 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel { _portraitToolsWrapperView.alpha = 1.0f; _landscapeToolsWrapperView.alpha = 1.0f; + _dotImageView.alpha = 1.0f; + _dotMarkerView.alpha = 1.0f; } completion:^(BOOL finished) { _scrubberView.layer.shouldRasterize = false; }]; @@ -387,6 +376,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel _cropView.transform = CGAffineTransformMakeScale(targetCropViewScale, targetCropViewScale); } completion:^(__unused BOOL finished) { + [_cropView removeFromSuperview]; _previewView.alpha = 1.0; if (self.finishedTransitionOut != nil) self.finishedTransitionOut(); @@ -394,8 +384,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel if (completion != nil) completion(); }]; - } else if (self.fromCamera) { - _previewView.alpha = 0.0f; + } else { + if (self.fromCamera) + _previewView.alpha = 0.0f; } switch (self.effectiveOrientation) @@ -438,9 +429,11 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel _portraitToolsWrapperView.alpha = 0.0f; _landscapeToolsWrapperView.alpha = 0.0f; _dotImageView.alpha = 0.0f; + _dotMarkerView.alpha = 0.0f; } completion:^(__unused BOOL finished) { if (!switching) { + [_cropView removeFromSuperview]; if (completion != nil) completion(); } @@ -544,17 +537,21 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel { _portraitToolsWrapperView.alpha = 0.0f; _landscapeToolsWrapperView.alpha = 0.0f; - _videoAreaView.alpha = 0.0f; _dotImageView.alpha = 0.0f; } completion:nil]; } +- (void)finishCustomTransitionOut +{ + [_cropView removeFromSuperview]; +} + - (CGRect)transitionOutReferenceFrame { if (_dismissingToCamera) { - return _fullPreviewView.frame; + return [_fullPreviewView.superview convertRect:_fullPreviewView.frame toView:self.view]; } else { - return _previewView.frame; + return [_wrapperView convertRect:_cropView.frame toView:self.view]; } } @@ -735,12 +732,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel CGRect containerFrame = [TGPhotoAvatarPreviewController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0 hasOnScreenNavigation:self.hasOnScreenNavigation]; CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size); previewView.frame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); - - [UIView performWithoutAnimation:^ - { - _videoAreaView.frame = _previewView.frame; - _flashView.frame = _videoAreaView.bounds; - }]; } - (void)updateLayout:(UIInterfaceOrientation)orientation @@ -826,29 +817,24 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel - (void)beginScrubbing:(bool)flash { - if (flash) + if (flash) { _coverLabel.alpha = 1.0f; + } } - (void)endScrubbing:(bool)flash completion:(bool (^)(void))completion { if (flash) { - [UIView animateWithDuration:0.12 animations:^{ - _flashView.alpha = 1.0f; - } completion:^(BOOL finished) { - [UIView animateWithDuration:0.2 animations:^{ - _flashView.alpha = 0.0f; - } completion:^(BOOL finished) { - TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{ - if (completion()) { - [UIView animateWithDuration:0.2 animations:^{ - _coverLabel.alpha = 0.7f; - }]; - - self.controlVideoPlayback(true); - } - }); - }]; + [_cropView flash:^{ + TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{ + if (completion()) { + [UIView animateWithDuration:0.2 animations:^{ + _coverLabel.alpha = 0.7f; + }]; + + self.controlVideoPlayback(true); + } + }); }]; } else { TGDispatchAfter(1.32, dispatch_get_main_queue(), ^{ diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m index fbbde23c7f..7320b06218 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m @@ -59,6 +59,8 @@ TGPhotoEditorTab _currentTab; TGPhotoEditorTabController *_currentTabController; + TGMediaEditingContext *_standaloneEditingContext; + UIView *_backgroundView; UIView *_containerView; UIView *_wrapperView; @@ -140,6 +142,7 @@ { _context = context; _actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true]; + _standaloneEditingContext = [[TGMediaEditingContext alloc] init]; self.automaticallyManageScrollViewInsets = false; self.autoManageStatusBarBackground = false; @@ -561,6 +564,9 @@ if (strongSelf->_ignoreDefaultPreviewViewTransitionIn) { + __strong TGPhotoEditorController *strongSelf = weakSelf; + if (strongSelf == nil) + return; TGDispatchOnMainThread(^ { if (strongSelf->_dismissed) @@ -575,6 +581,9 @@ { [photoEditor processAnimated:false completion:^ { + __strong TGPhotoEditorController *strongSelf = weakSelf; + if (strongSelf == nil) + return; TGDispatchOnMainThread(^ { if (strongSelf->_dismissed) @@ -1090,7 +1099,13 @@ rep = imageView; } [_currentTabController prepareForCustomTransitionOut]; - self.beginCustomTransitionOut([_currentTabController transitionOutReferenceFrame], rep, completion); + + TGPhotoEditorTabController *tabController = _currentTabController; + self.beginCustomTransitionOut([_currentTabController transitionOutReferenceFrame], rep, ^{ + [tabController finishCustomTransitionOut]; + if (completion) + completion(); + }); } else { @@ -1125,6 +1140,8 @@ { if (![currentController isDismissAllowed]) return; + + [self savePaintingData]; currentController.switchingToTab = tab; [currentController transitionOutSwitching:true completion:^ @@ -1203,7 +1220,11 @@ { bool skipInitialTransition = (![self presentedFromCamera] && self.navigationController != nil) || self.skipInitialTransition; - TGPhotoAvatarPreviewController *cropController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView scrubberView:_scrubberView dotImageView:_dotImageView fullPreviewView:_fullPreviewView]; + TGPhotoAvatarPreviewController *cropController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView]; + cropController.scrubberView = _scrubberView; + cropController.dotImageView = _dotImageView; + cropController.dotMarkerView = _dotMarkerView; + cropController.fullPreviewView = _fullPreviewView; cropController.fromCamera = [self presentedFromCamera]; cropController.skipTransitionIn = skipInitialTransition; if (snapshotImage != nil) @@ -1636,6 +1657,7 @@ self.view.frame = targetFrame; } completion:^(__unused BOOL finished) { + [_currentTabController finishCustomTransitionOut]; if (self.navigationController != nil) { [self.navigationController popViewControllerAnimated:false]; } else { @@ -1646,6 +1668,7 @@ else { if (self.navigationController != nil) { + [_currentTabController finishCustomTransitionOut]; [self.navigationController popViewControllerAnimated:false]; } else { [self dismiss]; @@ -1760,6 +1783,18 @@ } } +- (void)savePaintingData { + if (![_currentTabController isKindOfClass:[TGPhotoPaintController class]]) + return; + + TGPhotoPaintController *paintController = (TGPhotoPaintController *)_currentTabController; + TGPaintingData *paintingData = [paintController paintingData]; + _photoEditor.paintingData = paintingData; + + if (paintingData != nil) + [TGPaintingData storePaintingData:paintingData inContext:self.editingContext forItem:_item forVideo:(_intent == TGPhotoEditorControllerVideoIntent)]; +} + - (void)applyEditor { if (![_currentTabController isDismissAllowed]) @@ -1768,8 +1803,6 @@ self.view.userInteractionEnabled = false; [_currentTabController prepareTransitionOutSaving:true]; - TGPaintingData *paintingData = _photoEditor.paintingData; - bool saving = true; NSTimeInterval videoStartValue = 0.0; NSTimeInterval trimStartValue = 0.0; @@ -1777,12 +1810,7 @@ if ([_currentTabController isKindOfClass:[TGPhotoPaintController class]]) { - TGPhotoPaintController *paintController = (TGPhotoPaintController *)_currentTabController; - paintingData = [paintController paintingData]; - _photoEditor.paintingData = paintingData; - - if (paintingData != nil) - [TGPaintingData storePaintingData:paintingData inContext:_editingContext forItem:_item forVideo:(_intent == TGPhotoEditorControllerVideoIntent)]; + [self savePaintingData]; } else if ([_currentTabController isKindOfClass:[TGPhotoQualityController class]]) { @@ -1800,6 +1828,7 @@ [self stopVideoPlayback:true]; + TGPaintingData *paintingData = _photoEditor.paintingData; TGVideoEditAdjustments *adjustments = [_photoEditor exportAdjustmentsWithPaintingData:paintingData]; if ([self presentedForAvatarCreation] && _item.isVideo) { [[SQueue concurrentDefaultQueue] dispatch:^ @@ -1968,7 +1997,7 @@ thumbnailImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - [_editingContext setImage:fullImage thumbnailImage:thumbnailImage forItem:_item synchronous:true]; + [self.editingContext setImage:fullImage thumbnailImage:thumbnailImage forItem:_item synchronous:true]; }]; }]; } @@ -1990,6 +2019,14 @@ } } +- (TGMediaEditingContext *)editingContext +{ + if (_editingContext) + return _editingContext; + else + return _standaloneEditingContext; +} + - (void)doneButtonLongPressed:(UIButton *)sender { if (_intent == TGPhotoEditorControllerVideoIntent) @@ -2591,7 +2628,7 @@ return !strongSelf->_scrubberView.isScrubbing; }]; - dispatch_async(dispatch_get_main_queue(), ^{ + TGDispatchAfter(0.16, dispatch_get_main_queue(), ^{ [self updateDotImage:true]; }); } diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m b/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m index fe77eecf29..1f5a122725 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m @@ -215,6 +215,11 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f; } +- (void)finishCustomTransitionOut +{ + +} + - (void)transitionOutSwitching:(bool)__unused switching completion:(void (^)(void))__unused completion { diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m index 6c09b904e5..e1571159df 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m @@ -1842,7 +1842,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; _appeared = true; if ([transitionView isKindOfClass:[TGPhotoEditorPreviewView class]]) { - [_containerView insertSubview:transitionView belowSubview:_paintingWrapperView]; + } else { [transitionView removeFromSuperview]; } @@ -1853,6 +1853,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; [previewView setPaintingHidden:true]; previewView.hidden = false; [_containerView insertSubview:previewView belowSubview:_paintingWrapperView]; + [self updateContentViewLayout]; [previewView performTransitionInIfNeeded]; CGRect rect = [self fittedCropRect:true]; @@ -2142,6 +2143,14 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; [self updateLayout:toInterfaceOrientation]; } +- (void)updateContentViewLayout +{ + CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(TGRotationForOrientation(_photoEditor.cropOrientation)); + _contentView.transform = rotationTransform; + _contentView.frame = self.previewView.frame; + [self resetScrollView]; +} + - (void)updateLayout:(UIInterfaceOrientation)orientation { if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) diff --git a/submodules/LegacyComponents/Sources/TGPhotoToolsController.m b/submodules/LegacyComponents/Sources/TGPhotoToolsController.m index 269d13db6d..80d0bc6202 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoToolsController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoToolsController.m @@ -160,8 +160,9 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize if (strongSelf != nil) { [strongSelf->_hudView setText:nil]; - if (forVideo) { - strongSelf->_photoEditor.disableAll = false; + strongSelf->_photoEditor.disableAll = false; + if (!forVideo) { + [strongSelf->_photoEditor processAnimated:false completion:nil]; } } }; @@ -171,8 +172,9 @@ const CGFloat TGPhotoEditorToolsLandscapePanelSize = TGPhotoEditorToolsPanelSize if (strongSelf != nil) { [strongSelf->_hudView setText:TGLocalized(@"PhotoEditor.Original")]; - if (forVideo) { - strongSelf->_photoEditor.disableAll = true; + strongSelf->_photoEditor.disableAll = true; + if (!forVideo) { + [strongSelf->_photoEditor processAnimated:false completion:nil]; } } }; diff --git a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m index d346771c1b..8ce8132b53 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m +++ b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m @@ -10,6 +10,59 @@ @implementation TGPhotoVideoEditor ++ (void)presentWithContext:(id)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo +{ + id windowManager = [context makeOverlayWindowManager]; + + id editableItem; + if (image != nil) { + editableItem = image; + } else if (video != nil) { + editableItem = [[TGCameraCapturedVideo alloc] initWithURL:video]; + } + + TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:editableItem intent:TGPhotoEditorControllerAvatarIntent adjustments:nil caption:nil screenImage:nil availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab]; +// controller.stickersContext = _stickersContext; + controller.dontHideStatusBar = true; + controller.didFinishEditing = ^(__unused id adjustments, UIImage *resultImage, __unused UIImage *thumbnailImage, __unused bool hasChanges) + { + if (didFinishWithImage != nil) + didFinishWithImage(resultImage); + }; + controller.didFinishEditingVideo = ^(NSURL *url, id adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) { + if (didFinishWithVideo != nil) + didFinishWithVideo(resultImage, url, adjustments); + }; + controller.requestThumbnailImage = ^(id editableItem) + { + return [editableItem thumbnailImageSignal]; + }; + + controller.requestOriginalScreenSizeImage = ^(id editableItem, NSTimeInterval position) + { + return [editableItem screenImageSignal:position]; + }; + + controller.requestOriginalFullSizeImage = ^(id 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 { + return [editableItem originalImageSignal:position]; + } + }; + + TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:controller]; + controllerWindow.hidden = false; + controller.view.clipsToBounds = true; +} + + (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed { id windowManager = [context makeOverlayWindowManager]; diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift index def33cbaf0..1e35788b19 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift @@ -6,6 +6,30 @@ import LegacyComponents import TelegramPresentationData import LegacyUI +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 + + let emptyController = LegacyEmptyController(context: legacyController.context)! + let navigationController = makeLegacyNavigationController(rootController: emptyController) + navigationController.setNavigationBarHidden(true, animated: false) + navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) + + legacyController.bind(controller: navigationController) + + present(legacyController, nil) + + TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image, video: video, didFinishWithImage: { image in + if let image = image { + imageCompletion(image) + } + }, didFinishWithVideo: { image, url, adjustments in + if let image = image, let url = url { + videoCompletion(image, url, adjustments) + } + }) +} + public func presentLegacyAvatarPicker(holder: Atomic, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, openCurrent: (() -> Void)?, completion: @escaping (UIImage) -> Void) { let legacyController = LegacyController(presentation: .custom, theme: theme) legacyController.statusBar.statusBarStyle = .Ignore diff --git a/submodules/MediaPlayer/Sources/MediaTrackFrameBuffer.swift b/submodules/MediaPlayer/Sources/MediaTrackFrameBuffer.swift index 210fc7ab2a..598ae2be68 100644 --- a/submodules/MediaPlayer/Sources/MediaTrackFrameBuffer.swift +++ b/submodules/MediaPlayer/Sources/MediaTrackFrameBuffer.swift @@ -161,7 +161,7 @@ public final class MediaTrackFrameBuffer { if self.endOfStream, let decodedFrame = self.decoder.takeRemainingFrame() { return .frame(decodedFrame) } else { - if let bufferedUntilTime = bufferedUntilTime { + if let bufferedUntilTime = self.bufferedUntilTime { if CMTimeCompare(bufferedUntilTime, self.duration) >= 0 || self.endOfStream { return .finished } diff --git a/submodules/PeerAvatarGalleryUI/BUCK b/submodules/PeerAvatarGalleryUI/BUCK index f61fd2951b..b6d5a48e59 100644 --- a/submodules/PeerAvatarGalleryUI/BUCK +++ b/submodules/PeerAvatarGalleryUI/BUCK @@ -21,6 +21,8 @@ static_library( "//submodules/RadialStatusNode:RadialStatusNode", "//submodules/ShareController:ShareController", "//submodules/AppBundle:AppBundle", + "//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI", + "//submodules/SaveToCameraRoll:SaveToCameraRoll", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/PeerAvatarGalleryUI/BUILD b/submodules/PeerAvatarGalleryUI/BUILD index 8c8179ca5f..8f52dff372 100644 --- a/submodules/PeerAvatarGalleryUI/BUILD +++ b/submodules/PeerAvatarGalleryUI/BUILD @@ -22,6 +22,8 @@ swift_library( "//submodules/RadialStatusNode:RadialStatusNode", "//submodules/ShareController:ShareController", "//submodules/AppBundle:AppBundle", + "//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI", + "//submodules/SaveToCameraRoll:SaveToCameraRoll", ], visibility = [ "//visibility:public", diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 34e0aa6d08..2d539003d4 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -10,6 +10,8 @@ import SyncCore import TelegramPresentationData import AccountContext import GalleryUI +import LegacyMediaPickerUI +import SaveToCameraRoll public enum AvatarGalleryEntryId: Hashable { case topImage @@ -192,6 +194,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr private let replaceRootController: (ViewController, Promise?) -> Void + private let editDisposable = MetaDisposable () + public init(context: AccountContext, peer: Peer, sourceHasRoundCorners: Bool = true, remoteEntries: Promise<[AvatarGalleryEntry]>? = nil, centralEntryIndex: Int? = nil, replaceRootController: @escaping (ViewController, Promise?) -> Void, synchronousLoad: Bool = false) { self.context = context self.peer = peer @@ -265,7 +269,9 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self?.deleteEntry(entry) } : nil, setMain: { [weak self] in self?.setMainEntry(entry) - }) + }, edit: { [weak self] in + self?.editEntry(entry) + }) }), centralItemIndex: strongSelf.centralEntryIndex, synchronous: !isFirstTime) let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in @@ -332,6 +338,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr deinit { self.disposable.dispose() self.centralItemAttributesDisposable.dispose() + self.editDisposable.dispose() } @objc func donePressed() { @@ -384,6 +391,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() + self.galleryNode.pager.updateOnReplacement = true self.galleryNode.statusBar = self.statusBar self.galleryNode.navigationBar = self.navigationBar @@ -426,6 +434,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self?.deleteEntry(entry) } : nil, setMain: { [weak self] in self?.setMainEntry(entry) + }, edit: { [weak self] in + self?.editEntry(entry) }) }), centralItemIndex: self.centralEntryIndex) self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in @@ -584,7 +594,9 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self?.deleteEntry(entry) } : nil, setMain: { [weak self] in self?.setMainEntry(entry) - }) }), centralItemIndex: 0) + }, edit: { [weak self] in + self?.editEntry(entry) + }) }), centralItemIndex: 0, synchronous: true) self.entries = entries } } else { @@ -605,6 +617,50 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr } } + private func editEntry(_ rawEntry: AvatarGalleryEntry) { + let mediaReference: AnyMediaReference + if let video = rawEntry.videoRepresentations.last { + mediaReference = .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])])) + } else { + let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: rawEntry.representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []) + mediaReference = .standalone(media: media) + } + + self.editDisposable.set((fetchMediaData(context: self.context, postbox: self.context.account.postbox, mediaReference: mediaReference) + |> deliverOnMainQueue).start(next: { [weak self] state, isImage in + guard let strongSelf = self else { + return + } + switch state { + case let .progress(value): + break + case let .data(data): + let image: UIImage? + let video: URL? + if isImage { + if let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { + image = UIImage(data: fileData) + } else { + image = nil + } + video = nil + } else { + image = nil + video = URL(fileURLWithPath: data.path) + } + 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 + + }) + } + })) + } + private func deleteEntry(_ rawEntry: AvatarGalleryEntry) { var entry = rawEntry if case .topImage = entry, !self.entries.isEmpty { diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 2adb451be2..e33fa63399 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -54,8 +54,9 @@ class PeerAvatarImageGalleryItem: GalleryItem { let sourceHasRoundCorners: Bool let delete: (() -> Void)? let setMain: (() -> Void)? + let edit: (() -> Void)? - init(context: AccountContext, peer: Peer, presentationData: PresentationData, entry: AvatarGalleryEntry, sourceHasRoundCorners: Bool, delete: (() -> Void)?, setMain: (() -> Void)?) { + init(context: AccountContext, peer: Peer, presentationData: PresentationData, entry: AvatarGalleryEntry, sourceHasRoundCorners: Bool, delete: (() -> Void)?, setMain: (() -> Void)?, edit: (() -> Void)?) { self.context = context self.peer = peer self.presentationData = presentationData @@ -63,6 +64,7 @@ class PeerAvatarImageGalleryItem: GalleryItem { self.sourceHasRoundCorners = sourceHasRoundCorners self.delete = delete self.setMain = setMain + self.edit = edit } func node(synchronous: Bool) -> GalleryItemNode { @@ -75,6 +77,7 @@ class PeerAvatarImageGalleryItem: GalleryItem { node.setEntry(self.entry, synchronous: synchronous) node.footerContentNode.delete = self.delete node.footerContentNode.setMain = self.setMain + node.edit = self.edit return node } @@ -84,10 +87,17 @@ class PeerAvatarImageGalleryItem: GalleryItem { if let indexData = self.entry.indexData { node._title.set(.single(self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").0)) } - + let previousContentAnimations = node.imageNode.contentAnimations + if synchronous { + node.imageNode.contentAnimations = [] + } node.setEntry(self.entry, synchronous: synchronous) + if synchronous { + node.imageNode.contentAnimations = previousContentAnimations + } node.footerContentNode.delete = self.delete node.footerContentNode.setMain = self.setMain + node.edit = self.edit } } @@ -125,7 +135,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { private var entry: AvatarGalleryEntry? private let contentNode: PeerAvatarImageGalleryContentNode - private let imageNode: TransformImageNode + fileprivate let imageNode: TransformImageNode private var videoNode: UniversalVideoNode? private var videoContent: NativeVideoContent? @@ -142,6 +152,8 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { private var status: MediaResourceStatus? private let playbackStatusDisposable = MetaDisposable() + fileprivate var edit: (() -> Void)? + init(context: AccountContext, presentationData: PresentationData, peer: Peer, sourceHasRoundCorners: Bool) { self.context = context self.presentationData = presentationData @@ -212,7 +224,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { var footerContent: AvatarGalleryItemFooterContent if self.peer.id == self.context.account.peerId { footerContent = .own((entry.indexData?.position ?? 0) == 0) - let rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Settings_EditProfileMedia, style: .plain, target: self, action: #selector(editPressed)) + let rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Settings_EditProfileMedia, style: .plain, target: self, action: #selector(self.editPressed)) barButtonItems.append(rightBarButtonItem) } else { footerContent = .info @@ -507,7 +519,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { } @objc private func editPressed() { - + self.edit?() } override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> {