Merge commit '51a95f3f6ff23403490f3371b58dffac7eff87d8'

This commit is contained in:
Ali 2020-06-29 23:07:23 +04:00
commit 95b7ea333d
16 changed files with 510 additions and 238 deletions

View File

@ -5636,5 +5636,5 @@ Any member of this group will be able to see messages in the channel.";
"Settings.SetProfilePhotoOrVideo" = "Set Profile Photo or Video"; "Settings.SetProfilePhotoOrVideo" = "Set Profile Photo or Video";
"Settings.SetNewProfilePhotoOrVideo" = "Set New Profile Photo or Video"; "Settings.SetNewProfilePhotoOrVideo" = "Set New Profile Photo or Video";
"Conversation.Unarchive" = "Unarhive"; "Conversation.Unarchive" = "Unarchive";
"Conversation.UnarchiveDone" = "The chat was moved to your main list."; "Conversation.UnarchiveDone" = "The chat was moved to your main list.";

View File

@ -3,15 +3,15 @@
typedef NS_OPTIONS(NSUInteger, TGPhotoEditorTab) { typedef NS_OPTIONS(NSUInteger, TGPhotoEditorTab) {
TGPhotoEditorNoneTab = 0, TGPhotoEditorNoneTab = 0,
TGPhotoEditorCropTab = 1 << 0, TGPhotoEditorCropTab = 1 << 0,
TGPhotoEditorPaintTab = 1 << 1, TGPhotoEditorRotateTab = 1 << 1,
TGPhotoEditorEraserTab = 1 << 2, TGPhotoEditorMirrorTab = 1 << 2,
TGPhotoEditorStickerTab = 1 << 3, TGPhotoEditorPaintTab = 1 << 3,
TGPhotoEditorTextTab = 1 << 4, TGPhotoEditorEraserTab = 1 << 4,
TGPhotoEditorToolsTab = 1 << 5, TGPhotoEditorStickerTab = 1 << 5,
TGPhotoEditorRotateTab = 1 << 6, TGPhotoEditorTextTab = 1 << 6,
TGPhotoEditorQualityTab = 1 << 7, TGPhotoEditorToolsTab = 1 << 7,
TGPhotoEditorTimerTab = 1 << 8, TGPhotoEditorQualityTab = 1 << 8,
TGPhotoEditorMirrorTab = 1 << 9, TGPhotoEditorTimerTab = 1 << 9,
TGPhotoEditorAspectRatioTab = 1 << 10, TGPhotoEditorAspectRatioTab = 1 << 10,
TGPhotoEditorTintTab = 1 << 11, TGPhotoEditorTintTab = 1 << 11,
TGPhotoEditorBlurTab = 1 << 12, TGPhotoEditorBlurTab = 1 << 12,

View File

@ -908,8 +908,6 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if (strongSelf.avatarCompletionBlock != nil) if (strongSelf.avatarCompletionBlock != nil)
strongSelf.avatarCompletionBlock(resultImage); strongSelf.avatarCompletionBlock(resultImage);
[strongController dismissAnimated:true];
}; };
controller.didFinishEditingVideo = ^(NSURL *url, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) { controller.didFinishEditingVideo = ^(NSURL *url, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
if (!hasChanges) if (!hasChanges)
@ -925,8 +923,6 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if (strongSelf.avatarVideoCompletionBlock != nil) if (strongSelf.avatarVideoCompletionBlock != nil)
strongSelf.avatarVideoCompletionBlock(resultImage, url, adjustments); strongSelf.avatarVideoCompletionBlock(resultImage, url, adjustments);
[strongController dismissAnimated:true];
}; };
controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem) controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
{ {

View File

@ -1012,7 +1012,9 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL]; TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL];
if (strongSelf->_intent == TGCameraControllerAvatarIntent || strongSelf->_intent == TGCameraControllerSignupAvatarIntent) if (strongSelf->_intent == TGCameraControllerAvatarIntent || strongSelf->_intent == TGCameraControllerSignupAvatarIntent)
{ {
[strongSelf presentPhotoResultControllerWithImage:capturedVideo metadata:nil completion:^{}]; [strongSelf presentPhotoResultControllerWithImage:capturedVideo metadata:nil completion:^{
[strongSelf->_interfaceView setRecordingVideo:false animated:true];
}];
} else { } else {
[strongSelf addResultItem:capturedVideo]; [strongSelf addResultItem:capturedVideo];
if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil]) if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil])

View File

@ -44,6 +44,8 @@
- (void)setRecipientName:(NSString *)recipientName; - (void)setRecipientName:(NSString *)recipientName;
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position;
@end @end
@protocol TGMediaPickerGalleryVideoScrubberDelegate <NSObject> @protocol TGMediaPickerGalleryVideoScrubberDelegate <NSObject>

View File

@ -1286,6 +1286,11 @@ typedef enum
} }
} }
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position
{
return [self _scrubberPositionForPosition:position duration:_duration];
}
- (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration - (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
{ {
return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn]; return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn];

View File

@ -375,14 +375,23 @@ const CGFloat TGPhotoAvatarCropButtonsWrapperSize = 61.0f;
CGRect targetCropViewFrame = [self.view convertRect:targetFrame toView:_wrapperView]; CGRect targetCropViewFrame = [self.view convertRect:targetFrame toView:_wrapperView];
if (!self.item.isVideo) {
_previewView.hidden = true;
}
[UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionLayoutSubviews animations:^ [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionLayoutSubviews animations:^
{ {
snapshotView.frame = targetFrame; snapshotView.frame = targetFrame;
snapshotView.alpha = 1.0f; if (self.item.isVideo) {
_cropView.alpha = 0.0f;
} else {
snapshotView.alpha = 1.0f;
}
_cropView.frame = targetCropViewFrame; _cropView.frame = targetCropViewFrame;
[_cropView invalidateCropRect]; [_cropView invalidateCropRect];
} completion:^(__unused BOOL finished) } completion:^(__unused BOOL finished)
{ {
_previewView.hidden = false;
if (self.finishedTransitionOut != nil) if (self.finishedTransitionOut != nil)
self.finishedTransitionOut(); self.finishedTransitionOut();
}]; }];

View File

@ -7,10 +7,9 @@
@interface TGPhotoAvatarPreviewController : TGPhotoEditorTabController @interface TGPhotoAvatarPreviewController : TGPhotoEditorTabController
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView; - (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView dotImageView:(UIImageView *)dotImageView;
- (void)beginScrubbing; - (void)beginScrubbing:(bool)flash;
- (void)endScrubbing:(bool (^)(void))completion; - (void)endScrubbing:(bool)flash completion:(bool (^)(void))completion;
- (void)setPlayButtonHidden:(bool)hidden animated:(bool)animated;
@end @end

View File

@ -26,6 +26,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
TGPhotoEditorSparseView *_wrapperView; TGPhotoEditorSparseView *_wrapperView;
TGMediaPickerGalleryVideoScrubber *_scrubberView; TGMediaPickerGalleryVideoScrubber *_scrubberView;
UIImageView *_dotImageView;
UIView *_portraitToolsWrapperView; UIView *_portraitToolsWrapperView;
UIView *_landscapeToolsWrapperView; UIView *_landscapeToolsWrapperView;
UIView *_portraitWrapperBackgroundView; UIView *_portraitWrapperBackgroundView;
@ -35,8 +38,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
UIView *_flashView; UIView *_flashView;
UIView *_portraitToolControlView; UIView *_portraitToolControlView;
UIView *_landscapeToolControlView; UIView *_landscapeToolControlView;
UIImageView *_areaMaskView;
CGFloat _currentDiameter;
UILabel *_coverLabel; UILabel *_coverLabel;
} }
@ -47,7 +48,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
@implementation TGPhotoAvatarPreviewController @implementation TGPhotoAvatarPreviewController
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView - (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView scrubberView:(TGMediaPickerGalleryVideoScrubber *)scrubberView dotImageView:(UIImageView *)dotImageView
{ {
self = [super initWithContext:context]; self = [super initWithContext:context];
if (self != nil) if (self != nil)
@ -55,6 +56,8 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
self.photoEditor = photoEditor; self.photoEditor = photoEditor;
self.previewView = previewView; self.previewView = previewView;
_scrubberView = scrubberView; _scrubberView = scrubberView;
_dotImageView = dotImageView;
} }
return self; return self;
} }
@ -92,28 +95,26 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_videoAreaView = [[UIView alloc] init]; _videoAreaView = [[UIView alloc] init];
[self.view insertSubview:_videoAreaView belowSubview:_wrapperView]; [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];
_coverLabel.font = TGSystemFontOfSize(14.0f);
_coverLabel.textColor = [UIColor whiteColor];
_coverLabel.text = TGLocalized(@"PhotoEditor.SelectCoverFrame");
[_coverLabel sizeToFit];
[_portraitToolsWrapperView addSubview:_coverLabel];
[_wrapperView addSubview:_dotImageView];
} }
_flashView = [[UIView alloc] init];
_flashView.alpha = 0.0;
_flashView.backgroundColor = [UIColor whiteColor];
_flashView.userInteractionEnabled = false;
[_videoAreaView addSubview:_flashView];
_areaMaskView = [[UIImageView alloc] init];
_areaMaskView.alpha = 0.0f;
[self.view insertSubview:_areaMaskView aboveSubview:_videoAreaView];
[_portraitToolsWrapperView addSubview:_scrubberView];
_coverLabel = [[UILabel alloc] init];
_coverLabel.alpha = 0.7f;
_coverLabel.backgroundColor = [UIColor clearColor];
_coverLabel.font = TGSystemFontOfSize(14.0f);
_coverLabel.textColor = [UIColor whiteColor];
_coverLabel.text = TGLocalized(@"PhotoEditor.SelectCoverFrame");
[_coverLabel sizeToFit];
[_portraitToolsWrapperView addSubview:_coverLabel];
} }
- (void)viewDidAppear:(BOOL)animated - (void)viewDidAppear:(BOOL)animated
@ -232,7 +233,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_portraitToolsWrapperView.alpha = 0.0f; _portraitToolsWrapperView.alpha = 0.0f;
_landscapeToolsWrapperView.alpha = 0.0f; _landscapeToolsWrapperView.alpha = 0.0f;
_videoAreaView.alpha = 0.0f; _videoAreaView.alpha = 0.0f;
_areaMaskView.alpha = 0.0f;
} completion:^(__unused BOOL finished) } completion:^(__unused BOOL finished)
{ {
if (completion != nil) if (completion != nil)
@ -320,7 +320,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_portraitToolsWrapperView.alpha = 0.0f; _portraitToolsWrapperView.alpha = 0.0f;
_landscapeToolsWrapperView.alpha = 0.0f; _landscapeToolsWrapperView.alpha = 0.0f;
_videoAreaView.alpha = 0.0f; _videoAreaView.alpha = 0.0f;
_areaMaskView.alpha = 0.0f;
} completion:nil]; } completion:nil];
} }
@ -400,12 +399,10 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
CGSize referenceSize = [self referenceViewSize]; CGSize referenceSize = [self referenceViewSize];
CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoAvatarPreviewPanelSize; CGFloat screenSide = MAX(referenceSize.width, referenceSize.height);
_wrapperView.frame = CGRectMake((referenceSize.width - screenSide) / 2, (referenceSize.height - screenSide) / 2, screenSide, screenSide); _wrapperView.frame = CGRectMake((referenceSize.width - screenSide) / 2, (referenceSize.height - screenSide) / 2, screenSide, screenSide);
CGFloat panelSize = UIInterfaceOrientationIsPortrait(orientation) ? TGPhotoAvatarPreviewPanelSize : TGPhotoAvatarPreviewLandscapePanelSize; CGFloat panelSize = UIInterfaceOrientationIsPortrait(orientation) ? TGPhotoAvatarPreviewPanelSize : TGPhotoAvatarPreviewLandscapePanelSize;
// if (_portraitToolControlView != nil)
// panelSize = TGPhotoEditorPanelSize;
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize; CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize; CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
@ -497,36 +494,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
{ {
_videoAreaView.frame = _previewView.frame; _videoAreaView.frame = _previewView.frame;
_flashView.frame = _videoAreaView.bounds; _flashView.frame = _videoAreaView.bounds;
_areaMaskView.frame = _previewView.frame;
[self updateCircleImage];
}]; }];
} }
- (void)updateCircleImage
{
CGFloat diameter = _areaMaskView.frame.size.width;
if (fabs(diameter - _currentDiameter) < DBL_EPSILON)
return;
_currentDiameter = diameter;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [TGPhotoEditorInterfaceAssets cropTransparentOverlayColor].CGColor);
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, diameter, diameter)];
[path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, diameter, diameter)]];
path.usesEvenOddFillRule = true;
[path fill];
UIImage *areaMaskImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_areaMaskView.image = areaMaskImage;
}
- (void)updateLayout:(UIInterfaceOrientation)orientation - (void)updateLayout:(UIInterfaceOrientation)orientation
{ {
if ([self inFormSheet] || TGIsPad()) if ([self inFormSheet] || TGIsPad())
@ -540,7 +510,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
- (TGPhotoEditorTab)availableTabs - (TGPhotoEditorTab)availableTabs
{ {
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab; return TGPhotoEditorRotateTab | TGPhotoEditorMirrorTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
} }
- (TGPhotoEditorTab)activeTab - (TGPhotoEditorTab)activeTab
@ -561,58 +531,74 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
return tabs; return tabs;
} }
- (void)setPlayButtonHidden:(bool)hidden animated:(bool)animated - (void)handleTabAction:(TGPhotoEditorTab)tab
{ {
// if (animated) switch (tab)
// { {
// _actionButton.hidden = false; case TGPhotoEditorRotateTab:
// [UIView animateWithDuration:0.15f animations:^ {
// { [self rotate];
// _actionButton.alpha = hidden ? 0.0f : 1.0f; }
// } completion:^(BOOL finished) break;
// {
// if (finished) case TGPhotoEditorMirrorTab:
// _actionButton.hidden = hidden; {
// }]; [self mirror];
// } }
// else break;
// {
// _actionButton.alpha = hidden ? 0.0f : 1.0f; default:
// _actionButton.hidden = hidden; break;
// } }
} }
- (void)beginScrubbing #pragma mark - Cropping
{
_coverLabel.alpha = 1.0f;
[self setPlayButtonHidden:true animated:false]; - (void)rotate {
// [_cropView rotate90DegreesCCWAnimated:true];
[UIView animateWithDuration:0.2 animations:^{
_areaMaskView.alpha = 1.0f;
}];
} }
- (void)endScrubbing:(bool (^)(void))completion - (void)mirror {
// [_cropView mirror];
}
- (void)beginScrubbing:(bool)flash
{ {
[UIView animateWithDuration:0.12 animations:^{ if (flash)
_flashView.alpha = 1.0f; _coverLabel.alpha = 1.0f;
} completion:^(BOOL finished) { }
[UIView animateWithDuration:0.2 animations:^{
_flashView.alpha = 0.0f; - (void)endScrubbing:(bool)flash completion:(bool (^)(void))completion
{
if (flash) {
[UIView animateWithDuration:0.12 animations:^{
_flashView.alpha = 1.0f;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{ [UIView animateWithDuration:0.2 animations:^{
if (completion()) { _flashView.alpha = 0.0f;
[UIView animateWithDuration:0.2 animations:^{ } completion:^(BOOL finished) {
_areaMaskView.alpha = 0.0f; TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{
_coverLabel.alpha = 0.7f; if (completion()) {
}]; [UIView animateWithDuration:0.2 animations:^{
_coverLabel.alpha = 0.7f;
}];
self.controlVideoPlayback(true); self.controlVideoPlayback(true);
} }
}); });
}];
}]; }];
}]; } else {
TGDispatchAfter(1.32, dispatch_get_main_queue(), ^{
if (completion()) {
[UIView animateWithDuration:0.2 animations:^{
_coverLabel.alpha = 0.7f;
}];
self.controlVideoPlayback(true);
}
});
}
} }
@end @end

View File

@ -75,10 +75,13 @@
CMTime _chaseTime; CMTime _chaseTime;
bool _chasingTime; bool _chasingTime;
bool _isPlaying;
AVPlayerItem *_playerItem; AVPlayerItem *_playerItem;
SMetaDisposable *_playerItemDisposable; SMetaDisposable *_playerItemDisposable;
id _playerStartedObserver; id _playerStartedObserver;
id _playerReachedEndObserver; id _playerReachedEndObserver;
bool _registeredKeypathObserver;
NSTimer *_positionTimer;
bool _scheduledVideoPlayback; bool _scheduledVideoPlayback;
id<TGMediaEditAdjustments> _initialAdjustments; id<TGMediaEditAdjustments> _initialAdjustments;
@ -94,15 +97,22 @@
TGMenuContainerView *_menuContainerView; TGMenuContainerView *_menuContainerView;
UIDocumentInteractionController *_documentController; UIDocumentInteractionController *_documentController;
bool _dismissed;
bool _hadProgress; bool _hadProgress;
bool _progressVisible; bool _progressVisible;
TGMessageImageViewOverlayView *_progressView; TGMessageImageViewOverlayView *_progressView;
SMetaDisposable *_faceDetectorDisposable; SMetaDisposable *_faceDetectorDisposable;
bool _wasPlaying;
bool _initializedScrubber; bool _initializedScrubber;
TGMediaPickerGalleryVideoScrubber *_scrubberView; TGMediaPickerGalleryVideoScrubber *_scrubberView;
PGPhotoEditorView *_dotVideoView;
NSTimeInterval _dotPosition;
UIImageView *_dotMarkerView;
UIImageView *_dotImageView;
UIView *_dotImageSnapshotView;
bool _requestingThumbnails; bool _requestingThumbnails;
SMetaDisposable *_thumbnailsDisposable; SMetaDisposable *_thumbnailsDisposable;
@ -166,7 +176,6 @@
- (void)dealloc - (void)dealloc
{ {
[self stopVideoPlayback:true];
[_actionHandle reset]; [_actionHandle reset];
[_faceDetectorDisposable dispose]; [_faceDetectorDisposable dispose];
[_thumbnailsDisposable dispose]; [_thumbnailsDisposable dispose];
@ -308,10 +317,22 @@
[_photoEditor setPreviewOutput:_previewView]; [_photoEditor setPreviewOutput:_previewView];
[self updatePreviewView]; [self updatePreviewView];
_dotMarkerView = [[UIImageView alloc] initWithImage:TGCircleImage(7.0, [TGPhotoEditorInterfaceAssets accentColor])];
[_scrubberView addSubview:_dotMarkerView];
_dotMarkerView.center = CGPointMake(30.0, -20.0);
_dotImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 160.0, 160.0)];
_dotImageView.userInteractionEnabled = true;
UITapGestureRecognizer *dotTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDotTap)];
[_dotImageView addGestureRecognizer:dotTapRecognizer];
if ([self presentedForAvatarCreation] && _item.isVideo) { if ([self presentedForAvatarCreation] && _item.isVideo) {
_scrubberView = [[TGMediaPickerGalleryVideoScrubber alloc] initWithFrame:CGRectMake(0.0f, 0.0, _portraitToolbarView.frame.size.width, 68.0f)]; _scrubberView = [[TGMediaPickerGalleryVideoScrubber alloc] initWithFrame:CGRectMake(0.0f, 0.0, _portraitToolbarView.frame.size.width, 68.0f)];
_scrubberView.dataSource = self; _scrubberView.dataSource = self;
_scrubberView.delegate = self; _scrubberView.delegate = self;
_scrubberView.clipsToBounds = false;
} }
[self detectFaces]; [self detectFaces];
@ -319,6 +340,28 @@
[self presentEditorTab:_currentTab]; [self presentEditorTab:_currentTab];
} }
- (void)handleDotTap {
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
return;
[self stopVideoPlayback:false];
[self seekVideo:_dotPosition];
[previewController beginScrubbing:false];
[_scrubberView setValue:_dotPosition resetPosition:true];
__weak TGPhotoEditorController *weakSelf = self;
[previewController endScrubbing:false completion:^bool{
__strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf == nil)
return false;
return !strongSelf->_scrubberView.isScrubbing;
}];
}
- (void)setToolbarHidden:(bool)hidden animated:(bool)animated - (void)setToolbarHidden:(bool)hidden animated:(bool)animated
{ {
if (self.requestToolbarsHidden == nil) if (self.requestToolbarsHidden == nil)
@ -383,7 +426,6 @@
if (self.item.isVideo) { if (self.item.isVideo) {
_scrubberView.allowsTrimming = self.item.originalDuration >= TGVideoEditMinimumTrimmableDuration; _scrubberView.allowsTrimming = self.item.originalDuration >= TGVideoEditMinimumTrimmableDuration;
_scrubberView.hasDotPicker = true;
_scrubberView.disableZoom = true; _scrubberView.disableZoom = true;
_scrubberView.disableTimeDisplay = true; _scrubberView.disableTimeDisplay = true;
_scrubberView.trimStartValue = 0.0; _scrubberView.trimStartValue = 0.0;
@ -423,36 +465,46 @@
} }
} }
__weak TGPhotoEditorController *weakSelf = self;
PGPhotoEditor *photoEditor = _photoEditor;
[signal startWithNext:^(id next) [signal startWithNext:^(id next)
{ {
__strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
if (strongSelf->_dismissed)
return;
CGFloat progress = 0.0; CGFloat progress = 0.0;
bool progressVisible = false; bool progressVisible = false;
bool doneEnabled = true; bool doneEnabled = true;
if ([next isKindOfClass:[UIImage class]]) { if ([next isKindOfClass:[UIImage class]]) {
[_photoEditor setImage:(UIImage *)next forCropRect:_photoEditor.cropRect cropRotation:_photoEditor.cropRotation cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored fullSize:false]; [photoEditor setImage:(UIImage *)next forCropRect:photoEditor.cropRect cropRotation:photoEditor.cropRotation cropOrientation:photoEditor.cropOrientation cropMirrored:photoEditor.cropMirrored fullSize:false];
if (!((UIImage *)next).degraded) { if (!((UIImage *)next).degraded) {
progress = 1.0f; progress = 1.0f;
} }
} else if ([next isKindOfClass:[AVAsset class]]) { } else if ([next isKindOfClass:[AVAsset class]]) {
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next]; strongSelf->_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
_player = [AVPlayer playerWithPlayerItem:_playerItem]; strongSelf->_player = [AVPlayer playerWithPlayerItem:strongSelf->_playerItem];
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone; strongSelf->_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
_player.muted = true; strongSelf->_player.muted = true;
[_photoEditor setPlayerItem:_playerItem forCropRect:_photoEditor.cropRect cropRotation:0.0 cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored]; [photoEditor setPlayerItem:strongSelf->_playerItem forCropRect:photoEditor.cropRect cropRotation:0.0 cropOrientation:photoEditor.cropOrientation cropMirrored:photoEditor.cropMirrored];
TGDispatchOnMainThread(^ TGDispatchOnMainThread(^
{ {
if ([_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]]) if ([strongSelf->_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]])
[(TGPhotoAvatarCropController *)_currentTabController setPlayer:_player]; [(TGPhotoAvatarCropController *)strongSelf->_currentTabController setPlayer:strongSelf->_player];
[_previewView performTransitionInWithCompletion:^ [strongSelf->_previewView performTransitionInWithCompletion:^
{ {
}]; }];
if (_scheduledVideoPlayback) { if (strongSelf->_scheduledVideoPlayback) {
_scheduledVideoPlayback = false; strongSelf->_scheduledVideoPlayback = false;
[self startVideoPlayback:true]; [strongSelf startVideoPlayback:true];
} }
}); });
progress = 1.0f; progress = 1.0f;
@ -464,14 +516,16 @@
} }
TGDispatchOnMainThread(^{ TGDispatchOnMainThread(^{
if (progressVisible) if (strongSelf->_dismissed)
_hadProgress = true; return;
[self setProgressVisible:progressVisible value:progress animated:true];
[self updateDoneButtonEnabled:doneEnabled animated:true];
if (_hadProgress) { if (progressVisible)
[_scrubberView reloadThumbnails]; strongSelf->_hadProgress = true;
[self updateDotImage]; [strongSelf setProgressVisible:progressVisible value:progress animated:true];
[strongSelf updateDoneButtonEnabled:doneEnabled animated:true];
if (strongSelf->_hadProgress) {
[strongSelf->_scrubberView reloadThumbnails];
} }
}); });
@ -479,25 +533,29 @@
return; return;
} }
if (_ignoreDefaultPreviewViewTransitionIn) if (strongSelf->_ignoreDefaultPreviewViewTransitionIn)
{ {
TGDispatchOnMainThread(^ TGDispatchOnMainThread(^
{ {
if ([_currentTabController isKindOfClass:[TGPhotoQualityController class]]) if (strongSelf->_dismissed)
[_previewView setSnapshotImageOnTransition:next]; return;
if ([strongSelf->_currentTabController isKindOfClass:[TGPhotoQualityController class]])
[strongSelf->_previewView setSnapshotImageOnTransition:next];
else else
[_previewView setSnapshotImage:next]; [strongSelf->_previewView setSnapshotImage:next];
}); });
} }
else else
{ {
[_photoEditor processAnimated:false completion:^ [photoEditor processAnimated:false completion:^
{ {
TGDispatchOnMainThread(^ TGDispatchOnMainThread(^
{ {
[_previewView performTransitionInWithCompletion:^ if (strongSelf->_dismissed)
return;
[strongSelf->_previewView performTransitionInWithCompletion:^
{ {
[_previewView setSnapshotImage:next]; [strongSelf->_previewView setSnapshotImage:next];
}]; }];
}); });
}]; }];
@ -544,8 +602,9 @@
_playerReachedEndObserver = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:endTime]] queue:NULL usingBlock:^ _playerReachedEndObserver = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:endTime]] queue:NULL usingBlock:^
{ {
__strong TGPhotoEditorController *strongSelf = weakSelf; __strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf != nil) { if (strongSelf != nil && !strongSelf->_dismissed) {
[strongSelf->_player seekToTime:startTime]; [strongSelf->_player seekToTime:startTime];
[strongSelf->_scrubberView setValue:strongSelf->_photoEditor.trimEndValue resetPosition:true];
} }
}]; }];
} }
@ -565,9 +624,19 @@
[_player.currentItem seekToTime:targetTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; [_player.currentItem seekToTime:targetTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
[self _setupPlaybackStartedObserver]; [self _setupPlaybackStartedObserver];
if (!_registeredKeypathObserver) {
[_player addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
_registeredKeypathObserver = true;
}
} }
_isPlaying = true;
[_player play]; [_player play];
[_positionTimer invalidate];
_positionTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(positionTimerEvent) interval:0.25 repeat:true];
[self positionTimerEvent];
} }
- (void)stopVideoPlayback:(bool)reset { - (void)stopVideoPlayback:(bool)reset {
@ -576,8 +645,35 @@
[_player removeTimeObserver:_playerStartedObserver]; [_player removeTimeObserver:_playerStartedObserver];
if (_playerReachedEndObserver != nil) if (_playerReachedEndObserver != nil)
[_player removeTimeObserver:_playerReachedEndObserver]; [_player removeTimeObserver:_playerReachedEndObserver];
if (_registeredKeypathObserver) {
[_player removeObserver:self forKeyPath:@"rate" context:nil];
_registeredKeypathObserver = false;
}
} }
_isPlaying = false;
[_player pause]; [_player pause];
[_positionTimer invalidate];
_positionTimer = nil;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)__unused change context:(void *)__unused context
{
if (object == _player && [keyPath isEqualToString:@"rate"])
{
if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
[_scrubberView setIsPlaying:_player.rate > FLT_EPSILON];
}
}
}
- (void)positionTimerEvent
{
if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) {
[_scrubberView setValue:CMTimeGetSeconds(_player.currentItem.currentTime) resetPosition:false];
}
} }
- (void)seekVideo:(NSTimeInterval)position { - (void)seekVideo:(NSTimeInterval)position {
@ -730,10 +826,11 @@
- (void)createEditedImageWithEditorValues:(id<TGMediaEditAdjustments>)editorValues createThumbnail:(bool)createThumbnail saveOnly:(bool)saveOnly completion:(void (^)(UIImage *))completion - (void)createEditedImageWithEditorValues:(id<TGMediaEditAdjustments>)editorValues createThumbnail:(bool)createThumbnail saveOnly:(bool)saveOnly completion:(void (^)(UIImage *))completion
{ {
bool avatar = [self presentedForAvatarCreation];
if (!saveOnly) if (!saveOnly)
{ {
bool forAvatar = [self presentedForAvatarCreation]; if (!avatar && [editorValues isDefaultValuesForAvatar:false])
if (!forAvatar && [editorValues isDefaultValuesForAvatar:false])
{ {
if (self.willFinishEditing != nil) if (self.willFinishEditing != nil)
self.willFinishEditing(nil, [_currentTabController currentResultRepresentation], true); self.willFinishEditing(nil, [_currentTabController currentResultRepresentation], true);
@ -751,7 +848,7 @@
if (!saveOnly && self.willFinishEditing != nil) if (!saveOnly && self.willFinishEditing != nil)
self.willFinishEditing(editorValues, [_currentTabController currentResultRepresentation], true); self.willFinishEditing(editorValues, [_currentTabController currentResultRepresentation], true);
if (!saveOnly && completion != nil) if (!saveOnly && !avatar && completion != nil)
completion(nil); completion(nil);
UIImage *fullSizeImage = self.fullSizeImage; UIImage *fullSizeImage = self.fullSizeImage;
@ -832,19 +929,22 @@
} }
else else
{ {
void (^didFinishRenderingFullSizeImage)(UIImage *) = self.didFinishRenderingFullSizeImage;
void (^didFinishEditing)(id<TGMediaEditAdjustments>, UIImage *, UIImage *, bool ) = self.didFinishEditing;
[[[[renderedImageSignal map:^id(UIImage *image) [[[[renderedImageSignal map:^id(UIImage *image)
{ {
if (!hasImageAdjustments) if (!hasImageAdjustments)
{ {
if (hasPainting && !hasAnimation && self.didFinishRenderingFullSizeImage != nil) if (hasPainting && !hasAnimation && didFinishRenderingFullSizeImage != nil)
self.didFinishRenderingFullSizeImage(image); didFinishRenderingFullSizeImage(image);
return image; return image;
} }
else else
{ {
if (!saveOnly && !hasAnimation && self.didFinishRenderingFullSizeImage != nil) if (!saveOnly && !hasAnimation && didFinishRenderingFullSizeImage != nil)
self.didFinishRenderingFullSizeImage(image); didFinishRenderingFullSizeImage(image);
return TGPhotoEditorFitImage(image, TGPhotoEditorResultImageMaxSize); return TGPhotoEditorFitImage(image, TGPhotoEditorResultImageMaxSize);
} }
@ -881,8 +981,11 @@
UIImage *image = result[@"image"]; UIImage *image = result[@"image"];
UIImage *thumbnailImage = result[@"thumbnail"]; UIImage *thumbnailImage = result[@"thumbnail"];
if (!saveOnly && self.didFinishEditing != nil) if (avatar && completion != nil)
self.didFinishEditing(editorValues, image, thumbnailImage, true); completion(image);
if (!saveOnly && didFinishEditing != nil)
didFinishEditing(editorValues, image, thumbnailImage, true);
} error:^(__unused id error) } error:^(__unused id error)
{ {
TGLegacyLog(@"renderedImageSignal error"); TGLegacyLog(@"renderedImageSignal error");
@ -923,6 +1026,11 @@
- (void)transitionOutSaving:(bool)saving completion:(void (^)(void))completion - (void)transitionOutSaving:(bool)saving completion:(void (^)(void))completion
{ {
_dismissed = true;
if (!saving) {
[self stopVideoPlayback:true];
}
[UIView animateWithDuration:0.3f animations:^ [UIView animateWithDuration:0.3f animations:^
{ {
_portraitToolbarView.alpha = 0.0f; _portraitToolbarView.alpha = 0.0f;
@ -932,7 +1040,7 @@
_currentTabController.beginTransitionOut = self.beginTransitionOut; _currentTabController.beginTransitionOut = self.beginTransitionOut;
[self setToolbarHidden:false animated:true]; [self setToolbarHidden:false animated:true];
if (self.beginCustomTransitionOut != nil) if (self.beginCustomTransitionOut != nil && !saving)
{ {
id rep = [_currentTabController currentResultRepresentation]; id rep = [_currentTabController currentResultRepresentation];
if ([rep isKindOfClass:[UIImage class]]) if ([rep isKindOfClass:[UIImage class]])
@ -1373,10 +1481,10 @@
{ {
if ([_currentTabController isKindOfClass:[TGPhotoToolsController class]]) { if ([_currentTabController isKindOfClass:[TGPhotoToolsController class]]) {
[_scrubberView reloadDataAndReset:false]; [_scrubberView reloadDataAndReset:false];
[self updateDotImage]; [self updateDotImage:false];
} }
TGPhotoAvatarPreviewController *previewController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView scrubberView:_scrubberView]; TGPhotoAvatarPreviewController *previewController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView scrubberView:_scrubberView dotImageView:_dotImageView];
previewController.item = _item; previewController.item = _item;
previewController.toolbarLandscapeSize = TGPhotoEditorToolbarSize; previewController.toolbarLandscapeSize = TGPhotoEditorToolbarSize;
previewController.beginTransitionIn = ^UIView *(CGRect *referenceFrame, UIView **parentView, bool *noTransitionView) previewController.beginTransitionIn = ^UIView *(CGRect *referenceFrame, UIView **parentView, bool *noTransitionView)
@ -1386,8 +1494,16 @@
*noTransitionView = transitionNoTransitionView; *noTransitionView = transitionNoTransitionView;
__strong TGPhotoEditorController *strongSelf = weakSelf; __strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf != nil) if (strongSelf != nil) {
[strongSelf startVideoPlayback:true]; if ([currentController isKindOfClass:[TGPhotoAvatarCropController class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf stopVideoPlayback:false];
[strongSelf seekVideo:0];
});
} else {
[strongSelf startVideoPlayback:true];
}
}
return transitionReferenceView; return transitionReferenceView;
}; };
@ -1400,6 +1516,10 @@
if (isInitialAppearance && strongSelf.finishedTransitionIn != nil) if (isInitialAppearance && strongSelf.finishedTransitionIn != nil)
strongSelf.finishedTransitionIn(); strongSelf.finishedTransitionIn();
if ([currentController isKindOfClass:[TGPhotoAvatarCropController class]]) {
[strongSelf startVideoPlayback:false];
}
strongSelf->_switchingTab = false; strongSelf->_switchingTab = false;
}; };
previewController.controlVideoPlayback = ^(bool play) { previewController.controlVideoPlayback = ^(bool play) {
@ -1522,8 +1642,13 @@
- (void)dismissAnimated:(bool)animated - (void)dismissAnimated:(bool)animated
{ {
_dismissed = true;
self.view.userInteractionEnabled = false; self.view.userInteractionEnabled = false;
if (self.navigationController != nil)
animated = false;
if (animated) if (animated)
{ {
const CGFloat velocity = 2000.0f; const CGFloat velocity = 2000.0f;
@ -1535,12 +1660,20 @@
self.view.frame = targetFrame; self.view.frame = targetFrame;
} completion:^(__unused BOOL finished) } completion:^(__unused BOOL finished)
{ {
[self dismiss]; if (self.navigationController != nil) {
[self.navigationController popViewControllerAnimated:false];
} else {
[self dismiss];
}
}]; }];
} }
else else
{ {
[self dismiss]; if (self.navigationController != nil) {
[self.navigationController popViewControllerAnimated:false];
} else {
[self dismiss];
}
} }
} }
@ -1684,11 +1817,13 @@
[[NSUserDefaults standardUserDefaults] setObject:@(qualityController.preset) forKey:@"TG_preferredVideoPreset_v0"]; [[NSUserDefaults standardUserDefaults] setObject:@(qualityController.preset) forKey:@"TG_preferredVideoPreset_v0"];
} else if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]]) } else if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]])
{ {
videoStartValue = _scrubberView.value; videoStartValue = _dotPosition;
trimStartValue = _scrubberView.trimStartValue; trimStartValue = _scrubberView.trimStartValue;
trimEndValue = _scrubberView.trimEndValue; trimEndValue = _scrubberView.trimEndValue;
} }
[self stopVideoPlayback:true];
TGVideoEditAdjustments *adjustments = [_photoEditor exportAdjustmentsWithPaintingData:paintingData]; TGVideoEditAdjustments *adjustments = [_photoEditor exportAdjustmentsWithPaintingData:paintingData];
if ([self presentedForAvatarCreation] && _item.isVideo) { if ([self presentedForAvatarCreation] && _item.isVideo) {
[[SQueue concurrentDefaultQueue] dispatch:^ [[SQueue concurrentDefaultQueue] dispatch:^
@ -1745,10 +1880,7 @@
if (self.didFinishEditingVideo != nil) if (self.didFinishEditingVideo != nil)
self.didFinishEditingVideo(asset.URL, [adjustments editAdjustmentsWithPreset:TGMediaVideoConversionPresetProfile videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true); self.didFinishEditingVideo(asset.URL, [adjustments editAdjustmentsWithPreset:TGMediaVideoConversionPresetProfile videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true);
[self transitionOutSaving:true completion:^ [self dismissAnimated:true];
{
[self dismiss];
}];
}); });
}]; }];
}]; }];
@ -1766,9 +1898,10 @@
[NSObject cancelPreviousPerformRequestsWithTarget:progressWindow selector:@selector(showAnimated) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:progressWindow selector:@selector(showAnimated) object:nil];
[progressWindow dismiss:true]; [progressWindow dismiss:true];
if (forAvatar) if (forAvatar) {
[self dismissAnimated:true];
return; return;
}
[self transitionOutSaving:true completion:^ [self transitionOutSaving:true completion:^
{ {
[self dismiss]; [self dismiss];
@ -1856,10 +1989,14 @@
if (self.didFinishEditing != nil) if (self.didFinishEditing != nil)
self.didFinishEditing(hasChanges ? adjustments : nil, nil, nil, hasChanges); self.didFinishEditing(hasChanges ? adjustments : nil, nil, nil, hasChanges);
[self transitionOutSaving:saving completion:^ if ([self presentedForAvatarCreation]) {
{ [self dismissAnimated:true];
[self dismiss]; } else {
}]; [self transitionOutSaving:saving completion:^
{
[self dismiss];
}];
}
} }
} }
@ -2040,6 +2177,12 @@
return orientation; return orientation;
} }
- (UIEdgeInsets)screenEdges {
CGSize referenceSize = [self referenceViewSize];
CGFloat screenSide = MAX(referenceSize.width, referenceSize.height);
return UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2);
}
- (void)updateLayout:(UIInterfaceOrientation)orientation - (void)updateLayout:(UIInterfaceOrientation)orientation
{ {
orientation = [self effectiveOrientation:orientation]; orientation = [self effectiveOrientation:orientation];
@ -2098,8 +2241,6 @@
_initializedScrubber = true; _initializedScrubber = true;
[_scrubberView reloadData]; [_scrubberView reloadData];
[_scrubberView resetToStart]; [_scrubberView resetToStart];
[self updateDotImage];
} else { } else {
[_scrubberView reloadThumbnails]; [_scrubberView reloadThumbnails];
} }
@ -2240,6 +2381,27 @@
return avatarTabs; return avatarTabs;
} }
- (void)setPlayButtonHidden:(bool)hidden animated:(bool)animated
{
// if (animated)
// {
// _actionButton.hidden = false;
// [UIView animateWithDuration:0.15f animations:^
// {
// _actionButton.alpha = hidden ? 0.0f : 1.0f;
// } completion:^(BOOL finished)
// {
// if (finished)
// _actionButton.hidden = hidden;
// }];
// }
// else
// {
// _actionButton.alpha = hidden ? 0.0f : 1.0f;
// _actionButton.hidden = hidden;
// }
}
#pragma mark - Video Scrubber Data Source & Delegate #pragma mark - Video Scrubber Data Source & Delegate
#pragma mark Scrubbing #pragma mark Scrubbing
@ -2265,23 +2427,16 @@
{ {
[self stopVideoPlayback:false]; [self stopVideoPlayback:false];
if (_dotVideoView == nil) { [self setPlayButtonHidden:true animated:false];
_dotVideoView = [[PGPhotoEditorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 26.0, 44.0)];
[_scrubberView setDotVideoView:_dotVideoView];
_photoEditor.additionalOutputs = @[_dotVideoView];
} else {
_dotVideoView.hidden = false;
}
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController; TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]]) if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
return; return;
[previewController beginScrubbing]; [previewController beginScrubbing:true];
} }
- (void)updateDotImage { - (void)updateDotImage:(bool)animated {
AVPlayer *player = _player; AVPlayer *player = _player;
if (player == nil) { if (player == nil) {
return; return;
@ -2290,9 +2445,10 @@
[[SQueue concurrentDefaultQueue] dispatch:^{ [[SQueue concurrentDefaultQueue] dispatch:^{
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:player.currentItem.asset]; AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:player.currentItem.asset];
generator.appliesPreferredTrackTransform = true; generator.appliesPreferredTrackTransform = true;
generator.maximumSize = CGSizeMake(128.0f, 128.0f); generator.maximumSize = CGSizeMake(160.0f, 160.0f);
generator.requestedTimeToleranceAfter = kCMTimeZero; generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.requestedTimeToleranceBefore = kCMTimeZero; generator.requestedTimeToleranceBefore = kCMTimeZero;
CGImageRef imageRef = [generator copyCGImageAtTime:player.currentItem.currentTime actualTime:NULL error:NULL]; CGImageRef imageRef = [generator copyCGImageAtTime:player.currentItem.currentTime actualTime:NULL error:NULL];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
CGImageRelease(imageRef); CGImageRelease(imageRef);
@ -2304,21 +2460,102 @@
image = editor.currentResultImage; image = editor.currentResultImage;
} }
UIGraphicsBeginImageContextWithOptions(CGSizeMake(160.0, 160.0), false, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(context, CGRectMake(0.0, 0.0, 160.0, 160.0));
CGContextClip(context);
CGSize filledSize = TGScaleToFill(image.size, CGSizeMake(160, 160));
[image drawInRect:CGRectMake((160.0 - filledSize.width) / 2.0, (160.0 - filledSize.height) / 2.0, filledSize.width, filledSize.height)];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
TGDispatchOnMainThread(^{ TGDispatchOnMainThread(^{
[_scrubberView setDotImage:image]; if (animated) {
_dotVideoView.hidden = true; UIView *snapshotView = nil;
UIView *dotSnapshotView = nil;
if (_dotImageView.image != nil) {
dotSnapshotView = [_dotMarkerView snapshotViewAfterScreenUpdates:false];
dotSnapshotView.frame = _dotMarkerView.frame;
[_dotMarkerView.superview addSubview:dotSnapshotView];
snapshotView = [_dotImageView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = [_dotImageView.superview convertRect:_dotImageView.frame toView:_dotMarkerView.superview];
[_dotMarkerView.superview addSubview:snapshotView];
}
if (snapshotView != nil) {
[UIView animateWithDuration:0.15 animations:^{
snapshotView.center = _dotMarkerView.center;
snapshotView.transform = CGAffineTransformMakeScale(0.05, 0.05);
snapshotView.alpha = 0.0f;
dotSnapshotView.transform = CGAffineTransformMakeScale(0.3, 0.3);
dotSnapshotView.alpha = 0.0f;
} completion:^(BOOL finished) {
[snapshotView removeFromSuperview];
[dotSnapshotView removeFromSuperview];
}];
}
_dotImageView.image = finalImage;
[_scrubberView addSubview:_dotMarkerView];
_dotMarkerView.center = CGPointMake([_scrubberView scrubberPositionForPosition:_dotPosition].x + 7.0, 9.5);
_dotMarkerView.transform = CGAffineTransformMakeScale(0.3, 0.3);
_dotMarkerView.alpha = 0.0;
[UIView animateWithDuration:0.3 animations:^{
_dotMarkerView.transform = CGAffineTransformIdentity;
_dotMarkerView.alpha = 1.0;
}];
UIEdgeInsets screenEdges = [self screenEdges];
CGSize referenceSize = [self referenceViewSize];
CGRect containerFrame = [TGPhotoEditorTabController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:0.0 hasOnScreenNavigation:self.hasOnScreenNavigation];
containerFrame.origin.x += screenEdges.left;
containerFrame.origin.y += screenEdges.top;
CGFloat scale = containerFrame.size.width / 160.0;
_dotImageView.center = CGPointMake(CGRectGetMidX(containerFrame), CGRectGetMidY(containerFrame));
_dotImageView.transform = CGAffineTransformMakeScale(scale, scale);
CGPoint targetCenter = [_dotMarkerView.superview convertPoint:_dotMarkerView.center toView:_wrapperView];
targetCenter.y -= 27.0;
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:1.1 initialSpringVelocity:0.1 options:kNilOptions animations:^{
_dotImageView.center = targetCenter;
_dotImageView.transform = CGAffineTransformMakeScale(0.225, 0.225);
} completion:^(BOOL finished) {
}];
} else {
if (_dotImageView.image != nil) {
[_scrubberView addSubview:_dotMarkerView];
UIView *snapshotView;
if (_dotImageView.image != nil) {
_dotImageSnapshotView = [_dotImageView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = _dotImageView.bounds;
[_dotImageView addSubview:snapshotView];
}
_dotImageView.image = finalImage;
}
}
}); });
}]; }];
} }
- (void)videoScrubberDidEndScrubbing:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber - (void)videoScrubberDidEndScrubbing:(TGMediaPickerGalleryVideoScrubber *)videoScrubber
{ {
__weak TGPhotoEditorController *weakSelf = self; __weak TGPhotoEditorController *weakSelf = self;
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController; TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]]) if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
return; return;
[previewController endScrubbing:^bool{ _dotPosition = videoScrubber.value;
[previewController endScrubbing:true completion:^bool{
__strong TGPhotoEditorController *strongSelf = weakSelf; __strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf == nil) if (strongSelf == nil)
return false; return false;
@ -2327,7 +2564,7 @@
}]; }];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self updateDotImage]; [self updateDotImage:true];
}); });
} }
@ -2352,11 +2589,7 @@
{ {
[self stopVideoPlayback:false]; [self stopVideoPlayback:false];
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController; [self setPlayButtonHidden:true animated:false];
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
return;
[previewController setPlayButtonHidden:true animated:false];
} }
- (void)videoScrubberDidEndEditing:(TGMediaPickerGalleryVideoScrubber *)videoScrubber - (void)videoScrubberDidEndEditing:(TGMediaPickerGalleryVideoScrubber *)videoScrubber
@ -2366,11 +2599,7 @@
[self seekVideo:videoScrubber.trimStartValue]; [self seekVideo:videoScrubber.trimStartValue];
[self stopVideoPlayback:false]; [self stopVideoPlayback:false];
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController; [self setPlayButtonHidden:true animated:false];
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
return;
[previewController setPlayButtonHidden:true animated:false];
} }
- (void)videoScrubber:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber editingStartValueDidChange:(NSTimeInterval)startValue - (void)videoScrubber:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber editingStartValueDidChange:(NSTimeInterval)startValue
@ -2454,6 +2683,15 @@
if (index < timestamps.count) if (index < timestamps.count)
[strongSelf->_scrubberView setThumbnailImage:image forTimestamp:[timestamps[index] doubleValue] isSummaryThubmnail:isSummaryThumbnails]; [strongSelf->_scrubberView setThumbnailImage:image forTimestamp:[timestamps[index] doubleValue] isSummaryThubmnail:isSummaryThumbnails];
}]; }];
if (strongSelf->_dotImageSnapshotView != nil) {
[UIView animateWithDuration:0.2 animations:^{
strongSelf->_dotImageSnapshotView.alpha = 0.0f;
} completion:^(BOOL finished) {
[strongSelf->_dotImageSnapshotView removeFromSuperview];
strongSelf->_dotImageSnapshotView = nil;
}];
}
} completed:^ } completed:^
{ {
__strong TGPhotoEditorController *strongSelf = weakSelf; __strong TGPhotoEditorController *strongSelf = weakSelf;

View File

@ -113,8 +113,8 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<
var index: Int32 = 0 var index: Int32 = 0
for photo in photos { for photo in photos {
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
if result.isEmpty, let first = initialEntries.first, photo.image.videoRepresentations.isEmpty { if result.isEmpty, let first = initialEntries.first {
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, first.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData)) result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
} else { } else {
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData)) result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
} }
@ -140,8 +140,8 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry
var index: Int32 = 0 var index: Int32 = 0
for photo in photos { for photo in photos {
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
if result.isEmpty, let first = initialEntries.first, photo.image.videoRepresentations.isEmpty { if result.isEmpty, let first = initialEntries.first {
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, first.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData)) result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
} else { } else {
result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData)) result.append(.image(photo.image.imageId, photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
} }

View File

@ -1415,7 +1415,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
if let profileImage = peer?.smallProfileImage { if let profileImage = peer?.smallProfileImage {
state.updatingAvatar = .image(profileImage, false) state.updatingAvatar = .image(profileImage, false)
} else { } else {
state.updatingAvatar = .none state.updatingAvatar = ItemListAvatarAndNameInfoItemUpdatingAvatar.none
} }
return state return state
} }

View File

@ -1121,7 +1121,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if file.isAnimated { if file.isAnimated {
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(gifTitle)", size: nil, muted: false, active: false) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(gifTitle)", size: nil, muted: false, active: false)
} else { } else {
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: strings.Conversation_Processing, size: nil, muted: false, active: active) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: strings.Conversation_Processing, size: nil, muted: false, active: false)
} }
} }
if file.isAnimated && isMediaStreamable(message: message, media: file) { if file.isAnimated && isMediaStreamable(message: message, media: file) {

View File

@ -236,7 +236,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
if let video = videoRepresentations.last, let id = id { if let video = videoRepresentations.last, let id = id {
let mediaManager = self.context.sharedContext.mediaManager let mediaManager = self.context.sharedContext.mediaManager
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])])) let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: true, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded) let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
videoNode.isUserInteractionEnabled = false videoNode.isUserInteractionEnabled = false
videoNode.ownsContentNodeUpdated = { [weak self] owns in videoNode.ownsContentNodeUpdated = { [weak self] owns in
@ -626,7 +626,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
strongSelf.items = items strongSelf.items = items
strongSelf.itemsUpdated?(items) strongSelf.itemsUpdated?(items)
if let size = strongSelf.validLayout { if let size = strongSelf.validLayout {
strongSelf.updateItems(size: size, update: true, transition: .immediate, stripTransition: .immediate, synchronous: true) strongSelf.updateItems(size: size, update: true, transition: .immediate, stripTransition: .immediate, synchronous: synchronous)
} }
if items.isEmpty { if items.isEmpty {
if !strongSelf.didSetReady { if !strongSelf.didSetReady {
@ -762,7 +762,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
let context: AccountContext let context: AccountContext
let avatarNode: AvatarNode let avatarNode: AvatarNode
private var videoNode: UniversalVideoNode? fileprivate var videoNode: UniversalVideoNode?
private var videoContent: NativeVideoContent? private var videoContent: NativeVideoContent?
var tapped: (() -> Void)? var tapped: (() -> Void)?
@ -788,6 +788,21 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
} }
} }
func reattachVideoNode() {
if let videoNode = self.videoNode {
let maskPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(), size: self.avatarNode.frame.size))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
videoNode.layer.mask = shape
videoNode.transform = CATransform3DIdentity
videoNode.updateLayout(size: self.avatarNode.frame.size, transition: .immediate)
videoNode.frame = self.avatarNode.frame
self.addSubnode(videoNode)
}
}
func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) { func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool) {
if let peer = peer { if let peer = peer {
var overrideImage: AvatarNodeImageOverride? var overrideImage: AvatarNodeImageOverride?
@ -803,7 +818,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
if let item = item, case let .image(reference, representations, videoRepresentations, immediateThumbnailData) = item, let video = videoRepresentations.last, case let .cloud(imageId, _, _) = reference { if let item = item, case let .image(reference, representations, videoRepresentations, immediateThumbnailData) = item, let video = videoRepresentations.last, case let .cloud(imageId, _, _) = reference {
let id = imageId let id = imageId
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])])) let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear) let videoContent = NativeVideoContent(id: .profileVideo(id), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
if videoContent.id != self.videoContent?.id { if videoContent.id != self.videoContent?.id {
let mediaManager = self.context.sharedContext.mediaManager let mediaManager = self.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded) let videoNode = UniversalVideoNode(postbox: self.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .embedded)
@ -835,9 +850,19 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
videoNode.frame = self.avatarNode.frame videoNode.frame = self.avatarNode.frame
if isExpanded == videoNode.canAttachContent { if isExpanded == videoNode.canAttachContent {
videoNode.canAttachContent = !isExpanded let update = {
if videoNode.canAttachContent { videoNode.canAttachContent = !isExpanded
videoNode.play() if videoNode.canAttachContent {
videoNode.seek(0.0)
videoNode.play()
}
}
if isExpanded {
DispatchQueue.main.async {
update()
}
} else {
update()
} }
} }
} }
@ -1011,20 +1036,28 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
} }
func animateAvatarCollapse(transition: ContainedViewLayoutTransition) { func animateAvatarCollapse(transition: ContainedViewLayoutTransition) {
if let currentItemNode = self.listContainerNode.currentItemNode, let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage, case .animated = transition { if let currentItemNode = self.listContainerNode.currentItemNode, case .animated = transition {
let avatarCopyView = UIImageView() if let videoNode = self.avatarContainerNode.videoNode {
avatarCopyView.image = unroundedImage // videoNode.position = currentItemNode.imageNode.position
avatarCopyView.frame = self.avatarContainerNode.avatarNode.frame // currentItemNode.addSubnode(videoNode)
avatarCopyView.center = currentItemNode.imageNode.position // let scale = currentItemNode.imageNode.bounds.height / videoNode.bounds.height
currentItemNode.view.addSubview(avatarCopyView) // avatarCopyView.layer.transform = CATransform3DMakeScale(scale, scale, scale)
let scale = currentItemNode.imageNode.bounds.height / avatarCopyView.bounds.height // self.avatarContainerNode.reattachVideoNode()
avatarCopyView.layer.transform = CATransform3DMakeScale(scale, scale, scale) } else if let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage {
avatarCopyView.alpha = 0.0 let avatarCopyView = UIImageView()
transition.updateAlpha(layer: avatarCopyView.layer, alpha: 1.0, completion: { [weak avatarCopyView] _ in avatarCopyView.image = unroundedImage
Queue.mainQueue().after(0.1, { avatarCopyView.frame = self.avatarContainerNode.avatarNode.frame
avatarCopyView?.removeFromSuperview() avatarCopyView.center = currentItemNode.imageNode.position
currentItemNode.view.addSubview(avatarCopyView)
let scale = currentItemNode.imageNode.bounds.height / avatarCopyView.bounds.height
avatarCopyView.layer.transform = CATransform3DMakeScale(scale, scale, scale)
avatarCopyView.alpha = 0.0
transition.updateAlpha(layer: avatarCopyView.layer, alpha: 1.0, completion: { [weak avatarCopyView] _ in
Queue.mainQueue().after(0.1, {
avatarCopyView?.removeFromSuperview()
})
}) })
}) }
} }
} }
} }

View File

@ -103,7 +103,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
} }
} }
return (128.0 + additionalHeight, false) return (128.0 + additionalHeight, !self.listAppearance)
} }
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, info: StickerPackCollectionInfo, topItems: [StickerPackItem], topSeparator: Bool, regularInsets: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext, sectionTitle: String? = nil) { init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, info: StickerPackCollectionInfo, topItems: [StickerPackItem], topSeparator: Bool, regularInsets: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool, itemContext: StickerPaneSearchGlobalItemContext, sectionTitle: String? = nil) {

View File

@ -31,11 +31,12 @@ public final class NativeVideoContent: UniversalVideoContent {
public let baseRate: Double public let baseRate: Double
let fetchAutomatically: Bool let fetchAutomatically: Bool
let onlyFullSizeThumbnail: Bool let onlyFullSizeThumbnail: Bool
let autoFetchFullSizeThumbnail: Bool
let continuePlayingWithoutSoundOnLostAudioSession: Bool let continuePlayingWithoutSoundOnLostAudioSession: Bool
let placeholderColor: UIColor let placeholderColor: UIColor
let tempFilePath: String? let tempFilePath: String?
public init(id: NativeVideoContentId, fileReference: FileMediaReference, imageReference: ImageMediaReference? = nil, streamVideo: MediaPlayerStreaming = .none, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true, onlyFullSizeThumbnail: Bool = false, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor = .white, tempFilePath: String? = nil) { public init(id: NativeVideoContentId, fileReference: FileMediaReference, imageReference: ImageMediaReference? = nil, streamVideo: MediaPlayerStreaming = .none, loopVideo: Bool = false, enableSound: Bool = true, baseRate: Double = 1.0, fetchAutomatically: Bool = true, onlyFullSizeThumbnail: Bool = false, autoFetchFullSizeThumbnail: Bool = false, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor = .white, tempFilePath: String? = nil) {
self.id = id self.id = id
self.nativeId = id self.nativeId = id
self.fileReference = fileReference self.fileReference = fileReference
@ -60,13 +61,14 @@ public final class NativeVideoContent: UniversalVideoContent {
self.baseRate = baseRate self.baseRate = baseRate
self.fetchAutomatically = fetchAutomatically self.fetchAutomatically = fetchAutomatically
self.onlyFullSizeThumbnail = onlyFullSizeThumbnail self.onlyFullSizeThumbnail = onlyFullSizeThumbnail
self.autoFetchFullSizeThumbnail = autoFetchFullSizeThumbnail
self.continuePlayingWithoutSoundOnLostAudioSession = continuePlayingWithoutSoundOnLostAudioSession self.continuePlayingWithoutSoundOnLostAudioSession = continuePlayingWithoutSoundOnLostAudioSession
self.placeholderColor = placeholderColor self.placeholderColor = placeholderColor
self.tempFilePath = tempFilePath self.tempFilePath = tempFilePath
} }
public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode { public func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode {
return NativeVideoContentNode(postbox: postbox, audioSessionManager: audioSession, fileReference: self.fileReference, imageReference: self.imageReference, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically, onlyFullSizeThumbnail: self.onlyFullSizeThumbnail, continuePlayingWithoutSoundOnLostAudioSession: self.continuePlayingWithoutSoundOnLostAudioSession, placeholderColor: self.placeholderColor, tempFilePath: self.tempFilePath) return NativeVideoContentNode(postbox: postbox, audioSessionManager: audioSession, fileReference: self.fileReference, imageReference: self.imageReference, streamVideo: self.streamVideo, loopVideo: self.loopVideo, enableSound: self.enableSound, baseRate: self.baseRate, fetchAutomatically: self.fetchAutomatically, onlyFullSizeThumbnail: self.onlyFullSizeThumbnail, autoFetchFullSizeThumbnail: self.autoFetchFullSizeThumbnail, continuePlayingWithoutSoundOnLostAudioSession: self.continuePlayingWithoutSoundOnLostAudioSession, placeholderColor: self.placeholderColor, tempFilePath: self.tempFilePath)
} }
public func isEqual(to other: UniversalVideoContent) -> Bool { public func isEqual(to other: UniversalVideoContent) -> Bool {
@ -126,7 +128,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
private var shouldPlay: Bool = false private var shouldPlay: Bool = false
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, fileReference: FileMediaReference, imageReference: ImageMediaReference?, streamVideo: MediaPlayerStreaming, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, onlyFullSizeThumbnail: Bool, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor, tempFilePath: String?) { init(postbox: Postbox, audioSessionManager: ManagedAudioSession, fileReference: FileMediaReference, imageReference: ImageMediaReference?, streamVideo: MediaPlayerStreaming, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool, onlyFullSizeThumbnail: Bool, autoFetchFullSizeThumbnail: Bool, continuePlayingWithoutSoundOnLostAudioSession: Bool = false, placeholderColor: UIColor, tempFilePath: String?) {
self.postbox = postbox self.postbox = postbox
self.fileReference = fileReference self.fileReference = fileReference
self.placeholderColor = placeholderColor self.placeholderColor = placeholderColor
@ -163,7 +165,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
self?.performActionAtEnd() self?.performActionAtEnd()
} }
self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, videoReference: fileReference, imageReference: imageReference, onlyFullSize: onlyFullSizeThumbnail, autoFetchFullSizeThumbnail: fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, videoReference: fileReference, imageReference: imageReference, onlyFullSize: onlyFullSizeThumbnail, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail || fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in
Queue.mainQueue().async { Queue.mainQueue().async {
if let strongSelf = self, strongSelf.dimensions == nil { if let strongSelf = self, strongSelf.dimensions == nil {
if let dimensions = getSize() { if let dimensions = getSize() {