mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-24 20:20:51 +00:00
Merge commit '51a95f3f6ff23403490f3371b58dffac7eff87d8'
This commit is contained in:
commit
95b7ea333d
@ -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.SetNewProfilePhotoOrVideo" = "Set New Profile Photo or Video";
|
||||
|
||||
"Conversation.Unarchive" = "Unarhive";
|
||||
"Conversation.Unarchive" = "Unarchive";
|
||||
"Conversation.UnarchiveDone" = "The chat was moved to your main list.";
|
||||
|
@ -3,15 +3,15 @@
|
||||
typedef NS_OPTIONS(NSUInteger, TGPhotoEditorTab) {
|
||||
TGPhotoEditorNoneTab = 0,
|
||||
TGPhotoEditorCropTab = 1 << 0,
|
||||
TGPhotoEditorPaintTab = 1 << 1,
|
||||
TGPhotoEditorEraserTab = 1 << 2,
|
||||
TGPhotoEditorStickerTab = 1 << 3,
|
||||
TGPhotoEditorTextTab = 1 << 4,
|
||||
TGPhotoEditorToolsTab = 1 << 5,
|
||||
TGPhotoEditorRotateTab = 1 << 6,
|
||||
TGPhotoEditorQualityTab = 1 << 7,
|
||||
TGPhotoEditorTimerTab = 1 << 8,
|
||||
TGPhotoEditorMirrorTab = 1 << 9,
|
||||
TGPhotoEditorRotateTab = 1 << 1,
|
||||
TGPhotoEditorMirrorTab = 1 << 2,
|
||||
TGPhotoEditorPaintTab = 1 << 3,
|
||||
TGPhotoEditorEraserTab = 1 << 4,
|
||||
TGPhotoEditorStickerTab = 1 << 5,
|
||||
TGPhotoEditorTextTab = 1 << 6,
|
||||
TGPhotoEditorToolsTab = 1 << 7,
|
||||
TGPhotoEditorQualityTab = 1 << 8,
|
||||
TGPhotoEditorTimerTab = 1 << 9,
|
||||
TGPhotoEditorAspectRatioTab = 1 << 10,
|
||||
TGPhotoEditorTintTab = 1 << 11,
|
||||
TGPhotoEditorBlurTab = 1 << 12,
|
||||
|
@ -908,8 +908,6 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
|
||||
if (strongSelf.avatarCompletionBlock != nil)
|
||||
strongSelf.avatarCompletionBlock(resultImage);
|
||||
|
||||
[strongController dismissAnimated:true];
|
||||
};
|
||||
controller.didFinishEditingVideo = ^(NSURL *url, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage, bool hasChanges) {
|
||||
if (!hasChanges)
|
||||
@ -925,8 +923,6 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
|
||||
|
||||
if (strongSelf.avatarVideoCompletionBlock != nil)
|
||||
strongSelf.avatarVideoCompletionBlock(resultImage, url, adjustments);
|
||||
|
||||
[strongController dismissAnimated:true];
|
||||
};
|
||||
controller.requestThumbnailImage = ^(id<TGMediaEditableItem> editableItem)
|
||||
{
|
||||
|
@ -1012,7 +1012,9 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
||||
TGCameraCapturedVideo *capturedVideo = [[TGCameraCapturedVideo alloc] initWithURL:outputURL];
|
||||
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 {
|
||||
[strongSelf addResultItem:capturedVideo];
|
||||
if (![strongSelf maybePresentResultControllerForItem:capturedVideo completion:nil])
|
||||
|
@ -44,6 +44,8 @@
|
||||
|
||||
- (void)setRecipientName:(NSString *)recipientName;
|
||||
|
||||
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGMediaPickerGalleryVideoScrubberDelegate <NSObject>
|
||||
|
@ -1286,6 +1286,11 @@ typedef enum
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position
|
||||
{
|
||||
return [self _scrubberPositionForPosition:position duration:_duration];
|
||||
}
|
||||
|
||||
- (CGPoint)_scrubberPositionForPosition:(NSTimeInterval)position duration:(NSTimeInterval)duration
|
||||
{
|
||||
return [self _scrubberPositionForPosition:position duration:duration zoomedIn:_zoomedIn];
|
||||
|
@ -374,15 +374,24 @@ const CGFloat TGPhotoAvatarCropButtonsWrapperSize = 61.0f;
|
||||
[self.view addSubview:snapshotView];
|
||||
|
||||
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:^
|
||||
{
|
||||
snapshotView.frame = targetFrame;
|
||||
snapshotView.alpha = 1.0f;
|
||||
if (self.item.isVideo) {
|
||||
_cropView.alpha = 0.0f;
|
||||
} else {
|
||||
snapshotView.alpha = 1.0f;
|
||||
}
|
||||
_cropView.frame = targetCropViewFrame;
|
||||
[_cropView invalidateCropRect];
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
_previewView.hidden = false;
|
||||
if (self.finishedTransitionOut != nil)
|
||||
self.finishedTransitionOut();
|
||||
}];
|
||||
|
@ -7,10 +7,9 @@
|
||||
|
||||
@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)endScrubbing:(bool (^)(void))completion;
|
||||
- (void)setPlayButtonHidden:(bool)hidden animated:(bool)animated;
|
||||
- (void)beginScrubbing:(bool)flash;
|
||||
- (void)endScrubbing:(bool)flash completion:(bool (^)(void))completion;
|
||||
|
||||
@end
|
||||
|
@ -26,6 +26,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
TGPhotoEditorSparseView *_wrapperView;
|
||||
TGMediaPickerGalleryVideoScrubber *_scrubberView;
|
||||
|
||||
UIImageView *_dotImageView;
|
||||
|
||||
UIView *_portraitToolsWrapperView;
|
||||
UIView *_landscapeToolsWrapperView;
|
||||
UIView *_portraitWrapperBackgroundView;
|
||||
@ -35,8 +38,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
UIView *_flashView;
|
||||
UIView *_portraitToolControlView;
|
||||
UIView *_landscapeToolControlView;
|
||||
UIImageView *_areaMaskView;
|
||||
CGFloat _currentDiameter;
|
||||
UILabel *_coverLabel;
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
@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];
|
||||
if (self != nil)
|
||||
@ -55,6 +56,8 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
self.photoEditor = photoEditor;
|
||||
self.previewView = previewView;
|
||||
_scrubberView = scrubberView;
|
||||
|
||||
_dotImageView = dotImageView;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -92,28 +95,26 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
_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];
|
||||
_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
|
||||
@ -232,7 +233,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
_portraitToolsWrapperView.alpha = 0.0f;
|
||||
_landscapeToolsWrapperView.alpha = 0.0f;
|
||||
_videoAreaView.alpha = 0.0f;
|
||||
_areaMaskView.alpha = 0.0f;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
if (completion != nil)
|
||||
@ -320,7 +320,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
_portraitToolsWrapperView.alpha = 0.0f;
|
||||
_landscapeToolsWrapperView.alpha = 0.0f;
|
||||
_videoAreaView.alpha = 0.0f;
|
||||
_areaMaskView.alpha = 0.0f;
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
@ -400,12 +399,10 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
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);
|
||||
|
||||
CGFloat panelSize = UIInterfaceOrientationIsPortrait(orientation) ? TGPhotoAvatarPreviewPanelSize : TGPhotoAvatarPreviewLandscapePanelSize;
|
||||
// if (_portraitToolControlView != nil)
|
||||
// panelSize = TGPhotoEditorPanelSize;
|
||||
|
||||
CGFloat panelToolbarPortraitSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
CGFloat panelToolbarLandscapeSize = panelSize + TGPhotoEditorToolbarSize;
|
||||
@ -497,36 +494,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
{
|
||||
_videoAreaView.frame = _previewView.frame;
|
||||
_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
|
||||
{
|
||||
if ([self inFormSheet] || TGIsPad())
|
||||
@ -540,7 +510,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
|
||||
- (TGPhotoEditorTab)availableTabs
|
||||
{
|
||||
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
||||
return TGPhotoEditorRotateTab | TGPhotoEditorMirrorTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
|
||||
}
|
||||
|
||||
- (TGPhotoEditorTab)activeTab
|
||||
@ -561,58 +531,74 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
|
||||
return tabs;
|
||||
}
|
||||
|
||||
- (void)setPlayButtonHidden:(bool)hidden animated:(bool)animated
|
||||
- (void)handleTabAction:(TGPhotoEditorTab)tab
|
||||
{
|
||||
// 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;
|
||||
// }
|
||||
switch (tab)
|
||||
{
|
||||
case TGPhotoEditorRotateTab:
|
||||
{
|
||||
[self rotate];
|
||||
}
|
||||
break;
|
||||
|
||||
case TGPhotoEditorMirrorTab:
|
||||
{
|
||||
[self mirror];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beginScrubbing
|
||||
{
|
||||
_coverLabel.alpha = 1.0f;
|
||||
|
||||
[self setPlayButtonHidden:true animated:false];
|
||||
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
_areaMaskView.alpha = 1.0f;
|
||||
}];
|
||||
#pragma mark - Cropping
|
||||
|
||||
- (void)rotate {
|
||||
// [_cropView rotate90DegreesCCWAnimated:true];
|
||||
}
|
||||
|
||||
- (void)endScrubbing:(bool (^)(void))completion
|
||||
- (void)mirror {
|
||||
// [_cropView mirror];
|
||||
}
|
||||
|
||||
- (void)beginScrubbing:(bool)flash
|
||||
{
|
||||
[UIView animateWithDuration:0.12 animations:^{
|
||||
_flashView.alpha = 1.0f;
|
||||
} completion:^(BOOL finished) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
_flashView.alpha = 0.0f;
|
||||
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) {
|
||||
TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{
|
||||
if (completion()) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
_areaMaskView.alpha = 0.0f;
|
||||
_coverLabel.alpha = 0.7f;
|
||||
}];
|
||||
|
||||
self.controlVideoPlayback(true);
|
||||
}
|
||||
});
|
||||
[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);
|
||||
}
|
||||
});
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
} else {
|
||||
TGDispatchAfter(1.32, dispatch_get_main_queue(), ^{
|
||||
if (completion()) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
_coverLabel.alpha = 0.7f;
|
||||
}];
|
||||
|
||||
self.controlVideoPlayback(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -75,10 +75,13 @@
|
||||
|
||||
CMTime _chaseTime;
|
||||
bool _chasingTime;
|
||||
bool _isPlaying;
|
||||
AVPlayerItem *_playerItem;
|
||||
SMetaDisposable *_playerItemDisposable;
|
||||
id _playerStartedObserver;
|
||||
id _playerReachedEndObserver;
|
||||
bool _registeredKeypathObserver;
|
||||
NSTimer *_positionTimer;
|
||||
bool _scheduledVideoPlayback;
|
||||
|
||||
id<TGMediaEditAdjustments> _initialAdjustments;
|
||||
@ -94,15 +97,22 @@
|
||||
TGMenuContainerView *_menuContainerView;
|
||||
UIDocumentInteractionController *_documentController;
|
||||
|
||||
bool _dismissed;
|
||||
|
||||
bool _hadProgress;
|
||||
bool _progressVisible;
|
||||
TGMessageImageViewOverlayView *_progressView;
|
||||
|
||||
SMetaDisposable *_faceDetectorDisposable;
|
||||
|
||||
bool _wasPlaying;
|
||||
bool _initializedScrubber;
|
||||
TGMediaPickerGalleryVideoScrubber *_scrubberView;
|
||||
PGPhotoEditorView *_dotVideoView;
|
||||
|
||||
NSTimeInterval _dotPosition;
|
||||
UIImageView *_dotMarkerView;
|
||||
UIImageView *_dotImageView;
|
||||
UIView *_dotImageSnapshotView;
|
||||
|
||||
bool _requestingThumbnails;
|
||||
SMetaDisposable *_thumbnailsDisposable;
|
||||
@ -166,7 +176,6 @@
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stopVideoPlayback:true];
|
||||
[_actionHandle reset];
|
||||
[_faceDetectorDisposable dispose];
|
||||
[_thumbnailsDisposable dispose];
|
||||
@ -308,10 +317,22 @@
|
||||
[_photoEditor setPreviewOutput:_previewView];
|
||||
[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) {
|
||||
_scrubberView = [[TGMediaPickerGalleryVideoScrubber alloc] initWithFrame:CGRectMake(0.0f, 0.0, _portraitToolbarView.frame.size.width, 68.0f)];
|
||||
_scrubberView.dataSource = self;
|
||||
_scrubberView.delegate = self;
|
||||
_scrubberView.clipsToBounds = false;
|
||||
}
|
||||
|
||||
[self detectFaces];
|
||||
@ -319,6 +340,28 @@
|
||||
[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
|
||||
{
|
||||
if (self.requestToolbarsHidden == nil)
|
||||
@ -383,7 +426,6 @@
|
||||
|
||||
if (self.item.isVideo) {
|
||||
_scrubberView.allowsTrimming = self.item.originalDuration >= TGVideoEditMinimumTrimmableDuration;
|
||||
_scrubberView.hasDotPicker = true;
|
||||
_scrubberView.disableZoom = true;
|
||||
_scrubberView.disableTimeDisplay = true;
|
||||
_scrubberView.trimStartValue = 0.0;
|
||||
@ -423,36 +465,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
__weak TGPhotoEditorController *weakSelf = self;
|
||||
PGPhotoEditor *photoEditor = _photoEditor;
|
||||
|
||||
[signal startWithNext:^(id next)
|
||||
{
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf->_dismissed)
|
||||
return;
|
||||
|
||||
CGFloat progress = 0.0;
|
||||
bool progressVisible = false;
|
||||
bool doneEnabled = true;
|
||||
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) {
|
||||
progress = 1.0f;
|
||||
}
|
||||
} else if ([next isKindOfClass:[AVAsset class]]) {
|
||||
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
|
||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||
_player.muted = true;
|
||||
strongSelf->_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
|
||||
strongSelf->_player = [AVPlayer playerWithPlayerItem:strongSelf->_playerItem];
|
||||
strongSelf->_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||
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(^
|
||||
{
|
||||
if ([_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]])
|
||||
[(TGPhotoAvatarCropController *)_currentTabController setPlayer:_player];
|
||||
if ([strongSelf->_currentTabController isKindOfClass:[TGPhotoAvatarCropController class]])
|
||||
[(TGPhotoAvatarCropController *)strongSelf->_currentTabController setPlayer:strongSelf->_player];
|
||||
|
||||
[_previewView performTransitionInWithCompletion:^
|
||||
[strongSelf->_previewView performTransitionInWithCompletion:^
|
||||
{
|
||||
}];
|
||||
|
||||
if (_scheduledVideoPlayback) {
|
||||
_scheduledVideoPlayback = false;
|
||||
[self startVideoPlayback:true];
|
||||
if (strongSelf->_scheduledVideoPlayback) {
|
||||
strongSelf->_scheduledVideoPlayback = false;
|
||||
[strongSelf startVideoPlayback:true];
|
||||
}
|
||||
});
|
||||
progress = 1.0f;
|
||||
@ -464,14 +516,16 @@
|
||||
}
|
||||
|
||||
TGDispatchOnMainThread(^{
|
||||
if (progressVisible)
|
||||
_hadProgress = true;
|
||||
[self setProgressVisible:progressVisible value:progress animated:true];
|
||||
[self updateDoneButtonEnabled:doneEnabled animated:true];
|
||||
if (strongSelf->_dismissed)
|
||||
return;
|
||||
|
||||
if (_hadProgress) {
|
||||
[_scrubberView reloadThumbnails];
|
||||
[self updateDotImage];
|
||||
if (progressVisible)
|
||||
strongSelf->_hadProgress = true;
|
||||
[strongSelf setProgressVisible:progressVisible value:progress animated:true];
|
||||
[strongSelf updateDoneButtonEnabled:doneEnabled animated:true];
|
||||
|
||||
if (strongSelf->_hadProgress) {
|
||||
[strongSelf->_scrubberView reloadThumbnails];
|
||||
}
|
||||
});
|
||||
|
||||
@ -479,25 +533,29 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ignoreDefaultPreviewViewTransitionIn)
|
||||
if (strongSelf->_ignoreDefaultPreviewViewTransitionIn)
|
||||
{
|
||||
TGDispatchOnMainThread(^
|
||||
{
|
||||
if ([_currentTabController isKindOfClass:[TGPhotoQualityController class]])
|
||||
[_previewView setSnapshotImageOnTransition:next];
|
||||
if (strongSelf->_dismissed)
|
||||
return;
|
||||
if ([strongSelf->_currentTabController isKindOfClass:[TGPhotoQualityController class]])
|
||||
[strongSelf->_previewView setSnapshotImageOnTransition:next];
|
||||
else
|
||||
[_previewView setSnapshotImage:next];
|
||||
[strongSelf->_previewView setSnapshotImage:next];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
[_photoEditor processAnimated:false completion:^
|
||||
[photoEditor processAnimated:false completion:^
|
||||
{
|
||||
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:^
|
||||
{
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil) {
|
||||
if (strongSelf != nil && !strongSelf->_dismissed) {
|
||||
[strongSelf->_player seekToTime:startTime];
|
||||
[strongSelf->_scrubberView setValue:strongSelf->_photoEditor.trimEndValue resetPosition:true];
|
||||
}
|
||||
}];
|
||||
}
|
||||
@ -565,9 +624,19 @@
|
||||
[_player.currentItem seekToTime:targetTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
|
||||
|
||||
[self _setupPlaybackStartedObserver];
|
||||
|
||||
if (!_registeredKeypathObserver) {
|
||||
[_player addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
|
||||
_registeredKeypathObserver = true;
|
||||
}
|
||||
}
|
||||
|
||||
_isPlaying = true;
|
||||
[_player play];
|
||||
|
||||
[_positionTimer invalidate];
|
||||
_positionTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(positionTimerEvent) interval:0.25 repeat:true];
|
||||
[self positionTimerEvent];
|
||||
}
|
||||
|
||||
- (void)stopVideoPlayback:(bool)reset {
|
||||
@ -576,8 +645,35 @@
|
||||
[_player removeTimeObserver:_playerStartedObserver];
|
||||
if (_playerReachedEndObserver != nil)
|
||||
[_player removeTimeObserver:_playerReachedEndObserver];
|
||||
|
||||
if (_registeredKeypathObserver) {
|
||||
[_player removeObserver:self forKeyPath:@"rate" context:nil];
|
||||
_registeredKeypathObserver = false;
|
||||
}
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
[_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 {
|
||||
@ -730,10 +826,11 @@
|
||||
|
||||
- (void)createEditedImageWithEditorValues:(id<TGMediaEditAdjustments>)editorValues createThumbnail:(bool)createThumbnail saveOnly:(bool)saveOnly completion:(void (^)(UIImage *))completion
|
||||
{
|
||||
bool avatar = [self presentedForAvatarCreation];
|
||||
|
||||
if (!saveOnly)
|
||||
{
|
||||
bool forAvatar = [self presentedForAvatarCreation];
|
||||
if (!forAvatar && [editorValues isDefaultValuesForAvatar:false])
|
||||
if (!avatar && [editorValues isDefaultValuesForAvatar:false])
|
||||
{
|
||||
if (self.willFinishEditing != nil)
|
||||
self.willFinishEditing(nil, [_currentTabController currentResultRepresentation], true);
|
||||
@ -751,7 +848,7 @@
|
||||
if (!saveOnly && self.willFinishEditing != nil)
|
||||
self.willFinishEditing(editorValues, [_currentTabController currentResultRepresentation], true);
|
||||
|
||||
if (!saveOnly && completion != nil)
|
||||
if (!saveOnly && !avatar && completion != nil)
|
||||
completion(nil);
|
||||
|
||||
UIImage *fullSizeImage = self.fullSizeImage;
|
||||
@ -832,19 +929,22 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
void (^didFinishRenderingFullSizeImage)(UIImage *) = self.didFinishRenderingFullSizeImage;
|
||||
void (^didFinishEditing)(id<TGMediaEditAdjustments>, UIImage *, UIImage *, bool ) = self.didFinishEditing;
|
||||
|
||||
[[[[renderedImageSignal map:^id(UIImage *image)
|
||||
{
|
||||
if (!hasImageAdjustments)
|
||||
{
|
||||
if (hasPainting && !hasAnimation && self.didFinishRenderingFullSizeImage != nil)
|
||||
self.didFinishRenderingFullSizeImage(image);
|
||||
if (hasPainting && !hasAnimation && didFinishRenderingFullSizeImage != nil)
|
||||
didFinishRenderingFullSizeImage(image);
|
||||
|
||||
return image;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!saveOnly && !hasAnimation && self.didFinishRenderingFullSizeImage != nil)
|
||||
self.didFinishRenderingFullSizeImage(image);
|
||||
if (!saveOnly && !hasAnimation && didFinishRenderingFullSizeImage != nil)
|
||||
didFinishRenderingFullSizeImage(image);
|
||||
|
||||
return TGPhotoEditorFitImage(image, TGPhotoEditorResultImageMaxSize);
|
||||
}
|
||||
@ -881,8 +981,11 @@
|
||||
UIImage *image = result[@"image"];
|
||||
UIImage *thumbnailImage = result[@"thumbnail"];
|
||||
|
||||
if (!saveOnly && self.didFinishEditing != nil)
|
||||
self.didFinishEditing(editorValues, image, thumbnailImage, true);
|
||||
if (avatar && completion != nil)
|
||||
completion(image);
|
||||
|
||||
if (!saveOnly && didFinishEditing != nil)
|
||||
didFinishEditing(editorValues, image, thumbnailImage, true);
|
||||
} error:^(__unused id error)
|
||||
{
|
||||
TGLegacyLog(@"renderedImageSignal error");
|
||||
@ -923,6 +1026,11 @@
|
||||
|
||||
- (void)transitionOutSaving:(bool)saving completion:(void (^)(void))completion
|
||||
{
|
||||
_dismissed = true;
|
||||
if (!saving) {
|
||||
[self stopVideoPlayback:true];
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
_portraitToolbarView.alpha = 0.0f;
|
||||
@ -932,7 +1040,7 @@
|
||||
_currentTabController.beginTransitionOut = self.beginTransitionOut;
|
||||
[self setToolbarHidden:false animated:true];
|
||||
|
||||
if (self.beginCustomTransitionOut != nil)
|
||||
if (self.beginCustomTransitionOut != nil && !saving)
|
||||
{
|
||||
id rep = [_currentTabController currentResultRepresentation];
|
||||
if ([rep isKindOfClass:[UIImage class]])
|
||||
@ -1373,10 +1481,10 @@
|
||||
{
|
||||
if ([_currentTabController isKindOfClass:[TGPhotoToolsController class]]) {
|
||||
[_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.toolbarLandscapeSize = TGPhotoEditorToolbarSize;
|
||||
previewController.beginTransitionIn = ^UIView *(CGRect *referenceFrame, UIView **parentView, bool *noTransitionView)
|
||||
@ -1386,8 +1494,16 @@
|
||||
*noTransitionView = transitionNoTransitionView;
|
||||
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
[strongSelf startVideoPlayback:true];
|
||||
if (strongSelf != nil) {
|
||||
if ([currentController isKindOfClass:[TGPhotoAvatarCropController class]]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[strongSelf stopVideoPlayback:false];
|
||||
[strongSelf seekVideo:0];
|
||||
});
|
||||
} else {
|
||||
[strongSelf startVideoPlayback:true];
|
||||
}
|
||||
}
|
||||
|
||||
return transitionReferenceView;
|
||||
};
|
||||
@ -1400,6 +1516,10 @@
|
||||
if (isInitialAppearance && strongSelf.finishedTransitionIn != nil)
|
||||
strongSelf.finishedTransitionIn();
|
||||
|
||||
if ([currentController isKindOfClass:[TGPhotoAvatarCropController class]]) {
|
||||
[strongSelf startVideoPlayback:false];
|
||||
}
|
||||
|
||||
strongSelf->_switchingTab = false;
|
||||
};
|
||||
previewController.controlVideoPlayback = ^(bool play) {
|
||||
@ -1522,8 +1642,13 @@
|
||||
|
||||
- (void)dismissAnimated:(bool)animated
|
||||
{
|
||||
_dismissed = true;
|
||||
|
||||
self.view.userInteractionEnabled = false;
|
||||
|
||||
if (self.navigationController != nil)
|
||||
animated = false;
|
||||
|
||||
if (animated)
|
||||
{
|
||||
const CGFloat velocity = 2000.0f;
|
||||
@ -1535,12 +1660,20 @@
|
||||
self.view.frame = targetFrame;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
[self dismiss];
|
||||
if (self.navigationController != nil) {
|
||||
[self.navigationController popViewControllerAnimated:false];
|
||||
} else {
|
||||
[self dismiss];
|
||||
}
|
||||
}];
|
||||
}
|
||||
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"];
|
||||
} else if ([_currentTabController isKindOfClass:[TGPhotoAvatarPreviewController class]])
|
||||
{
|
||||
videoStartValue = _scrubberView.value;
|
||||
videoStartValue = _dotPosition;
|
||||
trimStartValue = _scrubberView.trimStartValue;
|
||||
trimEndValue = _scrubberView.trimEndValue;
|
||||
}
|
||||
|
||||
[self stopVideoPlayback:true];
|
||||
|
||||
TGVideoEditAdjustments *adjustments = [_photoEditor exportAdjustmentsWithPaintingData:paintingData];
|
||||
if ([self presentedForAvatarCreation] && _item.isVideo) {
|
||||
[[SQueue concurrentDefaultQueue] dispatch:^
|
||||
@ -1745,10 +1880,7 @@
|
||||
if (self.didFinishEditingVideo != nil)
|
||||
self.didFinishEditingVideo(asset.URL, [adjustments editAdjustmentsWithPreset:TGMediaVideoConversionPresetProfile videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true);
|
||||
|
||||
[self transitionOutSaving:true completion:^
|
||||
{
|
||||
[self dismiss];
|
||||
}];
|
||||
[self dismissAnimated:true];
|
||||
});
|
||||
}];
|
||||
}];
|
||||
@ -1766,9 +1898,10 @@
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:progressWindow selector:@selector(showAnimated) object:nil];
|
||||
[progressWindow dismiss:true];
|
||||
|
||||
if (forAvatar)
|
||||
if (forAvatar) {
|
||||
[self dismissAnimated:true];
|
||||
return;
|
||||
|
||||
}
|
||||
[self transitionOutSaving:true completion:^
|
||||
{
|
||||
[self dismiss];
|
||||
@ -1856,10 +1989,14 @@
|
||||
if (self.didFinishEditing != nil)
|
||||
self.didFinishEditing(hasChanges ? adjustments : nil, nil, nil, hasChanges);
|
||||
|
||||
[self transitionOutSaving:saving completion:^
|
||||
{
|
||||
[self dismiss];
|
||||
}];
|
||||
if ([self presentedForAvatarCreation]) {
|
||||
[self dismissAnimated:true];
|
||||
} else {
|
||||
[self transitionOutSaving:saving completion:^
|
||||
{
|
||||
[self dismiss];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2040,6 +2177,12 @@
|
||||
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
|
||||
{
|
||||
orientation = [self effectiveOrientation:orientation];
|
||||
@ -2098,8 +2241,6 @@
|
||||
_initializedScrubber = true;
|
||||
[_scrubberView reloadData];
|
||||
[_scrubberView resetToStart];
|
||||
|
||||
[self updateDotImage];
|
||||
} else {
|
||||
[_scrubberView reloadThumbnails];
|
||||
}
|
||||
@ -2240,6 +2381,27 @@
|
||||
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 Scrubbing
|
||||
@ -2264,24 +2426,17 @@
|
||||
- (void)videoScrubberDidBeginScrubbing:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber
|
||||
{
|
||||
[self stopVideoPlayback:false];
|
||||
|
||||
if (_dotVideoView == nil) {
|
||||
_dotVideoView = [[PGPhotoEditorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 26.0, 44.0)];
|
||||
[_scrubberView setDotVideoView:_dotVideoView];
|
||||
|
||||
_photoEditor.additionalOutputs = @[_dotVideoView];
|
||||
} else {
|
||||
_dotVideoView.hidden = false;
|
||||
}
|
||||
|
||||
[self setPlayButtonHidden:true animated:false];
|
||||
|
||||
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
|
||||
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
|
||||
return;
|
||||
|
||||
[previewController beginScrubbing];
|
||||
[previewController beginScrubbing:true];
|
||||
}
|
||||
|
||||
- (void)updateDotImage {
|
||||
- (void)updateDotImage:(bool)animated {
|
||||
AVPlayer *player = _player;
|
||||
if (player == nil) {
|
||||
return;
|
||||
@ -2290,9 +2445,10 @@
|
||||
[[SQueue concurrentDefaultQueue] dispatch:^{
|
||||
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:player.currentItem.asset];
|
||||
generator.appliesPreferredTrackTransform = true;
|
||||
generator.maximumSize = CGSizeMake(128.0f, 128.0f);
|
||||
generator.maximumSize = CGSizeMake(160.0f, 160.0f);
|
||||
generator.requestedTimeToleranceAfter = kCMTimeZero;
|
||||
generator.requestedTimeToleranceBefore = kCMTimeZero;
|
||||
|
||||
CGImageRef imageRef = [generator copyCGImageAtTime:player.currentItem.currentTime actualTime:NULL error:NULL];
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CGImageRelease(imageRef);
|
||||
@ -2304,21 +2460,102 @@
|
||||
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(^{
|
||||
[_scrubberView setDotImage:image];
|
||||
_dotVideoView.hidden = true;
|
||||
if (animated) {
|
||||
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;
|
||||
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
|
||||
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
|
||||
return;
|
||||
|
||||
[previewController endScrubbing:^bool{
|
||||
_dotPosition = videoScrubber.value;
|
||||
|
||||
[previewController endScrubbing:true completion:^bool{
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return false;
|
||||
@ -2327,7 +2564,7 @@
|
||||
}];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateDotImage];
|
||||
[self updateDotImage:true];
|
||||
});
|
||||
}
|
||||
|
||||
@ -2352,11 +2589,7 @@
|
||||
{
|
||||
[self stopVideoPlayback:false];
|
||||
|
||||
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
|
||||
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
|
||||
return;
|
||||
|
||||
[previewController setPlayButtonHidden:true animated:false];
|
||||
[self setPlayButtonHidden:true animated:false];
|
||||
}
|
||||
|
||||
- (void)videoScrubberDidEndEditing:(TGMediaPickerGalleryVideoScrubber *)videoScrubber
|
||||
@ -2366,11 +2599,7 @@
|
||||
[self seekVideo:videoScrubber.trimStartValue];
|
||||
[self stopVideoPlayback:false];
|
||||
|
||||
TGPhotoAvatarPreviewController *previewController = (TGPhotoAvatarPreviewController *)_currentTabController;
|
||||
if (![previewController isKindOfClass:[TGPhotoAvatarPreviewController class]])
|
||||
return;
|
||||
|
||||
[previewController setPlayButtonHidden:true animated:false];
|
||||
[self setPlayButtonHidden:true animated:false];
|
||||
}
|
||||
|
||||
- (void)videoScrubber:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber editingStartValueDidChange:(NSTimeInterval)startValue
|
||||
@ -2454,6 +2683,15 @@
|
||||
if (index < timestamps.count)
|
||||
[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:^
|
||||
{
|
||||
__strong TGPhotoEditorController *strongSelf = weakSelf;
|
||||
|
@ -113,8 +113,8 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<
|
||||
var index: Int32 = 0
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first, photo.image.videoRepresentations.isEmpty {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, first.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
|
||||
} 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))
|
||||
}
|
||||
@ -140,8 +140,8 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry
|
||||
var index: Int32 = 0
|
||||
for photo in photos {
|
||||
let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count))
|
||||
if result.isEmpty, let first = initialEntries.first, photo.image.videoRepresentations.isEmpty {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, first.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
|
||||
if result.isEmpty, let first = initialEntries.first {
|
||||
result.append(.image(photo.image.imageId, photo.image.reference, first.representations, photo.image.videoRepresentations, peer, photo.date, indexData, photo.messageId, photo.image.immediateThumbnailData))
|
||||
} 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))
|
||||
}
|
||||
|
@ -1415,7 +1415,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
if let profileImage = peer?.smallProfileImage {
|
||||
state.updatingAvatar = .image(profileImage, false)
|
||||
} else {
|
||||
state.updatingAvatar = .none
|
||||
state.updatingAvatar = ItemListAvatarAndNameInfoItemUpdatingAvatar.none
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
@ -1121,7 +1121,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
if file.isAnimated {
|
||||
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(gifTitle)", size: nil, muted: false, active: false)
|
||||
} 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) {
|
||||
|
@ -236,7 +236,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
if let video = videoRepresentations.last, let id = id {
|
||||
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 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)
|
||||
videoNode.isUserInteractionEnabled = false
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] owns in
|
||||
@ -626,7 +626,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
strongSelf.items = items
|
||||
strongSelf.itemsUpdated?(items)
|
||||
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 !strongSelf.didSetReady {
|
||||
@ -762,7 +762,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
let context: AccountContext
|
||||
let avatarNode: AvatarNode
|
||||
|
||||
private var videoNode: UniversalVideoNode?
|
||||
fileprivate var videoNode: UniversalVideoNode?
|
||||
private var videoContent: NativeVideoContent?
|
||||
|
||||
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) {
|
||||
if let peer = peer {
|
||||
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 {
|
||||
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 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 {
|
||||
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)
|
||||
@ -835,9 +850,19 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
||||
videoNode.frame = self.avatarNode.frame
|
||||
|
||||
if isExpanded == videoNode.canAttachContent {
|
||||
videoNode.canAttachContent = !isExpanded
|
||||
if videoNode.canAttachContent {
|
||||
videoNode.play()
|
||||
let update = {
|
||||
videoNode.canAttachContent = !isExpanded
|
||||
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) {
|
||||
if let currentItemNode = self.listContainerNode.currentItemNode, let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage, case .animated = transition {
|
||||
let avatarCopyView = UIImageView()
|
||||
avatarCopyView.image = unroundedImage
|
||||
avatarCopyView.frame = self.avatarContainerNode.avatarNode.frame
|
||||
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()
|
||||
if let currentItemNode = self.listContainerNode.currentItemNode, case .animated = transition {
|
||||
if let videoNode = self.avatarContainerNode.videoNode {
|
||||
// videoNode.position = currentItemNode.imageNode.position
|
||||
// currentItemNode.addSubnode(videoNode)
|
||||
// let scale = currentItemNode.imageNode.bounds.height / videoNode.bounds.height
|
||||
// avatarCopyView.layer.transform = CATransform3DMakeScale(scale, scale, scale)
|
||||
// self.avatarContainerNode.reattachVideoNode()
|
||||
} else if let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage {
|
||||
let avatarCopyView = UIImageView()
|
||||
avatarCopyView.image = unroundedImage
|
||||
avatarCopyView.frame = self.avatarContainerNode.avatarNode.frame
|
||||
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()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -31,11 +31,12 @@ public final class NativeVideoContent: UniversalVideoContent {
|
||||
public let baseRate: Double
|
||||
let fetchAutomatically: Bool
|
||||
let onlyFullSizeThumbnail: Bool
|
||||
let autoFetchFullSizeThumbnail: Bool
|
||||
let continuePlayingWithoutSoundOnLostAudioSession: Bool
|
||||
let placeholderColor: UIColor
|
||||
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.nativeId = id
|
||||
self.fileReference = fileReference
|
||||
@ -60,13 +61,14 @@ public final class NativeVideoContent: UniversalVideoContent {
|
||||
self.baseRate = baseRate
|
||||
self.fetchAutomatically = fetchAutomatically
|
||||
self.onlyFullSizeThumbnail = onlyFullSizeThumbnail
|
||||
self.autoFetchFullSizeThumbnail = autoFetchFullSizeThumbnail
|
||||
self.continuePlayingWithoutSoundOnLostAudioSession = continuePlayingWithoutSoundOnLostAudioSession
|
||||
self.placeholderColor = placeholderColor
|
||||
self.tempFilePath = tempFilePath
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -126,7 +128,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
|
||||
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.fileReference = fileReference
|
||||
self.placeholderColor = placeholderColor
|
||||
@ -163,7 +165,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
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 {
|
||||
if let strongSelf = self, strongSelf.dimensions == nil {
|
||||
if let dimensions = getSize() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user