Avatar fixes

This commit is contained in:
Ilya Laktyushin 2022-12-17 20:24:26 +04:00
parent 2d25f92cbe
commit fe904af993
31 changed files with 303 additions and 115 deletions

View File

@ -8512,7 +8512,7 @@ Sorry for the inconvenience.";
"Common.Paste" = "Paste"; "Common.Paste" = "Paste";
"PhotoEditor.SelectCoverFrameSuggestion" = "Choose a cover for profile video"; "PhotoEditor.SelectCoverFrameSuggestion" = "Choose a cover for this video";
"GroupInfo.TitleMembers_1" = "%@ Member"; "GroupInfo.TitleMembers_1" = "%@ Member";
"GroupInfo.TitleMembers_any" = "%@ Members"; "GroupInfo.TitleMembers_any" = "%@ Members";

View File

@ -608,9 +608,7 @@ private struct Line {
} }
final class Texture { final class Texture {
#if !targetEnvironment(simulator)
let buffer: MTLBuffer? let buffer: MTLBuffer?
#endif
let width: Int let width: Int
let height: Int let height: Int
@ -628,6 +626,7 @@ final class Texture {
if #available(iOS 12.0, *) { if #available(iOS 12.0, *) {
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
self.buffer = nil
let textureDescriptor = MTLTextureDescriptor() let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.textureType = .type2D textureDescriptor.textureType = .type2D
textureDescriptor.pixelFormat = .bgra8Unorm textureDescriptor.pixelFormat = .bgra8Unorm

View File

@ -409,13 +409,6 @@ final class PenTool: DrawingElement {
let r = min(limitRange, length) let r = min(limitRange, length)
// var r = limitRange - length
// if r < 0 {
// r = 0
// }
// print(r * lowerer)
return (r * lowerer) + constant return (r * lowerer) + constant
} }

View File

@ -978,6 +978,7 @@ public class StickerPickerScreen: ViewController {
var dismissing = false var dismissing = false
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0) { if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0) {
self.controller?.completion(nil)
self.controller?.dismiss(animated: true, completion: nil) self.controller?.dismiss(animated: true, completion: nil)
dismissing = true dismissing = true
} else if self.isExpanded { } else if self.isExpanded {

View File

@ -22,6 +22,7 @@ public class MediaDustNode: ASDisplayNode {
private var isExploding = false private var isExploding = false
public var revealed: () -> Void = {} public var revealed: () -> Void = {}
public var tapped: () -> Void = {}
public override init() { public override init() {
self.emitterNode = ASDisplayNode() self.emitterNode = ASDisplayNode()
@ -120,6 +121,8 @@ public class MediaDustNode: ASDisplayNode {
return return
} }
self.tapped()
self.isRevealed = true self.isRevealed = true
self.isExploding = true self.isExploding = true
@ -256,7 +259,6 @@ public class MediaDustNode: ASDisplayNode {
} }
} }
public func update(size: CGSize, color: UIColor, transition: ContainedViewLayoutTransition) { public func update(size: CGSize, color: UIColor, transition: ContainedViewLayoutTransition) {
self.currentParams = (size, color) self.currentParams = (size, color)

View File

@ -34,6 +34,7 @@
@property (nonatomic) bool hasSchedule; @property (nonatomic) bool hasSchedule;
@property (nonatomic) bool reminder; @property (nonatomic) bool reminder;
@property (nonatomic) bool forum; @property (nonatomic) bool forum;
@property (nonatomic) bool isSuggesting;
@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); @property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t));
@property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t));

View File

@ -64,6 +64,10 @@ typedef enum
@property (nonatomic, assign) bool hasSilentPosting; @property (nonatomic, assign) bool hasSilentPosting;
@property (nonatomic, assign) bool hasSchedule; @property (nonatomic, assign) bool hasSchedule;
@property (nonatomic, assign) bool reminder; @property (nonatomic, assign) bool reminder;
@property (nonatomic, assign) bool forum;
@property (nonatomic, assign) bool isSuggesting;
@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); @property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t));
@property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t));

View File

@ -30,7 +30,7 @@ typedef void (^TGMediaAvatarPresentImpl)(id<LegacyComponentsContext>, void (^)(U
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia; - (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia; - (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title; - (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title isSuggesting:(bool)isSuggesting;
- (TGMenuSheetController *)present; - (TGMenuSheetController *)present;
@end @end

View File

@ -30,6 +30,10 @@
@property (nonatomic, assign) bool hasSilentPosting; @property (nonatomic, assign) bool hasSilentPosting;
@property (nonatomic, assign) bool hasSchedule; @property (nonatomic, assign) bool hasSchedule;
@property (nonatomic, assign) bool reminder; @property (nonatomic, assign) bool reminder;
@property (nonatomic, assign) bool forum;
@property (nonatomic, assign) bool isSuggesting;
@property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t)); @property (nonatomic, copy) void (^presentScheduleController)(bool, void (^)(int32_t));
@property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t)); @property (nonatomic, copy) void (^presentTimerController)(void (^)(int32_t));

View File

@ -22,7 +22,8 @@ typedef enum {
TGPhotoEditorControllerWebIntent = (1 << 3), TGPhotoEditorControllerWebIntent = (1 << 3),
TGPhotoEditorControllerVideoIntent = (1 << 4), TGPhotoEditorControllerVideoIntent = (1 << 4),
TGPhotoEditorControllerForumAvatarIntent = (1 << 5), TGPhotoEditorControllerForumAvatarIntent = (1 << 5),
TGPhotoEditorControllerSuggestedAvatarIntent = (1 << 6) TGPhotoEditorControllerSuggestedAvatarIntent = (1 << 6),
TGPhotoEditorControllerSuggestingAvatarIntent = (1 << 7)
} TGPhotoEditorControllerIntent; } TGPhotoEditorControllerIntent;
@interface TGPhotoEditorController : TGOverlayController @interface TGPhotoEditorController : TGOverlayController

View File

@ -915,6 +915,9 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if (_forum) { if (_forum) {
intent |= TGPhotoEditorControllerForumAvatarIntent; intent |= TGPhotoEditorControllerForumAvatarIntent;
} }
if (_isSuggesting) {
intent |= TGPhotoEditorControllerSuggestingAvatarIntent;
}
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:editableItem intent:intent adjustments:nil caption:nil screenImage:thumbnailImage availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab]; TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithContext:[windowManager context] item:editableItem intent:intent adjustments:nil caption:nil screenImage:thumbnailImage availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
controller.editingContext = _editingContext; controller.editingContext = _editingContext;

View File

@ -260,6 +260,8 @@
pickerController.hasSilentPosting = strongController.hasSilentPosting; pickerController.hasSilentPosting = strongController.hasSilentPosting;
pickerController.hasSchedule = strongController.hasSchedule; pickerController.hasSchedule = strongController.hasSchedule;
pickerController.reminder = strongController.reminder; pickerController.reminder = strongController.reminder;
pickerController.forum = strongController.forum;
pickerController.isSuggesting = strongController.isSuggesting;
pickerController.presentScheduleController = strongController.presentScheduleController; pickerController.presentScheduleController = strongController.presentScheduleController;
pickerController.presentTimerController = strongController.presentTimerController; pickerController.presentTimerController = strongController.presentTimerController;
[strongController pushViewController:pickerController animated:true]; [strongController pushViewController:pickerController animated:true];
@ -363,6 +365,16 @@
self.pickerController.reminder = reminder; self.pickerController.reminder = reminder;
} }
- (void)setForum:(bool)forum {
_forum = forum;
self.pickerController.forum = forum;
}
- (void)setIsSuggesting:(bool)isSuggesting {
_isSuggesting = isSuggesting;
self.pickerController.isSuggesting = isSuggesting;
}
- (void)setPresentScheduleController:(void (^)(bool, void (^)(int32_t)))presentScheduleController { - (void)setPresentScheduleController:(void (^)(bool, void (^)(int32_t)))presentScheduleController {
_presentScheduleController = [presentScheduleController copy]; _presentScheduleController = [presentScheduleController copy];
self.pickerController.presentScheduleController = presentScheduleController; self.pickerController.presentScheduleController = presentScheduleController;

View File

@ -435,6 +435,14 @@
intent = TGPhotoEditorControllerSignupAvatarIntent; intent = TGPhotoEditorControllerSignupAvatarIntent;
} }
if (self.forum) {
intent |= TGPhotoEditorControllerForumAvatarIntent;
}
if (self.isSuggesting) {
intent |= TGPhotoEditorControllerSuggestingAvatarIntent;
}
id<TGMediaEditableItem> editableItem = asset; id<TGMediaEditableItem> editableItem = asset;
if (asset.type == TGMediaAssetGifType) { if (asset.type == TGMediaAssetGifType) {
editableItem = [[TGCameraCapturedVideo alloc] initWithAsset:asset livePhoto:false]; editableItem = [[TGCameraCapturedVideo alloc] initWithAsset:asset livePhoto:false];

View File

@ -28,6 +28,7 @@
bool _isVideo; bool _isVideo;
bool _forum; bool _forum;
NSString *_title; NSString *_title;
bool _isSuggesting;
} }
@end @end
@ -40,10 +41,10 @@
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia - (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasDeleteButton:(bool)hasDeleteButton personalPhoto:(bool)personalPhoto saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia
{ {
return [self initWithContext:context parentController:parentController hasSearchButton:false hasDeleteButton:hasDeleteButton hasViewButton:false personalPhoto:personalPhoto isVideo:false saveEditedPhotos:saveEditedPhotos saveCapturedMedia:saveCapturedMedia signup:false forum:false title:nil]; return [self initWithContext:context parentController:parentController hasSearchButton:false hasDeleteButton:hasDeleteButton hasViewButton:false personalPhoto:personalPhoto isVideo:false saveEditedPhotos:saveEditedPhotos saveCapturedMedia:saveCapturedMedia signup:false forum:false title:nil isSuggesting:false];
} }
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title - (instancetype)initWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController hasSearchButton:(bool)hasSearchButton hasDeleteButton:(bool)hasDeleteButton hasViewButton:(bool)hasViewButton personalPhoto:(bool)personalPhoto isVideo:(bool)isVideo saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia signup:(bool)signup forum:(bool)forum title:(NSString *)title isSuggesting:(bool)isSuggesting
{ {
self = [super init]; self = [super init];
if (self != nil) if (self != nil)
@ -60,6 +61,7 @@
_signup = signup; _signup = signup;
_forum = forum; _forum = forum;
_title = title; _title = title;
_isSuggesting = isSuggesting;
} }
return self; return self;
} }
@ -99,6 +101,7 @@
} }
TGAttachmentCarouselItemView *carouselItem = [[TGAttachmentCarouselItemView alloc] initWithContext:_context camera:true selfPortrait:_personalPhoto forProfilePhoto:true assetType:_signup ? TGMediaAssetPhotoType : TGMediaAssetAnyType saveEditedPhotos:_saveEditedPhotos allowGrouping:false]; TGAttachmentCarouselItemView *carouselItem = [[TGAttachmentCarouselItemView alloc] initWithContext:_context camera:true selfPortrait:_personalPhoto forProfilePhoto:true assetType:_signup ? TGMediaAssetPhotoType : TGMediaAssetAnyType saveEditedPhotos:_saveEditedPhotos allowGrouping:false];
carouselItem.isSuggesting = _isSuggesting;
carouselItem.forum = _forum; carouselItem.forum = _forum;
carouselItem.stickersContext = _stickersContext; carouselItem.stickersContext = _stickersContext;
carouselItem.parentController = _parentController; carouselItem.parentController = _parentController;
@ -456,6 +459,8 @@
TGMediaAssetsController *controller = [TGMediaAssetsController controllerWithContext:context assetGroup:group intent:strongSelf->_signup ? TGMediaAssetsControllerSetSignupProfilePhotoIntent : TGMediaAssetsControllerSetProfilePhotoIntent recipientName:nil saveEditedPhotos:strongSelf->_saveEditedPhotos allowGrouping:false selectionLimit:10]; TGMediaAssetsController *controller = [TGMediaAssetsController controllerWithContext:context assetGroup:group intent:strongSelf->_signup ? TGMediaAssetsControllerSetSignupProfilePhotoIntent : TGMediaAssetsControllerSetProfilePhotoIntent recipientName:nil saveEditedPhotos:strongSelf->_saveEditedPhotos allowGrouping:false selectionLimit:10];
__weak TGMediaAssetsController *weakController = controller; __weak TGMediaAssetsController *weakController = controller;
controller.stickersContext = _stickersContext; controller.stickersContext = _stickersContext;
controller.forum = _forum;
controller.isSuggesting = _isSuggesting;
controller.avatarCompletionBlock = ^(UIImage *resultImage) controller.avatarCompletionBlock = ^(UIImage *resultImage)
{ {
__strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf;

View File

@ -27,7 +27,7 @@
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext; @property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView isForum:(bool)isForum isSuggestion:(bool)isSuggestion senderName:(NSString *)senderName; - (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView isForum:(bool)isForum isSuggestion:(bool)isSuggestion isSuggesting:(bool)isSuggesting senderName:(NSString *)senderName;
- (void)setImage:(UIImage *)image; - (void)setImage:(UIImage *)image;
- (void)setSnapshotImage:(UIImage *)snapshotImage; - (void)setSnapshotImage:(UIImage *)snapshotImage;

View File

@ -57,6 +57,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
bool _isForum; bool _isForum;
bool _isSuggestion; bool _isSuggestion;
bool _isSuggesting;
NSString *_senderName; NSString *_senderName;
} }
@ -67,7 +68,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
@implementation TGPhotoAvatarPreviewController @implementation TGPhotoAvatarPreviewController
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView isForum:(bool)isForum isSuggestion:(bool)isSuggestion senderName:(NSString *)senderName { - (instancetype)initWithContext:(id<LegacyComponentsContext>)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView isForum:(bool)isForum isSuggestion:(bool)isSuggestion isSuggesting:(bool)isSuggesting senderName:(NSString *)senderName {
self = [super initWithContext:context]; self = [super initWithContext:context];
if (self != nil) if (self != nil)
{ {
@ -75,6 +76,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
self.previewView = previewView; self.previewView = previewView;
_isForum = isForum; _isForum = isForum;
_isSuggestion = isSuggestion; _isSuggestion = isSuggestion;
_isSuggesting = isSuggesting;
_senderName = senderName; _senderName = senderName;
} }
return self; return self;
@ -184,7 +186,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_coverLabel.backgroundColor = [UIColor clearColor]; _coverLabel.backgroundColor = [UIColor clearColor];
_coverLabel.font = TGSystemFontOfSize(14.0f); _coverLabel.font = TGSystemFontOfSize(14.0f);
_coverLabel.textColor = [UIColor whiteColor]; _coverLabel.textColor = [UIColor whiteColor];
_coverLabel.text = _isSuggestion ? TGLocalized(@"PhotoEditor.SelectCoverFrameSuggestion") : TGLocalized(@"PhotoEditor.SelectCoverFrame"); _coverLabel.text = _isSuggesting ? TGLocalized(@"PhotoEditor.SelectCoverFrameSuggestion") : TGLocalized(@"PhotoEditor.SelectCoverFrame");
[_coverLabel sizeToFit]; [_coverLabel sizeToFit];
[_portraitToolsWrapperView addSubview:_coverLabel]; [_portraitToolsWrapperView addSubview:_coverLabel];
@ -207,7 +209,9 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_subtitleLabel.numberOfLines = 2; _subtitleLabel.numberOfLines = 2;
_subtitleLabel.textAlignment = NSTextAlignmentCenter; _subtitleLabel.textAlignment = NSTextAlignmentCenter;
_subtitleLabel.text = [NSString stringWithFormat:self.item.isVideo ? TGLocalized(@"Conversation.SuggestedVideoText") : TGLocalized(@"Conversation.SuggestedPhotoText"), _senderName]; _subtitleLabel.text = [NSString stringWithFormat:self.item.isVideo ? TGLocalized(@"Conversation.SuggestedVideoText") : TGLocalized(@"Conversation.SuggestedPhotoText"), _senderName];
if (!self.item.isVideo) {
[_wrapperView addSubview:_subtitleLabel]; [_wrapperView addSubview:_subtitleLabel];
}
if (!self.item.isVideo) { if (!self.item.isVideo) {
_cancelButton = [[TGModernButton alloc] init]; _cancelButton = [[TGModernButton alloc] init];
@ -215,7 +219,6 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_cancelButton.titleLabel.font = TGSystemFontOfSize(17.0); _cancelButton.titleLabel.font = TGSystemFontOfSize(17.0);
[_cancelButton sizeToFit]; [_cancelButton sizeToFit];
[_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside]; [_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[_wrapperView addSubview:_cancelButton];
if (_stickersContext != nil) { if (_stickersContext != nil) {
_doneButton = [_stickersContext solidRoundedButton:self.item.isVideo ? TGLocalized(@"PhotoEditor.SetAsMyVideo") : TGLocalized(@"PhotoEditor.SetAsMyPhoto") action:^{ _doneButton = [_stickersContext solidRoundedButton:self.item.isVideo ? TGLocalized(@"PhotoEditor.SetAsMyVideo") : TGLocalized(@"PhotoEditor.SetAsMyPhoto") action:^{
@ -887,7 +890,7 @@ const CGFloat TGPhotoAvatarPreviewLandscapePanelSize = TGPhotoAvatarPreviewPanel
_coverLabel.frame = CGRectMake(floor((_portraitToolsWrapperView.frame.size.width - _coverLabel.frame.size.width) / 2.0), CGRectGetMaxY(_scrubberView.frame) + 6.0, _coverLabel.frame.size.width, _coverLabel.frame.size.height); _coverLabel.frame = CGRectMake(floor((_portraitToolsWrapperView.frame.size.width - _coverLabel.frame.size.width) / 2.0), CGRectGetMaxY(_scrubberView.frame) + 6.0, _coverLabel.frame.size.width, _coverLabel.frame.size.height);
_titleLabel.frame = CGRectMake(screenEdges.left + floor((referenceSize.width - _titleLabel.frame.size.width) / 2.0), screenEdges.top + floor((44.0 - _titleLabel.frame.size.height) / 2.0), _titleLabel.frame.size.width, _titleLabel.frame.size.height); _titleLabel.frame = CGRectMake(screenEdges.left + floor((referenceSize.width - _titleLabel.frame.size.width) / 2.0), screenEdges.top + floor((44.0 - _titleLabel.frame.size.height) / 2.0), _titleLabel.frame.size.width, _titleLabel.frame.size.height);
_subtitleLabel.frame = CGRectMake(screenEdges.left + floor((referenceSize.width - _subtitleLabel.frame.size.width) / 2.0), screenEdges.bottom - 56.0 - buttonSize.height - subtitleSize.height - 8.0, subtitleSize.width, subtitleSize.height); _subtitleLabel.frame = CGRectMake(screenEdges.left + floor((referenceSize.width - _subtitleLabel.frame.size.width) / 2.0), screenEdges.bottom - 56.0 - buttonSize.height - subtitleSize.height - 16.0, subtitleSize.width, subtitleSize.height);
_cancelButton.frame = CGRectMake(screenEdges.left + 16.0, screenEdges.top + floor((44.0 - _cancelButton.frame.size.height) / 2.0), _cancelButton.frame.size.width, _cancelButton.frame.size.height); _cancelButton.frame = CGRectMake(screenEdges.left + 16.0, screenEdges.top + floor((44.0 - _cancelButton.frame.size.height) / 2.0), _cancelButton.frame.size.width, _cancelButton.frame.size.height);

View File

@ -1145,6 +1145,11 @@
return _intent & (TGPhotoEditorControllerSuggestedAvatarIntent); return _intent & (TGPhotoEditorControllerSuggestedAvatarIntent);
} }
- (bool)presentedForSuggestingAvatar
{
return _intent & (TGPhotoEditorControllerSuggestingAvatarIntent);
}
#pragma mark - Transition #pragma mark - Transition
- (void)transitionIn - (void)transitionIn
@ -1317,7 +1322,7 @@
TGPhotoEditorBackButton backButtonType = TGPhotoEditorBackButtonCancel; TGPhotoEditorBackButton backButtonType = TGPhotoEditorBackButtonCancel;
TGPhotoEditorDoneButton doneButtonType = TGPhotoEditorDoneButtonCheck; TGPhotoEditorDoneButton doneButtonType = TGPhotoEditorDoneButtonCheck;
if ([self presentedForSuggestedAvatar]) { if ([self presentedForSuggestedAvatar] && !_item.isVideo) {
[_portraitToolbarView setCancelDoneButtonsHidden:tab == TGPhotoEditorCropTab animated:!isInitialAppearance]; [_portraitToolbarView setCancelDoneButtonsHidden:tab == TGPhotoEditorCropTab animated:!isInitialAppearance];
} }
@ -1336,7 +1341,7 @@
{ {
bool skipInitialTransition = (![self presentedFromCamera] && self.navigationController != nil) || self.skipInitialTransition; bool skipInitialTransition = (![self presentedFromCamera] && self.navigationController != nil) || self.skipInitialTransition;
TGPhotoAvatarPreviewController *cropController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView isForum:[self presentedForForumAvatarCreation] isSuggestion:[self presentedForSuggestedAvatar] senderName:self.senderName]; TGPhotoAvatarPreviewController *cropController = [[TGPhotoAvatarPreviewController alloc] initWithContext:_context photoEditor:_photoEditor previewView:_previewView isForum:[self presentedForForumAvatarCreation] isSuggestion:[self presentedForSuggestedAvatar] isSuggesting:[self presentedForSuggestingAvatar] senderName:self.senderName];
cropController.stickersContext = _stickersContext; cropController.stickersContext = _stickersContext;
cropController.scrubberView = _scrubberView; cropController.scrubberView = _scrubberView;
cropController.dotImageView = _dotImageView; cropController.dotImageView = _dotImageView;

View File

@ -545,18 +545,18 @@
if (hidden) { if (hidden) {
_cancelButton.modernHighlight = false; _cancelButton.modernHighlight = false;
} }
_cancelButton.hidden = false; // _cancelButton.hidden = false;
_doneButton.hidden = false; _doneButton.hidden = false;
[UIView animateWithDuration:0.2f [UIView animateWithDuration:0.2f
animations:^ animations:^
{ {
_cancelButton.alpha = targetAlpha; // _cancelButton.alpha = targetAlpha;
_doneButton.alpha = targetAlpha; _doneButton.alpha = targetAlpha;
} completion:^(__unused BOOL finished) } completion:^(__unused BOOL finished)
{ {
_animatingCancelDoneButtons = false; _animatingCancelDoneButtons = false;
_cancelButton.hidden = hidden; // _cancelButton.hidden = hidden;
_doneButton.hidden = hidden; _doneButton.hidden = hidden;
if (hidden) { if (hidden) {
@ -571,9 +571,9 @@
} }
else else
{ {
_cancelButton.alpha = targetAlpha; // _cancelButton.alpha = targetAlpha;
_doneButton.alpha = targetAlpha; _doneButton.alpha = targetAlpha;
_cancelButton.hidden = hidden; // _cancelButton.hidden = hidden;
_doneButton.hidden = hidden; _doneButton.hidden = hidden;
} }
} }

View File

@ -17,9 +17,7 @@
id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager]; id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager];
id<TGMediaEditableItem> editableItem; id<TGMediaEditableItem> editableItem;
if (image != nil) { if (video != nil) {
editableItem = image;
} else if (video != nil) {
if (![video.path.lowercaseString hasSuffix:@".mp4"]) { if (![video.path.lowercaseString hasSuffix:@".mp4"]) {
NSString *tmpPath = NSTemporaryDirectory(); NSString *tmpPath = NSTemporaryDirectory();
int64_t fileId = 0; int64_t fileId = 0;
@ -31,6 +29,8 @@
} }
editableItem = [[TGCameraCapturedVideo alloc] initWithURL:video]; editableItem = [[TGCameraCapturedVideo alloc] initWithURL:video];
} else if (image != nil) {
editableItem = image;
} }
void (^present)(UIImage *) = ^(UIImage *screenImage) { void (^present)(UIImage *) = ^(UIImage *screenImage) {

View File

@ -23,7 +23,7 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
present(legacyController, nil) present(legacyController, nil)
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: false, hasDeleteButton: false, hasViewButton: openCurrent != nil, personalPhoto: true, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup, forum: false, title: nil)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: false, hasDeleteButton: false, hasViewButton: openCurrent != nil, personalPhoto: true, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup, forum: false, title: nil, isSuggesting: false)!
let _ = holder.swap(mixin) let _ = holder.swap(mixin)
mixin.didFinishWithImage = { image in mixin.didFinishWithImage = { image in
guard let image = image else { guard let image = image else {
@ -53,21 +53,36 @@ public func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, t
} }
public func legacyAvatarEditor(context: AccountContext, media: AnyMediaReference, transitionView: UIView?, senderName: String? = nil, present: @escaping (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments) -> Void) { public func legacyAvatarEditor(context: AccountContext, media: AnyMediaReference, transitionView: UIView?, senderName: String? = nil, present: @escaping (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments) -> Void) {
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media) let isVideo = !((media.media as? TelegramMediaImage)?.videoRepresentations.isEmpty ?? true)
|> deliverOnMainQueue).start(next: { (value, isImage) in
guard case let .data(data) = value, data.complete else { let imageSignal = fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media, forceVideo: false)
return |> map { (value, _) -> (UIImage?, Bool) in
if case let .data(data) = value, data.complete {
return (UIImage(contentsOfFile: data.path), true)
} else {
return (nil, false)
}
} }
var image: UIImage? let videoSignal = isVideo ? fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media, forceVideo: true)
var url: URL? |> map { (value, isImage) -> (URL?, Bool) in
if let maybeImage = UIImage(contentsOfFile: data.path) { if case let .data(data) = value, data.complete && !isImage {
image = maybeImage return (URL(fileURLWithPath: data.path), true)
} else if data.complete { } else {
url = URL(fileURLWithPath: data.path) return (nil, false)
}
} : .single((nil, true))
let signals = combineLatest(queue: Queue.mainQueue(),
imageSignal,
videoSignal
)
|> filter { image, video in
return image.1 && video.1
} }
if image == nil && url == nil { let _ = signals.start(next: { image, video in
if image.0 == nil && video.0 == nil {
return return
} }
@ -92,7 +107,7 @@ public func legacyAvatarEditor(context: AccountContext, media: AnyMediaReference
present(legacyController, nil) present(legacyController, nil)
TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image, video: url, stickersContext: paintStickersContext, transitionView: transitionView, senderName: senderName, didFinishWithImage: { image in TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image.0, video: video.0, stickersContext: paintStickersContext, transitionView: transitionView, senderName: senderName, didFinishWithImage: { image in
if let image = image { if let image = image {
imageCompletion(image) imageCompletion(image)
} }

View File

@ -518,6 +518,7 @@ private let fadeWidth: CGFloat = 70.0
public final class PeerInfoAvatarListContainerNode: ASDisplayNode { public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
private let isSettings: Bool
public var peer: Peer? public var peer: Peer?
public let controlsContainerNode: ASDisplayNode public let controlsContainerNode: ASDisplayNode
@ -648,8 +649,9 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
self.playerUpdateTimer = nil self.playerUpdateTimer = nil
} }
public init(context: AccountContext) { public init(context: AccountContext, isSettings: Bool = false) {
self.context = context self.context = context
self.isSettings = isSettings
self.contentNode = ASDisplayNode() self.contentNode = ASDisplayNode()
@ -780,8 +782,10 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
self.controlsContainerNode.addSubnode(self.stripContainerNode) self.controlsContainerNode.addSubnode(self.stripContainerNode)
self.controlsClippingNode.addSubnode(self.controlsContainerNode) self.controlsClippingNode.addSubnode(self.controlsContainerNode)
self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode) self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode)
if self.isSettings {
self.stripContainerNode.addSubnode(self.setByYouNode) self.stripContainerNode.addSubnode(self.setByYouNode)
self.stripContainerNode.addSubnode(self.setByYouImageNode) self.stripContainerNode.addSubnode(self.setByYouImageNode)
}
self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {

View File

@ -15,14 +15,17 @@ public enum FetchMediaDataState {
case data(MediaResourceData) case data(MediaResourceData)
} }
public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal<(FetchMediaDataState, Bool), NoError> { public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference, forceVideo: Bool = false) -> Signal<(FetchMediaDataState, Bool), NoError> {
var resource: MediaResource? var resource: MediaResource?
var isImage = true var isImage = true
var fileExtension: String? var fileExtension: String?
var userContentType: MediaResourceUserContentType = .other var userContentType: MediaResourceUserContentType = .other
if let image = mediaReference.media as? TelegramMediaImage { if let image = mediaReference.media as? TelegramMediaImage {
userContentType = .image userContentType = .image
if let representation = largestImageRepresentation(image.representations) { if let video = image.videoRepresentations.first, forceVideo {
resource = video.resource
isImage = false
} else if let representation = largestImageRepresentation(image.representations) {
resource = representation.resource resource = representation.resource
} }
} else if let file = mediaReference.media as? TelegramMediaFile { } else if let file = mediaReference.media as? TelegramMediaFile {

View File

@ -627,8 +627,8 @@ public func privacyAndSecurityController(
hasTwoStepAuth: Bool? = nil, hasTwoStepAuth: Bool? = nil,
loginEmailPattern: Signal<String?, NoError>? = nil, loginEmailPattern: Signal<String?, NoError>? = nil,
updatedTwoStepAuthData: (() -> Void)? = nil, updatedTwoStepAuthData: (() -> Void)? = nil,
requestPublicPhotoSetup: (() -> Void)? = nil, requestPublicPhotoSetup: ((@escaping (UIImage?) -> Void) -> Void)? = nil,
requestPublicPhotoRemove: (() -> Void)? = nil requestPublicPhotoRemove: ((@escaping () -> Void) -> Void)? = nil
) -> ViewController { ) -> ViewController {
let statePromise = ValuePromise(PrivacyAndSecurityControllerState(), ignoreRepeated: true) let statePromise = ValuePromise(PrivacyAndSecurityControllerState(), ignoreRepeated: true)
let stateValue = Atomic(value: PrivacyAndSecurityControllerState()) let stateValue = Atomic(value: PrivacyAndSecurityControllerState())
@ -819,10 +819,10 @@ public func privacyAndSecurityController(
|> deliverOnMainQueue |> deliverOnMainQueue
currentInfoDisposable.set(signal.start(next: { [weak currentInfoDisposable] info in currentInfoDisposable.set(signal.start(next: { [weak currentInfoDisposable] info in
if let info = info { if let info = info {
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .profilePhoto, current: info.profilePhoto, requestPublicPhotoSetup: { pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .profilePhoto, current: info.profilePhoto, requestPublicPhotoSetup: { completion in
requestPublicPhotoSetup?() requestPublicPhotoSetup?(completion)
}, requestPublicPhotoRemove: { }, requestPublicPhotoRemove: { completion in
requestPublicPhotoRemove?() requestPublicPhotoRemove?(completion)
}, updated: { updated, _, _ in }, updated: { updated, _, _ in
if let currentInfoDisposable = currentInfoDisposable { if let currentInfoDisposable = currentInfoDisposable {
let applySetting: Signal<Void, NoError> = privacySettingsPromise.get() let applySetting: Signal<Void, NoError> = privacySettingsPromise.get()

View File

@ -106,7 +106,7 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case nobody(PresentationTheme, String, Bool) case nobody(PresentationTheme, String, Bool)
case settingInfo(PresentationTheme, String, String) case settingInfo(PresentationTheme, String, String)
case setPublicPhoto(PresentationTheme, String) case setPublicPhoto(PresentationTheme, String)
case removePublicPhoto(PresentationTheme, String, EnginePeer, TelegramMediaImage?) case removePublicPhoto(PresentationTheme, String, EnginePeer, TelegramMediaImage?, UIImage?)
case publicPhotoInfo(PresentationTheme, String) case publicPhotoInfo(PresentationTheme, String)
case exceptionsHeader(PresentationTheme, String) case exceptionsHeader(PresentationTheme, String)
case disableFor(PresentationTheme, String, String) case disableFor(PresentationTheme, String, String)
@ -253,8 +253,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .removePublicPhoto(lhsTheme, lhsText, lhsPeer, lhsRep): case let .removePublicPhoto(lhsTheme, lhsText, lhsPeer, lhsRep, lhsImage):
if case let .removePublicPhoto(rhsTheme, rhsText, rhsPeer, rhsRep) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsPeer == rhsPeer, lhsRep == rhsRep { if case let .removePublicPhoto(rhsTheme, rhsText, rhsPeer, rhsRep, rhsImage) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsPeer == rhsPeer, lhsRep == rhsRep, lhsImage === rhsImage {
return true return true
} else { } else {
return false return false
@ -415,8 +415,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addPhotoIcon(theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addPhotoIcon(theme), title: text, sectionId: self.section, height: .generic, color: .accent, editing: false, action: {
arguments.setPublicPhoto?() arguments.setPublicPhoto?()
}) })
case let .removePublicPhoto(_, text, peer, image): case let .removePublicPhoto(_, text, peer, image, completeImage):
return ItemListPeerActionItem(presentationData: presentationData, icon: nil, iconSignal: peerAvatarCompleteImage(account: arguments.context.account, peer: peer, forceProvidedRepresentation: true, representation: image?.representationForDisplayAtSize(PixelDimensions(width: 28, height: 28)), size: CGSize(width: 28.0, height: 28.0)), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: completeImage, iconSignal: completeImage == nil ? peerAvatarCompleteImage(account: arguments.context.account, peer: peer, forceProvidedRepresentation: true, representation: image?.representationForDisplayAtSize(PixelDimensions(width: 28, height: 28)), size: CGSize(width: 28.0, height: 28.0)) : nil, title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: {
arguments.removePublicPhoto?() arguments.removePublicPhoto?()
}) })
case let .publicPhotoInfo(_, text): case let .publicPhotoInfo(_, text):
@ -499,7 +499,9 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
let callIntegrationEnabled: Bool? let callIntegrationEnabled: Bool?
let phoneDiscoveryEnabled: Bool? let phoneDiscoveryEnabled: Bool?
init(setting: SelectivePrivacySettingType, enableFor: [PeerId: SelectivePrivacyPeer], disableFor: [PeerId: SelectivePrivacyPeer], saving: Bool, callDataSaving: VoiceCallDataSaving?, callP2PMode: SelectivePrivacySettingType?, callP2PEnableFor: [PeerId: SelectivePrivacyPeer]?, callP2PDisableFor: [PeerId: SelectivePrivacyPeer]?, callIntegrationAvailable: Bool?, callIntegrationEnabled: Bool?, phoneDiscoveryEnabled: Bool?) { let uploadedPhoto: UIImage?
init(setting: SelectivePrivacySettingType, enableFor: [PeerId: SelectivePrivacyPeer], disableFor: [PeerId: SelectivePrivacyPeer], saving: Bool, callDataSaving: VoiceCallDataSaving?, callP2PMode: SelectivePrivacySettingType?, callP2PEnableFor: [PeerId: SelectivePrivacyPeer]?, callP2PDisableFor: [PeerId: SelectivePrivacyPeer]?, callIntegrationAvailable: Bool?, callIntegrationEnabled: Bool?, phoneDiscoveryEnabled: Bool?, uploadedPhoto: UIImage?) {
self.setting = setting self.setting = setting
self.enableFor = enableFor self.enableFor = enableFor
self.disableFor = disableFor self.disableFor = disableFor
@ -511,6 +513,7 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
self.callIntegrationAvailable = callIntegrationAvailable self.callIntegrationAvailable = callIntegrationAvailable
self.callIntegrationEnabled = callIntegrationEnabled self.callIntegrationEnabled = callIntegrationEnabled
self.phoneDiscoveryEnabled = phoneDiscoveryEnabled self.phoneDiscoveryEnabled = phoneDiscoveryEnabled
self.uploadedPhoto = uploadedPhoto
} }
static func ==(lhs: SelectivePrivacySettingsControllerState, rhs: SelectivePrivacySettingsControllerState) -> Bool { static func ==(lhs: SelectivePrivacySettingsControllerState, rhs: SelectivePrivacySettingsControllerState) -> Bool {
@ -547,44 +550,51 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
if lhs.phoneDiscoveryEnabled != rhs.phoneDiscoveryEnabled { if lhs.phoneDiscoveryEnabled != rhs.phoneDiscoveryEnabled {
return false return false
} }
if lhs.uploadedPhoto !== rhs.uploadedPhoto {
return false
}
return true return true
} }
func withUpdatedSetting(_ setting: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState { func withUpdatedSetting(_ setting: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState { func withUpdatedEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState { func withUpdatedDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedSaving(_ saving: Bool) -> SelectivePrivacySettingsControllerState { func withUpdatedSaving(_ saving: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedCallP2PMode(_ mode: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState { func withUpdatedCallP2PMode(_ mode: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: mode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: mode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedCallP2PEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState { func withUpdatedCallP2PEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: enableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: enableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedCallP2PDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState { func withUpdatedCallP2PDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: disableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: disableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedCallsIntegrationEnabled(_ enabled: Bool) -> SelectivePrivacySettingsControllerState { func withUpdatedCallsIntegrationEnabled(_ enabled: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: enabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: enabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
} }
func withUpdatedPhoneDiscoveryEnabled(_ phoneDiscoveryEnabled: Bool) -> SelectivePrivacySettingsControllerState { func withUpdatedPhoneDiscoveryEnabled(_ phoneDiscoveryEnabled: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: phoneDiscoveryEnabled) return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: phoneDiscoveryEnabled, uploadedPhoto: self.uploadedPhoto)
}
func withUpdatedUploadedPhoto(_ uploadedPhoto: UIImage?) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled, uploadedPhoto: uploadedPhoto)
} }
} }
@ -680,7 +690,7 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
if case .profilePhoto = kind, let peer = peer, state.setting != .everybody { if case .profilePhoto = kind, let peer = peer, state.setting != .everybody {
if let publicPhoto = publicPhoto { if let publicPhoto = publicPhoto {
entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_UpdatePublicPhoto)) entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_UpdatePublicPhoto))
entries.append(.removePublicPhoto(presentationData.theme, !publicPhoto.videoRepresentations.isEmpty ? presentationData.strings.Privacy_ProfilePhoto_RemovePublicVideo : presentationData.strings.Privacy_ProfilePhoto_RemovePublicPhoto, peer, publicPhoto)) entries.append(.removePublicPhoto(presentationData.theme, !publicPhoto.videoRepresentations.isEmpty ? presentationData.strings.Privacy_ProfilePhoto_RemovePublicVideo : presentationData.strings.Privacy_ProfilePhoto_RemovePublicPhoto, peer, publicPhoto, state.uploadedPhoto))
} else { } else {
entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_SetPublicPhoto)) entries.append(.setPublicPhoto(presentationData.theme, presentationData.strings.Privacy_ProfilePhoto_SetPublicPhoto))
} }
@ -738,8 +748,8 @@ func selectivePrivacySettingsController(
phoneDiscoveryEnabled: Bool? = nil, phoneDiscoveryEnabled: Bool? = nil,
voipConfiguration: VoipConfiguration? = nil, voipConfiguration: VoipConfiguration? = nil,
callIntegrationAvailable: Bool? = nil, callIntegrationAvailable: Bool? = nil,
requestPublicPhotoSetup: (() -> Void)? = nil, requestPublicPhotoSetup: ((@escaping (UIImage?) -> Void) -> Void)? = nil,
requestPublicPhotoRemove: (() -> Void)? = nil, requestPublicPhotoRemove: ((@escaping () -> Void) -> Void)? = nil,
updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?, Bool?) -> Void updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?, Bool?) -> Void
) -> ViewController { ) -> ViewController {
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
@ -771,7 +781,7 @@ func selectivePrivacySettingsController(
} }
} }
let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, disableFor: initialDisableFor, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration, phoneDiscoveryEnabled: phoneDiscoveryEnabled) let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, disableFor: initialDisableFor, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration, phoneDiscoveryEnabled: phoneDiscoveryEnabled, uploadedPhoto: nil)
let statePromise = ValuePromise(initialState, ignoreRepeated: true) let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState) let stateValue = Atomic(value: initialState)
@ -1036,9 +1046,28 @@ func selectivePrivacySettingsController(
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}, setPublicPhoto: { }, setPublicPhoto: {
requestPublicPhotoSetup?() requestPublicPhotoSetup?({ result in
var result = result
if let image = result {
result = generateImage(CGSize(width: 28.0, height: 28.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
context.addPath(CGPath(ellipseIn: CGRect(origin: .zero, size: size), transform: nil))
context.clip()
if let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
}
}, opaque: false)
}
updateState { state in
return state.withUpdatedUploadedPhoto(result)
}
})
}, removePublicPhoto: { }, removePublicPhoto: {
requestPublicPhotoRemove?() requestPublicPhotoRemove?({
updateState { state in
return state.withUpdatedUploadedPhoto(nil)
}
})
}) })
let peer = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) let peer = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
@ -1082,7 +1111,7 @@ func selectivePrivacySettingsController(
title = presentationData.strings.Privacy_VoiceMessages title = presentationData.strings.Privacy_VoiceMessages
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber, peer: peer, publicPhoto: publicPhoto), style: .blocks, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber, peer: peer, publicPhoto: publicPhoto), style: .blocks, animateChanges: true)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@ -6165,7 +6165,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
// return controller // return controller
// } // }
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: peerId.namespace == Namespaces.Peer.CloudUser, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos && !fromGallery, hasViewButton: false, personalPhoto: peerId.namespace == Namespaces.Peer.CloudUser, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)!
mixin.forceDark = true mixin.forceDark = true
mixin.stickersContext = paintStickersContext mixin.stickersContext = paintStickersContext
let _ = strongSelf.currentAvatarMixin.swap(mixin) let _ = strongSelf.currentAvatarMixin.swap(mixin)

View File

@ -185,6 +185,9 @@ private class ExtendedMediaOverlayNode: ASDisplayNode {
private var maskView: UIView? private var maskView: UIView?
private var maskLayer: CAShapeLayer? private var maskLayer: CAShapeLayer?
var isRevealed = false
var tapped: () -> Void = {}
override init() { override init() {
self.blurredImageNode = TransformImageNode() self.blurredImageNode = TransformImageNode()
@ -252,6 +255,12 @@ private class ExtendedMediaOverlayNode: ASDisplayNode {
self.maskLayer = maskLayer self.maskLayer = maskLayer
} }
func reveal() {
self.blurredImageNode.removeFromSupernode()
self.dustNode.removeFromSupernode()
self.isUserInteractionEnabled = false
}
func update(size: CGSize, text: String, imageSignal: (Signal<(TransformImageArguments) -> DrawingContext?, NoError>, CGSize, CGSize)?, imageFrame: CGRect, corners: ImageCorners?) { func update(size: CGSize, text: String, imageSignal: (Signal<(TransformImageArguments) -> DrawingContext?, NoError>, CGSize, CGSize)?, imageFrame: CGRect, corners: ImageCorners?) {
let spacing: CGFloat = 2.0 let spacing: CGFloat = 2.0
let padding: CGFloat = 10.0 let padding: CGFloat = 10.0
@ -268,9 +277,13 @@ private class ExtendedMediaOverlayNode: ASDisplayNode {
self.isUserInteractionEnabled = !self.dustNode.isRevealed self.isUserInteractionEnabled = !self.dustNode.isRevealed
self.dustNode.revealed = { [weak self] in self.dustNode.revealed = { [weak self] in
self?.isRevealed = true
self?.blurredImageNode.removeFromSupernode() self?.blurredImageNode.removeFromSupernode()
self?.isUserInteractionEnabled = false self?.isUserInteractionEnabled = false
} }
self.dustNode.tapped = { [weak self] in
self?.tapped()
}
} else { } else {
self.blurredImageNode.isHidden = true self.blurredImageNode.isHidden = true
self.isUserInteractionEnabled = false self.isUserInteractionEnabled = false
@ -377,8 +390,16 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
var visibilityPromise = ValuePromise<Bool>(false, ignoreRepeated: true) var visibilityPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
var visibility: Bool = false { var visibility: Bool = false {
didSet { didSet {
self.updateVisibility()
}
}
private var internallyVisible = true
private func updateVisibility() {
let visibility = self.visibility && self.internallyVisible
if let videoNode = self.videoNode { if let videoNode = self.videoNode {
if self.visibility { if visibility {
if !videoNode.canAttachContent { if !videoNode.canAttachContent {
videoNode.canAttachContent = true videoNode.canAttachContent = true
if videoNode.hasAttachedContext { if videoNode.hasAttachedContext {
@ -389,9 +410,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
videoNode.canAttachContent = false videoNode.canAttachContent = false
} }
} }
self.animatedStickerNode?.visibility = self.visibility self.animatedStickerNode?.visibility = visibility
self.visibilityPromise.set(self.visibility) self.visibilityPromise.set(visibility)
}
} }
var activateLocalContent: (InteractiveMediaNodeActivateContent) -> Void = { _ in } var activateLocalContent: (InteractiveMediaNodeActivateContent) -> Void = { _ in }
@ -1034,6 +1054,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
updateImageSignal = { synchronousLoad, _ in updateImageSignal = { synchronousLoad, _ in
return mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile, autoFetchFullSizeThumbnail: true) return mediaGridMessageVideo(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile, autoFetchFullSizeThumbnail: true)
} }
updateBlurredImageSignal = { synchronousLoad, _ in
return chatSecretMessageVideo(account: context.account, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file))
}
} }
} }
@ -1319,6 +1342,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} }
if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }), strongSelf.extendedMediaOverlayNode == nil {
strongSelf.internallyVisible = false
}
if let videoNode = strongSelf.videoNode { if let videoNode = strongSelf.videoNode {
if !(replaceVideoNode ?? false), let decoration = videoNode.decoration as? ChatBubbleVideoDecoration, decoration.corners != corners { if !(replaceVideoNode ?? false), let decoration = videoNode.decoration as? ChatBubbleVideoDecoration, decoration.corners != corners {
decoration.updateCorners(corners) decoration.updateCorners(corners)
@ -1327,7 +1355,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
videoNode.updateLayout(size: arguments.drawingSize, transition: .immediate) videoNode.updateLayout(size: arguments.drawingSize, transition: .immediate)
videoNode.frame = CGRect(origin: CGPoint(), size: imageFrame.size) videoNode.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
if strongSelf.visibility { if strongSelf.visibility && strongSelf.internallyVisible {
if !videoNode.canAttachContent { if !videoNode.canAttachContent {
videoNode.canAttachContent = true videoNode.canAttachContent = true
if videoNode.hasAttachedContext { if videoNode.hasAttachedContext {
@ -1892,6 +1920,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if displaySpoiler { if displaySpoiler {
if self.extendedMediaOverlayNode == nil { if self.extendedMediaOverlayNode == nil {
let extendedMediaOverlayNode = ExtendedMediaOverlayNode() let extendedMediaOverlayNode = ExtendedMediaOverlayNode()
extendedMediaOverlayNode.tapped = { [weak self] in
self?.internallyVisible = true
self?.updateVisibility()
}
self.extendedMediaOverlayNode = extendedMediaOverlayNode self.extendedMediaOverlayNode = extendedMediaOverlayNode
self.pinchContainerNode.contentNode.insertSubnode(extendedMediaOverlayNode, aboveSubnode: self.imageNode) self.pinchContainerNode.contentNode.insertSubnode(extendedMediaOverlayNode, aboveSubnode: self.imageNode)
} }
@ -1979,6 +2011,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
func updateIsHidden(_ isHidden: Bool) { func updateIsHidden(_ isHidden: Bool) {
if isHidden && !self.internallyVisible {
self.internallyVisible = true
self.updateVisibility()
self.extendedMediaOverlayNode?.reveal()
}
if let badgeNode = self.badgeNode, badgeNode.isHidden != isHidden { if let badgeNode = self.badgeNode, badgeNode.isHidden != isHidden {
if isHidden { if isHidden {
badgeNode.isHidden = true badgeNode.isHidden = true

View File

@ -14,6 +14,9 @@ import TelegramStringFormatting
import WallpaperBackgroundNode import WallpaperBackgroundNode
import ReactionSelectionNode import ReactionSelectionNode
import PhotoResources import PhotoResources
import UniversalMediaPlayer
import TelegramUniversalVideoContent
import GalleryUI
class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode { class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode {
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode? private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
@ -22,6 +25,10 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
private let subtitleNode: TextNode private let subtitleNode: TextNode
private let imageNode: TransformImageNode private let imageNode: TransformImageNode
fileprivate var videoNode: UniversalVideoNode?
private var videoContent: NativeVideoContent?
private var videoStartTimestamp: Double?
private let buttonNode: HighlightTrackingButtonNode private let buttonNode: HighlightTrackingButtonNode
private let buttonStarsNode: PremiumStarsNode private let buttonStarsNode: PremiumStarsNode
private let buttonTitleNode: TextNode private let buttonTitleNode: TextNode
@ -195,6 +202,7 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
if let strongSelf = self { if let strongSelf = self {
strongSelf.item = item strongSelf.item = item
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - imageSize.width) / 2.0), y: 13.0), size: imageSize)
if let photo = photo { if let photo = photo {
if mediaUpdated { if mediaUpdated {
strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: photo), displayAtSize: nil, storeToDownloadsPeerType: nil).start()) strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: photo), displayAtSize: nil, storeToDownloadsPeerType: nil).start())
@ -207,11 +215,49 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
let apply = makeImageLayout(arguments) let apply = makeImageLayout(arguments)
apply() apply()
strongSelf.imageNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - imageSize.width) / 2.0), y: 13.0), size: imageSize) strongSelf.imageNode.frame = imageFrame
} }
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize) if let photo = photo, let video = photo.videoRepresentations.last, let id = photo.id?.id {
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0) let videoFileReference = FileMediaReference.message(message: MessageReference(item.message), media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: photo.representations, videoThumbnails: [], immediateThumbnailData: photo.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id, "action"), userLocation: .peer(item.message.id.peerId), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
if videoContent.id != strongSelf.videoContent?.id {
let mediaManager = item.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .secondaryOverlay)
videoNode.isUserInteractionEnabled = false
videoNode.ownsContentNodeUpdated = { [weak self] owns in
if let strongSelf = self {
strongSelf.videoNode?.isHidden = !owns
}
}
strongSelf.videoContent = videoContent
strongSelf.videoNode = videoNode
videoNode.updateLayout(size: imageSize, transition: .immediate)
videoNode.frame = imageFrame
videoNode.clipsToBounds = true
videoNode.cornerRadius = imageFrame.width / 2.0
strongSelf.addSubnode(videoNode)
videoNode.canAttachContent = true
if let videoStartTimestamp = video.startTimestamp {
videoNode.seek(videoStartTimestamp)
} else {
videoNode.seek(0.0)
}
videoNode.play()
}
} else if let videoNode = strongSelf.videoNode {
strongSelf.videoContent = nil
strongSelf.videoNode = nil
videoNode.removeFromSupernode()
}
let backgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize)
let mediaBackgroundFrame = backgroundFrame.insetBy(dx: -2.0, dy: -2.0)
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate) strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)

View File

@ -454,7 +454,7 @@ public func createChannelController(context: AccountContext) -> ViewController {
} }
} }
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)!
let _ = currentAvatarMixin.swap(mixin) let _ = currentAvatarMixin.swap(mixin)
mixin.requestSearchController = { assetsController in mixin.requestSearchController = { assetsController in
let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in

View File

@ -727,7 +727,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
} }
} }
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: stateValue.with({ $0.avatar }) != nil, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: false, title: nil, isSuggesting: false)!
let _ = currentAvatarMixin.swap(mixin) let _ = currentAvatarMixin.swap(mixin)
mixin.requestSearchController = { assetsController in mixin.requestSearchController = { assetsController in
let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: title, completion: { result in

View File

@ -919,7 +919,7 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context) self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context)
self.listContainerTransformNode = ASDisplayNode() self.listContainerTransformNode = ASDisplayNode()
self.listContainerNode = PeerInfoAvatarListContainerNode(context: context) self.listContainerNode = PeerInfoAvatarListContainerNode(context: context, isSettings: isSettings)
self.listContainerNode.clipsToBounds = true self.listContainerNode.clipsToBounds = true
self.listContainerNode.isHidden = true self.listContainerNode.isHidden = true

View File

@ -2878,7 +2878,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, sourceCorners: .round, remoteEntries: entriesPromise, skipInitial: true, centralEntryIndex: centralEntry.flatMap { entries.firstIndex(of: $0) }, replaceRootController: { controller, ready in let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, sourceCorners: .round, remoteEntries: entriesPromise, skipInitial: true, centralEntryIndex: centralEntry.flatMap { entries.firstIndex(of: $0) }, replaceRootController: { controller, ready in
}) })
galleryController.openAvatarSetup = { [weak self] completion in galleryController.openAvatarSetup = { [weak self] completion in
self?.openAvatarForEditing(fromGallery: true, completion: completion) self?.openAvatarForEditing(fromGallery: true, completion: { _ in
completion()
})
} }
galleryController.avatarPhotoEditCompletion = { [weak self] image in galleryController.avatarPhotoEditCompletion = { [weak self] image in
self?.updateProfilePhoto(image, mode: .generic) self?.updateProfilePhoto(image, mode: .generic)
@ -6810,8 +6812,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
dismissStatus = { [weak statusController] in dismissStatus = { [weak statusController] in
statusController?.dismiss() statusController?.dismiss()
} }
if let topController = self.controller?.navigationController?.topViewController as? ViewController {
topController.presentInGlobalOverlay(statusController)
} else {
self.controller?.presentInGlobalOverlay(statusController) self.controller?.presentInGlobalOverlay(statusController)
} }
}
self.updateAvatarDisposable.set((signal self.updateAvatarDisposable.set((signal
|> deliverOnMainQueue).start(next: { [weak self] result in |> deliverOnMainQueue).start(next: { [weak self] result in
@ -6976,8 +6982,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
dismissStatus = { [weak statusController] in dismissStatus = { [weak statusController] in
statusController?.dismiss() statusController?.dismiss()
} }
if let topController = self.controller?.navigationController?.topViewController as? ViewController {
topController.presentInGlobalOverlay(statusController)
} else {
self.controller?.presentInGlobalOverlay(statusController) self.controller?.presentInGlobalOverlay(statusController)
} }
}
let peerId = self.peerId let peerId = self.peerId
let isSettings = self.isSettings let isSettings = self.isSettings
@ -7048,7 +7058,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
})) }))
} }
fileprivate func openAvatarForEditing(mode: PeerInfoAvatarEditingMode = .generic, fromGallery: Bool = false, completion: @escaping () -> Void = {}) { fileprivate func openAvatarForEditing(mode: PeerInfoAvatarEditingMode = .generic, fromGallery: Bool = false, completion: @escaping (UIImage?) -> Void = { _ in }) {
guard let peer = self.data?.peer, mode != .generic || canEditPeerInfo(context: self.context, peer: peer, chatLocation: self.chatLocation, threadData: self.data?.threadData) else { guard let peer = self.data?.peer, mode != .generic || canEditPeerInfo(context: self.context, peer: peer, chatLocation: self.chatLocation, threadData: self.data?.threadData) else {
return return
} }
@ -7141,7 +7151,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
confirmationAction = nil confirmationAction = nil
} }
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasDeleteButton, hasViewButton: false, personalPhoto: strongSelf.isSettings, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum, title: title)! let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasDeleteButton, hasViewButton: false, personalPhoto: strongSelf.isSettings, isVideo: currentIsVideo, saveEditedPhotos: false, saveCapturedMedia: false, signup: false, forum: isForum, title: title, isSuggesting: mode == .suggest)!
mixin.stickersContext = paintStickersContext mixin.stickersContext = paintStickersContext
let _ = strongSelf.currentAvatarMixin.swap(mixin) let _ = strongSelf.currentAvatarMixin.swap(mixin)
mixin.requestSearchController = { [weak self] assetsController in mixin.requestSearchController = { [weak self] assetsController in
@ -7156,7 +7166,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
(strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller) (strongSelf.controller?.navigationController?.topViewController as? ViewController)?.push(controller)
if fromGallery { if fromGallery {
completion() completion(nil)
} }
} }
if let confirmationTextPhoto, let confirmationAction { if let confirmationTextPhoto, let confirmationAction {
@ -7181,13 +7191,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
mixin.didFinishWithImage = { [weak self] image in mixin.didFinishWithImage = { [weak self] image in
if let image = image { if let image = image {
completion() completion(image)
self?.updateProfilePhoto(image, mode: mode) self?.updateProfilePhoto(image, mode: mode)
} }
} }
mixin.didFinishWithVideo = { [weak self] image, asset, adjustments in mixin.didFinishWithVideo = { [weak self] image, asset, adjustments in
if let image = image, let asset = asset { if let image = image, let asset = asset {
completion() completion(image)
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode) self?.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode)
} }
} }
@ -7214,12 +7224,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}) })
} }
fileprivate func openAvatarRemoval(mode: PeerInfoAvatarEditingMode, peer: EnginePeer? = nil, item: PeerInfoAvatarListItem? = nil) { fileprivate func openAvatarRemoval(mode: PeerInfoAvatarEditingMode, peer: EnginePeer? = nil, item: PeerInfoAvatarListItem? = nil, completion: @escaping () -> Void = {}) {
let proceed = { [weak self] in let proceed = { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
completion()
if let item = item { if let item = item {
strongSelf.deleteProfilePhoto(item) strongSelf.deleteProfilePhoto(item)
} }
@ -7392,13 +7404,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
) )
} }
}, requestPublicPhotoSetup: { [weak self] in }, requestPublicPhotoSetup: { [weak self] completion in
if let strongSelf = self { if let strongSelf = self {
strongSelf.openAvatarForEditing(mode: .fallback) strongSelf.openAvatarForEditing(mode: .fallback, completion: completion)
} }
}, requestPublicPhotoRemove: { [weak self] in }, requestPublicPhotoRemove: { [weak self] completion in
if let strongSelf = self { if let strongSelf = self {
strongSelf.openAvatarRemoval(mode: .fallback) strongSelf.openAvatarRemoval(mode: .fallback, completion: completion)
} }
})) }))
} }